From 69b8354f8d444415bdbb2587fa1ac5e60822164f Mon Sep 17 00:00:00 2001 From: Mushaheed Syed Date: Tue, 12 Aug 2025 04:34:08 +0530 Subject: [PATCH 1/4] Add jetpack javascript engine --- .../javascript_android/analysis_options.yaml | 3 + .../javascript_android/android/build.gradle | 10 +- .../android/src/main/cxx/CMakeLists.txt | 48 - .../javascript_android/Messages.kt | 162 + .../javascript_android/JavaScriptAndroid.kt | 107 + .../javascript_android/JavaScriptPlugin.kt | 23 +- .../javascript_android/Messages.kt | 655 + .../javascript/javascript_android/cxx/ffi.cpp | 417 - .../javascript/javascript_android/cxx/ffi.h | 137 - .../javascript_android/cxx/prebuild.sh | 22 - .../javascript_android/cxx/quickjs.cmake | 21 - .../cxx/quickjs/.github/workflows/ci.yml | 286 - .../javascript_android/cxx/quickjs/.gitignore | 31 - .../javascript_android/cxx/quickjs/Changelog | 206 - .../javascript_android/cxx/quickjs/LICENSE | 22 - .../javascript_android/cxx/quickjs/Makefile | 537 - .../javascript_android/cxx/quickjs/TODO | 66 - .../javascript_android/cxx/quickjs/VERSION | 1 - .../cxx/quickjs/compat/test-closefrom.c | 6 - .../javascript_android/cxx/quickjs/cutils.c | 633 - .../javascript_android/cxx/quickjs/cutils.h | 423 - .../cxx/quickjs/doc/quickjs.texi | 1071 - .../javascript_android/cxx/quickjs/dtoa.c | 1620 - .../javascript_android/cxx/quickjs/dtoa.h | 83 - .../cxx/quickjs/examples/fib.c | 72 - .../cxx/quickjs/examples/fib_module.js | 10 - .../cxx/quickjs/examples/hello.js | 1 - .../cxx/quickjs/examples/hello_module.js | 8 - .../cxx/quickjs/examples/message.json | 2 - .../cxx/quickjs/examples/pi_bigint.js | 118 - .../cxx/quickjs/examples/point.c | 151 - .../cxx/quickjs/examples/test_fib.js | 6 - .../cxx/quickjs/examples/test_point.js | 40 - .../cxx/quickjs/fuzz/README | 27 - .../cxx/quickjs/fuzz/fuzz.dict | 254 - .../cxx/quickjs/fuzz/fuzz_common.c | 58 - .../cxx/quickjs/fuzz/fuzz_common.h | 22 - .../cxx/quickjs/fuzz/fuzz_compile.c | 93 - .../cxx/quickjs/fuzz/fuzz_eval.c | 49 - .../cxx/quickjs/fuzz/fuzz_regexp.c | 66 - .../cxx/quickjs/fuzz/generate_dict.js | 24 - .../cxx/quickjs/libregexp-opcode.h | 67 - .../cxx/quickjs/libregexp.c | 3259 - .../cxx/quickjs/libregexp.h | 61 - .../cxx/quickjs/libunicode-table.h | 5149 -- .../cxx/quickjs/libunicode.c | 2123 - .../cxx/quickjs/libunicode.h | 186 - .../javascript_android/cxx/quickjs/list.h | 99 - .../javascript_android/cxx/quickjs/qjs.c | 551 - .../javascript_android/cxx/quickjs/qjsc.c | 873 - .../cxx/quickjs/quickjs-atom.h | 270 - .../cxx/quickjs/quickjs-libc.c | 4342 -- .../cxx/quickjs/quickjs-libc.h | 66 - .../cxx/quickjs/quickjs-opcode.h | 370 - .../javascript_android/cxx/quickjs/quickjs.c | 55899 ---------------- .../javascript_android/cxx/quickjs/quickjs.h | 1166 - .../cxx/quickjs/readme-cosmo.txt | 21 - .../javascript_android/cxx/quickjs/readme.txt | 1 - .../javascript_android/cxx/quickjs/release.sh | 184 - .../javascript_android/cxx/quickjs/repl.js | 1292 - .../cxx/quickjs/run-test262.c | 2261 - .../cxx/quickjs/test262.conf | 344 - .../cxx/quickjs/test262o.conf | 413 - .../cxx/quickjs/tests/assert.js | 43 - .../cxx/quickjs/tests/bjson.c | 96 - .../quickjs/tests/fixture_cyclic_import.js | 2 - .../cxx/quickjs/tests/microbench.js | 1490 - .../cxx/quickjs/tests/test262.patch | 135 - .../cxx/quickjs/tests/test_bigint.js | 249 - .../cxx/quickjs/tests/test_bjson.js | 177 - .../cxx/quickjs/tests/test_builtin.js | 1167 - .../cxx/quickjs/tests/test_closure.js | 221 - .../cxx/quickjs/tests/test_cyclic_import.js | 12 - .../cxx/quickjs/tests/test_language.js | 654 - .../cxx/quickjs/tests/test_loop.js | 402 - .../cxx/quickjs/tests/test_std.js | 336 - .../cxx/quickjs/tests/test_worker.js | 62 - .../cxx/quickjs/tests/test_worker_module.js | 32 - .../cxx/quickjs/unicode_download.sh | 23 - .../cxx/quickjs/unicode_gen.c | 3779 -- .../cxx/quickjs/unicode_gen_def.h | 318 - .../javascript_android/cxx/revision | 1 - .../javascript_android/cxx/update.sh | 10 - .../lib/javascript_android.dart | 91 +- .../lib/src/engine_context.dart | 17 + .../lib/src/pigeons/messages.pigeon.dart | 146 + .../lib/src/scripts/messaging.dart | 48 + .../lib/src/third_party/flutter_qjs/LICENSE | 21 - .../flutter_qjs/lib/flutter_qjs.dart | 13 - .../flutter_qjs/lib/src/engine.dart | 182 - .../third_party/flutter_qjs/lib/src/ffi.dart | 1011 - .../flutter_qjs/lib/src/isolate.dart | 291 - .../flutter_qjs/lib/src/object.dart | 314 - .../flutter_qjs/lib/src/wrapper.dart | 249 - .../lib/src/third_party/vendor-state.yaml | 13 - .../lib/src/user_scripts.dart | 5 + .../lib/weak_reference_utils.dart | 34 - .../javascript_android/pigeons/copyright.txt | 1 + .../javascript_android/pigeons/schema.dart | 31 + .../javascript_android/pubspec.yaml | 2 - .../javascript/javascript_android/vendor.yaml | 26 - 101 files changed, 1251 insertions(+), 97041 deletions(-) delete mode 100644 packages/javascript/javascript_android/android/src/main/cxx/CMakeLists.txt create mode 100644 packages/javascript/javascript_android/android/src/main/java/org/reclaimprotocol/javascript_android/Messages.kt create mode 100644 packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptAndroid.kt create mode 100644 packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/Messages.kt delete mode 100644 packages/javascript/javascript_android/cxx/ffi.cpp delete mode 100644 packages/javascript/javascript_android/cxx/ffi.h delete mode 100644 packages/javascript/javascript_android/cxx/prebuild.sh delete mode 100644 packages/javascript/javascript_android/cxx/quickjs.cmake delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/.github/workflows/ci.yml delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/.gitignore delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/Changelog delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/LICENSE delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/Makefile delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/TODO delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/VERSION delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/compat/test-closefrom.c delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/cutils.c delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/cutils.h delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/doc/quickjs.texi delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/dtoa.c delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/dtoa.h delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/examples/fib.c delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/examples/fib_module.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/examples/hello.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/examples/hello_module.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/examples/message.json delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/examples/pi_bigint.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/examples/point.c delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/examples/test_fib.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/examples/test_point.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/fuzz/README delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz.dict delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_common.c delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_common.h delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_compile.c delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_eval.c delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_regexp.c delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/fuzz/generate_dict.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/libregexp-opcode.h delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/libregexp.c delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/libregexp.h delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/libunicode-table.h delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/libunicode.c delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/libunicode.h delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/list.h delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/qjs.c delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/qjsc.c delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/quickjs-atom.h delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/quickjs-libc.c delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/quickjs-libc.h delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/quickjs-opcode.h delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/quickjs.c delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/quickjs.h delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/readme-cosmo.txt delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/readme.txt delete mode 100755 packages/javascript/javascript_android/cxx/quickjs/release.sh delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/repl.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/run-test262.c delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/test262.conf delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/test262o.conf delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/tests/assert.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/tests/bjson.c delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/tests/fixture_cyclic_import.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/tests/microbench.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/tests/test262.patch delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/tests/test_bigint.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/tests/test_bjson.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/tests/test_builtin.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/tests/test_closure.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/tests/test_cyclic_import.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/tests/test_language.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/tests/test_loop.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/tests/test_std.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/tests/test_worker.js delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/tests/test_worker_module.js delete mode 100755 packages/javascript/javascript_android/cxx/quickjs/unicode_download.sh delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/unicode_gen.c delete mode 100644 packages/javascript/javascript_android/cxx/quickjs/unicode_gen_def.h delete mode 100644 packages/javascript/javascript_android/cxx/revision delete mode 100755 packages/javascript/javascript_android/cxx/update.sh create mode 100644 packages/javascript/javascript_android/lib/src/engine_context.dart create mode 100644 packages/javascript/javascript_android/lib/src/pigeons/messages.pigeon.dart create mode 100644 packages/javascript/javascript_android/lib/src/scripts/messaging.dart delete mode 100644 packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/LICENSE delete mode 100644 packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/flutter_qjs.dart delete mode 100644 packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/engine.dart delete mode 100644 packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/ffi.dart delete mode 100644 packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/isolate.dart delete mode 100644 packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/object.dart delete mode 100644 packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/wrapper.dart delete mode 100644 packages/javascript/javascript_android/lib/src/third_party/vendor-state.yaml create mode 100644 packages/javascript/javascript_android/lib/src/user_scripts.dart delete mode 100644 packages/javascript/javascript_android/lib/weak_reference_utils.dart create mode 100644 packages/javascript/javascript_android/pigeons/copyright.txt create mode 100644 packages/javascript/javascript_android/pigeons/schema.dart delete mode 100644 packages/javascript/javascript_android/vendor.yaml diff --git a/packages/javascript/javascript_android/analysis_options.yaml b/packages/javascript/javascript_android/analysis_options.yaml index f9b3034..31674fe 100644 --- a/packages/javascript/javascript_android/analysis_options.yaml +++ b/packages/javascript/javascript_android/analysis_options.yaml @@ -1 +1,4 @@ include: package:flutter_lints/flutter.yaml +analyzer: + errors: + constant_identifier_names: ignore diff --git a/packages/javascript/javascript_android/android/build.gradle b/packages/javascript/javascript_android/android/build.gradle index efa29ba..d9c9628 100644 --- a/packages/javascript/javascript_android/android/build.gradle +++ b/packages/javascript/javascript_android/android/build.gradle @@ -29,13 +29,6 @@ android { jvmTarget = '1.8' } - externalNativeBuild { - cmake { - path "src/main/cxx/CMakeLists.txt" - version "4.0.2" - } - } - sourceSets { main.java.srcDirs += 'src/main/kotlin' test.java.srcDirs += 'src/test/kotlin' @@ -48,6 +41,9 @@ android { dependencies { testImplementation 'org.jetbrains.kotlin:kotlin-test' testImplementation 'org.mockito:mockito-core:5.0.0' + + implementation "androidx.javascriptengine:javascriptengine:1.0.0" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.6.0"` } testOptions { diff --git a/packages/javascript/javascript_android/android/src/main/cxx/CMakeLists.txt b/packages/javascript/javascript_android/android/src/main/cxx/CMakeLists.txt deleted file mode 100644 index dbba15f..0000000 --- a/packages/javascript/javascript_android/android/src/main/cxx/CMakeLists.txt +++ /dev/null @@ -1,48 +0,0 @@ -# For more information about using CMake with Android Studio, read the -# documentation: https://d.android.com/studio/projects/add-native-code.html - -# Sets the minimum version of CMake required to build the native library. - -cmake_minimum_required(VERSION 4.0.1) -project(qjs) -set(JNI_LIB_NAME qjs) - -# Creates and names a library, sets it as either STATIC -# or SHARED, and provides the relative paths to its source code. -# You can define multiple libraries, and CMake builds them for you. -# Gradle automatically packages shared libraries with your APK. - -include("${CMAKE_CURRENT_SOURCE_DIR}/../../../../cxx/quickjs.cmake") - -add_library( # Sets the name of the library. - ${JNI_LIB_NAME} - - # Sets the library as a shared library. - SHARED - - # Provides a relative path to your source file(s). - ${CXX_LIB_DIR}/ffi.cpp ) - -# Searches for a specified prebuilt library and stores the path as a -# variable. Because CMake includes system libraries in the search path by -# default, you only need to specify the name of the public NDK library -# you want to add. CMake verifies that the library exists before -# completing its build. - -find_library( # Sets the name of the path variable. - log-lib - - # Specifies the name of the NDK library that - # you want CMake to locate. - log ) - -# Specifies libraries CMake should link to your target library. You -# can link multiple libraries, such as libraries you define in this -# build script, prebuilt third-party libraries, or system libraries. - -target_link_libraries( # Specifies the target library. - ${JNI_LIB_NAME} - quickjs - # Links the target library to the log library - # included in the NDK. - ${log-lib} ) \ No newline at end of file diff --git a/packages/javascript/javascript_android/android/src/main/java/org/reclaimprotocol/javascript_android/Messages.kt b/packages/javascript/javascript_android/android/src/main/java/org/reclaimprotocol/javascript_android/Messages.kt new file mode 100644 index 0000000..6cc0435 --- /dev/null +++ b/packages/javascript/javascript_android/android/src/main/java/org/reclaimprotocol/javascript_android/Messages.kt @@ -0,0 +1,162 @@ +// Copyright 2025, Reclaim Protocol. Use of this source code is governed by a license that can be found in the LICENSE file. +// Autogenerated from Pigeon (v26.0.0), do not edit directly. +// See also: https://pub.dev/packages/pigeon +@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") + +package org.reclaimprotocol.javascript_android + +import android.util.Log +import io.flutter.plugin.common.BasicMessageChannel +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.EventChannel +import io.flutter.plugin.common.MessageCodec +import io.flutter.plugin.common.StandardMethodCodec +import io.flutter.plugin.common.StandardMessageCodec +import java.io.ByteArrayOutputStream +import java.nio.ByteBuffer +private object MessagesPigeonUtils { + + fun wrapResult(result: Any?): List { + return listOf(result) + } + + fun wrapError(exception: Throwable): List { + return if (exception is FlutterError) { + listOf( + exception.code, + exception.message, + exception.details + ) + } else { + listOf( + exception.javaClass.simpleName, + exception.toString(), + "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception) + ) + } + } +} + +/** + * Error class for passing custom error details to Flutter via a thrown PlatformException. + * @property code The error code. + * @property message The error message. + * @property details The error details. Must be a datatype supported by the api codec. + */ +class FlutterError ( + val code: String, + override val message: String? = null, + val details: Any? = null +) : Throwable() +private open class MessagesPigeonCodec : StandardMessageCodec() { + override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { + return super.readValueOfType(type, buffer) + } + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { + super.writeValue(stream, value) + } +} + + +/** + * Apis implemented by the Reclaim module for use by the host. + * + * Generated interface from Pigeon that represents a handler of messages from Flutter. + */ +interface JavaScriptAndroidPlatformApi { + fun startJavaScriptEngine(javascriptEngineId: String, callback: (Result) -> Unit) + fun dispose(javascriptEngineId: String, callback: (Result) -> Unit) + fun runJavaScriptReturningResult(javascriptEngineId: String, javaScript: String, callback: (Result) -> Unit) + fun setIsInspectable(javascriptEngineId: String, isInspectable: Boolean, callback: (Result) -> Unit) + + companion object { + /** The codec used by JavaScriptAndroidPlatformApi. */ + val codec: MessageCodec by lazy { + MessagesPigeonCodec() + } + /** Sets up an instance of `JavaScriptAndroidPlatformApi` to handle messages through the `binaryMessenger`. */ + @JvmOverloads + fun setUp(binaryMessenger: BinaryMessenger, api: JavaScriptAndroidPlatformApi?, messageChannelSuffix: String = "") { + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.startJavaScriptEngine$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val javascriptEngineIdArg = args[0] as String + api.startJavaScriptEngine(javascriptEngineIdArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(MessagesPigeonUtils.wrapError(error)) + } else { + reply.reply(MessagesPigeonUtils.wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.dispose$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val javascriptEngineIdArg = args[0] as String + api.dispose(javascriptEngineIdArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(MessagesPigeonUtils.wrapError(error)) + } else { + reply.reply(MessagesPigeonUtils.wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.runJavaScriptReturningResult$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val javascriptEngineIdArg = args[0] as String + val javaScriptArg = args[1] as String + api.runJavaScriptReturningResult(javascriptEngineIdArg, javaScriptArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(MessagesPigeonUtils.wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(MessagesPigeonUtils.wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.setIsInspectable$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val javascriptEngineIdArg = args[0] as String + val isInspectableArg = args[1] as Boolean + api.setIsInspectable(javascriptEngineIdArg, isInspectableArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(MessagesPigeonUtils.wrapError(error)) + } else { + reply.reply(MessagesPigeonUtils.wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + } + } +} diff --git a/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptAndroid.kt b/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptAndroid.kt new file mode 100644 index 0000000..4d4542d --- /dev/null +++ b/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptAndroid.kt @@ -0,0 +1,107 @@ +package org.reclaimprotocol.javascript_android + +import android.util.Log +import androidx.core.content.ContextCompat +import androidx.javascriptengine.IsolateStartupParameters +import androidx.javascriptengine.IsolateTerminatedException +import androidx.javascriptengine.JavaScriptException +import androidx.javascriptengine.JavaScriptIsolate +import androidx.javascriptengine.JavaScriptSandbox +import com.google.common.util.concurrent.FutureCallback +import com.google.common.util.concurrent.Futures +import com.google.common.util.concurrent.ListenableFuture +import java.util.concurrent.TimeUnit + + +class JavaScriptAndroid(private var applicationContext: android.content.Context) : + JavaScriptAndroidPlatformApi { + companion object { + private const val TAG = "JavaScriptAndroid" + + private var sandbox: ListenableFuture? = null + + + } + + private fun getJSSandbox(): ListenableFuture { + val s = sandbox ?: JavaScriptSandbox.createConnectedInstanceAsync(applicationContext) + sandbox = s + return s + } + + private val activeJsIsolates = mutableMapOf() + + override fun startJavaScriptEngine( + javascriptEngineId: String, callback: (Result) -> Unit + ) { + try { + val sandboxFuture = getJSSandbox() + val executor = ContextCompat.getMainExecutor(applicationContext) + Futures.transform(sandboxFuture, { sandbox -> + val startupParams = IsolateStartupParameters() + if (sandbox.isFeatureSupported(JavaScriptSandbox.JS_FEATURE_ISOLATE_MAX_HEAP_SIZE)) { + startupParams.setMaxHeapSizeBytes(100000000) + } + val jsIsolate = sandbox.createIsolate(startupParams) + activeJsIsolates.put(javascriptEngineId, jsIsolate) + callback(Result.success(Unit)) + }, executor) + } catch (e: Exception) { + callback(Result.failure(e)) + } + } + + fun requireJsIsolateById(javascriptEngineId: String): JavaScriptIsolate { + val jsIsolate = activeJsIsolates[javascriptEngineId] + if (jsIsolate == null) { + throw IllegalStateException("No active isolate with id $javascriptEngineId") + } + return jsIsolate + } + + override fun dispose( + javascriptEngineId: String, callback: (Result) -> Unit + ) { + try { + val js = requireJsIsolateById(javascriptEngineId) + js.close() + activeJsIsolates.remove(javascriptEngineId) + callback(Result.success(Unit)) + } catch (e: Exception) { + if (e is IsolateTerminatedException) { + // its okay + callback(Result.success(Unit)) + } else { + callback(Result.failure(e)) + } + } + } + + override fun runJavaScriptReturningResult( + javascriptEngineId: String, javaScript: String, callback: (Result) -> Unit + ) { + try { + val js = requireJsIsolateById(javascriptEngineId) + + val result = js.evaluateJavaScriptAsync(javaScript).get(10, TimeUnit.MINUTES) + + Log.i("JavaScriptAndroid", "result: $result") + callback(Result.success(result)) + } catch (e: Exception) { + callback(Result.failure(e)) + } + } + + override fun setIsInspectable( + javascriptEngineId: String, isInspectable: Boolean, callback: (Result) -> Unit + ) { + try { + requireJsIsolateById(javascriptEngineId) + // unsupported + callback(Result.success(Unit)) + } catch (e: Exception) { + callback(Result.failure(e)) + } + } + +} \ No newline at end of file diff --git a/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptPlugin.kt b/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptPlugin.kt index 76b6111..7d0d4d7 100644 --- a/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptPlugin.kt +++ b/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptPlugin.kt @@ -1,7 +1,10 @@ package org.reclaimprotocol.javascript_android +import android.util.Log import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding +import io.flutter.embedding.engine.plugins.activity.ActivityAware +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding /** * Plugin implementation that uses the new `io.flutter.embedding` package. @@ -10,11 +13,25 @@ import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding * Instantiate this in an add to app scenario to gracefully handle activity and context changes. */ public class JavaScriptPlugin : FlutterPlugin { - override fun onAttachedToEngine(binding: FlutterPluginBinding) {} + private var javaScriptAndroid: JavaScriptAndroid? = null - override fun onDetachedFromEngine(binding: FlutterPluginBinding) {} + override fun onAttachedToEngine(binding: FlutterPluginBinding) { + val api = JavaScriptAndroid(binding.applicationContext) + javaScriptAndroid = api + JavaScriptAndroidPlatformApi.setUp(binding.binaryMessenger, api) + } + + override fun onDetachedFromEngine(binding: FlutterPluginBinding) { + if (javaScriptAndroid == null) { + Log.wtf(TAG, "Already detached from the engine.") + return + } + + JavaScriptAndroidPlatformApi.setUp(binding.binaryMessenger, null) + javaScriptAndroid = null + } companion object { - private const val TAG = "JavaScriptPlugin" + private const val TAG = "UrlLauncherPlugin" } } \ No newline at end of file diff --git a/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/Messages.kt b/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/Messages.kt new file mode 100644 index 0000000..2bc9c86 --- /dev/null +++ b/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/Messages.kt @@ -0,0 +1,655 @@ +// Copyright 2025, Reclaim Protocol. Use of this source code is governed by a license that can be found in the LICENSE file. +// Autogenerated from Pigeon (v26.0.0), do not edit directly. +// See also: https://pub.dev/packages/pigeon +@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") + +package org.reclaimprotocol.javascript_android + +import android.util.Log +import io.flutter.plugin.common.BasicMessageChannel +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.EventChannel +import io.flutter.plugin.common.MessageCodec +import io.flutter.plugin.common.StandardMethodCodec +import io.flutter.plugin.common.StandardMessageCodec +import java.io.ByteArrayOutputStream +import java.nio.ByteBuffer +private object MessagesPigeonUtils { + + fun createConnectionError(channelName: String): FlutterError { + return FlutterError("channel-error", "Unable to establish connection on channel: '$channelName'.", "") } + + fun wrapResult(result: Any?): List { + return listOf(result) + } + + fun wrapError(exception: Throwable): List { + return if (exception is FlutterError) { + listOf( + exception.code, + exception.message, + exception.details + ) + } else { + listOf( + exception.javaClass.simpleName, + exception.toString(), + "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception) + ) + } + } +} + +/** + * Error class for passing custom error details to Flutter via a thrown PlatformException. + * @property code The error code. + * @property message The error message. + * @property details The error details. Must be a datatype supported by the api codec. + */ +class FlutterError ( + val code: String, + override val message: String? = null, + val details: Any? = null +) : Throwable() +/** + * Maintains instances used to communicate with the corresponding objects in Dart. + * + * Objects stored in this container are represented by an object in Dart that is also stored in + * an InstanceManager with the same identifier. + * + * When an instance is added with an identifier, either can be used to retrieve the other. + * + * Added instances are added as a weak reference and a strong reference. When the strong + * reference is removed with [remove] and the weak reference is deallocated, the + * `finalizationListener.onFinalize` is called with the instance's identifier. However, if the strong + * reference is removed and then the identifier is retrieved with the intention to pass the identifier + * to Dart (e.g. calling [getIdentifierForStrongReference]), the strong reference to the instance + * is recreated. The strong reference will then need to be removed manually again. + */ +@Suppress("UNCHECKED_CAST", "MemberVisibilityCanBePrivate") +class MessagesPigeonInstanceManager(private val finalizationListener: PigeonFinalizationListener) { + /** Interface for listening when a weak reference of an instance is removed from the manager. */ + interface PigeonFinalizationListener { + fun onFinalize(identifier: Long) + } + + private val identifiers = java.util.WeakHashMap() + private val weakInstances = HashMap>() + private val strongInstances = HashMap() + private val referenceQueue = java.lang.ref.ReferenceQueue() + private val weakReferencesToIdentifiers = HashMap, Long>() + private val handler = android.os.Handler(android.os.Looper.getMainLooper()) + private val releaseAllFinalizedInstancesRunnable = Runnable { + this.releaseAllFinalizedInstances() + } + private var nextIdentifier: Long = minHostCreatedIdentifier + private var hasFinalizationListenerStopped = false + + /** + * Modifies the time interval used to define how often this instance removes garbage collected + * weak references to native Android objects that this instance was managing. + */ + var clearFinalizedWeakReferencesInterval: Long = 3000 + set(value) { + handler.removeCallbacks(releaseAllFinalizedInstancesRunnable) + field = value + releaseAllFinalizedInstances() + } + + init { + handler.postDelayed(releaseAllFinalizedInstancesRunnable, clearFinalizedWeakReferencesInterval) + } + + companion object { + // Identifiers are locked to a specific range to avoid collisions with objects + // created simultaneously from Dart. + // Host uses identifiers >= 2^16 and Dart is expected to use values n where, + // 0 <= n < 2^16. + private const val minHostCreatedIdentifier: Long = 65536 + private const val tag = "PigeonInstanceManager" + + /** + * Instantiate a new manager with a listener for garbage collected weak + * references. + * + * When the manager is no longer needed, [stopFinalizationListener] must be called. + */ + fun create(finalizationListener: PigeonFinalizationListener): MessagesPigeonInstanceManager { + return MessagesPigeonInstanceManager(finalizationListener) + } + } + + /** + * Removes `identifier` and return its associated strongly referenced instance, if present, + * from the manager. + */ + fun remove(identifier: Long): T? { + logWarningIfFinalizationListenerHasStopped() + return strongInstances.remove(identifier) as T? + } + + /** + * Retrieves the identifier paired with an instance, if present, otherwise `null`. + * + * + * If the manager contains a strong reference to `instance`, it will return the identifier + * associated with `instance`. If the manager contains only a weak reference to `instance`, a new + * strong reference to `instance` will be added and will need to be removed again with [remove]. + * + * + * If this method returns a nonnull identifier, this method also expects the Dart + * `MessagesPigeonInstanceManager` to have, or recreate, a weak reference to the Dart instance the + * identifier is associated with. + */ + fun getIdentifierForStrongReference(instance: Any?): Long? { + logWarningIfFinalizationListenerHasStopped() + val identifier = identifiers[instance] + if (identifier != null) { + strongInstances[identifier] = instance!! + } + return identifier + } + + /** + * Adds a new instance that was instantiated from Dart. + * + * The same instance can be added multiple times, but each identifier must be unique. This + * allows two objects that are equivalent (e.g. the `equals` method returns true and their + * hashcodes are equal) to both be added. + * + * [identifier] must be >= 0 and unique. + */ + fun addDartCreatedInstance(instance: Any, identifier: Long) { + logWarningIfFinalizationListenerHasStopped() + addInstance(instance, identifier) + } + + /** + * Adds a new unique instance that was instantiated from the host platform. + * + * If the manager contains [instance], this returns the corresponding identifier. If the + * manager does not contain [instance], this adds the instance and returns a unique + * identifier for that [instance]. + */ + fun addHostCreatedInstance(instance: Any): Long { + logWarningIfFinalizationListenerHasStopped() + require(!containsInstance(instance)) { "Instance of ${instance.javaClass} has already been added." } + val identifier = nextIdentifier++ + addInstance(instance, identifier) + return identifier + } + + /** Retrieves the instance associated with identifier, if present, otherwise `null`. */ + fun getInstance(identifier: Long): T? { + logWarningIfFinalizationListenerHasStopped() + val instance = weakInstances[identifier] as java.lang.ref.WeakReference? + return instance?.get() + } + + /** Returns whether this manager contains the given `instance`. */ + fun containsInstance(instance: Any?): Boolean { + logWarningIfFinalizationListenerHasStopped() + return identifiers.containsKey(instance) + } + + /** + * Stops the periodic run of the [PigeonFinalizationListener] for instances that have been garbage + * collected. + * + * The InstanceManager can continue to be used, but the [PigeonFinalizationListener] will no + * longer be called and methods will log a warning. + */ + fun stopFinalizationListener() { + handler.removeCallbacks(releaseAllFinalizedInstancesRunnable) + hasFinalizationListenerStopped = true + } + + /** + * Removes all of the instances from this manager. + * + * The manager will be empty after this call returns. + */ + fun clear() { + identifiers.clear() + weakInstances.clear() + strongInstances.clear() + weakReferencesToIdentifiers.clear() + } + + /** + * Whether the [PigeonFinalizationListener] is still being called for instances that are garbage + * collected. + * + * See [stopFinalizationListener]. + */ + fun hasFinalizationListenerStopped(): Boolean { + return hasFinalizationListenerStopped + } + + private fun releaseAllFinalizedInstances() { + if (hasFinalizationListenerStopped()) { + return + } + var reference: java.lang.ref.WeakReference? + while ((referenceQueue.poll() as java.lang.ref.WeakReference?).also { reference = it } != null) { + val identifier = weakReferencesToIdentifiers.remove(reference) + if (identifier != null) { + weakInstances.remove(identifier) + strongInstances.remove(identifier) + finalizationListener.onFinalize(identifier) + } + } + handler.postDelayed(releaseAllFinalizedInstancesRunnable, clearFinalizedWeakReferencesInterval) + } + + private fun addInstance(instance: Any, identifier: Long) { + require(identifier >= 0) { "Identifier must be >= 0: $identifier" } + require(!weakInstances.containsKey(identifier)) { + "Identifier has already been added: $identifier" + } + val weakReference = java.lang.ref.WeakReference(instance, referenceQueue) + identifiers[instance] = identifier + weakInstances[identifier] = weakReference + weakReferencesToIdentifiers[weakReference] = identifier + strongInstances[identifier] = instance + } + + private fun logWarningIfFinalizationListenerHasStopped() { + if (hasFinalizationListenerStopped()) { + Log.w( + tag, + "The manager was used after calls to the PigeonFinalizationListener has been stopped." + ) + } + } +} + + +/** Generated API for managing the Dart and native `InstanceManager`s. */ +private class MessagesPigeonInstanceManagerApi(val binaryMessenger: BinaryMessenger) { + companion object { + /** The codec used by MessagesPigeonInstanceManagerApi. */ + val codec: MessageCodec by lazy { + MessagesPigeonCodec() + } + + /** + * Sets up an instance of `MessagesPigeonInstanceManagerApi` to handle messages from the + * `binaryMessenger`. + */ + fun setUpMessageHandlers(binaryMessenger: BinaryMessenger, instanceManager: MessagesPigeonInstanceManager?) { + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.PigeonInternalInstanceManager.removeStrongReference", codec) + if (instanceManager != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val identifierArg = args[0] as Long + val wrapped: List = try { + instanceManager.remove(identifierArg) + listOf(null) + } catch (exception: Throwable) { + MessagesPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.PigeonInternalInstanceManager.clear", codec) + if (instanceManager != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = try { + instanceManager.clear() + listOf(null) + } catch (exception: Throwable) { + MessagesPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + } + } + + fun removeStrongReference(identifierArg: Long, callback: (Result) -> Unit) +{ + val channelName = "dev.flutter.pigeon.javascript_android.PigeonInternalInstanceManager.removeStrongReference" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(identifierArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(MessagesPigeonUtils.createConnectionError(channelName))) + } + } + } +} +/** + * Provides implementations for each ProxyApi implementation and provides access to resources + * needed by any implementation. + */ +abstract class MessagesPigeonProxyApiRegistrar(val binaryMessenger: BinaryMessenger) { + /** Whether APIs should ignore calling to Dart. */ + public var ignoreCallsToDart = false + val instanceManager: MessagesPigeonInstanceManager + private var _codec: MessageCodec? = null + val codec: MessageCodec + get() { + if (_codec == null) { + _codec = MessagesPigeonProxyApiBaseCodec(this) + } + return _codec!! + } + + init { + val api = MessagesPigeonInstanceManagerApi(binaryMessenger) + instanceManager = MessagesPigeonInstanceManager.create( + object : MessagesPigeonInstanceManager.PigeonFinalizationListener { + override fun onFinalize(identifier: Long) { + api.removeStrongReference(identifier) { + if (it.isFailure) { + Log.e( + "PigeonProxyApiRegistrar", + "Failed to remove Dart strong reference with identifier: $identifier" + ) + } + } + } + } + ) + } + /** + * An implementation of [PigeonApiJavaScriptChannel] used to add a new Dart instance of + * `JavaScriptChannel` to the Dart `InstanceManager`. + */ + abstract fun getPigeonApiJavaScriptChannel(): PigeonApiJavaScriptChannel + + fun setUp() { + MessagesPigeonInstanceManagerApi.setUpMessageHandlers(binaryMessenger, instanceManager) + PigeonApiJavaScriptChannel.setUpMessageHandlers(binaryMessenger, getPigeonApiJavaScriptChannel()) + } + fun tearDown() { + MessagesPigeonInstanceManagerApi.setUpMessageHandlers(binaryMessenger, null) + PigeonApiJavaScriptChannel.setUpMessageHandlers(binaryMessenger, null) + } +} +private class MessagesPigeonProxyApiBaseCodec(val registrar: MessagesPigeonProxyApiRegistrar) : MessagesPigeonCodec() { + override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { + return when (type) { + 128.toByte() -> { + val identifier: Long = readValue(buffer) as Long + val instance: Any? = registrar.instanceManager.getInstance(identifier) + if (instance == null) { + Log.e( + "PigeonProxyApiBaseCodec", + "Failed to find instance with identifier: $identifier" + ) + } + return instance + } + else -> super.readValueOfType(type, buffer) + } + } + + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { + if (value is Boolean || value is ByteArray || value is Double || value is DoubleArray || value is FloatArray || value is Int || value is IntArray || value is List<*> || value is Long || value is LongArray || value is Map<*, *> || value is String || value == null) { + super.writeValue(stream, value) + return + } + + if (value is JavaScriptChannel) { + registrar.getPigeonApiJavaScriptChannel().pigeon_newInstance(value) { } + } + + when { + registrar.instanceManager.containsInstance(value) -> { + stream.write(128) + writeValue(stream, registrar.instanceManager.getIdentifierForStrongReference(value)) + } + else -> throw IllegalArgumentException("Unsupported value: '$value' of type '${value.javaClass.name}'") + } + } +} +private open class MessagesPigeonCodec : StandardMessageCodec() { + override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { + return super.readValueOfType(type, buffer) + } + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { + super.writeValue(stream, value) + } +} + + +/** + * A JavaScript interface for exposing Javascript callbacks to Dart. + * + * This is a custom class for the wrapper that is annotated with + * [JavascriptInterface](https://developer.android.com/reference/android/webkit/JavascriptInterface). + */ +@Suppress("UNCHECKED_CAST") +abstract class PigeonApiJavaScriptChannel(open val pigeonRegistrar: MessagesPigeonProxyApiRegistrar) { + abstract fun pigeon_defaultConstructor(channelName: String): JavaScriptChannel + + companion object { + @Suppress("LocalVariableName") + fun setUpMessageHandlers(binaryMessenger: BinaryMessenger, api: PigeonApiJavaScriptChannel?) { + val codec = api?.pigeonRegistrar?.codec ?: MessagesPigeonCodec() + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptChannel.pigeon_defaultConstructor", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pigeon_identifierArg = args[0] as Long + val channelNameArg = args[1] as String + val wrapped: List = try { + api.pigeonRegistrar.instanceManager.addDartCreatedInstance(api.pigeon_defaultConstructor(channelNameArg), pigeon_identifierArg) + listOf(null) + } catch (exception: Throwable) { + MessagesPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + } + } + + @Suppress("LocalVariableName", "FunctionName") + /** Creates a Dart instance of JavaScriptChannel and attaches it to [pigeon_instanceArg]. */ + fun pigeon_newInstance(pigeon_instanceArg: JavaScriptChannel, callback: (Result) -> Unit) +{ + if (pigeonRegistrar.ignoreCallsToDart) { + callback( + Result.failure( + FlutterError("ignore-calls-error", "Calls to Dart are being ignored.", ""))) + } else if (pigeonRegistrar.instanceManager.containsInstance(pigeon_instanceArg)) { + callback(Result.success(Unit)) + } else { + callback( + Result.failure( + FlutterError("new-instance-error", "Attempting to create a new Dart instance of JavaScriptChannel, but the class has a nonnull callback method.", ""))) + } + } + + /** Handles callbacks messages from JavaScript. */ + fun postMessage(pigeon_instanceArg: JavaScriptChannel, messageArg: String?, callback: (Result) -> Unit) +{ + if (pigeonRegistrar.ignoreCallsToDart) { + callback( + Result.failure( + FlutterError("ignore-calls-error", "Calls to Dart are being ignored.", ""))) + return + } + val binaryMessenger = pigeonRegistrar.binaryMessenger + val codec = pigeonRegistrar.codec + val channelName = "dev.flutter.pigeon.javascript_android.JavaScriptChannel.postMessage" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(pigeon_instanceArg, messageArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + val output = it[0] as String? + callback(Result.success(output)) + } + } else { + callback(Result.failure(MessagesPigeonUtils.createConnectionError(channelName))) + } + } + } + +} +/** + * Apis implemented by the Reclaim module for use by the host. + * + * Generated interface from Pigeon that represents a handler of messages from Flutter. + */ +interface JavaScriptAndroidPlatformApi { + fun startJavaScriptEngine(javascriptEngineId: String, callback: (Result) -> Unit) + fun addJavaScriptChannel(javascriptEngineId: String, javaScriptChannelParams: JavaScriptChannel, callback: (Result) -> Unit) + fun dispose(javascriptEngineId: String, callback: (Result) -> Unit) + fun removeJavaScriptChannel(javascriptEngineId: String, javaScriptChannelName: String, callback: (Result) -> Unit) + fun runJavaScriptReturningResult(javascriptEngineId: String, javaScript: String, callback: (Result) -> Unit) + fun setIsInspectable(javascriptEngineId: String, isInspectable: Boolean, callback: (Result) -> Unit) + + companion object { + /** The codec used by JavaScriptAndroidPlatformApi. */ + val codec: MessageCodec by lazy { + MessagesPigeonCodec() + } + /** Sets up an instance of `JavaScriptAndroidPlatformApi` to handle messages through the `binaryMessenger`. */ + @JvmOverloads + fun setUp(binaryMessenger: BinaryMessenger, api: JavaScriptAndroidPlatformApi?, messageChannelSuffix: String = "") { + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.startJavaScriptEngine$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val javascriptEngineIdArg = args[0] as String + api.startJavaScriptEngine(javascriptEngineIdArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(MessagesPigeonUtils.wrapError(error)) + } else { + reply.reply(MessagesPigeonUtils.wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.addJavaScriptChannel$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val javascriptEngineIdArg = args[0] as String + val javaScriptChannelParamsArg = args[1] as JavaScriptChannel + api.addJavaScriptChannel(javascriptEngineIdArg, javaScriptChannelParamsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(MessagesPigeonUtils.wrapError(error)) + } else { + reply.reply(MessagesPigeonUtils.wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.dispose$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val javascriptEngineIdArg = args[0] as String + api.dispose(javascriptEngineIdArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(MessagesPigeonUtils.wrapError(error)) + } else { + reply.reply(MessagesPigeonUtils.wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.removeJavaScriptChannel$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val javascriptEngineIdArg = args[0] as String + val javaScriptChannelNameArg = args[1] as String + api.removeJavaScriptChannel(javascriptEngineIdArg, javaScriptChannelNameArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(MessagesPigeonUtils.wrapError(error)) + } else { + reply.reply(MessagesPigeonUtils.wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.runJavaScriptReturningResult$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val javascriptEngineIdArg = args[0] as String + val javaScriptArg = args[1] as String + api.runJavaScriptReturningResult(javascriptEngineIdArg, javaScriptArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(MessagesPigeonUtils.wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(MessagesPigeonUtils.wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.setIsInspectable$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val javascriptEngineIdArg = args[0] as String + val isInspectableArg = args[1] as Boolean + api.setIsInspectable(javascriptEngineIdArg, isInspectableArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(MessagesPigeonUtils.wrapError(error)) + } else { + reply.reply(MessagesPigeonUtils.wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + } + } +} diff --git a/packages/javascript/javascript_android/cxx/ffi.cpp b/packages/javascript/javascript_android/cxx/ffi.cpp deleted file mode 100644 index 04d91e7..0000000 --- a/packages/javascript/javascript_android/cxx/ffi.cpp +++ /dev/null @@ -1,417 +0,0 @@ -/* - * @Description: - * @Author: ekibun - * @Date: 2020-09-06 18:32:45 - * @LastEditors: ekibun - * @LastEditTime: 2020-12-02 11:11:42 - */ - #include "ffi.h" - #include - #include - #include - - extern "C" - { - - DLLEXPORT JSValue *jsThrow(JSContext *ctx, JSValue *obj) - { - return new JSValue(JS_Throw(ctx, JS_DupValue(ctx, *obj))); - } - - DLLEXPORT JSValue *jsEXCEPTION() - { - return new JSValue(JS_EXCEPTION); - } - - DLLEXPORT JSValue *jsUNDEFINED() - { - return new JSValue(JS_UNDEFINED); - } - - DLLEXPORT JSValue *jsNULL() - { - return new JSValue(JS_NULL); - } - - struct RuntimeOpaque { - JSChannel * channel; - int64_t timeout; - int64_t start; - }; - - JSModuleDef *js_module_loader( - JSContext *ctx, - const char *module_name, void *opaque) - { - const char *str = (char *)((RuntimeOpaque *)opaque)->channel(ctx, JSChannelType_MODULE, (void *)module_name); - if (str == 0) - return NULL; - JSValue func_val = JS_Eval(ctx, str, strlen(str), module_name, JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); - if (JS_IsException(func_val)) - return NULL; - /* the module is already referenced, so we must free it */ - JSModuleDef *m = (JSModuleDef *)JS_VALUE_GET_PTR(func_val); - JS_FreeValue(ctx, func_val); - return m; - } - - JSValue js_channel(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data) - { - JSRuntime *rt = JS_GetRuntime(ctx); - RuntimeOpaque *opaque = (RuntimeOpaque *)JS_GetRuntimeOpaque(rt); - void *data[4]; - data[0] = &this_val; - data[1] = &argc; - data[2] = argv; - data[3] = func_data; - return *(JSValue *)opaque->channel(ctx, JSChannelType_METHON, data); - } - - void js_promise_rejection_tracker(JSContext *ctx, JSValueConst promise, - JSValueConst reason, - JS_BOOL is_handled, void *opaque) - { - if (is_handled) - return; - ((RuntimeOpaque *)opaque)->channel(ctx, JSChannelType_PROMISE_TRACK, &reason); - } - - int js_interrupt_handler(JSRuntime * rt, void * opaque) { - RuntimeOpaque *op = (RuntimeOpaque *)opaque; - if(op->timeout && op->start && (clock() - op->start) > op->timeout * CLOCKS_PER_SEC / 1000) { - op->start = 0; - return 1; - } - return 0; - } - - DLLEXPORT JSRuntime *jsNewRuntime(JSChannel channel, int64_t timeout) - { - JSRuntime *rt = JS_NewRuntime(); - RuntimeOpaque *opaque = new RuntimeOpaque({channel, timeout, 0}); - JS_SetRuntimeOpaque(rt, opaque); - JS_SetHostPromiseRejectionTracker(rt, js_promise_rejection_tracker, opaque); - JS_SetModuleLoaderFunc(rt, nullptr, js_module_loader, opaque); - JS_SetInterruptHandler(rt, js_interrupt_handler, opaque); - return rt; - } - - DLLEXPORT uint32_t jsNewClass(JSContext *ctx, const char *name) - { - JSClassID QJSClassId = 0; - JS_NewClassID(&QJSClassId); - JSRuntime *rt = JS_GetRuntime(ctx); - if (!JS_IsRegisteredClass(rt, QJSClassId)) - { - JSClassDef def{ - name, - // destructor - [](JSRuntime *rt, JSValue obj) noexcept - { - JSClassID classid = JS_GetClassID(obj); - void *opaque = JS_GetOpaque(obj, classid); - RuntimeOpaque *runtimeOpaque = (RuntimeOpaque *)JS_GetRuntimeOpaque(rt); - if (runtimeOpaque == nullptr) - return; - runtimeOpaque->channel((JSContext *)rt, JSChannelType_FREE_OBJECT, opaque); - }}; - int e = JS_NewClass(rt, QJSClassId, &def); - if (e < 0) - { - JS_ThrowInternalError(ctx, "Cant register class %s", name); - return 0; - } - } - return QJSClassId; - } - - DLLEXPORT void *jsGetObjectOpaque(JSValue *obj, uint32_t classid) - { - return JS_GetOpaque(*obj, classid); - } - - DLLEXPORT JSValue *jsNewObjectClass(JSContext *ctx, uint32_t QJSClassId, void *opaque) - { - auto jsobj = new JSValue(JS_NewObjectClass(ctx, QJSClassId)); - if (JS_IsException(*jsobj)) - return jsobj; - JS_SetOpaque(*jsobj, opaque); - return jsobj; - } - - DLLEXPORT void jsSetMaxStackSize(JSRuntime *rt, size_t stack_size) - { - JS_SetMaxStackSize(rt, stack_size); - } - - DLLEXPORT void jsSetMemoryLimit(JSRuntime *rt, size_t limit) - { - JS_SetMemoryLimit(rt, limit); - } - - DLLEXPORT void jsFreeRuntime(JSRuntime *rt) - { - RuntimeOpaque *opauqe = (RuntimeOpaque *)JS_GetRuntimeOpaque(rt); - if (opauqe) - delete opauqe; - JS_SetRuntimeOpaque(rt, nullptr); - JS_FreeRuntime(rt); - } - - DLLEXPORT JSValue *jsNewCFunction(JSContext *ctx, JSValue *funcData) - { - return new JSValue(JS_NewCFunctionData(ctx, js_channel, 0, 0, 1, funcData)); - } - - DLLEXPORT JSContext *jsNewContext(JSRuntime *rt) - { - JS_UpdateStackTop(rt); - JSContext *ctx = JS_NewContext(rt); - return ctx; - } - - DLLEXPORT void jsFreeContext(JSContext *ctx) - { - JS_FreeContext(ctx); - } - - DLLEXPORT JSRuntime *jsGetRuntime(JSContext *ctx) - { - return JS_GetRuntime(ctx); - } - - void js_begin_call(JSRuntime *rt) { - JS_UpdateStackTop(rt); - RuntimeOpaque * opaque = (RuntimeOpaque *)JS_GetRuntimeOpaque(rt); - if(opaque) opaque->start = clock(); - } - - DLLEXPORT JSValue *jsEval(JSContext *ctx, const char *input, size_t input_len, const char *filename, int32_t eval_flags) - { - JSRuntime *rt = JS_GetRuntime(ctx); - js_begin_call(rt); - JSValue *ret = new JSValue(JS_Eval(ctx, input, input_len, filename, eval_flags)); - return ret; - } - - DLLEXPORT int32_t jsValueGetTag(JSValue *val) - { - return JS_VALUE_GET_TAG(*val); - } - - DLLEXPORT void *jsValueGetPtr(JSValue *val) - { - return JS_VALUE_GET_PTR(*val); - } - - DLLEXPORT int32_t jsTagIsFloat64(int32_t tag) - { - return JS_TAG_IS_FLOAT64(tag); - } - - DLLEXPORT JSValue *jsNewBool(JSContext *ctx, int32_t val) - { - return new JSValue(JS_NewBool(ctx, val)); - } - - DLLEXPORT JSValue *jsNewInt64(JSContext *ctx, int64_t val) - { - return new JSValue(JS_NewInt64(ctx, val)); - } - - DLLEXPORT JSValue *jsNewFloat64(JSContext *ctx, double val) - { - return new JSValue(JS_NewFloat64(ctx, val)); - } - - DLLEXPORT JSValue *jsNewString(JSContext *ctx, const char *str) - { - return new JSValue(JS_NewString(ctx, str)); - } - - DLLEXPORT JSValue *jsNewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len) - { - return new JSValue(JS_NewArrayBufferCopy(ctx, buf, len)); - } - - DLLEXPORT JSValue *jsNewArray(JSContext *ctx) - { - return new JSValue(JS_NewArray(ctx)); - } - - DLLEXPORT JSValue *jsNewObject(JSContext *ctx) - { - return new JSValue(JS_NewObject(ctx)); - } - - DLLEXPORT void jsFreeValue(JSContext *ctx, JSValue *v, int32_t free) - { - JS_FreeValue(ctx, *v); - if (free) - delete v; - } - - DLLEXPORT void jsFreeValueRT(JSRuntime *rt, JSValue *v, int32_t free) - { - JS_FreeValueRT(rt, *v); - if (free) - delete v; - } - - DLLEXPORT JSValue *jsDupValue(JSContext *ctx, JSValueConst *v) - { - return new JSValue(JS_DupValue(ctx, *v)); - } - - DLLEXPORT JSValue *jsDupValueRT(JSRuntime *rt, JSValue *v) - { - return new JSValue(JS_DupValueRT(rt, *v)); - } - - DLLEXPORT int32_t jsToBool(JSContext *ctx, JSValueConst *val) - { - return JS_ToBool(ctx, *val); - } - - DLLEXPORT int64_t jsToInt64(JSContext *ctx, JSValueConst *val) - { - int64_t p; - JS_ToInt64(ctx, &p, *val); - return p; - } - - DLLEXPORT double jsToFloat64(JSContext *ctx, JSValueConst *val) - { - double p; - JS_ToFloat64(ctx, &p, *val); - return p; - } - - DLLEXPORT const char *jsToCString(JSContext *ctx, JSValueConst *val) - { - JSRuntime *rt = JS_GetRuntime(ctx); - js_begin_call(rt); - const char *ret = JS_ToCString(ctx, *val); - return ret; - } - - DLLEXPORT void jsFreeCString(JSContext *ctx, const char *ptr) - { - return JS_FreeCString(ctx, ptr); - } - - DLLEXPORT uint8_t *jsGetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst *obj) - { - return JS_GetArrayBuffer(ctx, psize, *obj); - } - - DLLEXPORT int32_t jsIsFunction(JSContext *ctx, JSValueConst *val) - { - return JS_IsFunction(ctx, *val); - } - - // DLLEXPORT int32_t jsIsPromise(JSContext *ctx, JSValueConst *val) - // { - // return JS_IsPromise(ctx, *val); - // } - - DLLEXPORT int32_t jsIsArray(JSContext *ctx, JSValueConst *val) - { - return JS_IsArray(ctx, *val); - } - - DLLEXPORT int32_t jsIsError(JSContext *ctx, JSValueConst *val) - { - return JS_IsError(ctx, *val); - } - - DLLEXPORT JSValue *jsNewError(JSContext *ctx) - { - return new JSValue(JS_NewError(ctx)); - } - - DLLEXPORT JSValue *jsGetProperty(JSContext *ctx, JSValueConst *this_obj, - JSAtom prop) - { - return new JSValue(JS_GetProperty(ctx, *this_obj, prop)); - } - - DLLEXPORT int32_t jsDefinePropertyValue(JSContext *ctx, JSValueConst *this_obj, - JSAtom prop, JSValue *val, int32_t flags) - { - return JS_DefinePropertyValue(ctx, *this_obj, prop, *val, flags); - } - - DLLEXPORT void jsFreeAtom(JSContext *ctx, JSAtom v) - { - JS_FreeAtom(ctx, v); - } - - DLLEXPORT JSAtom jsValueToAtom(JSContext *ctx, JSValueConst *val) - { - return JS_ValueToAtom(ctx, *val); - } - - DLLEXPORT JSValue *jsAtomToValue(JSContext *ctx, JSAtom val) - { - return new JSValue(JS_AtomToValue(ctx, val)); - } - - DLLEXPORT int32_t jsGetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, - uint32_t *plen, JSValueConst *obj, int32_t flags) - { - return JS_GetOwnPropertyNames(ctx, ptab, plen, *obj, flags); - } - - DLLEXPORT JSAtom jsPropertyEnumGetAtom(JSPropertyEnum *ptab, int32_t i) - { - return ptab[i].atom; - } - - DLLEXPORT uint32_t sizeOfJSValue() - { - return sizeof(JSValue); - } - - DLLEXPORT void setJSValueList(JSValue *list, uint32_t i, JSValue *val) - { - list[i] = *val; - } - - DLLEXPORT JSValue *jsCall(JSContext *ctx, JSValueConst *func_obj, JSValueConst *this_obj, - int32_t argc, JSValueConst *argv) - { - JSRuntime *rt = JS_GetRuntime(ctx); - js_begin_call(rt); - JSValue *ret = new JSValue(JS_Call(ctx, *func_obj, *this_obj, argc, argv)); - return ret; - } - - DLLEXPORT int32_t jsIsException(JSValueConst *val) - { - return JS_IsException(*val); - } - - DLLEXPORT JSValue *jsGetException(JSContext *ctx) - { - return new JSValue(JS_GetException(ctx)); - } - - DLLEXPORT int32_t jsExecutePendingJob(JSRuntime *rt) - { - js_begin_call(rt); - JSContext *ctx; - int ret = JS_ExecutePendingJob(rt, &ctx); - return ret; - } - - DLLEXPORT JSValue *jsNewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs) - { - return new JSValue(JS_NewPromiseCapability(ctx, resolving_funcs)); - } - - DLLEXPORT void jsFree(JSContext *ctx, void *ptab) - { - js_free(ctx, ptab); - } - } \ No newline at end of file diff --git a/packages/javascript/javascript_android/cxx/ffi.h b/packages/javascript/javascript_android/cxx/ffi.h deleted file mode 100644 index 6939105..0000000 --- a/packages/javascript/javascript_android/cxx/ffi.h +++ /dev/null @@ -1,137 +0,0 @@ -#include "quickjs/quickjs.h" - -#ifdef _MSC_VER -#define DLLEXPORT __declspec(dllexport) -#else -#define DLLEXPORT __attribute__((visibility("default"))) __attribute__((used)) -#endif - -extern "C" -{ - enum JSChannelType { - JSChannelType_METHON = 0, - JSChannelType_MODULE = 1, - JSChannelType_PROMISE_TRACK = 2, - JSChannelType_FREE_OBJECT = 3, - }; - - typedef void *JSChannel(JSContext *ctx, size_t type, void *argv); - - DLLEXPORT JSValue *jsThrow(JSContext *ctx, JSValue *obj); - - DLLEXPORT JSValue *jsEXCEPTION(); - - DLLEXPORT JSValue *jsUNDEFINED(); - - DLLEXPORT JSValue *jsNULL(); - - DLLEXPORT JSRuntime *jsNewRuntime(JSChannel channel, int64_t timeout); - - DLLEXPORT uint32_t jsNewClass(JSContext *ctx, const char *name); - - DLLEXPORT void *jsGetObjectOpaque(JSValue *obj, uint32_t classid); - - DLLEXPORT JSValue *jsNewObjectClass(JSContext *ctx, uint32_t QJSClassId, void *opaque); - - DLLEXPORT void jsSetMaxStackSize(JSRuntime *rt, size_t stack_size); - - DLLEXPORT void jsSetMemoryLimit(JSRuntime *rt, size_t limit); - - DLLEXPORT void jsFreeRuntime(JSRuntime *rt); - - DLLEXPORT JSValue *jsNewCFunction(JSContext *ctx, JSValue *funcData); - - DLLEXPORT JSValue *jsGetGlobalObject(JSContext *ctx); - - DLLEXPORT JSContext *jsNewContext(JSRuntime *rt); - - DLLEXPORT void jsFreeContext(JSContext *ctx); - - DLLEXPORT JSRuntime *jsGetRuntime(JSContext *ctx); - - DLLEXPORT JSValue *jsEval(JSContext *ctx, const char *input, size_t input_len, const char *filename, int32_t eval_flags); - - DLLEXPORT int32_t jsValueGetTag(JSValue *val); - - DLLEXPORT void *jsValueGetPtr(JSValue *val); - - DLLEXPORT int32_t jsTagIsFloat64(int32_t tag); - - DLLEXPORT JSValue *jsNewBool(JSContext *ctx, int32_t val); - - DLLEXPORT JSValue *jsNewInt64(JSContext *ctx, int64_t val); - - DLLEXPORT JSValue *jsNewFloat64(JSContext *ctx, double val); - - DLLEXPORT JSValue *jsNewString(JSContext *ctx, const char *str); - - DLLEXPORT JSValue *jsNewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len); - - DLLEXPORT JSValue *jsNewArray(JSContext *ctx); - - DLLEXPORT JSValue *jsNewObject(JSContext *ctx); - - DLLEXPORT void jsFreeValue(JSContext *ctx, JSValue *v, int32_t free); - - DLLEXPORT void jsFreeValueRT(JSRuntime *rt, JSValue *v, int32_t free); - - DLLEXPORT JSValue *jsDupValue(JSContext *ctx, JSValueConst *v); - - DLLEXPORT JSValue *jsDupValueRT(JSRuntime *rt, JSValue *v); - - DLLEXPORT int32_t jsToBool(JSContext *ctx, JSValueConst *val); - - DLLEXPORT int64_t jsToInt64(JSContext *ctx, JSValueConst *val); - - DLLEXPORT double jsToFloat64(JSContext *ctx, JSValueConst *val); - - DLLEXPORT const char *jsToCString(JSContext *ctx, JSValueConst *val); - - DLLEXPORT void jsFreeCString(JSContext *ctx, const char *ptr); - - DLLEXPORT uint8_t *jsGetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst *obj); - - DLLEXPORT int32_t jsIsFunction(JSContext *ctx, JSValueConst *val); - - DLLEXPORT int32_t jsIsPromise(JSContext *ctx, JSValueConst *val); - - DLLEXPORT int32_t jsIsArray(JSContext *ctx, JSValueConst *val); - - DLLEXPORT int32_t jsIsError(JSContext *ctx, JSValueConst *val); - - DLLEXPORT JSValue *jsNewError(JSContext *ctx); - - DLLEXPORT JSValue *jsGetProperty(JSContext *ctx, JSValueConst *this_obj, - JSAtom prop); - - DLLEXPORT int32_t jsDefinePropertyValue(JSContext *ctx, JSValueConst *this_obj, - JSAtom prop, JSValue *val, int32_t flags); - - DLLEXPORT void jsFreeAtom(JSContext *ctx, JSAtom v); - - DLLEXPORT JSAtom jsValueToAtom(JSContext *ctx, JSValueConst *val); - - DLLEXPORT JSValue *jsAtomToValue(JSContext *ctx, JSAtom val); - - DLLEXPORT int32_t jsGetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, - uint32_t *plen, JSValueConst *obj, int32_t flags); - - DLLEXPORT JSAtom jsPropertyEnumGetAtom(JSPropertyEnum *ptab, int32_t i); - - DLLEXPORT uint32_t sizeOfJSValue(); - - DLLEXPORT void setJSValueList(JSValue *list, uint32_t i, JSValue *val); - - DLLEXPORT JSValue *jsCall(JSContext *ctx, JSValueConst *func_obj, JSValueConst *this_obj, - int32_t argc, JSValueConst *argv); - - DLLEXPORT int32_t jsIsException(JSValueConst *val); - - DLLEXPORT JSValue *jsGetException(JSContext *ctx); - - DLLEXPORT int32_t jsExecutePendingJob(JSRuntime *rt); - - DLLEXPORT JSValue *jsNewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs); - - DLLEXPORT void jsFree(JSContext *ctx, void *ptab); -} \ No newline at end of file diff --git a/packages/javascript/javascript_android/cxx/prebuild.sh b/packages/javascript/javascript_android/cxx/prebuild.sh deleted file mode 100644 index 3fa7548..0000000 --- a/packages/javascript/javascript_android/cxx/prebuild.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -if [ -d "./cxx/" ];then - rm -r ./cxx -fi - -mkdir ./cxx - -sed 's/\#include \"quickjs\/quickjs.h\"/\#include \"quickjs.h\"/g' ../cxx/ffi.h > ./cxx/ffi.h -cp ../cxx/ffi.cpp ./cxx/ffi.cpp - -cp ../cxx/quickjs/*.h ./cxx/ -cp ../cxx/quickjs/cutils.c ./cxx/ -cp ../cxx/quickjs/libregexp.c ./cxx/ -cp ../cxx/quickjs/libunicode.c ./cxx/ - -quickjs_version=$(cat ../cxx/quickjs/VERSION) - -sed '1i\ -\#define CONFIG_VERSION \"'$quickjs_version'\"\ -\#define DUMP_LEAKS 1\ -' ../cxx/quickjs/quickjs.c > ./cxx/quickjs.c \ No newline at end of file diff --git a/packages/javascript/javascript_android/cxx/quickjs.cmake b/packages/javascript/javascript_android/cxx/quickjs.cmake deleted file mode 100644 index b368134..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs.cmake +++ /dev/null @@ -1,21 +0,0 @@ -cmake_minimum_required(VERSION 3.7 FATAL_ERROR) -set(CXX_LIB_DIR ${CMAKE_CURRENT_LIST_DIR}) - -# quickjs -set(QUICK_JS_LIB_DIR ${CXX_LIB_DIR}/quickjs) -file (STRINGS "${QUICK_JS_LIB_DIR}/VERSION" QUICKJS_VERSION) -add_library(quickjs STATIC - ${QUICK_JS_LIB_DIR}/cutils.c - ${QUICK_JS_LIB_DIR}/libregexp.c - ${QUICK_JS_LIB_DIR}/libunicode.c - ${QUICK_JS_LIB_DIR}/quickjs.c -) - -project(quickjs LANGUAGES C) -target_compile_options(quickjs PRIVATE "-DCONFIG_VERSION=\"${QUICKJS_VERSION}\"") -target_compile_options(quickjs PRIVATE "-DDUMP_LEAKS") - -if(MSVC) - # https://github.com/ekibun/flutter_qjs/issues/7 - target_compile_options(quickjs PRIVATE "/Oi-") -endif() \ No newline at end of file diff --git a/packages/javascript/javascript_android/cxx/quickjs/.github/workflows/ci.yml b/packages/javascript/javascript_android/cxx/quickjs/.github/workflows/ci.yml deleted file mode 100644 index c9ccf62..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/.github/workflows/ci.yml +++ /dev/null @@ -1,286 +0,0 @@ -name: ci - -on: - pull_request: - paths: - - '**' - - '!.gitignore' - - '!LICENSE' - - '!TODO' - - '!doc/**' - - '!examples/**' - - '.github/workflows/ci.yml' - push: - branches: - - '*' - -jobs: - linux: - name: Linux (Ubuntu) - runs-on: ubuntu-latest - strategy: - fail-fast: false - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Build - run: | - make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y - - name: Stats - run: | - ./qjs -qd - - name: Run built-in tests - run: | - make test - - name: Run microbench - run: | - make microbench - - linux-lto: - name: Linux LTO - runs-on: ubuntu-latest - strategy: - fail-fast: false - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Build - run: | - make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_LTO=y - - name: Run built-in tests - run: | - make test - - name: Run microbench - run: | - make microbench - - linux-32bit: - name: Linux 32bit - runs-on: ubuntu-latest - strategy: - fail-fast: false - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Install gcc-multilib - run: | - sudo apt install -y gcc-multilib - - name: Build - run: | - make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_M32=y - - name: Run built-in tests - run: | - make CONFIG_M32=y test - - linux-asan: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Build - run: | - make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_ASAN=y - - name: Run built-in tests - env: - ASAN_OPTIONS: halt_on_error=1 - run: | - make CONFIG_ASAN=y test - - linux-msan: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Build - env: - CC: clang - run: | - make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_MSAN=y CONFIG_CLANG=y - - name: Run built-in tests - env: - MSAN_OPTIONS: halt_on_error=1 - run: | - make CONFIG_MSAN=y CONFIG_CLANG=y test - - linux-ubsan: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Build - run: | - make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_UBSAN=y - - name: Run built-in tests - env: - UBSAN_OPTIONS: halt_on_error=1 - run: | - make CONFIG_UBSAN=y test - - macos: - name: macOS - runs-on: macos-latest - strategy: - fail-fast: false - steps: - - uses: actions/checkout@v4 - - name: Build - run: | - make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y - - name: Stats - run: | - ./qjs -qd - - name: Run built-in tests - run: | - make test - - macos-asan: - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - name: Build - run: | - make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_ASAN=y - - name: Run built-in tests - env: - ASAN_OPTIONS: halt_on_error=1 - run: | - make CONFIG_ASAN=y test - - macos-ubsan: - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - name: Build - run: | - make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_UBSAN=y - - name: Run built-in tests - env: - UBSAN_OPTIONS: halt_on_error=1 - run: | - make CONFIG_UBSAN=y test - - freebsd: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Build + test - uses: vmactions/freebsd-vm@v1 - with: - usesh: true - prepare: | - pkg install -y gmake - run: | - gmake - ./qjs -qd - gmake test - - cosmopolitan: - name: Cosmopolitan - runs-on: ubuntu-latest - strategy: - fail-fast: false - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Install Cosmopolitan - run: | - mkdir ~/cosmocc - cd ~/cosmocc - wget https://cosmo.zip/pub/cosmocc/cosmocc.zip - unzip cosmocc.zip - echo "$HOME/cosmocc/bin" >> "$GITHUB_PATH" - - name: Build - run: | - make CONFIG_COSMO=y - - name: Run built-in tests - run: | - make CONFIG_COSMO=y test - - mingw-windows: - name: MinGW Windows target - runs-on: ubuntu-latest - strategy: - fail-fast: false - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Install MinGW and Wine - run: | - sudo apt update - sudo apt install -y wine mingw-w64 - cp /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll . - - name: Setup Wine - run: | - wine --version - winecfg /v - # binfmt doesn't work in GitHub Actions - #sudo apt install -y binfmt-support wine-binfmt - #echo ":Wine:M::MZ::/usr/bin/wine:" > /etc/binfmt.d/wine.conf - #sudo systemctl restart systemd-binfmt - - name: Build - run: | - make CONFIG_WIN32=y - - name: Run built-in tests - run: | - # If binfmt support worked, could just run `make CONFIG_WIN32=y test` - make WINE=/usr/bin/wine CONFIG_WIN32=y test - - windows-msys: - name: Windows MSYS2 - runs-on: windows-latest - defaults: - run: - shell: msys2 {0} - steps: - - uses: actions/checkout@v4 - - uses: msys2/setup-msys2@v2 - with: - msystem: UCRT64 - update: true - install: git make mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-dlfcn - - name: Build - run: | - make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y - - name: Stats - run: | - ./qjs -qd - - name: Run built-in tests - run: | - make test - - name: Run microbench - run: | - make microbench - - - qemu-alpine: - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - platform: - - linux/386 - - linux/riscv64 - - linux/arm64 - - linux/arm/v6 - - linux/arm/v7 - - linux/s390x - - linux/ppc64le - - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - name: Get qemu - # See https://github.com/tonistiigi/binfmt/issues/215#issuecomment-2613004741 - run: docker run --privileged --rm tonistiigi/binfmt:master --install all - - name: Run tests on ${{ matrix.platform }} - run: docker run --rm --interactive --mount type=bind,source=$(pwd),target=/host --platform ${{ matrix.platform }} alpine sh -c "apk add git patch make gcc libc-dev && cd /host && make test" diff --git a/packages/javascript/javascript_android/cxx/quickjs/.gitignore b/packages/javascript/javascript_android/cxx/quickjs/.gitignore deleted file mode 100644 index ba32a84..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -*.a -.obj/ -tests/bjson.so -examples/test_fib -test_fib.c -examples/*.so -examples/hello -examples/hello_module -examples/hello.exe -examples/test_fib.exe -hello.c -microbench*.txt -qjs -qjs.exe -qjsc -qjsc.exe -host-qjsc -qjscalc -qjscalc.c -repl.c -run-test262 -run-test262.exe -test262 -test262_*.txt -test262o -test262o_*.txt -unicode -unicode_gen -run_octane -run_sunspider_like -libwinpthread*.dll diff --git a/packages/javascript/javascript_android/cxx/quickjs/Changelog b/packages/javascript/javascript_android/cxx/quickjs/Changelog deleted file mode 100644 index b1443f5..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/Changelog +++ /dev/null @@ -1,206 +0,0 @@ -- added JSON modules and import attributes -- added JS_PrintValue() API -- qjs: pretty print objects in print() and console.log() -- qjs: better promise rejection tracker heuristics -- added RegExp v flag -- added RegExp modifiers -- added RegExp.escape -- added Float16Array -- added Promise.try -- improved JSON parser spec conformance -- qjs: improved compatibility of std.parseExtJSON() with JSON5 and - accept JSON5 modules -- added JS_FreePropertyEnum() and JS_AtomToCStringLen() API -- added Error.isError() - -2025-04-26: - -- removed the bignum extensions and qjscalc -- new BigInt implementation optimized for small numbers -- added WeakRef, FinalizationRegistry and symbols as weakrefs -- added builtin float64 printing and parsing functions for more correctness -- faster repeated string concatenation -- qjs: promise unhandled rejections are fatal errors by default -- added column number in debug information -- removed the "use strip" extension -- qjs: added -s and --strip-source options -- qjsc: added -s and --keep-source options -- added JS_GetAnyOpaque() -- added more callbacks for exotic objects in JSClassExoticMethods -- misc bug fixes - -2024-01-13: - -- top-level-await support in modules -- allow 'await' in the REPL -- added Array.prototype.{with,toReversed,toSpliced,toSorted} and -TypedArray.prototype.{with,toReversed,toSorted} -- added String.prototype.isWellFormed and String.prototype.toWellFormed -- added Object.groupBy and Map.groupBy -- added Promise.withResolvers -- class static block -- 'in' operator support for private fields -- optional chaining fixes -- added RegExp 'd' flag -- fixed RegExp zero length match logic -- fixed RegExp case insensitive flag -- added os.sleepAsync(), os.getpid() and os.now() -- added cosmopolitan build -- misc bug fixes - -2023-12-09: - -- added Object.hasOwn, {String|Array|TypedArray}.prototype.at, - {Array|TypedArray}.prototype.findLast{Index} -- BigInt support is enabled even if CONFIG_BIGNUM disabled -- updated to Unicode 15.0.0 -- misc bug fixes - -2021-03-27: - -- faster Array.prototype.push and Array.prototype.unshift -- added JS_UpdateStackTop() -- fixed Windows console -- misc bug fixes - -2020-11-08: - -- improved function parameter initializers -- added std.setenv(), std.unsetenv() and std.getenviron() -- added JS_EvalThis() -- misc bug fixes - -2020-09-06: - -- added logical assignment operators -- added IsHTMLDDA support -- faster for-of loops -- os.Worker now takes a module filename as parameter -- qjsc: added -D option to compile dynamically loaded modules or workers -- misc bug fixes - -2020-07-05: - -- modified JS_GetPrototype() to return a live value -- REPL: support unicode characters larger than 16 bits -- added os.Worker -- improved object serialization -- added std.parseExtJSON -- misc bug fixes - -2020-04-12: - -- added cross realm support -- added AggregateError and Promise.any -- added env, uid and gid options in os.exec() -- misc bug fixes - -2020-03-16: - -- reworked error handling in std and os libraries: suppressed I/O - exceptions in std FILE functions and return a positive errno value - when it is explicit -- output exception messages to stderr -- added std.loadFile(), std.strerror(), std.FILE.prototype.tello() -- added JS_GetRuntimeOpaque(), JS_SetRuntimeOpaque(), JS_NewUint32() -- updated to Unicode 13.0.0 -- misc bug fixes - -2020-01-19: - -- keep CONFIG_BIGNUM in the makefile -- added os.chdir() -- qjs: added -I option -- more memory checks in the bignum operations -- modified operator overloading semantics to be closer to the TC39 - proposal -- suppressed "use bigint" mode. Simplified "use math" mode -- BigDecimal: changed suffix from 'd' to 'm' -- misc bug fixes - -2020-01-05: - -- always compile the bignum code. Added '--bignum' option to qjs. -- added BigDecimal -- added String.prototype.replaceAll -- misc bug fixes - -2019-12-21: - -- added nullish coalescing operator (ES2020) -- added optional chaining (ES2020) -- removed recursions in garbage collector -- test stack overflow in the parser -- improved backtrace logic -- added JS_SetHostPromiseRejectionTracker() -- allow exotic constructors -- improved c++ compatibility -- misc bug fixes - -2019-10-27: - -- added example of C class in a module (examples/test_point.js) -- added JS_GetTypedArrayBuffer() -- misc bug fixes - -2019-09-18: - -- added os.exec and other system calls -- exported JS_ValueToAtom() -- qjsc: added 'qjsc_' prefix to the generated C identifiers -- added cross-compilation support -- misc bug fixes - -2019-09-01: - -- added globalThis -- documented JS_EVAL_FLAG_COMPILE_ONLY -- added import.meta.url and import.meta.main -- added 'debugger' statement -- misc bug fixes - -2019-08-18: - -- added os.realpath, os.getcwd, os.mkdir, os.stat, os.lstat, - os.readlink, os.readdir, os.utimes, std.popen -- module autodetection -- added import.meta -- misc bug fixes - -2019-08-10: - -- added public class fields and private class fields, methods and - accessors (TC39 proposal) -- changed JS_ToCStringLen() prototype -- qjsc: handle '-' in module names and modules with the same filename -- added std.urlGet -- exported JS_GetOwnPropertyNames() and JS_GetOwnProperty() -- exported some bigint C functions -- added support for eshost in run-test262 -- misc bug fixes - -2019-07-28: - -- added dynamic import -- added Promise.allSettled -- added String.prototype.matchAll -- added Object.fromEntries -- reduced number of ticks in await -- added BigInt support in Atomics -- exported JS_NewPromiseCapability() -- misc async function and async generator fixes -- enabled hashbang support by default - -2019-07-21: - -- updated test262 tests -- updated to Unicode version 12.1.0 -- fixed missing Date object in qjsc -- fixed multi-context creation -- misc ES2020 related fixes -- simplified power and division operators in bignum extension -- fixed several crash conditions - -2019-07-09: - -- first public release diff --git a/packages/javascript/javascript_android/cxx/quickjs/LICENSE b/packages/javascript/javascript_android/cxx/quickjs/LICENSE deleted file mode 100644 index 2cf449d..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -QuickJS Javascript Engine - -Copyright (c) 2017-2021 Fabrice Bellard -Copyright (c) 2017-2021 Charlie Gordon - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/packages/javascript/javascript_android/cxx/quickjs/Makefile b/packages/javascript/javascript_android/cxx/quickjs/Makefile deleted file mode 100644 index 3b1c745..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/Makefile +++ /dev/null @@ -1,537 +0,0 @@ -# -# QuickJS Javascript Engine -# -# Copyright (c) 2017-2021 Fabrice Bellard -# Copyright (c) 2017-2021 Charlie Gordon -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -ifeq ($(shell uname -s),Darwin) -CONFIG_DARWIN=y -endif -ifeq ($(shell uname -s),FreeBSD) -CONFIG_FREEBSD=y -endif -# Windows cross compilation from Linux -# May need to have libwinpthread*.dll alongside the executable -# (On Ubuntu/Debian may be installed with mingw-w64-x86-64-dev -# to /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll) -#CONFIG_WIN32=y -# use link time optimization (smaller and faster executables but slower build) -#CONFIG_LTO=y -# consider warnings as errors (for development) -#CONFIG_WERROR=y -# force 32 bit build on x86_64 -#CONFIG_M32=y -# cosmopolitan build (see https://github.com/jart/cosmopolitan) -#CONFIG_COSMO=y - -# installation directory -PREFIX?=/usr/local - -# use the gprof profiler -#CONFIG_PROFILE=y -# use address sanitizer -#CONFIG_ASAN=y -# use memory sanitizer -#CONFIG_MSAN=y -# use UB sanitizer -#CONFIG_UBSAN=y - -OBJDIR=.obj - -ifdef CONFIG_ASAN -OBJDIR:=$(OBJDIR)/asan -endif -ifdef CONFIG_MSAN -OBJDIR:=$(OBJDIR)/msan -endif -ifdef CONFIG_UBSAN -OBJDIR:=$(OBJDIR)/ubsan -endif - -ifdef CONFIG_DARWIN -# use clang instead of gcc -CONFIG_CLANG=y -CONFIG_DEFAULT_AR=y -endif -ifdef CONFIG_FREEBSD -# use clang instead of gcc -CONFIG_CLANG=y -CONFIG_DEFAULT_AR=y -CONFIG_LTO= -endif - -ifdef CONFIG_WIN32 - ifdef CONFIG_M32 - CROSS_PREFIX?=i686-w64-mingw32- - else - CROSS_PREFIX?=x86_64-w64-mingw32- - endif - EXE=.exe -else ifdef MSYSTEM - CONFIG_WIN32=y - CROSS_PREFIX?= - EXE=.exe -else - CROSS_PREFIX?= - EXE= -endif - -ifdef CONFIG_CLANG - HOST_CC=clang - CC=$(CROSS_PREFIX)clang - CFLAGS+=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d - CFLAGS += -Wextra - CFLAGS += -Wno-sign-compare - CFLAGS += -Wno-missing-field-initializers - CFLAGS += -Wundef -Wuninitialized - CFLAGS += -Wunused -Wno-unused-parameter - CFLAGS += -Wwrite-strings - CFLAGS += -Wchar-subscripts -funsigned-char - CFLAGS += -MMD -MF $(OBJDIR)/$(@F).d - ifdef CONFIG_DEFAULT_AR - AR=$(CROSS_PREFIX)ar - else - ifdef CONFIG_LTO - AR=$(CROSS_PREFIX)llvm-ar - else - AR=$(CROSS_PREFIX)ar - endif - endif - LIB_FUZZING_ENGINE ?= "-fsanitize=fuzzer" -else ifdef CONFIG_COSMO - CONFIG_LTO= - HOST_CC=gcc - CC=cosmocc - # cosmocc does not correct support -MF - CFLAGS=-g -Wall #-MMD -MF $(OBJDIR)/$(@F).d - CFLAGS += -Wno-array-bounds -Wno-format-truncation - AR=cosmoar -else - HOST_CC=gcc - CC=$(CROSS_PREFIX)gcc - CFLAGS+=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d - CFLAGS += -Wno-array-bounds -Wno-format-truncation -Wno-infinite-recursion - ifdef CONFIG_LTO - AR=$(CROSS_PREFIX)gcc-ar - else - AR=$(CROSS_PREFIX)ar - endif -endif -STRIP?=$(CROSS_PREFIX)strip -ifdef CONFIG_M32 -CFLAGS+=-msse2 -mfpmath=sse # use SSE math for correct FP rounding -ifndef CONFIG_WIN32 -CFLAGS+=-m32 -LDFLAGS+=-m32 -endif -endif -CFLAGS+=-fwrapv # ensure that signed overflows behave as expected -ifdef CONFIG_WERROR -CFLAGS+=-Werror -endif -DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\" -ifdef CONFIG_WIN32 -DEFINES+=-D__USE_MINGW_ANSI_STDIO # for standard snprintf behavior -endif -ifndef CONFIG_WIN32 -ifeq ($(shell $(CC) -o /dev/null compat/test-closefrom.c 2>/dev/null && echo 1),1) -DEFINES+=-DHAVE_CLOSEFROM -endif -endif - -CFLAGS+=$(DEFINES) -CFLAGS_DEBUG=$(CFLAGS) -O0 -CFLAGS_SMALL=$(CFLAGS) -Os -CFLAGS_OPT=$(CFLAGS) -O2 -CFLAGS_NOLTO:=$(CFLAGS_OPT) -ifdef CONFIG_COSMO -LDFLAGS+=-s # better to strip by default -else -LDFLAGS+=-g -endif -ifdef CONFIG_LTO -CFLAGS_SMALL+=-flto -CFLAGS_OPT+=-flto -LDFLAGS+=-flto -endif -ifdef CONFIG_PROFILE -CFLAGS+=-p -LDFLAGS+=-p -endif -ifdef CONFIG_ASAN -CFLAGS+=-fsanitize=address -fno-omit-frame-pointer -LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer -endif -ifdef CONFIG_MSAN -CFLAGS+=-fsanitize=memory -fno-omit-frame-pointer -LDFLAGS+=-fsanitize=memory -fno-omit-frame-pointer -endif -ifdef CONFIG_UBSAN -CFLAGS+=-fsanitize=undefined -fno-omit-frame-pointer -LDFLAGS+=-fsanitize=undefined -fno-omit-frame-pointer -endif -ifdef CONFIG_WIN32 -LDEXPORT= -else -LDEXPORT=-rdynamic -endif - -ifndef CONFIG_COSMO -ifndef CONFIG_DARWIN -ifndef CONFIG_WIN32 -CONFIG_SHARED_LIBS=y # building shared libraries is supported -endif -endif -endif - -PROGS=qjs$(EXE) qjsc$(EXE) run-test262$(EXE) - -ifneq ($(CROSS_PREFIX),) -QJSC_CC=gcc -QJSC=./host-qjsc -PROGS+=$(QJSC) -else -QJSC_CC=$(CC) -QJSC=./qjsc$(EXE) -endif -PROGS+=libquickjs.a -ifdef CONFIG_LTO -PROGS+=libquickjs.lto.a -endif - -# examples -ifeq ($(CROSS_PREFIX),) -ifndef CONFIG_ASAN -ifndef CONFIG_MSAN -ifndef CONFIG_UBSAN -PROGS+=examples/hello examples/test_fib -# no -m32 option in qjsc -ifndef CONFIG_M32 -ifndef CONFIG_WIN32 -PROGS+=examples/hello_module -endif -endif -ifdef CONFIG_SHARED_LIBS -PROGS+=examples/fib.so examples/point.so -endif -endif -endif -endif -endif - -all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS) - -QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/dtoa.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o - -QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS) - -HOST_LIBS=-lm -ldl -lpthread -LIBS=-lm -lpthread -ifndef CONFIG_WIN32 -LIBS+=-ldl -endif -LIBS+=$(EXTRA_LIBS) - -$(OBJDIR): - mkdir -p $(OBJDIR) $(OBJDIR)/examples $(OBJDIR)/tests - -qjs$(EXE): $(QJS_OBJS) - $(CC) $(LDFLAGS) $(LDEXPORT) -o $@ $^ $(LIBS) - -qjs-debug$(EXE): $(patsubst %.o, %.debug.o, $(QJS_OBJS)) - $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) - -qjsc$(EXE): $(OBJDIR)/qjsc.o $(QJS_LIB_OBJS) - $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) - -fuzz_eval: $(OBJDIR)/fuzz_eval.o $(OBJDIR)/fuzz_common.o libquickjs.fuzz.a - $(CC) $(CFLAGS_OPT) $^ -o fuzz_eval $(LIB_FUZZING_ENGINE) - -fuzz_compile: $(OBJDIR)/fuzz_compile.o $(OBJDIR)/fuzz_common.o libquickjs.fuzz.a - $(CC) $(CFLAGS_OPT) $^ -o fuzz_compile $(LIB_FUZZING_ENGINE) - -fuzz_regexp: $(OBJDIR)/fuzz_regexp.o $(OBJDIR)/libregexp.fuzz.o $(OBJDIR)/cutils.fuzz.o $(OBJDIR)/libunicode.fuzz.o - $(CC) $(CFLAGS_OPT) $^ -o fuzz_regexp $(LIB_FUZZING_ENGINE) - -libfuzzer: fuzz_eval fuzz_compile fuzz_regexp - -ifneq ($(CROSS_PREFIX),) - -$(QJSC): $(OBJDIR)/qjsc.host.o \ - $(patsubst %.o, %.host.o, $(QJS_LIB_OBJS)) - $(HOST_CC) $(LDFLAGS) -o $@ $^ $(HOST_LIBS) - -endif #CROSS_PREFIX - -QJSC_DEFINES:=-DCONFIG_CC=\"$(QJSC_CC)\" -DCONFIG_PREFIX=\"$(PREFIX)\" -ifdef CONFIG_LTO -QJSC_DEFINES+=-DCONFIG_LTO -endif -QJSC_HOST_DEFINES:=-DCONFIG_CC=\"$(HOST_CC)\" -DCONFIG_PREFIX=\"$(PREFIX)\" - -$(OBJDIR)/qjsc.o: CFLAGS+=$(QJSC_DEFINES) -$(OBJDIR)/qjsc.host.o: CFLAGS+=$(QJSC_HOST_DEFINES) - -ifdef CONFIG_LTO -LTOEXT=.lto -else -LTOEXT= -endif - -libquickjs$(LTOEXT).a: $(QJS_LIB_OBJS) - $(AR) rcs $@ $^ - -ifdef CONFIG_LTO -libquickjs.a: $(patsubst %.o, %.nolto.o, $(QJS_LIB_OBJS)) - $(AR) rcs $@ $^ -endif # CONFIG_LTO - -libquickjs.fuzz.a: $(patsubst %.o, %.fuzz.o, $(QJS_LIB_OBJS)) - $(AR) rcs $@ $^ - -repl.c: $(QJSC) repl.js - $(QJSC) -s -c -o $@ -m repl.js - -ifneq ($(wildcard unicode/UnicodeData.txt),) -$(OBJDIR)/libunicode.o $(OBJDIR)/libunicode.nolto.o: libunicode-table.h - -libunicode-table.h: unicode_gen - ./unicode_gen unicode $@ -endif - -run-test262$(EXE): $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS) - $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) - -run-test262-debug: $(patsubst %.o, %.debug.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS)) - $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) - -# object suffix order: nolto - -$(OBJDIR)/%.o: %.c | $(OBJDIR) - $(CC) $(CFLAGS_OPT) -c -o $@ $< - -$(OBJDIR)/fuzz_%.o: fuzz/fuzz_%.c | $(OBJDIR) - $(CC) $(CFLAGS_OPT) -c -I. -o $@ $< - -$(OBJDIR)/%.host.o: %.c | $(OBJDIR) - $(HOST_CC) $(CFLAGS_OPT) -c -o $@ $< - -$(OBJDIR)/%.pic.o: %.c | $(OBJDIR) - $(CC) $(CFLAGS_OPT) -fPIC -DJS_SHARED_LIBRARY -c -o $@ $< - -$(OBJDIR)/%.nolto.o: %.c | $(OBJDIR) - $(CC) $(CFLAGS_NOLTO) -c -o $@ $< - -$(OBJDIR)/%.debug.o: %.c | $(OBJDIR) - $(CC) $(CFLAGS_DEBUG) -c -o $@ $< - -$(OBJDIR)/%.fuzz.o: %.c | $(OBJDIR) - $(CC) $(CFLAGS_OPT) -fsanitize=fuzzer-no-link -c -o $@ $< - -$(OBJDIR)/%.check.o: %.c | $(OBJDIR) - $(CC) $(CFLAGS) -DCONFIG_CHECK_JSVALUE -c -o $@ $< - -regexp_test: libregexp.c libunicode.c cutils.c - $(CC) $(LDFLAGS) $(CFLAGS) -DTEST -o $@ libregexp.c libunicode.c cutils.c $(LIBS) - -unicode_gen: $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o libunicode.c unicode_gen_def.h - $(HOST_CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o - -clean: - rm -f repl.c out.c - rm -f *.a *.o *.d *~ unicode_gen regexp_test fuzz_eval fuzz_compile fuzz_regexp $(PROGS) - rm -f hello.c test_fib.c - rm -f examples/*.so tests/*.so - rm -rf $(OBJDIR)/ *.dSYM/ qjs-debug$(EXE) - rm -rf run-test262-debug$(EXE) - rm -f run_octane run_sunspider_like - -install: all - mkdir -p "$(DESTDIR)$(PREFIX)/bin" - $(STRIP) qjs$(EXE) qjsc$(EXE) - install -m755 qjs$(EXE) qjsc$(EXE) "$(DESTDIR)$(PREFIX)/bin" - mkdir -p "$(DESTDIR)$(PREFIX)/lib/quickjs" - install -m644 libquickjs.a "$(DESTDIR)$(PREFIX)/lib/quickjs" -ifdef CONFIG_LTO - install -m644 libquickjs.lto.a "$(DESTDIR)$(PREFIX)/lib/quickjs" -endif - mkdir -p "$(DESTDIR)$(PREFIX)/include/quickjs" - install -m644 quickjs.h quickjs-libc.h "$(DESTDIR)$(PREFIX)/include/quickjs" - -############################################################################### -# examples - -# example of static JS compilation -HELLO_SRCS=examples/hello.js -HELLO_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \ - -fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \ - -fno-date -fno-module-loader - -hello.c: $(QJSC) $(HELLO_SRCS) - $(QJSC) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS) - -examples/hello: $(OBJDIR)/hello.o $(QJS_LIB_OBJS) - $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) - -# example of static JS compilation with modules -HELLO_MODULE_SRCS=examples/hello_module.js -HELLO_MODULE_OPTS=-fno-string-normalize -fno-map -fno-typedarray \ - -fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \ - -fno-date -m -examples/hello_module: $(QJSC) libquickjs$(LTOEXT).a $(HELLO_MODULE_SRCS) - $(QJSC) $(HELLO_MODULE_OPTS) -o $@ $(HELLO_MODULE_SRCS) - -# use of an external C module (static compilation) - -test_fib.c: $(QJSC) examples/test_fib.js - $(QJSC) -e -M examples/fib.so,fib -m -o $@ examples/test_fib.js - -examples/test_fib: $(OBJDIR)/test_fib.o $(OBJDIR)/examples/fib.o libquickjs$(LTOEXT).a - $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) - -examples/fib.so: $(OBJDIR)/examples/fib.pic.o - $(CC) $(LDFLAGS) -shared -o $@ $^ - -examples/point.so: $(OBJDIR)/examples/point.pic.o - $(CC) $(LDFLAGS) -shared -o $@ $^ - -############################################################################### -# documentation - -DOCS=doc/quickjs.pdf doc/quickjs.html - -build_doc: $(DOCS) - -clean_doc: - rm -f $(DOCS) - -doc/version.texi: VERSION - @echo "@set VERSION `cat $<`" > $@ - -doc/%.pdf: doc/%.texi doc/version.texi - texi2pdf --clean -o $@ -q $< - -doc/%.html.pre: doc/%.texi doc/version.texi - makeinfo --html --no-headers --no-split --number-sections -o $@ $< - -doc/%.html: doc/%.html.pre - sed -e 's||\n|' < $< > $@ - -############################################################################### -# tests - -ifdef CONFIG_SHARED_LIBS -test: tests/bjson.so examples/point.so -endif - -test: qjs$(EXE) - $(WINE) ./qjs$(EXE) tests/test_closure.js - $(WINE) ./qjs$(EXE) tests/test_language.js - $(WINE) ./qjs$(EXE) --std tests/test_builtin.js - $(WINE) ./qjs$(EXE) tests/test_loop.js - $(WINE) ./qjs$(EXE) tests/test_bigint.js - $(WINE) ./qjs$(EXE) tests/test_cyclic_import.js - $(WINE) ./qjs$(EXE) tests/test_worker.js -ifndef CONFIG_WIN32 - $(WINE) ./qjs$(EXE) tests/test_std.js -endif -ifdef CONFIG_SHARED_LIBS - $(WINE) ./qjs$(EXE) tests/test_bjson.js - $(WINE) ./qjs$(EXE) examples/test_point.js -endif - -stats: qjs$(EXE) - $(WINE) ./qjs$(EXE) -qd - -microbench: qjs$(EXE) - $(WINE) ./qjs$(EXE) --std tests/microbench.js - -ifeq ($(wildcard test262o/tests.txt),) -test2o test2o-update: - @echo test262o tests not installed -else -# ES5 tests (obsolete) -test2o: run-test262 - time ./run-test262 -t -m -c test262o.conf - -test2o-update: run-test262 - ./run-test262 -t -u -c test262o.conf -endif - -ifeq ($(wildcard test262/features.txt),) -test2 test2-update test2-default test2-check: - @echo test262 tests not installed -else -# Test262 tests -test2-default: run-test262 - time ./run-test262 -t -m -c test262.conf - -test2: run-test262 - time ./run-test262 -t -m -c test262.conf -a - -test2-update: run-test262 - ./run-test262 -t -u -c test262.conf -a - -test2-check: run-test262 - time ./run-test262 -t -m -c test262.conf -E -a -endif - -testall: all test microbench test2o test2 - -testall-complete: testall - -node-test: - node tests/test_closure.js - node tests/test_language.js - node tests/test_builtin.js - node tests/test_loop.js - node tests/test_bigint.js - -node-microbench: - node tests/microbench.js -s microbench-node.txt - node --jitless tests/microbench.js -s microbench-node-jitless.txt - -bench-v8: qjs - make -C tests/bench-v8 - ./qjs -d tests/bench-v8/combined.js - -node-bench-v8: - make -C tests/bench-v8 - node --jitless tests/bench-v8/combined.js - -tests/bjson.so: $(OBJDIR)/tests/bjson.pic.o - $(CC) $(LDFLAGS) -shared -o $@ $^ $(LIBS) - -BENCHMARKDIR=../quickjs-benchmarks - -run_sunspider_like: $(BENCHMARKDIR)/run_sunspider_like.c - $(CC) $(CFLAGS) $(LDFLAGS) -DNO_INCLUDE_DIR -I. -o $@ $< libquickjs$(LTOEXT).a $(LIBS) - -run_octane: $(BENCHMARKDIR)/run_octane.c - $(CC) $(CFLAGS) $(LDFLAGS) -DNO_INCLUDE_DIR -I. -o $@ $< libquickjs$(LTOEXT).a $(LIBS) - -benchmarks: run_sunspider_like run_octane - ./run_sunspider_like $(BENCHMARKDIR)/kraken-1.0/ - ./run_sunspider_like $(BENCHMARKDIR)/kraken-1.1/ - ./run_sunspider_like $(BENCHMARKDIR)/sunspider-1.0/ - ./run_octane $(BENCHMARKDIR)/ - --include $(wildcard $(OBJDIR)/*.d) diff --git a/packages/javascript/javascript_android/cxx/quickjs/TODO b/packages/javascript/javascript_android/cxx/quickjs/TODO deleted file mode 100644 index 651a9f1..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/TODO +++ /dev/null @@ -1,66 +0,0 @@ -Misc ideas: -- use custom printf to avoid compatibility issues with floating point numbers -- consistent naming for preprocessor defines -- unify coding style and naming conventions -- use names from the ECMA spec in library implementation -- use byte code emitters with typed arguments (for clarity) -- use 2 bytecode DynBufs in JSFunctionDef, one for reading, one for writing - and use the same wrappers in all phases -- use more generic method for line numbers in resolve_variables and resolve_labels -- use custom timezone support to avoid C library compatibility issues - -Memory: -- use memory pools for objects, etc? -- test border cases for max number of atoms, object properties, string length -- add emergency malloc mode for out of memory exceptions. -- test all DynBuf memory errors -- test all js_realloc memory errors -- improve JS_ComputeMemoryUsage() with more info - -Built-in standard library: -- BSD sockets -- modules: use realpath in module name normalizer and put it in quickjs-libc -- modules: if no ".", use a well known module loading path ? -- get rid of __loadScript, use more common name - -REPL: -- debugger -- readline: support MS Windows terminal -- readline: handle dynamic terminal resizing -- readline: handle double width unicode characters -- multiline editing -- runtime object and function inspectors -- interactive object browser -- use more generic approach to display evaluation results -- improve directive handling: dispatch, colorize, completion... -- save history -- close all predefined methods in repl.js and jscalc.js - -Optimization ideas: -- use 64 bit JSValue in 64 bit mode -- use JSValue as atoms and use a specific constant pool in functions to - reference atoms from the bytecode -- reuse stack slots for disjoint scopes, if strip -- add heuristic to avoid some cycles in closures -- small String (1 codepoint) with immediate storage -- perform static string concatenation at compile time -- add implicit numeric strings for Uint32 numbers? -- optimize `s += a + b`, `s += a.b` and similar simple expressions -- ensure string canonical representation and optimise comparisons and hashes? -- property access optimization on the global object, functions, - prototypes and special non extensible objects. -- create object literals with the correct length by backpatching length argument -- remove redundant set_loc_uninitialized/check_uninitialized opcodes -- peephole optim: push_atom_value, to_propkey -> push_atom_value -- peephole optim: put_loc x, get_loc_check x -> set_loc x -- convert slow array to fast array when all properties != length are numeric -- optimize destructuring assignments for global and local variables -- implement some form of tail-call-optimization -- optimize OP_apply -- optimize f(...b) - -Test262o: 0/11262 errors, 463 excluded -Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch) - -Result: 47/79398 errors, 1637 excluded, 6771 skipped -Test262 commit: 1e38cbeb1c878a352b55c3ebe03ee8eda74a33ed diff --git a/packages/javascript/javascript_android/cxx/quickjs/VERSION b/packages/javascript/javascript_android/cxx/quickjs/VERSION deleted file mode 100644 index c76e76d..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/VERSION +++ /dev/null @@ -1 +0,0 @@ -2025-04-26 diff --git a/packages/javascript/javascript_android/cxx/quickjs/compat/test-closefrom.c b/packages/javascript/javascript_android/cxx/quickjs/compat/test-closefrom.c deleted file mode 100644 index 1324e97..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/compat/test-closefrom.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main(void) { - closefrom(3); - return 0; -} diff --git a/packages/javascript/javascript_android/cxx/quickjs/cutils.c b/packages/javascript/javascript_android/cxx/quickjs/cutils.c deleted file mode 100644 index c038cf4..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/cutils.c +++ /dev/null @@ -1,633 +0,0 @@ -/* - * C utilities - * - * Copyright (c) 2017 Fabrice Bellard - * Copyright (c) 2018 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include -#include -#include -#include - -#include "cutils.h" - -void pstrcpy(char *buf, int buf_size, const char *str) -{ - int c; - char *q = buf; - - if (buf_size <= 0) - return; - - for(;;) { - c = *str++; - if (c == 0 || q >= buf + buf_size - 1) - break; - *q++ = c; - } - *q = '\0'; -} - -/* strcat and truncate. */ -char *pstrcat(char *buf, int buf_size, const char *s) -{ - int len; - len = strlen(buf); - if (len < buf_size) - pstrcpy(buf + len, buf_size - len, s); - return buf; -} - -int strstart(const char *str, const char *val, const char **ptr) -{ - const char *p, *q; - p = str; - q = val; - while (*q != '\0') { - if (*p != *q) - return 0; - p++; - q++; - } - if (ptr) - *ptr = p; - return 1; -} - -int has_suffix(const char *str, const char *suffix) -{ - size_t len = strlen(str); - size_t slen = strlen(suffix); - return (len >= slen && !memcmp(str + len - slen, suffix, slen)); -} - -/* Dynamic buffer package */ - -static void *dbuf_default_realloc(void *opaque, void *ptr, size_t size) -{ - return realloc(ptr, size); -} - -void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func) -{ - memset(s, 0, sizeof(*s)); - if (!realloc_func) - realloc_func = dbuf_default_realloc; - s->opaque = opaque; - s->realloc_func = realloc_func; -} - -void dbuf_init(DynBuf *s) -{ - dbuf_init2(s, NULL, NULL); -} - -/* return < 0 if error */ -int dbuf_realloc(DynBuf *s, size_t new_size) -{ - size_t size; - uint8_t *new_buf; - if (new_size > s->allocated_size) { - if (s->error) - return -1; - size = s->allocated_size * 3 / 2; - if (size > new_size) - new_size = size; - new_buf = s->realloc_func(s->opaque, s->buf, new_size); - if (!new_buf) { - s->error = TRUE; - return -1; - } - s->buf = new_buf; - s->allocated_size = new_size; - } - return 0; -} - -int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len) -{ - size_t end; - end = offset + len; - if (dbuf_realloc(s, end)) - return -1; - memcpy(s->buf + offset, data, len); - if (end > s->size) - s->size = end; - return 0; -} - -int dbuf_put(DynBuf *s, const uint8_t *data, size_t len) -{ - if (unlikely((s->size + len) > s->allocated_size)) { - if (dbuf_realloc(s, s->size + len)) - return -1; - } - memcpy_no_ub(s->buf + s->size, data, len); - s->size += len; - return 0; -} - -int dbuf_put_self(DynBuf *s, size_t offset, size_t len) -{ - if (unlikely((s->size + len) > s->allocated_size)) { - if (dbuf_realloc(s, s->size + len)) - return -1; - } - memcpy(s->buf + s->size, s->buf + offset, len); - s->size += len; - return 0; -} - -int dbuf_putc(DynBuf *s, uint8_t c) -{ - return dbuf_put(s, &c, 1); -} - -int dbuf_putstr(DynBuf *s, const char *str) -{ - return dbuf_put(s, (const uint8_t *)str, strlen(str)); -} - -int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s, - const char *fmt, ...) -{ - va_list ap; - char buf[128]; - int len; - - va_start(ap, fmt); - len = vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - if (len < 0) - return -1; - if (len < sizeof(buf)) { - /* fast case */ - return dbuf_put(s, (uint8_t *)buf, len); - } else { - if (dbuf_realloc(s, s->size + len + 1)) - return -1; - va_start(ap, fmt); - vsnprintf((char *)(s->buf + s->size), s->allocated_size - s->size, - fmt, ap); - va_end(ap); - s->size += len; - } - return 0; -} - -void dbuf_free(DynBuf *s) -{ - /* we test s->buf as a fail safe to avoid crashing if dbuf_free() - is called twice */ - if (s->buf) { - s->realloc_func(s->opaque, s->buf, 0); - } - memset(s, 0, sizeof(*s)); -} - -/* Note: at most 31 bits are encoded. At most UTF8_CHAR_LEN_MAX bytes - are output. */ -int unicode_to_utf8(uint8_t *buf, unsigned int c) -{ - uint8_t *q = buf; - - if (c < 0x80) { - *q++ = c; - } else { - if (c < 0x800) { - *q++ = (c >> 6) | 0xc0; - } else { - if (c < 0x10000) { - *q++ = (c >> 12) | 0xe0; - } else { - if (c < 0x00200000) { - *q++ = (c >> 18) | 0xf0; - } else { - if (c < 0x04000000) { - *q++ = (c >> 24) | 0xf8; - } else if (c < 0x80000000) { - *q++ = (c >> 30) | 0xfc; - *q++ = ((c >> 24) & 0x3f) | 0x80; - } else { - return 0; - } - *q++ = ((c >> 18) & 0x3f) | 0x80; - } - *q++ = ((c >> 12) & 0x3f) | 0x80; - } - *q++ = ((c >> 6) & 0x3f) | 0x80; - } - *q++ = (c & 0x3f) | 0x80; - } - return q - buf; -} - -static const unsigned int utf8_min_code[5] = { - 0x80, 0x800, 0x10000, 0x00200000, 0x04000000, -}; - -static const unsigned char utf8_first_code_mask[5] = { - 0x1f, 0xf, 0x7, 0x3, 0x1, -}; - -/* return -1 if error. *pp is not updated in this case. max_len must - be >= 1. The maximum length for a UTF8 byte sequence is 6 bytes. */ -int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp) -{ - int l, c, b, i; - - c = *p++; - if (c < 0x80) { - *pp = p; - return c; - } - switch(c) { - case 0xc0: case 0xc1: case 0xc2: case 0xc3: - case 0xc4: case 0xc5: case 0xc6: case 0xc7: - case 0xc8: case 0xc9: case 0xca: case 0xcb: - case 0xcc: case 0xcd: case 0xce: case 0xcf: - case 0xd0: case 0xd1: case 0xd2: case 0xd3: - case 0xd4: case 0xd5: case 0xd6: case 0xd7: - case 0xd8: case 0xd9: case 0xda: case 0xdb: - case 0xdc: case 0xdd: case 0xde: case 0xdf: - l = 1; - break; - case 0xe0: case 0xe1: case 0xe2: case 0xe3: - case 0xe4: case 0xe5: case 0xe6: case 0xe7: - case 0xe8: case 0xe9: case 0xea: case 0xeb: - case 0xec: case 0xed: case 0xee: case 0xef: - l = 2; - break; - case 0xf0: case 0xf1: case 0xf2: case 0xf3: - case 0xf4: case 0xf5: case 0xf6: case 0xf7: - l = 3; - break; - case 0xf8: case 0xf9: case 0xfa: case 0xfb: - l = 4; - break; - case 0xfc: case 0xfd: - l = 5; - break; - default: - return -1; - } - /* check that we have enough characters */ - if (l > (max_len - 1)) - return -1; - c &= utf8_first_code_mask[l - 1]; - for(i = 0; i < l; i++) { - b = *p++; - if (b < 0x80 || b >= 0xc0) - return -1; - c = (c << 6) | (b & 0x3f); - } - if (c < utf8_min_code[l - 1]) - return -1; - *pp = p; - return c; -} - -#if 0 - -#if defined(EMSCRIPTEN) || defined(__ANDROID__) - -static void *rqsort_arg; -static int (*rqsort_cmp)(const void *, const void *, void *); - -static int rqsort_cmp2(const void *p1, const void *p2) -{ - return rqsort_cmp(p1, p2, rqsort_arg); -} - -/* not reentrant, but not needed with emscripten */ -void rqsort(void *base, size_t nmemb, size_t size, - int (*cmp)(const void *, const void *, void *), - void *arg) -{ - rqsort_arg = arg; - rqsort_cmp = cmp; - qsort(base, nmemb, size, rqsort_cmp2); -} - -#endif - -#else - -typedef void (*exchange_f)(void *a, void *b, size_t size); -typedef int (*cmp_f)(const void *, const void *, void *opaque); - -static void exchange_bytes(void *a, void *b, size_t size) { - uint8_t *ap = (uint8_t *)a; - uint8_t *bp = (uint8_t *)b; - - while (size-- != 0) { - uint8_t t = *ap; - *ap++ = *bp; - *bp++ = t; - } -} - -static void exchange_one_byte(void *a, void *b, size_t size) { - uint8_t *ap = (uint8_t *)a; - uint8_t *bp = (uint8_t *)b; - uint8_t t = *ap; - *ap = *bp; - *bp = t; -} - -static void exchange_int16s(void *a, void *b, size_t size) { - uint16_t *ap = (uint16_t *)a; - uint16_t *bp = (uint16_t *)b; - - for (size /= sizeof(uint16_t); size-- != 0;) { - uint16_t t = *ap; - *ap++ = *bp; - *bp++ = t; - } -} - -static void exchange_one_int16(void *a, void *b, size_t size) { - uint16_t *ap = (uint16_t *)a; - uint16_t *bp = (uint16_t *)b; - uint16_t t = *ap; - *ap = *bp; - *bp = t; -} - -static void exchange_int32s(void *a, void *b, size_t size) { - uint32_t *ap = (uint32_t *)a; - uint32_t *bp = (uint32_t *)b; - - for (size /= sizeof(uint32_t); size-- != 0;) { - uint32_t t = *ap; - *ap++ = *bp; - *bp++ = t; - } -} - -static void exchange_one_int32(void *a, void *b, size_t size) { - uint32_t *ap = (uint32_t *)a; - uint32_t *bp = (uint32_t *)b; - uint32_t t = *ap; - *ap = *bp; - *bp = t; -} - -static void exchange_int64s(void *a, void *b, size_t size) { - uint64_t *ap = (uint64_t *)a; - uint64_t *bp = (uint64_t *)b; - - for (size /= sizeof(uint64_t); size-- != 0;) { - uint64_t t = *ap; - *ap++ = *bp; - *bp++ = t; - } -} - -static void exchange_one_int64(void *a, void *b, size_t size) { - uint64_t *ap = (uint64_t *)a; - uint64_t *bp = (uint64_t *)b; - uint64_t t = *ap; - *ap = *bp; - *bp = t; -} - -static void exchange_int128s(void *a, void *b, size_t size) { - uint64_t *ap = (uint64_t *)a; - uint64_t *bp = (uint64_t *)b; - - for (size /= sizeof(uint64_t) * 2; size-- != 0; ap += 2, bp += 2) { - uint64_t t = ap[0]; - uint64_t u = ap[1]; - ap[0] = bp[0]; - ap[1] = bp[1]; - bp[0] = t; - bp[1] = u; - } -} - -static void exchange_one_int128(void *a, void *b, size_t size) { - uint64_t *ap = (uint64_t *)a; - uint64_t *bp = (uint64_t *)b; - uint64_t t = ap[0]; - uint64_t u = ap[1]; - ap[0] = bp[0]; - ap[1] = bp[1]; - bp[0] = t; - bp[1] = u; -} - -static inline exchange_f exchange_func(const void *base, size_t size) { - switch (((uintptr_t)base | (uintptr_t)size) & 15) { - case 0: - if (size == sizeof(uint64_t) * 2) - return exchange_one_int128; - else - return exchange_int128s; - case 8: - if (size == sizeof(uint64_t)) - return exchange_one_int64; - else - return exchange_int64s; - case 4: - case 12: - if (size == sizeof(uint32_t)) - return exchange_one_int32; - else - return exchange_int32s; - case 2: - case 6: - case 10: - case 14: - if (size == sizeof(uint16_t)) - return exchange_one_int16; - else - return exchange_int16s; - default: - if (size == 1) - return exchange_one_byte; - else - return exchange_bytes; - } -} - -static void heapsortx(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque) -{ - uint8_t *basep = (uint8_t *)base; - size_t i, n, c, r; - exchange_f swap = exchange_func(base, size); - - if (nmemb > 1) { - i = (nmemb / 2) * size; - n = nmemb * size; - - while (i > 0) { - i -= size; - for (r = i; (c = r * 2 + size) < n; r = c) { - if (c < n - size && cmp(basep + c, basep + c + size, opaque) <= 0) - c += size; - if (cmp(basep + r, basep + c, opaque) > 0) - break; - swap(basep + r, basep + c, size); - } - } - for (i = n - size; i > 0; i -= size) { - swap(basep, basep + i, size); - - for (r = 0; (c = r * 2 + size) < i; r = c) { - if (c < i - size && cmp(basep + c, basep + c + size, opaque) <= 0) - c += size; - if (cmp(basep + r, basep + c, opaque) > 0) - break; - swap(basep + r, basep + c, size); - } - } - } -} - -static inline void *med3(void *a, void *b, void *c, cmp_f cmp, void *opaque) -{ - return cmp(a, b, opaque) < 0 ? - (cmp(b, c, opaque) < 0 ? b : (cmp(a, c, opaque) < 0 ? c : a )) : - (cmp(b, c, opaque) > 0 ? b : (cmp(a, c, opaque) < 0 ? a : c )); -} - -/* pointer based version with local stack and insertion sort threshhold */ -void rqsort(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque) -{ - struct { uint8_t *base; size_t count; int depth; } stack[50], *sp = stack; - uint8_t *ptr, *pi, *pj, *plt, *pgt, *top, *m; - size_t m4, i, lt, gt, span, span2; - int c, depth; - exchange_f swap = exchange_func(base, size); - exchange_f swap_block = exchange_func(base, size | 128); - - if (nmemb < 2 || size <= 0) - return; - - sp->base = (uint8_t *)base; - sp->count = nmemb; - sp->depth = 0; - sp++; - - while (sp > stack) { - sp--; - ptr = sp->base; - nmemb = sp->count; - depth = sp->depth; - - while (nmemb > 6) { - if (++depth > 50) { - /* depth check to ensure worst case logarithmic time */ - heapsortx(ptr, nmemb, size, cmp, opaque); - nmemb = 0; - break; - } - /* select median of 3 from 1/4, 1/2, 3/4 positions */ - /* should use median of 5 or 9? */ - m4 = (nmemb >> 2) * size; - m = med3(ptr + m4, ptr + 2 * m4, ptr + 3 * m4, cmp, opaque); - swap(ptr, m, size); /* move the pivot to the start or the array */ - i = lt = 1; - pi = plt = ptr + size; - gt = nmemb; - pj = pgt = top = ptr + nmemb * size; - for (;;) { - while (pi < pj && (c = cmp(ptr, pi, opaque)) >= 0) { - if (c == 0) { - swap(plt, pi, size); - lt++; - plt += size; - } - i++; - pi += size; - } - while (pi < (pj -= size) && (c = cmp(ptr, pj, opaque)) <= 0) { - if (c == 0) { - gt--; - pgt -= size; - swap(pgt, pj, size); - } - } - if (pi >= pj) - break; - swap(pi, pj, size); - i++; - pi += size; - } - /* array has 4 parts: - * from 0 to lt excluded: elements identical to pivot - * from lt to pi excluded: elements smaller than pivot - * from pi to gt excluded: elements greater than pivot - * from gt to n excluded: elements identical to pivot - */ - /* move elements identical to pivot in the middle of the array: */ - /* swap values in ranges [0..lt[ and [i-lt..i[ - swapping the smallest span between lt and i-lt is sufficient - */ - span = plt - ptr; - span2 = pi - plt; - lt = i - lt; - if (span > span2) - span = span2; - swap_block(ptr, pi - span, span); - /* swap values in ranges [gt..top[ and [i..top-(top-gt)[ - swapping the smallest span between top-gt and gt-i is sufficient - */ - span = top - pgt; - span2 = pgt - pi; - pgt = top - span2; - gt = nmemb - (gt - i); - if (span > span2) - span = span2; - swap_block(pi, top - span, span); - - /* now array has 3 parts: - * from 0 to lt excluded: elements smaller than pivot - * from lt to gt excluded: elements identical to pivot - * from gt to n excluded: elements greater than pivot - */ - /* stack the larger segment and keep processing the smaller one - to minimize stack use for pathological distributions */ - if (lt > nmemb - gt) { - sp->base = ptr; - sp->count = lt; - sp->depth = depth; - sp++; - ptr = pgt; - nmemb -= gt; - } else { - sp->base = pgt; - sp->count = nmemb - gt; - sp->depth = depth; - sp++; - nmemb = lt; - } - } - /* Use insertion sort for small fragments */ - for (pi = ptr + size, top = ptr + nmemb * size; pi < top; pi += size) { - for (pj = pi; pj > ptr && cmp(pj - size, pj, opaque) > 0; pj -= size) - swap(pj, pj - size, size); - } - } -} - -#endif diff --git a/packages/javascript/javascript_android/cxx/quickjs/cutils.h b/packages/javascript/javascript_android/cxx/quickjs/cutils.h deleted file mode 100644 index 9fcb7a6..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/cutils.h +++ /dev/null @@ -1,423 +0,0 @@ -/* - * C utilities - * - * Copyright (c) 2017 Fabrice Bellard - * Copyright (c) 2018 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef CUTILS_H -#define CUTILS_H - -#include -#include -#include - -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) -#define force_inline inline __attribute__((always_inline)) -#define no_inline __attribute__((noinline)) -#define __maybe_unused __attribute__((unused)) - -#define xglue(x, y) x ## y -#define glue(x, y) xglue(x, y) -#define stringify(s) tostring(s) -#define tostring(s) #s - -#ifndef offsetof -#define offsetof(type, field) ((size_t) &((type *)0)->field) -#endif -#ifndef countof -#define countof(x) (sizeof(x) / sizeof((x)[0])) -#endif -#ifndef container_of -/* return the pointer of type 'type *' containing 'ptr' as field 'member' */ -#define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member))) -#endif - -#if !defined(_MSC_VER) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -#define minimum_length(n) static n -#else -#define minimum_length(n) n -#endif - -typedef int BOOL; - -#ifndef FALSE -enum { - FALSE = 0, - TRUE = 1, -}; -#endif - -void pstrcpy(char *buf, int buf_size, const char *str); -char *pstrcat(char *buf, int buf_size, const char *s); -int strstart(const char *str, const char *val, const char **ptr); -int has_suffix(const char *str, const char *suffix); - -/* Prevent UB when n == 0 and (src == NULL or dest == NULL) */ -static inline void memcpy_no_ub(void *dest, const void *src, size_t n) { - if (n) - memcpy(dest, src, n); -} - -static inline int max_int(int a, int b) -{ - if (a > b) - return a; - else - return b; -} - -static inline int min_int(int a, int b) -{ - if (a < b) - return a; - else - return b; -} - -static inline uint32_t max_uint32(uint32_t a, uint32_t b) -{ - if (a > b) - return a; - else - return b; -} - -static inline uint32_t min_uint32(uint32_t a, uint32_t b) -{ - if (a < b) - return a; - else - return b; -} - -static inline int64_t max_int64(int64_t a, int64_t b) -{ - if (a > b) - return a; - else - return b; -} - -static inline int64_t min_int64(int64_t a, int64_t b) -{ - if (a < b) - return a; - else - return b; -} - -/* WARNING: undefined if a = 0 */ -static inline int clz32(unsigned int a) -{ - return __builtin_clz(a); -} - -/* WARNING: undefined if a = 0 */ -static inline int clz64(uint64_t a) -{ - return __builtin_clzll(a); -} - -/* WARNING: undefined if a = 0 */ -static inline int ctz32(unsigned int a) -{ - return __builtin_ctz(a); -} - -/* WARNING: undefined if a = 0 */ -static inline int ctz64(uint64_t a) -{ - return __builtin_ctzll(a); -} - -struct __attribute__((packed)) packed_u64 { - uint64_t v; -}; - -struct __attribute__((packed)) packed_u32 { - uint32_t v; -}; - -struct __attribute__((packed)) packed_u16 { - uint16_t v; -}; - -static inline uint64_t get_u64(const uint8_t *tab) -{ - return ((const struct packed_u64 *)tab)->v; -} - -static inline int64_t get_i64(const uint8_t *tab) -{ - return (int64_t)((const struct packed_u64 *)tab)->v; -} - -static inline void put_u64(uint8_t *tab, uint64_t val) -{ - ((struct packed_u64 *)tab)->v = val; -} - -static inline uint32_t get_u32(const uint8_t *tab) -{ - return ((const struct packed_u32 *)tab)->v; -} - -static inline int32_t get_i32(const uint8_t *tab) -{ - return (int32_t)((const struct packed_u32 *)tab)->v; -} - -static inline void put_u32(uint8_t *tab, uint32_t val) -{ - ((struct packed_u32 *)tab)->v = val; -} - -static inline uint32_t get_u16(const uint8_t *tab) -{ - return ((const struct packed_u16 *)tab)->v; -} - -static inline int32_t get_i16(const uint8_t *tab) -{ - return (int16_t)((const struct packed_u16 *)tab)->v; -} - -static inline void put_u16(uint8_t *tab, uint16_t val) -{ - ((struct packed_u16 *)tab)->v = val; -} - -static inline uint32_t get_u8(const uint8_t *tab) -{ - return *tab; -} - -static inline int32_t get_i8(const uint8_t *tab) -{ - return (int8_t)*tab; -} - -static inline void put_u8(uint8_t *tab, uint8_t val) -{ - *tab = val; -} - -#ifndef bswap16 -static inline uint16_t bswap16(uint16_t x) -{ - return (x >> 8) | (x << 8); -} -#endif - -#ifndef bswap32 -static inline uint32_t bswap32(uint32_t v) -{ - return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) | - ((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24); -} -#endif - -#ifndef bswap64 -static inline uint64_t bswap64(uint64_t v) -{ - return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) | - ((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) | - ((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) | - ((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) | - ((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) | - ((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) | - ((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) | - ((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8)); -} -#endif - -/* XXX: should take an extra argument to pass slack information to the caller */ -typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size); - -typedef struct DynBuf { - uint8_t *buf; - size_t size; - size_t allocated_size; - BOOL error; /* true if a memory allocation error occurred */ - DynBufReallocFunc *realloc_func; - void *opaque; /* for realloc_func */ -} DynBuf; - -void dbuf_init(DynBuf *s); -void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func); -int dbuf_realloc(DynBuf *s, size_t new_size); -int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len); -int dbuf_put(DynBuf *s, const uint8_t *data, size_t len); -int dbuf_put_self(DynBuf *s, size_t offset, size_t len); -int dbuf_putc(DynBuf *s, uint8_t c); -int dbuf_putstr(DynBuf *s, const char *str); -static inline int dbuf_put_u16(DynBuf *s, uint16_t val) -{ - return dbuf_put(s, (uint8_t *)&val, 2); -} -static inline int dbuf_put_u32(DynBuf *s, uint32_t val) -{ - return dbuf_put(s, (uint8_t *)&val, 4); -} -static inline int dbuf_put_u64(DynBuf *s, uint64_t val) -{ - return dbuf_put(s, (uint8_t *)&val, 8); -} -int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s, - const char *fmt, ...); -void dbuf_free(DynBuf *s); -static inline BOOL dbuf_error(DynBuf *s) { - return s->error; -} -static inline void dbuf_set_error(DynBuf *s) -{ - s->error = TRUE; -} - -#define UTF8_CHAR_LEN_MAX 6 - -int unicode_to_utf8(uint8_t *buf, unsigned int c); -int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp); - -static inline BOOL is_surrogate(uint32_t c) -{ - return (c >> 11) == (0xD800 >> 11); // 0xD800-0xDFFF -} - -static inline BOOL is_hi_surrogate(uint32_t c) -{ - return (c >> 10) == (0xD800 >> 10); // 0xD800-0xDBFF -} - -static inline BOOL is_lo_surrogate(uint32_t c) -{ - return (c >> 10) == (0xDC00 >> 10); // 0xDC00-0xDFFF -} - -static inline uint32_t get_hi_surrogate(uint32_t c) -{ - return (c >> 10) - (0x10000 >> 10) + 0xD800; -} - -static inline uint32_t get_lo_surrogate(uint32_t c) -{ - return (c & 0x3FF) | 0xDC00; -} - -static inline uint32_t from_surrogate(uint32_t hi, uint32_t lo) -{ - return 0x10000 + 0x400 * (hi - 0xD800) + (lo - 0xDC00); -} - -static inline int from_hex(int c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - else if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - else if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - else - return -1; -} - -void rqsort(void *base, size_t nmemb, size_t size, - int (*cmp)(const void *, const void *, void *), - void *arg); - -static inline uint64_t float64_as_uint64(double d) -{ - union { - double d; - uint64_t u64; - } u; - u.d = d; - return u.u64; -} - -static inline double uint64_as_float64(uint64_t u64) -{ - union { - double d; - uint64_t u64; - } u; - u.u64 = u64; - return u.d; -} - -static inline double fromfp16(uint16_t v) -{ - double d; - uint32_t v1; - v1 = v & 0x7fff; - if (unlikely(v1 >= 0x7c00)) - v1 += 0x1f8000; /* NaN or infinity */ - d = uint64_as_float64(((uint64_t)(v >> 15) << 63) | ((uint64_t)v1 << (52 - 10))); - return d * 0x1p1008; -} - -static inline uint16_t tofp16(double d) -{ - uint64_t a, addend; - uint32_t v, sgn; - int shift; - - a = float64_as_uint64(d); - sgn = a >> 63; - a = a & 0x7fffffffffffffff; - if (unlikely(a > 0x7ff0000000000000)) { - /* nan */ - v = 0x7c01; - } else if (a < 0x3f10000000000000) { /* 0x1p-14 */ - /* subnormal f16 number or zero */ - if (a <= 0x3e60000000000000) { /* 0x1p-25 */ - v = 0x0000; /* zero */ - } else { - shift = 1051 - (a >> 52); - a = ((uint64_t)1 << 52) | (a & (((uint64_t)1 << 52) - 1)); - addend = ((a >> shift) & 1) + (((uint64_t)1 << (shift - 1)) - 1); - v = (a + addend) >> shift; - } - } else { - /* normal number or infinity */ - a -= 0x3f00000000000000; /* adjust the exponent */ - /* round */ - addend = ((a >> (52 - 10)) & 1) + (((uint64_t)1 << (52 - 11)) - 1); - v = (a + addend) >> (52 - 10); - /* overflow ? */ - if (unlikely(v > 0x7c00)) - v = 0x7c00; - } - return v | (sgn << 15); -} - -static inline int isfp16nan(uint16_t v) -{ - return (v & 0x7FFF) > 0x7C00; -} - -static inline int isfp16zero(uint16_t v) -{ - return (v & 0x7FFF) == 0; -} - -#endif /* CUTILS_H */ diff --git a/packages/javascript/javascript_android/cxx/quickjs/doc/quickjs.texi b/packages/javascript/javascript_android/cxx/quickjs/doc/quickjs.texi deleted file mode 100644 index 9130b47..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/doc/quickjs.texi +++ /dev/null @@ -1,1071 +0,0 @@ -\input texinfo - -@iftex -@afourpaper -@headings double -@end iftex - -@include version.texi - -@titlepage -@afourpaper -@sp 7 -@center @titlefont{QuickJS Javascript Engine} -@sp 3 -@center Version: @value{VERSION} -@end titlepage - -@setfilename spec.info -@settitle QuickJS Javascript Engine - -@contents - -@chapter Introduction - -QuickJS (version @value{VERSION}) is a small and embeddable Javascript -engine. It supports most of the ES2023 specification -@footnote{@url{https://tc39.es/ecma262/2023 }} including modules, -asynchronous generators, proxies and BigInt. - -@section Main Features - -@itemize - -@item Small and easily embeddable: just a few C files, no external dependency, 210 KiB of x86 code for a simple ``hello world'' program. - -@item Fast interpreter with very low startup time: runs the 77000 tests of the ECMAScript Test Suite@footnote{@url{https://github.com/tc39/test262}} in less than 2 minutes on a single core of a desktop PC. The complete life cycle of a runtime instance completes in less than 300 microseconds. - -@item Almost complete ES2023 support including modules, asynchronous -generators and full Annex B support (legacy web compatibility). Some -features from the upcoming ES2024 specification -@footnote{@url{https://tc39.es/ecma262/}} are also supported. - -@item Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2023 features. - -@item Compile Javascript sources to executables with no external dependency. - -@item Garbage collection using reference counting (to reduce memory usage and have deterministic behavior) with cycle removal. - -@item Command line interpreter with contextual colorization and completion implemented in Javascript. - -@item Small built-in standard library with C library wrappers. - -@end itemize - -@chapter Usage - -@section Installation - -A Makefile is provided to compile the engine on Linux or MacOS/X. A -preliminary Windows support is available thru cross compilation on a -Linux host with the MingGW tools. - -Edit the top of the @code{Makefile} if you wish to select specific -options then run @code{make}. - -You can type @code{make install} as root if you wish to install the binaries and support files to -@code{/usr/local} (this is not necessary to use QuickJS). - -Note: On some OSes atomic operations are not available or need a -specific library. If you get related errors, you should either add -@code{-latomics} in the Makefile @code{LIBS} variable or disable -@code{CONFIG_ATOMICS} in @file{quickjs.c}. - -@section Quick start - -@code{qjs} is the command line interpreter (Read-Eval-Print Loop). You can pass -Javascript files and/or expressions as arguments to execute them: - -@example -./qjs examples/hello.js -@end example - -@code{qjsc} is the command line compiler: - -@example -./qjsc -o hello examples/hello.js -./hello -@end example - -generates a @code{hello} executable with no external dependency. - -@section Command line options - -@subsection @code{qjs} interpreter - -@verbatim -usage: qjs [options] [file [args]] -@end verbatim - -Options are: -@table @code -@item -h -@item --help -List options. - -@item -e @code{EXPR} -@item --eval @code{EXPR} -Evaluate EXPR. - -@item -i -@item --interactive -Go to interactive mode (it is not the default when files are provided on the command line). - -@item -m -@item --module -Load as ES6 module (default=autodetect). A module is autodetected if -the filename extension is @code{.mjs} or if the first keyword of the -source is @code{import}. - -@item --script -Load as ES6 script (default=autodetect). - -@item -I file -@item --include file -Include an additional file. - -@end table - -Advanced options are: - -@table @code -@item --std -Make the @code{std} and @code{os} modules available to the loaded -script even if it is not a module. - -@item -d -@item --dump -Dump the memory usage stats. - -@item -q -@item --quit -just instantiate the interpreter and quit. - -@end table - -@subsection @code{qjsc} compiler - -@verbatim -usage: qjsc [options] [files] -@end verbatim - -Options are: -@table @code -@item -c -Only output bytecode in a C file. The default is to output an executable file. -@item -e -Output @code{main()} and bytecode in a C file. The default is to output an -executable file. -@item -o output -Set the output filename (default = @file{out.c} or @file{a.out}). - -@item -N cname -Set the C name of the generated data. - -@item -m -Compile as Javascript module (default=autodetect). - -@item -D module_name -Compile a dynamically loaded module and its dependencies. This option -is needed when your code uses the @code{import} keyword or the -@code{os.Worker} constructor because the compiler cannot statically -find the name of the dynamically loaded modules. - -@item -M module_name[,cname] -Add initialization code for an external C module. See the -@code{c_module} example. - -@item -x -Byte swapped output (only used for cross compilation). - -@item -flto -Use link time optimization. The compilation is slower but the -executable is smaller and faster. This option is automatically set -when the @code{-fno-x} options are used. - -@item -fno-[eval|string-normalize|regexp|json|proxy|map|typedarray|promise|bigint] -Disable selected language features to produce a smaller executable file. - -@end table - -@section Built-in tests - -Run @code{make test} to run the few built-in tests included in the -QuickJS archive. - -@section Test262 (ECMAScript Test Suite) - -A test262 runner is included in the QuickJS archive. The test262 tests -can be installed in the QuickJS source directory with: - -@example -git clone https://github.com/tc39/test262.git test262 -cd test262 -patch -p1 < ../tests/test262.patch -cd .. -@end example - -The patch adds the implementation specific @code{harness} functions -and optimizes the inefficient RegExp character classes and Unicode -property escapes tests (the tests themselves are not modified, only a -slow string initialization function is optimized). - -The tests can be run with -@example -make test2 -@end example - -The configuration files @code{test262.conf} -(resp. @code{test262o.conf} for the old ES5.1 tests@footnote{The old -ES5.1 tests can be extracted with @code{git clone --single-branch ---branch es5-tests https://github.com/tc39/test262.git test262o}})) -contain the options to run the various tests. Tests can be excluded -based on features or filename. - -The file @code{test262_errors.txt} contains the current list of -errors. The runner displays a message when a new error appears or when -an existing error is corrected or modified. Use the @code{-u} option -to update the current list of errors (or @code{make test2-update}). - -The file @code{test262_report.txt} contains the logs of all the -tests. It is useful to have a clearer analysis of a particular -error. In case of crash, the last line corresponds to the failing -test. - -Use the syntax @code{./run-test262 -c test262.conf -f filename.js} to -run a single test. Use the syntax @code{./run-test262 -c test262.conf -N} to start testing at test number @code{N}. - -For more information, run @code{./run-test262} to see the command line -options of the test262 runner. - -@code{run-test262} accepts the @code{-N} option to be invoked from -@code{test262-harness}@footnote{@url{https://github.com/bterlson/test262-harness}} -thru @code{eshost}. Unless you want to compare QuickJS with other -engines under the same conditions, we do not recommend to run the -tests this way as it is much slower (typically half an hour instead of -about 100 seconds). - -@chapter Specifications - -@section Language support - -@subsection ES2023 support - -The ES2023 specification is almost fully supported including the Annex -B (legacy web compatibility) and the Unicode related features. - -The following features are not supported yet: - -@itemize - -@item Tail calls@footnote{We believe the current specification of tails calls is too complicated and presents limited practical interests.} - -@end itemize - -@subsection ECMA402 - -ECMA402 (Internationalization API) is not supported. - -@section Modules - -ES6 modules are fully supported. The default name resolution is the -following: - -@itemize - -@item Module names with a leading @code{.} or @code{..} are relative -to the current module path. - -@item Module names without a leading @code{.} or @code{..} are system -modules, such as @code{std} or @code{os}. - -@item Module names ending with @code{.so} are native modules using the -QuickJS C API. - -@end itemize - -@section Standard library - -The standard library is included by default in the command line -interpreter. It contains the two modules @code{std} and @code{os} and -a few global objects. - -@subsection Global objects - -@table @code -@item scriptArgs -Provides the command line arguments. The first argument is the script name. -@item print(...args) -Print the arguments separated by spaces and a trailing newline. -@item console.log(...args) -Same as print(). - -@end table - -@subsection @code{std} module - -The @code{std} module provides wrappers to the libc @file{stdlib.h} -and @file{stdio.h} and a few other utilities. - -Available exports: - -@table @code - -@item exit(n) -Exit the process. - -@item evalScript(str, options = undefined) -Evaluate the string @code{str} as a script (global -eval). @code{options} is an optional object containing the following -optional properties: - - @table @code - @item backtrace_barrier - Boolean (default = false). If true, error backtraces do not list the - stack frames below the evalScript. - @item async - Boolean (default = false). If true, @code{await} is accepted in the - script and a promise is returned. The promise is resolved with an - object whose @code{value} property holds the value returned by the - script. - @end table - -@item loadScript(filename) -Evaluate the file @code{filename} as a script (global eval). - -@item loadFile(filename) -Load the file @code{filename} and return it as a string assuming UTF-8 -encoding. Return @code{null} in case of I/O error. - -@item open(filename, flags, errorObj = undefined) -Open a file (wrapper to the libc @code{fopen()}). Return the FILE -object or @code{null} in case of I/O error. If @code{errorObj} is not -undefined, set its @code{errno} property to the error code or to 0 if -no error occured. - -@item popen(command, flags, errorObj = undefined) -Open a process by creating a pipe (wrapper to the libc -@code{popen()}). Return the FILE -object or @code{null} in case of I/O error. If @code{errorObj} is not -undefined, set its @code{errno} property to the error code or to 0 if -no error occured. - -@item fdopen(fd, flags, errorObj = undefined) -Open a file from a file handle (wrapper to the libc -@code{fdopen()}). Return the FILE -object or @code{null} in case of I/O error. If @code{errorObj} is not -undefined, set its @code{errno} property to the error code or to 0 if -no error occured. - -@item tmpfile(errorObj = undefined) -Open a temporary file. Return the FILE -object or @code{null} in case of I/O error. If @code{errorObj} is not -undefined, set its @code{errno} property to the error code or to 0 if -no error occured. - -@item puts(str) -Equivalent to @code{std.out.puts(str)}. - -@item printf(fmt, ...args) -Equivalent to @code{std.out.printf(fmt, ...args)}. - -@item sprintf(fmt, ...args) -Equivalent to the libc sprintf(). - -@item in -@item out -@item err -Wrappers to the libc file @code{stdin}, @code{stdout}, @code{stderr}. - -@item SEEK_SET -@item SEEK_CUR -@item SEEK_END -Constants for seek(). - -@item Error - -Enumeration object containing the integer value of common errors -(additional error codes may be defined): - - @table @code - @item EINVAL - @item EIO - @item EACCES - @item EEXIST - @item ENOSPC - @item ENOSYS - @item EBUSY - @item ENOENT - @item EPERM - @item EPIPE - @end table - -@item strerror(errno) -Return a string that describes the error @code{errno}. - -@item gc() -Manually invoke the cycle removal algorithm. The cycle removal -algorithm is automatically started when needed, so this function is -useful in case of specific memory constraints or for testing. - -@item getenv(name) -Return the value of the environment variable @code{name} or -@code{undefined} if it is not defined. - -@item setenv(name, value) -Set the value of the environment variable @code{name} to the string -@code{value}. - -@item unsetenv(name) -Delete the environment variable @code{name}. - -@item getenviron() -Return an object containing the environment variables as key-value pairs. - -@item urlGet(url, options = undefined) - -Download @code{url} using the @file{curl} command line -utility. @code{options} is an optional object containing the following -optional properties: - - @table @code - @item binary - Boolean (default = false). If true, the response is an ArrayBuffer - instead of a string. When a string is returned, the data is assumed - to be UTF-8 encoded. - - @item full - - Boolean (default = false). If true, return the an object contains - the properties @code{response} (response content), - @code{responseHeaders} (headers separated by CRLF), @code{status} - (status code). @code{response} is @code{null} is case of protocol or - network error. If @code{full} is false, only the response is - returned if the status is between 200 and 299. Otherwise @code{null} - is returned. - - @end table - -@item parseExtJSON(str) - - Parse @code{str} using a superset of @code{JSON.parse}. The superset - is very close to the JSON5 specification. The following extensions - are accepted: - - @itemize - @item Single line and multiline comments - @item unquoted properties (ASCII-only Javascript identifiers) - @item trailing comma in array and object definitions - @item single quoted strings - @item @code{\v} escape and multi-line strings with trailing @code{\} - @item @code{\f} and @code{\v} are accepted as space characters - @item leading plus or decimal point in numbers - @item hexadecimal (@code{0x} prefix), octal (@code{0o} prefix) and binary (@code{0b} prefix) integers - @item @code{NaN} and @code{Infinity} are accepted as numbers - @end itemize -@end table - -FILE prototype: - -@table @code -@item close() -Close the file. Return 0 if OK or @code{-errno} in case of I/O error. -@item puts(str) -Outputs the string with the UTF-8 encoding. -@item printf(fmt, ...args) -Formatted printf. - -The same formats as the standard C library @code{printf} are -supported. Integer format types (e.g. @code{%d}) truncate the Numbers -or BigInts to 32 bits. Use the @code{l} modifier (e.g. @code{%ld}) to -truncate to 64 bits. - -@item flush() -Flush the buffered file. -@item seek(offset, whence) -Seek to a give file position (whence is -@code{std.SEEK_*}). @code{offset} can be a number or a bigint. Return -0 if OK or @code{-errno} in case of I/O error. -@item tell() -Return the current file position. -@item tello() -Return the current file position as a bigint. -@item eof() -Return true if end of file. -@item fileno() -Return the associated OS handle. -@item error() -Return true if there was an error. -@item clearerr() -Clear the error indication. - -@item read(buffer, position, length) -Read @code{length} bytes from the file to the ArrayBuffer @code{buffer} at byte -position @code{position} (wrapper to the libc @code{fread}). - -@item write(buffer, position, length) -Write @code{length} bytes to the file from the ArrayBuffer @code{buffer} at byte -position @code{position} (wrapper to the libc @code{fwrite}). - -@item getline() -Return the next line from the file, assuming UTF-8 encoding, excluding -the trailing line feed. - -@item readAsString(max_size = undefined) -Read @code{max_size} bytes from the file and return them as a string -assuming UTF-8 encoding. If @code{max_size} is not present, the file -is read up its end. - -@item getByte() -Return the next byte from the file. Return -1 if the end of file is reached. - -@item putByte(c) -Write one byte to the file. -@end table - -@subsection @code{os} module - -The @code{os} module provides Operating System specific functions: - -@itemize -@item low level file access -@item signals -@item timers -@item asynchronous I/O -@item workers (threads) -@end itemize - -The OS functions usually return 0 if OK or an OS specific negative -error code. - -Available exports: - -@table @code -@item open(filename, flags, mode = 0o666) -Open a file. Return a handle or < 0 if error. - -@item O_RDONLY -@item O_WRONLY -@item O_RDWR -@item O_APPEND -@item O_CREAT -@item O_EXCL -@item O_TRUNC -POSIX open flags. - -@item O_TEXT -(Windows specific). Open the file in text mode. The default is binary mode. - -@item close(fd) -Close the file handle @code{fd}. - -@item seek(fd, offset, whence) -Seek in the file. Use @code{std.SEEK_*} for -@code{whence}. @code{offset} is either a number or a bigint. If -@code{offset} is a bigint, a bigint is returned too. - -@item read(fd, buffer, offset, length) -Read @code{length} bytes from the file handle @code{fd} to the -ArrayBuffer @code{buffer} at byte position @code{offset}. -Return the number of read bytes or < 0 if error. - -@item write(fd, buffer, offset, length) -Write @code{length} bytes to the file handle @code{fd} from the -ArrayBuffer @code{buffer} at byte position @code{offset}. -Return the number of written bytes or < 0 if error. - -@item isatty(fd) -Return @code{true} is @code{fd} is a TTY (terminal) handle. - -@item ttyGetWinSize(fd) -Return the TTY size as @code{[width, height]} or @code{null} if not available. - -@item ttySetRaw(fd) -Set the TTY in raw mode. - -@item remove(filename) -Remove a file. Return 0 if OK or @code{-errno}. - -@item rename(oldname, newname) -Rename a file. Return 0 if OK or @code{-errno}. - -@item realpath(path) -Return @code{[str, err]} where @code{str} is the canonicalized absolute -pathname of @code{path} and @code{err} the error code. - -@item getcwd() -Return @code{[str, err]} where @code{str} is the current working directory -and @code{err} the error code. - -@item chdir(path) -Change the current directory. Return 0 if OK or @code{-errno}. - -@item mkdir(path, mode = 0o777) -Create a directory at @code{path}. Return 0 if OK or @code{-errno}. - -@item stat(path) -@item lstat(path) - -Return @code{[obj, err]} where @code{obj} is an object containing the -file status of @code{path}. @code{err} is the error code. The -following fields are defined in @code{obj}: dev, ino, mode, nlink, -uid, gid, rdev, size, blocks, atime, mtime, ctime. The times are -specified in milliseconds since 1970. @code{lstat()} is the same as -@code{stat()} excepts that it returns information about the link -itself. - -@item S_IFMT -@item S_IFIFO -@item S_IFCHR -@item S_IFDIR -@item S_IFBLK -@item S_IFREG -@item S_IFSOCK -@item S_IFLNK -@item S_ISGID -@item S_ISUID -Constants to interpret the @code{mode} property returned by -@code{stat()}. They have the same value as in the C system header -@file{sys/stat.h}. - -@item utimes(path, atime, mtime) -Change the access and modification times of the file @code{path}. The -times are specified in milliseconds since 1970. Return 0 if OK or @code{-errno}. - -@item symlink(target, linkpath) -Create a link at @code{linkpath} containing the string @code{target}. Return 0 if OK or @code{-errno}. - -@item readlink(path) -Return @code{[str, err]} where @code{str} is the link target and @code{err} -the error code. - -@item readdir(path) -Return @code{[array, err]} where @code{array} is an array of strings -containing the filenames of the directory @code{path}. @code{err} is -the error code. - -@item setReadHandler(fd, func) -Add a read handler to the file handle @code{fd}. @code{func} is called -each time there is data pending for @code{fd}. A single read handler -per file handle is supported. Use @code{func = null} to remove the -handler. - -@item setWriteHandler(fd, func) -Add a write handler to the file handle @code{fd}. @code{func} is -called each time data can be written to @code{fd}. A single write -handler per file handle is supported. Use @code{func = null} to remove -the handler. - -@item signal(signal, func) -Call the function @code{func} when the signal @code{signal} -happens. Only a single handler per signal number is supported. Use -@code{null} to set the default handler or @code{undefined} to ignore -the signal. Signal handlers can only be defined in the main thread. - -@item SIGINT -@item SIGABRT -@item SIGFPE -@item SIGILL -@item SIGSEGV -@item SIGTERM -POSIX signal numbers. - -@item kill(pid, sig) -Send the signal @code{sig} to the process @code{pid}. - -@item exec(args[, options]) -Execute a process with the arguments @code{args}. @code{options} is an -object containing optional parameters: - - @table @code - @item block - Boolean (default = true). If true, wait until the process is - terminated. In this case, @code{exec} return the exit code if positive - or the negated signal number if the process was interrupted by a - signal. If false, do not block and return the process id of the child. - - @item usePath - Boolean (default = true). If true, the file is searched in the - @code{PATH} environment variable. - - @item file - String (default = @code{args[0]}). Set the file to be executed. - - @item cwd - String. If present, set the working directory of the new process. - - @item stdin - @item stdout - @item stderr - If present, set the handle in the child for stdin, stdout or stderr. - - @item env - Object. If present, set the process environment from the object - key-value pairs. Otherwise use the same environment as the current - process. - - @item uid - Integer. If present, the process uid with @code{setuid}. - - @item gid - Integer. If present, the process gid with @code{setgid}. - - @end table - -@item getpid() -Return the current process ID. - -@item waitpid(pid, options) -@code{waitpid} Unix system call. Return the array @code{[ret, -status]}. @code{ret} contains @code{-errno} in case of error. - -@item WNOHANG -Constant for the @code{options} argument of @code{waitpid}. - -@item dup(fd) -@code{dup} Unix system call. - -@item dup2(oldfd, newfd) -@code{dup2} Unix system call. - -@item pipe() -@code{pipe} Unix system call. Return two handles as @code{[read_fd, -write_fd]} or null in case of error. - -@item sleep(delay_ms) -Sleep during @code{delay_ms} milliseconds. - -@item sleepAsync(delay_ms) -Asynchronouse sleep during @code{delay_ms} milliseconds. Returns a promise. Example: -@example -await os.sleepAsync(500); -@end example - -@item now() -Return a timestamp in milliseconds with more precision than -@code{Date.now()}. The time origin is unspecified and is normally not -impacted by system clock adjustments. - -@item setTimeout(func, delay) -Call the function @code{func} after @code{delay} ms. Return a handle -to the timer. - -@item clearTimeout(handle) -Cancel a timer. - -@item platform -Return a string representing the platform: @code{"linux"}, @code{"darwin"}, -@code{"win32"} or @code{"js"}. - -@item Worker(module_filename) -Constructor to create a new thread (worker) with an API close to the -@code{WebWorkers}. @code{module_filename} is a string specifying the -module filename which is executed in the newly created thread. As for -dynamically imported module, it is relative to the current script or -module path. Threads normally don't share any data and communicate -between each other with messages. Nested workers are not supported. An -example is available in @file{tests/test_worker.js}. - -The worker class has the following static properties: - - @table @code - @item parent - In the created worker, @code{Worker.parent} represents the parent - worker and is used to send or receive messages. - @end table - -The worker instances have the following properties: - - @table @code - @item postMessage(msg) - - Send a message to the corresponding worker. @code{msg} is cloned in - the destination worker using an algorithm similar to the @code{HTML} - structured clone algorithm. @code{SharedArrayBuffer} are shared - between workers. - - Current limitations: @code{Map} and @code{Set} are not supported - yet. - - @item onmessage - - Getter and setter. Set a function which is called each time a - message is received. The function is called with a single - argument. It is an object with a @code{data} property containing the - received message. The thread is not terminated if there is at least - one non @code{null} @code{onmessage} handler. - - @end table - -@end table - -@section QuickJS C API - -The C API was designed to be simple and efficient. The C API is -defined in the header @code{quickjs.h}. - -@subsection Runtime and contexts - -@code{JSRuntime} represents a Javascript runtime corresponding to an -object heap. Several runtimes can exist at the same time but they -cannot exchange objects. Inside a given runtime, no multi-threading is -supported. - -@code{JSContext} represents a Javascript context (or Realm). Each -JSContext has its own global objects and system objects. There can be -several JSContexts per JSRuntime and they can share objects, similar -to frames of the same origin sharing Javascript objects in a -web browser. - -@subsection JSValue - -@code{JSValue} represents a Javascript value which can be a primitive -type or an object. Reference counting is used, so it is important to -explicitly duplicate (@code{JS_DupValue()}, increment the reference -count) or free (@code{JS_FreeValue()}, decrement the reference count) -JSValues. - -@subsection C functions - -C functions can be created with -@code{JS_NewCFunction()}. @code{JS_SetPropertyFunctionList()} is a -shortcut to easily add functions, setters and getters properties to a -given object. - -Unlike other embedded Javascript engines, there is no implicit stack, -so C functions get their parameters as normal C parameters. As a -general rule, C functions take constant @code{JSValue}s as parameters -(so they don't need to free them) and return a newly allocated (=live) -@code{JSValue}. - -@subsection Exceptions - -Exceptions: most C functions can return a Javascript exception. It -must be explicitly tested and handled by the C code. The specific -@code{JSValue} @code{JS_EXCEPTION} indicates that an exception -occurred. The actual exception object is stored in the -@code{JSContext} and can be retrieved with @code{JS_GetException()}. - -@subsection Script evaluation - -Use @code{JS_Eval()} to evaluate a script or module source. - -If the script or module was compiled to bytecode with @code{qjsc}, it -can be evaluated by calling @code{js_std_eval_binary()}. The advantage -is that no compilation is needed so it is faster and smaller because -the compiler can be removed from the executable if no @code{eval} is -required. - -Note: the bytecode format is linked to a given QuickJS -version. Moreover, no security check is done before its -execution. Hence the bytecode should not be loaded from untrusted -sources. That's why there is no option to output the bytecode to a -binary file in @code{qjsc}. - -@subsection JS Classes - -C opaque data can be attached to a Javascript object. The type of the -C opaque data is determined with the class ID (@code{JSClassID}) of -the object. Hence the first step is to register a new class ID and JS -class (@code{JS_NewClassID()}, @code{JS_NewClass()}). Then you can -create objects of this class with @code{JS_NewObjectClass()} and get or -set the C opaque point with -@code{JS_GetOpaque()}/@code{JS_SetOpaque()}. - -When defining a new JS class, it is possible to declare a finalizer -which is called when the object is destroyed. The finalizer should be -used to release C resources. It is invalid to execute JS code from -it. A @code{gc_mark} method can be provided so that the cycle removal -algorithm can find the other objects referenced by this object. Other -methods are available to define exotic object behaviors. - -The Class ID are globally allocated (i.e. for all runtimes). The -JSClass are allocated per @code{JSRuntime}. @code{JS_SetClassProto()} -is used to define a prototype for a given class in a given -JSContext. @code{JS_NewObjectClass()} sets this prototype in the -created object. - -Examples are available in @file{quickjs-libc.c}. - -@subsection C Modules - -Native ES6 modules are supported and can be dynamically or statically -linked. Look at the @file{test_bjson} and @file{bjson.so} -examples. The standard library @file{quickjs-libc.c} is also a good example -of a native module. - -@subsection Memory handling - -Use @code{JS_SetMemoryLimit()} to set a global memory allocation limit -to a given JSRuntime. - -Custom memory allocation functions can be provided with -@code{JS_NewRuntime2()}. - -The maximum system stack size can be set with @code{JS_SetMaxStackSize()}. - -@subsection Execution timeout and interrupts - -Use @code{JS_SetInterruptHandler()} to set a callback which is -regularly called by the engine when it is executing code. This -callback can be used to implement an execution timeout. - -It is used by the command line interpreter to implement a -@code{Ctrl-C} handler. - -@chapter Internals - -@section Bytecode - -The compiler generates bytecode directly with no intermediate -representation such as a parse tree, hence it is very fast. Several -optimizations passes are done over the generated bytecode. - -A stack-based bytecode was chosen because it is simple and generates -compact code. - -For each function, the maximum stack size is computed at compile time so that -no runtime stack overflow tests are needed. - -A separate compressed line number table is maintained for the debug -information. - -Access to closure variables is optimized and is almost as fast as local -variables. - -Direct @code{eval} in strict mode is optimized. - -@section Executable generation - -@subsection @code{qjsc} compiler - -The @code{qjsc} compiler generates C sources from Javascript files. By -default the C sources are compiled with the system compiler -(@code{gcc} or @code{clang}). - -The generated C source contains the bytecode of the compiled functions -or modules. If a full complete executable is needed, it also -contains a @code{main()} function with the necessary C code to initialize the -Javascript engine and to load and execute the compiled functions and -modules. - -Javascript code can be mixed with C modules. - -In order to have smaller executables, specific Javascript features can -be disabled, in particular @code{eval} or the regular expressions. The -code removal relies on the Link Time Optimization of the system -compiler. - -@subsection Binary JSON - -@code{qjsc} works by compiling scripts or modules and then serializing -them to a binary format. A subset of this format (without functions or -modules) can be used as binary JSON. The example @file{test_bjson.js} -shows how to use it. - -Warning: the binary JSON format may change without notice, so it -should not be used to store persistent data. The @file{test_bjson.js} -example is only used to test the binary object format functions. - -@section Runtime - -@subsection Strings - -Strings are stored either as an 8 bit or a 16 bit array of -characters. Hence random access to characters is always fast. - -The C API provides functions to convert Javascript Strings to C UTF-8 encoded -strings. The most common case where the Javascript string contains -only ASCII characters involves no copying. - -@subsection Objects - -The object shapes (object prototype, property names and flags) are shared -between objects to save memory. - -Arrays with no holes (except at the end of the array) are optimized. - -TypedArray accesses are optimized. - -@subsection Atoms - -Object property names and some strings are stored as Atoms (unique -strings) to save memory and allow fast comparison. Atoms are -represented as a 32 bit integer. Half of the atom range is reserved for -immediate integer literals from @math{0} to @math{2^{31}-1}. - -@subsection Numbers - -Numbers are represented either as 32-bit signed integers or 64-bit IEEE-754 -floating point values. Most operations have fast paths for the 32-bit -integer case. - -@subsection Garbage collection - -Reference counting is used to free objects automatically and -deterministically. A separate cycle removal pass is done when the allocated -memory becomes too large. The cycle removal algorithm only uses the -reference counts and the object content, so no explicit garbage -collection roots need to be manipulated in the C code. - -@subsection JSValue - -It is a Javascript value which can be a primitive type (such as -Number, String, ...) or an Object. NaN boxing is used in the 32-bit version -to store 64-bit floating point numbers. The representation is -optimized so that 32-bit integers and reference counted values can be -efficiently tested. - -In 64-bit code, JSValue are 128-bit large and no NaN boxing is used. The -rationale is that in 64-bit code memory usage is less critical. - -In both cases (32 or 64 bits), JSValue exactly fits two CPU registers, -so it can be efficiently returned by C functions. - -@subsection Function call - -The engine is optimized so that function calls are fast. The system -stack holds the Javascript parameters and local variables. - -@section RegExp - -A specific regular expression engine was developed. It is both small -and efficient and supports all the ES2023 features including the -Unicode properties. As the Javascript compiler, it directly generates -bytecode without a parse tree. - -Backtracking with an explicit stack is used so that there is no -recursion on the system stack. Simple quantifiers are specifically -optimized to avoid recursions. - -The full regexp library weights about 15 KiB (x86 code), excluding the -Unicode library. - -@section Unicode - -A specific Unicode library was developed so that there is no -dependency on an external large Unicode library such as ICU. All the -Unicode tables are compressed while keeping a reasonable access -speed. - -The library supports case conversion, Unicode normalization, Unicode -script queries, Unicode general category queries and all Unicode -binary properties. - -The full Unicode library weights about 45 KiB (x86 code). - -@section BigInt - -BigInts are represented using binary two's complement notation. An -additional short bigint value is used to optimize the performance on -small BigInt values. - -@chapter License - -QuickJS is released under the MIT license. - -Unless otherwise specified, the QuickJS sources are copyright Fabrice -Bellard and Charlie Gordon. - -@bye diff --git a/packages/javascript/javascript_android/cxx/quickjs/dtoa.c b/packages/javascript/javascript_android/cxx/quickjs/dtoa.c deleted file mode 100644 index ac1be8d..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/dtoa.c +++ /dev/null @@ -1,1620 +0,0 @@ -/* - * Tiny float64 printing and parsing library - * - * Copyright (c) 2024 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cutils.h" -#include "dtoa.h" - -/* - TODO: - - test n_digits=101 instead of 100 - - simplify subnormal handling - - reduce max memory usage - - free format: could add shortcut if exact result - - use 64 bit limb_t when possible - - use another algorithm for free format dtoa in base 10 (ryu ?) -*/ - -#define USE_POW5_TABLE -/* use fast path to print small integers in free format */ -#define USE_FAST_INT - -#define LIMB_LOG2_BITS 5 - -#define LIMB_BITS (1 << LIMB_LOG2_BITS) - -typedef int32_t slimb_t; -typedef uint32_t limb_t; -typedef uint64_t dlimb_t; - -#define LIMB_DIGITS 9 - -#define JS_RADIX_MAX 36 - -#define DBIGNUM_LEN_MAX 52 /* ~ 2^(1072+53)*36^100 (dtoa) */ -#define MANT_LEN_MAX 18 /* < 36^100 */ - -typedef intptr_t mp_size_t; - -/* the represented number is sum(i, tab[i]*2^(LIMB_BITS * i)) */ -typedef struct { - int len; /* >= 1 */ - limb_t tab[]; -} mpb_t; - -static limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n) -{ - size_t i; - limb_t k, a; - - k=b; - for(i=0;i> LIMB_BITS; - } - return l; -} - -/* WARNING: d must be >= 2^(LIMB_BITS-1) */ -static inline limb_t udiv1norm_init(limb_t d) -{ - limb_t a0, a1; - a1 = -d - 1; - a0 = -1; - return (((dlimb_t)a1 << LIMB_BITS) | a0) / d; -} - -/* return the quotient and the remainder in '*pr'of 'a1*2^LIMB_BITS+a0 - / d' with 0 <= a1 < d. */ -static inline limb_t udiv1norm(limb_t *pr, limb_t a1, limb_t a0, - limb_t d, limb_t d_inv) -{ - limb_t n1m, n_adj, q, r, ah; - dlimb_t a; - n1m = ((slimb_t)a0 >> (LIMB_BITS - 1)); - n_adj = a0 + (n1m & d); - a = (dlimb_t)d_inv * (a1 - n1m) + n_adj; - q = (a >> LIMB_BITS) + a1; - /* compute a - q * r and update q so that the remainder is between - 0 and d - 1 */ - a = ((dlimb_t)a1 << LIMB_BITS) | a0; - a = a - (dlimb_t)q * d - d; - ah = a >> LIMB_BITS; - q += 1 + ah; - r = (limb_t)a + (ah & d); - *pr = r; - return q; -} - -static limb_t mp_div1(limb_t *tabr, const limb_t *taba, limb_t n, - limb_t b, limb_t r) -{ - slimb_t i; - dlimb_t a1; - for(i = n - 1; i >= 0; i--) { - a1 = ((dlimb_t)r << LIMB_BITS) | taba[i]; - tabr[i] = a1 / b; - r = a1 % b; - } - return r; -} - -/* r = (a + high*B^n) >> shift. Return the remainder r (0 <= r < 2^shift). - 1 <= shift <= LIMB_BITS - 1 */ -static limb_t mp_shr(limb_t *tab_r, const limb_t *tab, mp_size_t n, - int shift, limb_t high) -{ - mp_size_t i; - limb_t l, a; - - assert(shift >= 1 && shift < LIMB_BITS); - l = high; - for(i = n - 1; i >= 0; i--) { - a = tab[i]; - tab_r[i] = (a >> shift) | (l << (LIMB_BITS - shift)); - l = a; - } - return l & (((limb_t)1 << shift) - 1); -} - -/* r = (a << shift) + low. 1 <= shift <= LIMB_BITS - 1, 0 <= low < - 2^shift. */ -static limb_t mp_shl(limb_t *tab_r, const limb_t *tab, mp_size_t n, - int shift, limb_t low) -{ - mp_size_t i; - limb_t l, a; - - assert(shift >= 1 && shift < LIMB_BITS); - l = low; - for(i = 0; i < n; i++) { - a = tab[i]; - tab_r[i] = (a << shift) | l; - l = (a >> (LIMB_BITS - shift)); - } - return l; -} - -static no_inline limb_t mp_div1norm(limb_t *tabr, const limb_t *taba, limb_t n, - limb_t b, limb_t r, limb_t b_inv, int shift) -{ - slimb_t i; - - if (shift != 0) { - r = (r << shift) | mp_shl(tabr, taba, n, shift, 0); - } - for(i = n - 1; i >= 0; i--) { - tabr[i] = udiv1norm(&r, r, taba[i], b, b_inv); - } - r >>= shift; - return r; -} - -static __maybe_unused void mpb_dump(const char *str, const mpb_t *a) -{ - int i; - - printf("%s= 0x", str); - for(i = a->len - 1; i >= 0; i--) { - printf("%08x", a->tab[i]); - if (i != 0) - printf("_"); - } - printf("\n"); -} - -static void mpb_renorm(mpb_t *r) -{ - while (r->len > 1 && r->tab[r->len - 1] == 0) - r->len--; -} - -#ifdef USE_POW5_TABLE -static const uint32_t pow5_table[17] = { - 0x00000005, 0x00000019, 0x0000007d, 0x00000271, - 0x00000c35, 0x00003d09, 0x0001312d, 0x0005f5e1, - 0x001dcd65, 0x009502f9, 0x02e90edd, 0x0e8d4a51, - 0x48c27395, 0x6bcc41e9, 0x1afd498d, 0x86f26fc1, - 0xa2bc2ec5, -}; - -static const uint8_t pow5h_table[4] = { - 0x00000001, 0x00000007, 0x00000023, 0x000000b1, -}; - -static const uint32_t pow5_inv_table[13] = { - 0x99999999, 0x47ae147a, 0x0624dd2f, 0xa36e2eb1, - 0x4f8b588e, 0x0c6f7a0b, 0xad7f29ab, 0x5798ee23, - 0x12e0be82, 0xb7cdfd9d, 0x5fd7fe17, 0x19799812, - 0xc25c2684, -}; -#endif - -/* return a^b */ -static uint64_t pow_ui(uint32_t a, uint32_t b) -{ - int i, n_bits; - uint64_t r; - if (b == 0) - return 1; - if (b == 1) - return a; -#ifdef USE_POW5_TABLE - if ((a == 5 || a == 10) && b <= 17) { - r = pow5_table[b - 1]; - if (b >= 14) { - r |= (uint64_t)pow5h_table[b - 14] << 32; - } - if (a == 10) - r <<= b; - return r; - } -#endif - r = a; - n_bits = 32 - clz32(b); - for(i = n_bits - 2; i >= 0; i--) { - r *= r; - if ((b >> i) & 1) - r *= a; - } - return r; -} - -static uint32_t pow_ui_inv(uint32_t *pr_inv, int *pshift, uint32_t a, uint32_t b) -{ - uint32_t r_inv, r; - int shift; -#ifdef USE_POW5_TABLE - if (a == 5 && b >= 1 && b <= 13) { - r = pow5_table[b - 1]; - shift = clz32(r); - r <<= shift; - r_inv = pow5_inv_table[b - 1]; - } else -#endif - { - r = pow_ui(a, b); - shift = clz32(r); - r <<= shift; - r_inv = udiv1norm_init(r); - } - *pshift = shift; - *pr_inv = r_inv; - return r; -} - -enum { - JS_RNDN, /* round to nearest, ties to even */ - JS_RNDNA, /* round to nearest, ties away from zero */ - JS_RNDZ, -}; - -static int mpb_get_bit(const mpb_t *r, int k) -{ - int l; - - l = (unsigned)k / LIMB_BITS; - k = k & (LIMB_BITS - 1); - if (l >= r->len) - return 0; - else - return (r->tab[l] >> k) & 1; -} - -/* compute round(r / 2^shift). 'shift' can be negative */ -static void mpb_shr_round(mpb_t *r, int shift, int rnd_mode) -{ - int l, i; - - if (shift == 0) - return; - if (shift < 0) { - shift = -shift; - l = (unsigned)shift / LIMB_BITS; - shift = shift & (LIMB_BITS - 1); - if (shift != 0) { - r->tab[r->len] = mp_shl(r->tab, r->tab, r->len, shift, 0); - r->len++; - mpb_renorm(r); - } - if (l > 0) { - for(i = r->len - 1; i >= 0; i--) - r->tab[i + l] = r->tab[i]; - for(i = 0; i < l; i++) - r->tab[i] = 0; - r->len += l; - } - } else { - limb_t bit1, bit2; - int k, add_one; - - switch(rnd_mode) { - default: - case JS_RNDZ: - add_one = 0; - break; - case JS_RNDN: - case JS_RNDNA: - bit1 = mpb_get_bit(r, shift - 1); - if (bit1) { - if (rnd_mode == JS_RNDNA) { - bit2 = 1; - } else { - /* bit2 = oring of all the bits after bit1 */ - bit2 = 0; - if (shift >= 2) { - k = shift - 1; - l = (unsigned)k / LIMB_BITS; - k = k & (LIMB_BITS - 1); - for(i = 0; i < min_int(l, r->len); i++) - bit2 |= r->tab[i]; - if (l < r->len) - bit2 |= r->tab[l] & (((limb_t)1 << k) - 1); - } - } - if (bit2) { - add_one = 1; - } else { - /* round to even */ - add_one = mpb_get_bit(r, shift); - } - } else { - add_one = 0; - } - break; - } - - l = (unsigned)shift / LIMB_BITS; - shift = shift & (LIMB_BITS - 1); - if (l >= r->len) { - r->len = 1; - r->tab[0] = add_one; - } else { - if (l > 0) { - r->len -= l; - for(i = 0; i < r->len; i++) - r->tab[i] = r->tab[i + l]; - } - if (shift != 0) { - mp_shr(r->tab, r->tab, r->len, shift, 0); - mpb_renorm(r); - } - if (add_one) { - limb_t a; - a = mp_add_ui(r->tab, 1, r->len); - if (a) - r->tab[r->len++] = a; - } - } - } -} - -/* return -1, 0 or 1 */ -static int mpb_cmp(const mpb_t *a, const mpb_t *b) -{ - mp_size_t i; - if (a->len < b->len) - return -1; - else if (a->len > b->len) - return 1; - for(i = a->len - 1; i >= 0; i--) { - if (a->tab[i] != b->tab[i]) { - if (a->tab[i] < b->tab[i]) - return -1; - else - return 1; - } - } - return 0; -} - -static void mpb_set_u64(mpb_t *r, uint64_t m) -{ -#if LIMB_BITS == 64 - r->tab[0] = m; - r->len = 1; -#else - r->tab[0] = m; - r->tab[1] = m >> LIMB_BITS; - if (r->tab[1] == 0) - r->len = 1; - else - r->len = 2; -#endif -} - -static uint64_t mpb_get_u64(mpb_t *r) -{ -#if LIMB_BITS == 64 - return r->tab[0]; -#else - if (r->len == 1) { - return r->tab[0]; - } else { - return r->tab[0] | ((uint64_t)r->tab[1] << LIMB_BITS); - } -#endif -} - -/* floor_log2() = position of the first non zero bit or -1 if zero. */ -static int mpb_floor_log2(mpb_t *a) -{ - limb_t v; - v = a->tab[a->len - 1]; - if (v == 0) - return -1; - else - return a->len * LIMB_BITS - 1 - clz32(v); -} - -#define MUL_LOG2_RADIX_BASE_LOG2 24 - -/* round((1 << MUL_LOG2_RADIX_BASE_LOG2)/log2(i + 2)) */ -static const uint32_t mul_log2_radix_table[JS_RADIX_MAX - 1] = { - 0x000000, 0xa1849d, 0x000000, 0x6e40d2, - 0x6308c9, 0x5b3065, 0x000000, 0x50c24e, - 0x4d104d, 0x4a0027, 0x4768ce, 0x452e54, - 0x433d00, 0x418677, 0x000000, 0x3ea16b, - 0x3d645a, 0x3c43c2, 0x3b3b9a, 0x3a4899, - 0x39680b, 0x3897b3, 0x37d5af, 0x372069, - 0x367686, 0x35d6df, 0x354072, 0x34b261, - 0x342bea, 0x33ac62, 0x000000, 0x32bfd9, - 0x3251dd, 0x31e8d6, 0x318465, -}; - -/* return floor(a / log2(radix)) for -2048 <= a <= 2047 */ -static int mul_log2_radix(int a, int radix) -{ - int radix_bits, mult; - - if ((radix & (radix - 1)) == 0) { - /* if the radix is a power of two better to do it exactly */ - radix_bits = 31 - clz32(radix); - if (a < 0) - a -= radix_bits - 1; - return a / radix_bits; - } else { - mult = mul_log2_radix_table[radix - 2]; - return ((int64_t)a * mult) >> MUL_LOG2_RADIX_BASE_LOG2; - } -} - -#if 0 -static void build_mul_log2_radix_table(void) -{ - int base, radix, mult, col, base_log2; - - base_log2 = 24; - base = 1 << base_log2; - col = 0; - for(radix = 2; radix <= 36; radix++) { - if ((radix & (radix - 1)) == 0) - mult = 0; - else - mult = lrint((double)base / log2(radix)); - printf("0x%06x, ", mult); - if (++col == 4) { - printf("\n"); - col = 0; - } - } - printf("\n"); -} - -static void mul_log2_radix_test(void) -{ - int radix, i, ref, r; - - for(radix = 2; radix <= 36; radix++) { - for(i = -2048; i <= 2047; i++) { - ref = (int)floor((double)i / log2(radix)); - r = mul_log2_radix(i, radix); - if (ref != r) { - printf("ERROR: radix=%d i=%d r=%d ref=%d\n", - radix, i, r, ref); - exit(1); - } - } - } - if (0) - build_mul_log2_radix_table(); -} -#endif - -static void u32toa_len(char *buf, uint32_t n, size_t len) -{ - int digit, i; - for(i = len - 1; i >= 0; i--) { - digit = n % 10; - n = n / 10; - buf[i] = digit + '0'; - } -} - -/* for power of 2 radixes. len >= 1 */ -static void u64toa_bin_len(char *buf, uint64_t n, unsigned int radix_bits, int len) -{ - int digit, i; - unsigned int mask; - - mask = (1 << radix_bits) - 1; - for(i = len - 1; i >= 0; i--) { - digit = n & mask; - n >>= radix_bits; - if (digit < 10) - digit += '0'; - else - digit += 'a' - 10; - buf[i] = digit; - } -} - -/* len >= 1. 2 <= radix <= 36 */ -static void limb_to_a(char *buf, limb_t n, unsigned int radix, int len) -{ - int digit, i; - - if (radix == 10) { - /* specific case with constant divisor */ -#if LIMB_BITS == 32 - u32toa_len(buf, n, len); -#else - /* XXX: optimize */ - for(i = len - 1; i >= 0; i--) { - digit = (limb_t)n % 10; - n = (limb_t)n / 10; - buf[i] = digit + '0'; - } -#endif - } else { - for(i = len - 1; i >= 0; i--) { - digit = (limb_t)n % radix; - n = (limb_t)n / radix; - if (digit < 10) - digit += '0'; - else - digit += 'a' - 10; - buf[i] = digit; - } - } -} - -size_t u32toa(char *buf, uint32_t n) -{ - char buf1[10], *q; - size_t len; - - q = buf1 + sizeof(buf1); - do { - *--q = n % 10 + '0'; - n /= 10; - } while (n != 0); - len = buf1 + sizeof(buf1) - q; - memcpy(buf, q, len); - return len; -} - -size_t i32toa(char *buf, int32_t n) -{ - if (n >= 0) { - return u32toa(buf, n); - } else { - buf[0] = '-'; - return u32toa(buf + 1, -(uint32_t)n) + 1; - } -} - -#ifdef USE_FAST_INT -size_t u64toa(char *buf, uint64_t n) -{ - if (n < 0x100000000) { - return u32toa(buf, n); - } else { - uint64_t n1; - char *q = buf; - uint32_t n2; - - n1 = n / 1000000000; - n %= 1000000000; - if (n1 >= 0x100000000) { - n2 = n1 / 1000000000; - n1 = n1 % 1000000000; - /* at most two digits */ - if (n2 >= 10) { - *q++ = n2 / 10 + '0'; - n2 %= 10; - } - *q++ = n2 + '0'; - u32toa_len(q, n1, 9); - q += 9; - } else { - q += u32toa(q, n1); - } - u32toa_len(q, n, 9); - q += 9; - return q - buf; - } -} - -size_t i64toa(char *buf, int64_t n) -{ - if (n >= 0) { - return u64toa(buf, n); - } else { - buf[0] = '-'; - return u64toa(buf + 1, -(uint64_t)n) + 1; - } -} - -/* XXX: only tested for 1 <= n < 2^53 */ -size_t u64toa_radix(char *buf, uint64_t n, unsigned int radix) -{ - int radix_bits, l; - if (likely(radix == 10)) - return u64toa(buf, n); - if ((radix & (radix - 1)) == 0) { - radix_bits = 31 - clz32(radix); - if (n == 0) - l = 1; - else - l = (64 - clz64(n) + radix_bits - 1) / radix_bits; - u64toa_bin_len(buf, n, radix_bits, l); - return l; - } else { - char buf1[41], *q; /* maximum length for radix = 3 */ - size_t len; - int digit; - q = buf1 + sizeof(buf1); - do { - digit = n % radix; - n /= radix; - if (digit < 10) - digit += '0'; - else - digit += 'a' - 10; - *--q = digit; - } while (n != 0); - len = buf1 + sizeof(buf1) - q; - memcpy(buf, q, len); - return len; - } -} - -size_t i64toa_radix(char *buf, int64_t n, unsigned int radix) -{ - if (n >= 0) { - return u64toa_radix(buf, n, radix); - } else { - buf[0] = '-'; - return u64toa_radix(buf + 1, -(uint64_t)n, radix) + 1; - } -} -#endif /* USE_FAST_INT */ - -static const uint8_t digits_per_limb_table[JS_RADIX_MAX - 1] = { -#if LIMB_BITS == 32 -32,20,16,13,12,11,10,10, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -#else -64,40,32,27,24,22,21,20,19,18,17,17,16,16,16,15,15,15,14,14,14,14,13,13,13,13,13,13,13,12,12,12,12,12,12, -#endif -}; - -static const uint32_t radix_base_table[JS_RADIX_MAX - 1] = { - 0x00000000, 0xcfd41b91, 0x00000000, 0x48c27395, - 0x81bf1000, 0x75db9c97, 0x40000000, 0xcfd41b91, - 0x3b9aca00, 0x8c8b6d2b, 0x19a10000, 0x309f1021, - 0x57f6c100, 0x98c29b81, 0x00000000, 0x18754571, - 0x247dbc80, 0x3547667b, 0x4c4b4000, 0x6b5a6e1d, - 0x94ace180, 0xcaf18367, 0x0b640000, 0x0e8d4a51, - 0x1269ae40, 0x17179149, 0x1cb91000, 0x23744899, - 0x2b73a840, 0x34e63b41, 0x40000000, 0x4cfa3cc1, - 0x5c13d840, 0x6d91b519, 0x81bf1000, -}; - -/* XXX: remove the table ? */ -static uint8_t dtoa_max_digits_table[JS_RADIX_MAX - 1] = { - 54, 35, 28, 24, 22, 20, 19, 18, 17, 17, 16, 16, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, -}; - -/* we limit the maximum number of significant digits for atod to about - 128 bits of precision for non power of two bases. The only - requirement for Javascript is at least 20 digits in base 10. For - power of two bases, we do an exact rounding in all the cases. */ -static uint8_t atod_max_digits_table[JS_RADIX_MAX - 1] = { - 64, 80, 32, 55, 49, 45, 21, 40, 38, 37, 35, 34, 33, 32, 16, 31, 30, 30, 29, 29, 28, 28, 27, 27, 27, 26, 26, 26, 26, 25, 12, 25, 25, 24, 24, -}; - -/* if abs(d) >= B^max_exponent, it is an overflow */ -static const int16_t max_exponent[JS_RADIX_MAX - 1] = { - 1024, 647, 512, 442, 397, 365, 342, 324, - 309, 297, 286, 277, 269, 263, 256, 251, - 246, 242, 237, 234, 230, 227, 224, 221, - 218, 216, 214, 211, 209, 207, 205, 203, - 202, 200, 199, -}; - -/* if abs(d) <= B^min_exponent, it is an underflow */ -static const int16_t min_exponent[JS_RADIX_MAX - 1] = { --1075, -679, -538, -463, -416, -383, -359, -340, - -324, -311, -300, -291, -283, -276, -269, -263, - -258, -254, -249, -245, -242, -238, -235, -232, - -229, -227, -224, -222, -220, -217, -215, -214, - -212, -210, -208, -}; - -#if 0 -void build_tables(void) -{ - int r, j, radix, n, col, i; - - /* radix_base_table */ - for(radix = 2; radix <= 36; radix++) { - r = 1; - for(j = 0; j < digits_per_limb_table[radix - 2]; j++) { - r *= radix; - } - printf(" 0x%08x,", r); - if ((radix % 4) == 1) - printf("\n"); - } - printf("\n"); - - /* dtoa_max_digits_table */ - for(radix = 2; radix <= 36; radix++) { - /* Note: over estimated when the radix is a power of two */ - printf(" %d,", 1 + (int)ceil(53.0 / log2(radix))); - } - printf("\n"); - - /* atod_max_digits_table */ - for(radix = 2; radix <= 36; radix++) { - if ((radix & (radix - 1)) == 0) { - /* 64 bits is more than enough */ - n = (int)floor(64.0 / log2(radix)); - } else { - n = (int)floor(128.0 / log2(radix)); - } - printf(" %d,", n); - } - printf("\n"); - - printf("static const int16_t max_exponent[JS_RADIX_MAX - 1] = {\n"); - col = 0; - for(radix = 2; radix <= 36; radix++) { - printf("%5d, ", (int)ceil(1024 / log2(radix))); - if (++col == 8) { - col = 0; - printf("\n"); - } - } - printf("\n};\n\n"); - - printf("static const int16_t min_exponent[JS_RADIX_MAX - 1] = {\n"); - col = 0; - for(radix = 2; radix <= 36; radix++) { - printf("%5d, ", (int)floor(-1075 / log2(radix))); - if (++col == 8) { - col = 0; - printf("\n"); - } - } - printf("\n};\n\n"); - - printf("static const uint32_t pow5_table[16] = {\n"); - col = 0; - for(i = 2; i <= 17; i++) { - r = 1; - for(j = 0; j < i; j++) { - r *= 5; - } - printf("0x%08x, ", r); - if (++col == 4) { - col = 0; - printf("\n"); - } - } - printf("\n};\n\n"); - - /* high part */ - printf("static const uint8_t pow5h_table[4] = {\n"); - col = 0; - for(i = 14; i <= 17; i++) { - uint64_t r1; - r1 = 1; - for(j = 0; j < i; j++) { - r1 *= 5; - } - printf("0x%08x, ", (uint32_t)(r1 >> 32)); - if (++col == 4) { - col = 0; - printf("\n"); - } - } - printf("\n};\n\n"); -} -#endif - -/* n_digits >= 1. 0 <= dot_pos <= n_digits. If dot_pos == n_digits, - the dot is not displayed. 'a' is modified. */ -static int output_digits(char *buf, - mpb_t *a, int radix, int n_digits1, - int dot_pos) -{ - int n_digits, digits_per_limb, radix_bits, n, len; - - n_digits = n_digits1; - if ((radix & (radix - 1)) == 0) { - /* radix = 2^radix_bits */ - radix_bits = 31 - clz32(radix); - } else { - radix_bits = 0; - } - digits_per_limb = digits_per_limb_table[radix - 2]; - if (radix_bits != 0) { - for(;;) { - n = min_int(n_digits, digits_per_limb); - n_digits -= n; - u64toa_bin_len(buf + n_digits, a->tab[0], radix_bits, n); - if (n_digits == 0) - break; - mpb_shr_round(a, digits_per_limb * radix_bits, JS_RNDZ); - } - } else { - limb_t r; - while (n_digits != 0) { - n = min_int(n_digits, digits_per_limb); - n_digits -= n; - r = mp_div1(a->tab, a->tab, a->len, radix_base_table[radix - 2], 0); - mpb_renorm(a); - limb_to_a(buf + n_digits, r, radix, n); - } - } - - /* add the dot */ - len = n_digits1; - if (dot_pos != n_digits1) { - memmove(buf + dot_pos + 1, buf + dot_pos, n_digits1 - dot_pos); - buf[dot_pos] = '.'; - len++; - } - return len; -} - -/* return (a, e_offset) such that a = a * (radix1*2^radix_shift)^f * - 2^-e_offset. 'f' can be negative. */ -static int mul_pow(mpb_t *a, int radix1, int radix_shift, int f, BOOL is_int, int e) -{ - int e_offset, d, n, n0; - - e_offset = -f * radix_shift; - if (radix1 != 1) { - d = digits_per_limb_table[radix1 - 2]; - if (f >= 0) { - limb_t h, b; - - b = 0; - n0 = 0; - while (f != 0) { - n = min_int(f, d); - if (n != n0) { - b = pow_ui(radix1, n); - n0 = n; - } - h = mp_mul1(a->tab, a->tab, a->len, b, 0); - if (h != 0) { - a->tab[a->len++] = h; - } - f -= n; - } - } else { - int extra_bits, l, shift; - limb_t r, rem, b, b_inv; - - f = -f; - l = (f + d - 1) / d; /* high bound for the number of limbs (XXX: make it better) */ - e_offset += l * LIMB_BITS; - if (!is_int) { - /* at least 'e' bits are needed in the final result for rounding */ - extra_bits = max_int(e - mpb_floor_log2(a), 0); - } else { - /* at least two extra bits are needed in the final result - for rounding */ - extra_bits = max_int(2 + e - e_offset, 0); - } - e_offset += extra_bits; - mpb_shr_round(a, -(l * LIMB_BITS + extra_bits), JS_RNDZ); - - b = 0; - b_inv = 0; - shift = 0; - n0 = 0; - rem = 0; - while (f != 0) { - n = min_int(f, d); - if (n != n0) { - b = pow_ui_inv(&b_inv, &shift, radix1, n); - n0 = n; - } - r = mp_div1norm(a->tab, a->tab, a->len, b, 0, b_inv, shift); - rem |= r; - mpb_renorm(a); - f -= n; - } - /* if the remainder is non zero, use it for rounding */ - a->tab[0] |= (rem != 0); - } - } - return e_offset; -} - -/* tmp1 = round(m*2^e*radix^f). 'tmp0' is a temporary storage */ -static void mul_pow_round(mpb_t *tmp1, uint64_t m, int e, int radix1, int radix_shift, int f, - int rnd_mode) -{ - int e_offset; - - mpb_set_u64(tmp1, m); - e_offset = mul_pow(tmp1, radix1, radix_shift, f, TRUE, e); - mpb_shr_round(tmp1, -e + e_offset, rnd_mode); -} - -/* return round(a*2^e_offset) rounded as a float64. 'a' is modified */ -static uint64_t round_to_d(int *pe, mpb_t *a, int e_offset, int rnd_mode) -{ - int e; - uint64_t m; - - if (a->tab[0] == 0 && a->len == 1) { - /* zero result */ - m = 0; - e = 0; /* don't care */ - } else { - int prec, prec1, e_min; - e = mpb_floor_log2(a) + 1 - e_offset; - prec1 = 53; - e_min = -1021; - if (e < e_min) { - /* subnormal result or zero */ - prec = prec1 - (e_min - e); - } else { - prec = prec1; - } - mpb_shr_round(a, e + e_offset - prec, rnd_mode); - m = mpb_get_u64(a); - m <<= (53 - prec); - /* mantissa overflow due to rounding */ - if (m >= (uint64_t)1 << 53) { - m >>= 1; - e++; - } - } - *pe = e; - return m; -} - -/* return (m, e) such that m*2^(e-53) = round(a * radix^f) with 2^52 - <= m < 2^53 or m = 0. - 'a' is modified. */ -static uint64_t mul_pow_round_to_d(int *pe, mpb_t *a, - int radix1, int radix_shift, int f, int rnd_mode) -{ - int e_offset; - - e_offset = mul_pow(a, radix1, radix_shift, f, FALSE, 55); - return round_to_d(pe, a, e_offset, rnd_mode); -} - -#ifdef JS_DTOA_DUMP_STATS -static int out_len_count[17]; - -void js_dtoa_dump_stats(void) -{ - int i, sum; - sum = 0; - for(i = 0; i < 17; i++) - sum += out_len_count[i]; - for(i = 0; i < 17; i++) { - printf("%2d %8d %5.2f%%\n", - i + 1, out_len_count[i], (double)out_len_count[i] / sum * 100); - } -} -#endif - -/* return a maximum bound of the string length. The bound depends on - 'd' only if format = JS_DTOA_FORMAT_FRAC or if JS_DTOA_EXP_DISABLED - is enabled. */ -int js_dtoa_max_len(double d, int radix, int n_digits, int flags) -{ - int fmt = flags & JS_DTOA_FORMAT_MASK; - int n, e; - uint64_t a; - - if (fmt != JS_DTOA_FORMAT_FRAC) { - if (fmt == JS_DTOA_FORMAT_FREE) { - n = dtoa_max_digits_table[radix - 2]; - } else { - n = n_digits; - } - if ((flags & JS_DTOA_EXP_MASK) == JS_DTOA_EXP_DISABLED) { - /* no exponential */ - a = float64_as_uint64(d); - e = (a >> 52) & 0x7ff; - if (e == 0x7ff) { - /* NaN, Infinity */ - n = 0; - } else { - e -= 1023; - /* XXX: adjust */ - n += 10 + abs(mul_log2_radix(e - 1, radix)); - } - } else { - /* extra: sign, 1 dot and exponent "e-1000" */ - n += 1 + 1 + 6; - } - } else { - a = float64_as_uint64(d); - e = (a >> 52) & 0x7ff; - if (e == 0x7ff) { - /* NaN, Infinity */ - n = 0; - } else { - /* high bound for the integer part */ - e -= 1023; - /* x < 2^(e + 1) */ - if (e < 0) { - n = 1; - } else { - n = 2 + mul_log2_radix(e - 1, radix); - } - /* sign, extra digit, 1 dot */ - n += 1 + 1 + 1 + n_digits; - } - } - return max_int(n, 9); /* also include NaN and [-]Infinity */ -} - -#if defined(__SANITIZE_ADDRESS__) && 0 -static void *dtoa_malloc(uint64_t **pptr, size_t size) -{ - return malloc(size); -} -static void dtoa_free(void *ptr) -{ - free(ptr); -} -#else -static void *dtoa_malloc(uint64_t **pptr, size_t size) -{ - void *ret; - ret = *pptr; - *pptr += (size + 7) / 8; - return ret; -} - -static void dtoa_free(void *ptr) -{ -} -#endif - -/* return the length */ -int js_dtoa(char *buf, double d, int radix, int n_digits, int flags, - JSDTOATempMem *tmp_mem) -{ - uint64_t a, m, *mptr = tmp_mem->mem; - int e, sgn, l, E, P, i, E_max, radix1, radix_shift; - char *q; - mpb_t *tmp1, *mant_max; - int fmt = flags & JS_DTOA_FORMAT_MASK; - - tmp1 = dtoa_malloc(&mptr, sizeof(mpb_t) + sizeof(limb_t) * DBIGNUM_LEN_MAX); - mant_max = dtoa_malloc(&mptr, sizeof(mpb_t) + sizeof(limb_t) * MANT_LEN_MAX); - assert((mptr - tmp_mem->mem) <= sizeof(JSDTOATempMem) / sizeof(mptr[0])); - - radix_shift = ctz32(radix); - radix1 = radix >> radix_shift; - a = float64_as_uint64(d); - sgn = a >> 63; - e = (a >> 52) & 0x7ff; - m = a & (((uint64_t)1 << 52) - 1); - q = buf; - if (e == 0x7ff) { - if (m == 0) { - if (sgn) - *q++ = '-'; - memcpy(q, "Infinity", 8); - q += 8; - } else { - memcpy(q, "NaN", 3); - q += 3; - } - goto done; - } else if (e == 0) { - if (m == 0) { - tmp1->len = 1; - tmp1->tab[0] = 0; - E = 1; - if (fmt == JS_DTOA_FORMAT_FREE) - P = 1; - else if (fmt == JS_DTOA_FORMAT_FRAC) - P = n_digits + 1; - else - P = n_digits; - /* "-0" is displayed as "0" if JS_DTOA_MINUS_ZERO is not present */ - if (sgn && (flags & JS_DTOA_MINUS_ZERO)) - *q++ = '-'; - goto output; - } - /* denormal number: convert to a normal number */ - l = clz64(m) - 11; - e -= l - 1; - m <<= l; - } else { - m |= (uint64_t)1 << 52; - } - if (sgn) - *q++ = '-'; - /* remove the bias */ - e -= 1022; - /* d = 2^(e-53)*m */ - // printf("m=0x%016" PRIx64 " e=%d\n", m, e); -#ifdef USE_FAST_INT - if (fmt == JS_DTOA_FORMAT_FREE && - e >= 1 && e <= 53 && - (m & (((uint64_t)1 << (53 - e)) - 1)) == 0 && - (flags & JS_DTOA_EXP_MASK) != JS_DTOA_EXP_ENABLED) { - m >>= 53 - e; - /* 'm' is never zero */ - q += u64toa_radix(q, m, radix); - goto done; - } -#endif - - /* this choice of E implies F=round(x*B^(P-E) is such as: - B^(P-1) <= F < 2.B^P. */ - E = 1 + mul_log2_radix(e - 1, radix); - - if (fmt == JS_DTOA_FORMAT_FREE) { - int P_max, E0, e1, E_found, P_found; - uint64_t m1, mant_found, mant, mant_max1; - /* P_max is guarranteed to work by construction */ - P_max = dtoa_max_digits_table[radix - 2]; - E0 = E; - E_found = 0; - P_found = 0; - mant_found = 0; - /* find the minimum number of digits by successive tries */ - P = P_max; /* P_max is guarateed to work */ - for(;;) { - /* mant_max always fits on 64 bits */ - mant_max1 = pow_ui(radix, P); - /* compute the mantissa in base B */ - E = E0; - for(;;) { - /* XXX: add inexact flag */ - mul_pow_round(tmp1, m, e - 53, radix1, radix_shift, P - E, JS_RNDN); - mant = mpb_get_u64(tmp1); - if (mant < mant_max1) - break; - E++; /* at most one iteration is possible */ - } - /* remove useless trailing zero digits */ - while ((mant % radix) == 0) { - mant /= radix; - P--; - } - /* garanteed to work for P = P_max */ - if (P_found == 0) - goto prec_found; - /* convert back to base 2 */ - mpb_set_u64(tmp1, mant); - m1 = mul_pow_round_to_d(&e1, tmp1, radix1, radix_shift, E - P, JS_RNDN); - // printf("P=%2d: m=0x%016" PRIx64 " e=%d m1=0x%016" PRIx64 " e1=%d\n", P, m, e, m1, e1); - /* Note: (m, e) is never zero here, so the exponent for m1 - = 0 does not matter */ - if (m1 == m && e1 == e) { - prec_found: - P_found = P; - E_found = E; - mant_found = mant; - if (P == 1) - break; - P--; /* try lower exponent */ - } else { - break; - } - } - P = P_found; - E = E_found; - mpb_set_u64(tmp1, mant_found); -#ifdef JS_DTOA_DUMP_STATS - if (radix == 10) { - out_len_count[P - 1]++; - } -#endif - } else if (fmt == JS_DTOA_FORMAT_FRAC) { - int len; - - assert(n_digits >= 0 && n_digits <= JS_DTOA_MAX_DIGITS); - /* P = max_int(E, 1) + n_digits; */ - /* frac is rounded using RNDNA */ - mul_pow_round(tmp1, m, e - 53, radix1, radix_shift, n_digits, JS_RNDNA); - - /* we add one extra digit on the left and remove it if needed - to avoid testing if the result is < radix^P */ - len = output_digits(q, tmp1, radix, max_int(E + 1, 1) + n_digits, - max_int(E + 1, 1)); - if (q[0] == '0' && len >= 2 && q[1] != '.') { - len--; - memmove(q, q + 1, len); - } - q += len; - goto done; - } else { - int pow_shift; - assert(n_digits >= 1 && n_digits <= JS_DTOA_MAX_DIGITS); - P = n_digits; - /* mant_max = radix^P */ - mant_max->len = 1; - mant_max->tab[0] = 1; - pow_shift = mul_pow(mant_max, radix1, radix_shift, P, FALSE, 0); - mpb_shr_round(mant_max, pow_shift, JS_RNDZ); - - for(;;) { - /* fixed and frac are rounded using RNDNA */ - mul_pow_round(tmp1, m, e - 53, radix1, radix_shift, P - E, JS_RNDNA); - if (mpb_cmp(tmp1, mant_max) < 0) - break; - E++; /* at most one iteration is possible */ - } - } - output: - if (fmt == JS_DTOA_FORMAT_FIXED) - E_max = n_digits; - else - E_max = dtoa_max_digits_table[radix - 2] + 4; - if ((flags & JS_DTOA_EXP_MASK) == JS_DTOA_EXP_ENABLED || - ((flags & JS_DTOA_EXP_MASK) == JS_DTOA_EXP_AUTO && (E <= -6 || E > E_max))) { - q += output_digits(q, tmp1, radix, P, 1); - E--; - if (radix == 10) { - *q++ = 'e'; - } else if (radix1 == 1 && radix_shift <= 4) { - E *= radix_shift; - *q++ = 'p'; - } else { - *q++ = '@'; - } - if (E < 0) { - *q++ = '-'; - E = -E; - } else { - *q++ = '+'; - } - q += u32toa(q, E); - } else if (E <= 0) { - *q++ = '0'; - *q++ = '.'; - for(i = 0; i < -E; i++) - *q++ = '0'; - q += output_digits(q, tmp1, radix, P, P); - } else { - q += output_digits(q, tmp1, radix, P, min_int(P, E)); - for(i = 0; i < E - P; i++) - *q++ = '0'; - } - done: - *q = '\0'; - dtoa_free(mant_max); - dtoa_free(tmp1); - return q - buf; -} - -static inline int to_digit(int c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - else if (c >= 'A' && c <= 'Z') - return c - 'A' + 10; - else if (c >= 'a' && c <= 'z') - return c - 'a' + 10; - else - return 36; -} - -/* r = r * radix_base + a. radix_base = 0 means radix_base = 2^32 */ -static void mpb_mul1_base(mpb_t *r, limb_t radix_base, limb_t a) -{ - int i; - if (r->tab[0] == 0 && r->len == 1) { - r->tab[0] = a; - } else { - if (radix_base == 0) { - for(i = r->len; i >= 0; i--) { - r->tab[i + 1] = r->tab[i]; - } - r->tab[0] = a; - } else { - r->tab[r->len] = mp_mul1(r->tab, r->tab, r->len, - radix_base, a); - } - r->len++; - mpb_renorm(r); - } -} - -/* XXX: add fast path for small integers */ -double js_atod(const char *str, const char **pnext, int radix, int flags, - JSATODTempMem *tmp_mem) -{ - uint64_t *mptr = tmp_mem->mem; - const char *p, *p_start; - limb_t cur_limb, radix_base, extra_digits; - int is_neg, digit_count, limb_digit_count, digits_per_limb, sep, radix1, radix_shift; - int radix_bits, expn, e, max_digits, expn_offset, dot_pos, sig_pos, pos; - mpb_t *tmp0; - double dval; - BOOL is_bin_exp, is_zero, expn_overflow; - uint64_t m, a; - - tmp0 = dtoa_malloc(&mptr, sizeof(mpb_t) + sizeof(limb_t) * DBIGNUM_LEN_MAX); - assert((mptr - tmp_mem->mem) <= sizeof(JSATODTempMem) / sizeof(mptr[0])); - /* optional separator between digits */ - sep = (flags & JS_ATOD_ACCEPT_UNDERSCORES) ? '_' : 256; - - p = str; - is_neg = 0; - if (p[0] == '+') { - p++; - p_start = p; - } else if (p[0] == '-') { - is_neg = 1; - p++; - p_start = p; - } else { - p_start = p; - } - - if (p[0] == '0') { - if ((p[1] == 'x' || p[1] == 'X') && - (radix == 0 || radix == 16)) { - p += 2; - radix = 16; - } else if ((p[1] == 'o' || p[1] == 'O') && - radix == 0 && (flags & JS_ATOD_ACCEPT_BIN_OCT)) { - p += 2; - radix = 8; - } else if ((p[1] == 'b' || p[1] == 'B') && - radix == 0 && (flags & JS_ATOD_ACCEPT_BIN_OCT)) { - p += 2; - radix = 2; - } else if ((p[1] >= '0' && p[1] <= '9') && - radix == 0 && (flags & JS_ATOD_ACCEPT_LEGACY_OCTAL)) { - int i; - sep = 256; - for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++) - continue; - if (p[i] == '8' || p[i] == '9') - goto no_prefix; - p += 1; - radix = 8; - } else { - goto no_prefix; - } - /* there must be a digit after the prefix */ - if (to_digit((uint8_t)*p) >= radix) - goto fail; - no_prefix: ; - } else { - if (!(flags & JS_ATOD_INT_ONLY) && strstart(p, "Infinity", &p)) - goto overflow; - } - if (radix == 0) - radix = 10; - - cur_limb = 0; - expn_offset = 0; - digit_count = 0; - limb_digit_count = 0; - max_digits = atod_max_digits_table[radix - 2]; - digits_per_limb = digits_per_limb_table[radix - 2]; - radix_base = radix_base_table[radix - 2]; - radix_shift = ctz32(radix); - radix1 = radix >> radix_shift; - if (radix1 == 1) { - /* radix = 2^radix_bits */ - radix_bits = radix_shift; - } else { - radix_bits = 0; - } - tmp0->len = 1; - tmp0->tab[0] = 0; - extra_digits = 0; - pos = 0; - dot_pos = -1; - /* skip leading zeros */ - for(;;) { - if (*p == '.' && (p > p_start || to_digit(p[1]) < radix) && - !(flags & JS_ATOD_INT_ONLY)) { - if (*p == sep) - goto fail; - if (dot_pos >= 0) - break; - dot_pos = pos; - p++; - } - if (*p == sep && p > p_start && p[1] == '0') - p++; - if (*p != '0') - break; - p++; - pos++; - } - - sig_pos = pos; - for(;;) { - limb_t c; - if (*p == '.' && (p > p_start || to_digit(p[1]) < radix) && - !(flags & JS_ATOD_INT_ONLY)) { - if (*p == sep) - goto fail; - if (dot_pos >= 0) - break; - dot_pos = pos; - p++; - } - if (*p == sep && p > p_start && to_digit(p[1]) < radix) - p++; - c = to_digit(*p); - if (c >= radix) - break; - p++; - pos++; - if (digit_count < max_digits) { - /* XXX: could be faster when radix_bits != 0 */ - cur_limb = cur_limb * radix + c; - limb_digit_count++; - if (limb_digit_count == digits_per_limb) { - mpb_mul1_base(tmp0, radix_base, cur_limb); - cur_limb = 0; - limb_digit_count = 0; - } - digit_count++; - } else { - extra_digits |= c; - } - } - if (limb_digit_count != 0) { - mpb_mul1_base(tmp0, pow_ui(radix, limb_digit_count), cur_limb); - } - if (digit_count == 0) { - is_zero = TRUE; - expn_offset = 0; - } else { - is_zero = FALSE; - if (dot_pos < 0) - dot_pos = pos; - expn_offset = sig_pos + digit_count - dot_pos; - } - - /* Use the extra digits for rounding if the base is a power of - two. Otherwise they are just truncated. */ - if (radix_bits != 0 && extra_digits != 0) { - tmp0->tab[0] |= 1; - } - - /* parse the exponent, if any */ - expn = 0; - expn_overflow = FALSE; - is_bin_exp = FALSE; - if (!(flags & JS_ATOD_INT_ONLY) && - ((radix == 10 && (*p == 'e' || *p == 'E')) || - (radix != 10 && (*p == '@' || - (radix_bits >= 1 && radix_bits <= 4 && (*p == 'p' || *p == 'P'))))) && - p > p_start) { - BOOL exp_is_neg; - int c; - is_bin_exp = (*p == 'p' || *p == 'P'); - p++; - exp_is_neg = 0; - if (*p == '+') { - p++; - } else if (*p == '-') { - exp_is_neg = 1; - p++; - } - c = to_digit(*p); - if (c >= 10) - goto fail; /* XXX: could stop before the exponent part */ - expn = c; - p++; - for(;;) { - if (*p == sep && to_digit(p[1]) < 10) - p++; - c = to_digit(*p); - if (c >= 10) - break; - if (!expn_overflow) { - if (unlikely(expn > ((INT32_MAX - 2 - 9) / 10))) { - expn_overflow = TRUE; - } else { - expn = expn * 10 + c; - } - } - p++; - } - if (exp_is_neg) - expn = -expn; - /* if zero result, the exponent can be arbitrarily large */ - if (!is_zero && expn_overflow) { - if (exp_is_neg) - a = 0; - else - a = (uint64_t)0x7ff << 52; /* infinity */ - goto done; - } - } - - if (p == p_start) - goto fail; - - if (is_zero) { - a = 0; - } else { - int expn1; - if (radix_bits != 0) { - if (!is_bin_exp) - expn *= radix_bits; - expn -= expn_offset * radix_bits; - expn1 = expn + digit_count * radix_bits; - if (expn1 >= 1024 + radix_bits) - goto overflow; - else if (expn1 <= -1075) - goto underflow; - m = round_to_d(&e, tmp0, -expn, JS_RNDN); - } else { - expn -= expn_offset; - expn1 = expn + digit_count; - if (expn1 >= max_exponent[radix - 2] + 1) - goto overflow; - else if (expn1 <= min_exponent[radix - 2]) - goto underflow; - m = mul_pow_round_to_d(&e, tmp0, radix1, radix_shift, expn, JS_RNDN); - } - if (m == 0) { - underflow: - a = 0; - } else if (e > 1024) { - overflow: - /* overflow */ - a = (uint64_t)0x7ff << 52; - } else if (e < -1073) { - /* underflow */ - /* XXX: check rounding */ - a = 0; - } else if (e < -1021) { - /* subnormal */ - a = m >> (-e - 1021); - } else { - a = ((uint64_t)(e + 1022) << 52) | (m & (((uint64_t)1 << 52) - 1)); - } - } - done: - a |= (uint64_t)is_neg << 63; - dval = uint64_as_float64(a); - done1: - if (pnext) - *pnext = p; - dtoa_free(tmp0); - return dval; - fail: - dval = NAN; - goto done1; -} diff --git a/packages/javascript/javascript_android/cxx/quickjs/dtoa.h b/packages/javascript/javascript_android/cxx/quickjs/dtoa.h deleted file mode 100644 index de76f1a..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/dtoa.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Tiny float64 printing and parsing library - * - * Copyright (c) 2024 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -//#define JS_DTOA_DUMP_STATS - -/* maximum number of digits for fixed and frac formats */ -#define JS_DTOA_MAX_DIGITS 101 - -/* radix != 10 is only supported with flags = JS_DTOA_FORMAT_FREE */ -/* use as many digits as necessary */ -#define JS_DTOA_FORMAT_FREE (0 << 0) -/* use n_digits significant digits (1 <= n_digits <= JS_DTOA_MAX_DIGITS) */ -#define JS_DTOA_FORMAT_FIXED (1 << 0) -/* force fractional format: [-]dd.dd with n_digits fractional digits. - 0 <= n_digits <= JS_DTOA_MAX_DIGITS */ -#define JS_DTOA_FORMAT_FRAC (2 << 0) -#define JS_DTOA_FORMAT_MASK (3 << 0) - -/* select exponential notation either in fixed or free format */ -#define JS_DTOA_EXP_AUTO (0 << 2) -#define JS_DTOA_EXP_ENABLED (1 << 2) -#define JS_DTOA_EXP_DISABLED (2 << 2) -#define JS_DTOA_EXP_MASK (3 << 2) - -#define JS_DTOA_MINUS_ZERO (1 << 4) /* show the minus sign for -0 */ - -/* only accepts integers (no dot, no exponent) */ -#define JS_ATOD_INT_ONLY (1 << 0) -/* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */ -#define JS_ATOD_ACCEPT_BIN_OCT (1 << 1) -/* accept O prefix as octal if radix == 0 and properly formed (Annex B) */ -#define JS_ATOD_ACCEPT_LEGACY_OCTAL (1 << 2) -/* accept _ between digits as a digit separator */ -#define JS_ATOD_ACCEPT_UNDERSCORES (1 << 3) - -typedef struct { - uint64_t mem[37]; -} JSDTOATempMem; - -typedef struct { - uint64_t mem[27]; -} JSATODTempMem; - -/* return a maximum bound of the string length */ -int js_dtoa_max_len(double d, int radix, int n_digits, int flags); -/* return the string length */ -int js_dtoa(char *buf, double d, int radix, int n_digits, int flags, - JSDTOATempMem *tmp_mem); -double js_atod(const char *str, const char **pnext, int radix, int flags, - JSATODTempMem *tmp_mem); - -#ifdef JS_DTOA_DUMP_STATS -void js_dtoa_dump_stats(void); -#endif - -/* additional exported functions */ -size_t u32toa(char *buf, uint32_t n); -size_t i32toa(char *buf, int32_t n); -size_t u64toa(char *buf, uint64_t n); -size_t i64toa(char *buf, int64_t n); -size_t u64toa_radix(char *buf, uint64_t n, unsigned int radix); -size_t i64toa_radix(char *buf, int64_t n, unsigned int radix); diff --git a/packages/javascript/javascript_android/cxx/quickjs/examples/fib.c b/packages/javascript/javascript_android/cxx/quickjs/examples/fib.c deleted file mode 100644 index be90af5..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/examples/fib.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * QuickJS: Example of C module - * - * Copyright (c) 2017-2018 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "../quickjs.h" - -#define countof(x) (sizeof(x) / sizeof((x)[0])) - -static int fib(int n) -{ - if (n <= 0) - return 0; - else if (n == 1) - return 1; - else - return fib(n - 1) + fib(n - 2); -} - -static JSValue js_fib(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int n, res; - if (JS_ToInt32(ctx, &n, argv[0])) - return JS_EXCEPTION; - res = fib(n); - return JS_NewInt32(ctx, res); -} - -static const JSCFunctionListEntry js_fib_funcs[] = { - JS_CFUNC_DEF("fib", 1, js_fib ), -}; - -static int js_fib_init(JSContext *ctx, JSModuleDef *m) -{ - return JS_SetModuleExportList(ctx, m, js_fib_funcs, - countof(js_fib_funcs)); -} - -#ifdef JS_SHARED_LIBRARY -#define JS_INIT_MODULE js_init_module -#else -#define JS_INIT_MODULE js_init_module_fib -#endif - -JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name) -{ - JSModuleDef *m; - m = JS_NewCModule(ctx, module_name, js_fib_init); - if (!m) - return NULL; - JS_AddModuleExportList(ctx, m, js_fib_funcs, countof(js_fib_funcs)); - return m; -} diff --git a/packages/javascript/javascript_android/cxx/quickjs/examples/fib_module.js b/packages/javascript/javascript_android/cxx/quickjs/examples/fib_module.js deleted file mode 100644 index 6a81071..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/examples/fib_module.js +++ /dev/null @@ -1,10 +0,0 @@ -/* fib module */ -export function fib(n) -{ - if (n <= 0) - return 0; - else if (n == 1) - return 1; - else - return fib(n - 1) + fib(n - 2); -} diff --git a/packages/javascript/javascript_android/cxx/quickjs/examples/hello.js b/packages/javascript/javascript_android/cxx/quickjs/examples/hello.js deleted file mode 100644 index accefce..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/examples/hello.js +++ /dev/null @@ -1 +0,0 @@ -console.log("Hello World"); diff --git a/packages/javascript/javascript_android/cxx/quickjs/examples/hello_module.js b/packages/javascript/javascript_android/cxx/quickjs/examples/hello_module.js deleted file mode 100644 index 5d4c78e..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/examples/hello_module.js +++ /dev/null @@ -1,8 +0,0 @@ -/* example of JS and JSON modules */ - -import { fib } from "./fib_module.js"; -import msg from "./message.json"; - -console.log("Hello World"); -console.log("fib(10)=", fib(10)); -console.log("msg=", msg); diff --git a/packages/javascript/javascript_android/cxx/quickjs/examples/message.json b/packages/javascript/javascript_android/cxx/quickjs/examples/message.json deleted file mode 100644 index 3b7fe48..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/examples/message.json +++ /dev/null @@ -1,2 +0,0 @@ -{ "x" : 1, "tab": [ 1, 2, 3 ] } - diff --git a/packages/javascript/javascript_android/cxx/quickjs/examples/pi_bigint.js b/packages/javascript/javascript_android/cxx/quickjs/examples/pi_bigint.js deleted file mode 100644 index e15abd1..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/examples/pi_bigint.js +++ /dev/null @@ -1,118 +0,0 @@ -/* - * PI computation in Javascript using the BigInt type - */ -"use strict"; - -/* return floor(log2(a)) for a > 0 and 0 for a = 0 */ -function floor_log2(a) -{ - var k_max, a1, k, i; - k_max = 0n; - while ((a >> (2n ** k_max)) != 0n) { - k_max++; - } - k = 0n; - a1 = a; - for(i = k_max - 1n; i >= 0n; i--) { - a1 = a >> (2n ** i); - if (a1 != 0n) { - a = a1; - k |= (1n << i); - } - } - return k; -} - -/* return ceil(log2(a)) for a > 0 */ -function ceil_log2(a) -{ - return floor_log2(a - 1n) + 1n; -} - -/* return floor(sqrt(a)) (not efficient but simple) */ -function int_sqrt(a) -{ - var l, u, s; - if (a == 0n) - return a; - l = ceil_log2(a); - u = 1n << ((l + 1n) / 2n); - /* u >= floor(sqrt(a)) */ - for(;;) { - s = u; - u = ((a / s) + s) / 2n; - if (u >= s) - break; - } - return s; -} - -/* return pi * 2**prec */ -function calc_pi(prec) { - const CHUD_A = 13591409n; - const CHUD_B = 545140134n; - const CHUD_C = 640320n; - const CHUD_C3 = 10939058860032000n; /* C^3/24 */ - const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */ - - /* return [P, Q, G] */ - function chud_bs(a, b, need_G) { - var c, P, Q, G, P1, Q1, G1, P2, Q2, G2; - if (a == (b - 1n)) { - G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n); - P = G * (CHUD_B * b + CHUD_A); - if (b & 1n) - P = -P; - Q = b * b * b * CHUD_C3; - } else { - c = (a + b) >> 1n; - [P1, Q1, G1] = chud_bs(a, c, true); - [P2, Q2, G2] = chud_bs(c, b, need_G); - P = P1 * Q2 + P2 * G1; - Q = Q1 * Q2; - if (need_G) - G = G1 * G2; - else - G = 0n; - } - return [P, Q, G]; - } - - var n, P, Q, G; - /* number of serie terms */ - n = BigInt(Math.ceil(Number(prec) / CHUD_BITS_PER_TERM)) + 10n; - [P, Q, G] = chud_bs(0n, n, false); - Q = (CHUD_C / 12n) * (Q << prec) / (P + Q * CHUD_A); - G = int_sqrt(CHUD_C << (2n * prec)); - return (Q * G) >> prec; -} - -function main(args) { - var r, n_digits, n_bits, out; - if (args.length < 1) { - print("usage: pi n_digits"); - return; - } - n_digits = args[0] | 0; - - /* we add more bits to reduce the probability of bad rounding for - the last digits */ - n_bits = BigInt(Math.ceil(n_digits * Math.log2(10))) + 32n; - r = calc_pi(n_bits); - r = ((10n ** BigInt(n_digits)) * r) >> n_bits; - out = r.toString(); - print(out[0] + "." + out.slice(1)); -} - -var args; -if (typeof scriptArgs != "undefined") { - args = scriptArgs; - args.shift(); -} else if (typeof arguments != "undefined") { - args = arguments; -} else { - /* default: 1000 digits */ - args=[1000]; -} - -main(args); diff --git a/packages/javascript/javascript_android/cxx/quickjs/examples/point.c b/packages/javascript/javascript_android/cxx/quickjs/examples/point.c deleted file mode 100644 index 0386230..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/examples/point.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * QuickJS: Example of C module with a class - * - * Copyright (c) 2019 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "../quickjs.h" -#include - -#define countof(x) (sizeof(x) / sizeof((x)[0])) - -/* Point Class */ - -typedef struct { - int x; - int y; -} JSPointData; - -static JSClassID js_point_class_id; - -static void js_point_finalizer(JSRuntime *rt, JSValue val) -{ - JSPointData *s = JS_GetOpaque(val, js_point_class_id); - /* Note: 's' can be NULL in case JS_SetOpaque() was not called */ - js_free_rt(rt, s); -} - -static JSValue js_point_ctor(JSContext *ctx, - JSValueConst new_target, - int argc, JSValueConst *argv) -{ - JSPointData *s; - JSValue obj = JS_UNDEFINED; - JSValue proto; - - s = js_mallocz(ctx, sizeof(*s)); - if (!s) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &s->x, argv[0])) - goto fail; - if (JS_ToInt32(ctx, &s->y, argv[1])) - goto fail; - /* using new_target to get the prototype is necessary when the - class is extended. */ - proto = JS_GetPropertyStr(ctx, new_target, "prototype"); - if (JS_IsException(proto)) - goto fail; - obj = JS_NewObjectProtoClass(ctx, proto, js_point_class_id); - JS_FreeValue(ctx, proto); - if (JS_IsException(obj)) - goto fail; - JS_SetOpaque(obj, s); - return obj; - fail: - js_free(ctx, s); - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue js_point_get_xy(JSContext *ctx, JSValueConst this_val, int magic) -{ - JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); - if (!s) - return JS_EXCEPTION; - if (magic == 0) - return JS_NewInt32(ctx, s->x); - else - return JS_NewInt32(ctx, s->y); -} - -static JSValue js_point_set_xy(JSContext *ctx, JSValueConst this_val, JSValue val, int magic) -{ - JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); - int v; - if (!s) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &v, val)) - return JS_EXCEPTION; - if (magic == 0) - s->x = v; - else - s->y = v; - return JS_UNDEFINED; -} - -static JSValue js_point_norm(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); - if (!s) - return JS_EXCEPTION; - return JS_NewFloat64(ctx, sqrt((double)s->x * s->x + (double)s->y * s->y)); -} - -static JSClassDef js_point_class = { - "Point", - .finalizer = js_point_finalizer, -}; - -static const JSCFunctionListEntry js_point_proto_funcs[] = { - JS_CGETSET_MAGIC_DEF("x", js_point_get_xy, js_point_set_xy, 0), - JS_CGETSET_MAGIC_DEF("y", js_point_get_xy, js_point_set_xy, 1), - JS_CFUNC_DEF("norm", 0, js_point_norm), -}; - -static int js_point_init(JSContext *ctx, JSModuleDef *m) -{ - JSValue point_proto, point_class; - - /* create the Point class */ - JS_NewClassID(&js_point_class_id); - JS_NewClass(JS_GetRuntime(ctx), js_point_class_id, &js_point_class); - - point_proto = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, point_proto, js_point_proto_funcs, countof(js_point_proto_funcs)); - - point_class = JS_NewCFunction2(ctx, js_point_ctor, "Point", 2, JS_CFUNC_constructor, 0); - /* set proto.constructor and ctor.prototype */ - JS_SetConstructor(ctx, point_class, point_proto); - JS_SetClassProto(ctx, js_point_class_id, point_proto); - - JS_SetModuleExport(ctx, m, "Point", point_class); - return 0; -} - -JSModuleDef *js_init_module(JSContext *ctx, const char *module_name) -{ - JSModuleDef *m; - m = JS_NewCModule(ctx, module_name, js_point_init); - if (!m) - return NULL; - JS_AddModuleExport(ctx, m, "Point"); - return m; -} diff --git a/packages/javascript/javascript_android/cxx/quickjs/examples/test_fib.js b/packages/javascript/javascript_android/cxx/quickjs/examples/test_fib.js deleted file mode 100644 index 70d26bd..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/examples/test_fib.js +++ /dev/null @@ -1,6 +0,0 @@ -/* example of JS module importing a C module */ - -import { fib } from "./fib.so"; - -console.log("Hello World"); -console.log("fib(10)=", fib(10)); diff --git a/packages/javascript/javascript_android/cxx/quickjs/examples/test_point.js b/packages/javascript/javascript_android/cxx/quickjs/examples/test_point.js deleted file mode 100644 index 0659bc3..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/examples/test_point.js +++ /dev/null @@ -1,40 +0,0 @@ -/* example of JS module importing a C module */ -import { Point } from "./point.so"; - -function assert(b, str) -{ - if (b) { - return; - } else { - throw Error("assertion failed: " + str); - } -} - -class ColorPoint extends Point { - constructor(x, y, color) { - super(x, y); - this.color = color; - } - get_color() { - return this.color; - } -}; - -function main() -{ - var pt, pt2; - - pt = new Point(2, 3); - assert(pt.x === 2); - assert(pt.y === 3); - pt.x = 4; - assert(pt.x === 4); - assert(pt.norm() == 5); - - pt2 = new ColorPoint(2, 3, 0xffffff); - assert(pt2.x === 2); - assert(pt2.color === 0xffffff); - assert(pt2.get_color() === 0xffffff); -} - -main(); diff --git a/packages/javascript/javascript_android/cxx/quickjs/fuzz/README b/packages/javascript/javascript_android/cxx/quickjs/fuzz/README deleted file mode 100644 index 18c71cd..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/fuzz/README +++ /dev/null @@ -1,27 +0,0 @@ -libFuzzer support for QuickJS -============================= - -Build QuickJS with libFuzzer support as follows: - - CONFIG_CLANG=y make libfuzzer - -This can be extended with sanitizer support to improve efficacy: - - CONFIG_CLANG=y CONFIG_ASAN=y make libfuzzer - - -Currently, there are three fuzzing targets defined: fuzz_eval, fuzz_compile and fuzz_regexp. -The above build command will produce an executable binary for each of them, which can be -simply executed as: - - ./fuzz_eval - -or with an initial corpus: - - ./fuzz_compile corpus_dir/ - -or with a predefined dictionary to improve its efficacy: - - ./fuzz_eval -dict fuzz/fuzz.dict - -or with arbitrary CLI arguments provided by libFuzzer (https://llvm.org/docs/LibFuzzer.html). diff --git a/packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz.dict b/packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz.dict deleted file mode 100644 index f31eb9f..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz.dict +++ /dev/null @@ -1,254 +0,0 @@ -"__loadScript" -"abs" -"acos" -"acosh" -"add" -"AggregateError" -"and" -"apply" -"Array" -"ArrayBuffer" -"asin" -"asinh" -"atan" -"atan2" -"atanh" -"Atomics" -"BigInt" -"BigInt64Array" -"BigUint64Array" -"Boolean" -"cbrt" -"ceil" -"chdir" -"clearTimeout" -"close" -"clz32" -"compareExchange" -"console" -"construct" -"cos" -"cosh" -"DataView" -"Date" -"decodeURI" -"decodeURIComponent" -"defineProperty" -"deleteProperty" -"dup" -"dup2" -"E" -"encodeURI" -"encodeURIComponent" -"err" -"Error" -"escape" -"eval" -"EvalError" -"evalScript" -"exchange" -"exec" -"exit" -"exp" -"expm1" -"fdopen" -"Float32Array" -"Float64Array" -"floor" -"fround" -"Function" -"gc" -"get" -"getcwd" -"getenv" -"getenviron" -"getOwnPropertyDescriptor" -"getpid" -"getPrototypeOf" -"globalThis" -"has" -"hypot" -"imul" -"in" -"Infinity" -"Int16Array" -"Int32Array" -"Int8Array" -"InternalError" -"isatty" -"isExtensible" -"isFinite" -"isLockFree" -"isNaN" -"iterateBuiltIns" -"JSON" -"kill" -"length" -"LN10" -"LN2" -"load" -"loadFile" -"loadScript" -"log" -"log10" -"LOG10E" -"log1p" -"log2" -"LOG2E" -"lstat" -"Map" -"Math" -"max" -"min" -"mkdir" -"NaN" -"notify" -"now" -"Number" -"O_APPEND" -"O_CREAT" -"O_EXCL" -"O_RDONLY" -"O_RDWR" -"O_TRUNC" -"O_WRONLY" -"Object" -"open" -"Operators" -"or" -"os" -"out" -"ownKeys" -"parse" -"parseExtJSON" -"parseFloat" -"parseInt" -"PI" -"pipe" -"platform" -"popen" -"pow" -"preventExtensions" -"print" -"printf" -"Promise" -"Proxy" -"puts" -"random" -"RangeError" -"read" -"readdir" -"readlink" -"realpath" -"ReferenceError" -"Reflect" -"RegExp" -"remove" -"rename" -"round" -"S_IFBLK" -"S_IFCHR" -"S_IFDIR" -"S_IFIFO" -"S_IFLNK" -"S_IFMT" -"S_IFREG" -"S_IFSOCK" -"S_ISGID" -"S_ISUID" -"scriptArgs" -"seek" -"SEEK_CUR" -"SEEK_END" -"SEEK_SET" -"set" -"Set" -"setenv" -"setPrototypeOf" -"setReadHandler" -"setTimeout" -"setWriteHandler" -"SharedArrayBuffer" -"SIGABRT" -"SIGALRM" -"SIGCHLD" -"SIGCONT" -"SIGFPE" -"SIGILL" -"SIGINT" -"sign" -"signal" -"SIGPIPE" -"SIGQUIT" -"SIGSEGV" -"SIGSTOP" -"SIGTERM" -"SIGTSTP" -"SIGTTIN" -"SIGTTOU" -"SIGUSR1" -"SIGUSR2" -"sin" -"sinh" -"sleep" -"sleepAsync" -"sprintf" -"sqrt" -"SQRT1_2" -"SQRT2" -"stat" -"std" -"store" -"strerror" -"String" -"stringify" -"sub" -"Symbol" -"symlink" -"SyntaxError" -"tan" -"tanh" -"tmpfile" -"trunc" -"ttyGetWinSize" -"ttySetRaw" -"TypeError" -"Uint16Array" -"Uint32Array" -"Uint8Array" -"Uint8ClampedArray" -"undefined" -"unescape" -"unsetenv" -"URIError" -"urlGet" -"utimes" -"wait" -"waitpid" -"WeakMap" -"WeakSet" -"WNOHANG" -"Worker" -"write" -"xor" -"v0" -"v1" -"v2" -"v3" -"v4" -"v5" -"v6" -"v7" -"v8" -"v9" -"v10" -"v11" -"v12" -"v13" -"v14" -"v15" -"v16" -"v17" -"v18" -"v19" -"v20" diff --git a/packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_common.c b/packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_common.c deleted file mode 100644 index 92548d2..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_common.c +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright 2020 Google Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -#include - -#include "fuzz/fuzz_common.h" - -// handle timeouts from infinite loops -static int interrupt_handler(JSRuntime *rt, void *opaque) -{ - nbinterrupts++; - return (nbinterrupts > 100); -} - -void reset_nbinterrupts() { - nbinterrupts = 0; -} - -void test_one_input_init(JSRuntime *rt, JSContext *ctx) { - // 64 Mo - JS_SetMemoryLimit(rt, 0x4000000); - // 64 Kb - JS_SetMaxStackSize(rt, 0x10000); - - JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); - JS_SetInterruptHandler(JS_GetRuntime(ctx), interrupt_handler, NULL); - js_std_add_helpers(ctx, 0, NULL); - - // Load os and std - js_std_init_handlers(rt); - js_init_module_std(ctx, "std"); - js_init_module_os(ctx, "os"); - const char *str = "import * as std from 'std';\n" - "import * as os from 'os';\n" - "globalThis.std = std;\n" - "globalThis.os = os;\n"; - JSValue std_val = JS_Eval(ctx, str, strlen(str), "", JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); - if (!JS_IsException(std_val)) { - js_module_set_import_meta(ctx, std_val, 1, 1); - std_val = JS_EvalFunction(ctx, std_val); - } else { - js_std_dump_error(ctx); - } - std_val = js_std_await(ctx, std_val); - JS_FreeValue(ctx, std_val); -} diff --git a/packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_common.h b/packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_common.h deleted file mode 100644 index 10cb497..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_common.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright 2020 Google Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -#include "quickjs.h" -#include "quickjs-libc.h" - -static int nbinterrupts = 0; - -void reset_nbinterrupts(); -void test_one_input_init(JSRuntime *rt, JSContext *ctx); diff --git a/packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_compile.c b/packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_compile.c deleted file mode 100644 index 0ab1b03..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_compile.c +++ /dev/null @@ -1,93 +0,0 @@ -/* Copyright 2020 Google Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -#include "quickjs.h" -#include "quickjs-libc.h" -#include "cutils.h" -#include "fuzz/fuzz_common.h" - -#include -#include - - -int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - if (size == 0) - return 0; - - JSRuntime *rt = JS_NewRuntime(); - JSContext *ctx = JS_NewContext(rt); - test_one_input_init(rt, ctx); - - uint8_t *null_terminated_data = malloc(size + 1); - memcpy(null_terminated_data, data, size); - null_terminated_data[size] = 0; - - JSValue obj = JS_Eval(ctx, (const char *)null_terminated_data, size, "", JS_EVAL_FLAG_COMPILE_ONLY | JS_EVAL_TYPE_MODULE); - free(null_terminated_data); - //TODO target with JS_ParseJSON - if (JS_IsException(obj)) { - js_std_free_handlers(rt); - JS_FreeValue(ctx, obj); - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - return 0; - } - obj = js_std_await(ctx, obj); - size_t bytecode_size; - uint8_t* bytecode = JS_WriteObject(ctx, &bytecode_size, obj, JS_WRITE_OBJ_BYTECODE); - JS_FreeValue(ctx, obj); - if (!bytecode) { - js_std_free_handlers(rt); - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - return 0; - } - obj = JS_ReadObject(ctx, bytecode, bytecode_size, JS_READ_OBJ_BYTECODE); - js_free(ctx, bytecode); - if (JS_IsException(obj)) { - js_std_free_handlers(rt); - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - return 0; - } - reset_nbinterrupts(); - /* this is based on - * js_std_eval_binary(ctx, bytecode, bytecode_size, 0); - * modified so as not to exit on JS exception - */ - JSValue val; - if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) { - if (JS_ResolveModule(ctx, obj) < 0) { - JS_FreeValue(ctx, obj); - js_std_free_handlers(rt); - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - return 0; - } - js_module_set_import_meta(ctx, obj, FALSE, TRUE); - } - val = JS_EvalFunction(ctx, obj); - if (JS_IsException(val)) { - js_std_dump_error(ctx); - } else { - js_std_loop(ctx); - } - JS_FreeValue(ctx, val); - js_std_free_handlers(rt); - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - - return 0; -} diff --git a/packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_eval.c b/packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_eval.c deleted file mode 100644 index aa26f1e..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_eval.c +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright 2020 Google Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -#include "quickjs.h" -#include "quickjs-libc.h" -#include "fuzz/fuzz_common.h" - -#include -#include -#include - -int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - if (size == 0) - return 0; - - JSRuntime *rt = JS_NewRuntime(); - JSContext *ctx = JS_NewContext(rt); - test_one_input_init(rt, ctx); - - uint8_t *null_terminated_data = malloc(size + 1); - memcpy(null_terminated_data, data, size); - null_terminated_data[size] = 0; - - reset_nbinterrupts(); - //the final 0 does not count (as in strlen) - JSValue val = JS_Eval(ctx, (const char *)null_terminated_data, size, "", JS_EVAL_TYPE_GLOBAL); - free(null_terminated_data); - //TODO targets with JS_ParseJSON, JS_ReadObject - if (!JS_IsException(val)) { - js_std_loop(ctx); - JS_FreeValue(ctx, val); - } - js_std_free_handlers(rt); - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - return 0; -} diff --git a/packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_regexp.c b/packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_regexp.c deleted file mode 100644 index ae929e8..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/fuzz/fuzz_regexp.c +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright 2020 Google Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -#include "libregexp.h" -#include "quickjs-libc.h" - -static int nbinterrupts = 0; - -int lre_check_stack_overflow(void *opaque, size_t alloca_size) { return 0; } - -void *lre_realloc(void *opaque, void *ptr, size_t size) -{ - return realloc(ptr, size); -} - -int lre_check_timeout(void *opaque) - { - nbinterrupts++; - return (nbinterrupts > 100); - } - -int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - int len, ret, i; - uint8_t *bc; - char error_msg[64]; - const uint8_t *input; - uint8_t *capture[255 * 2]; - size_t size1 = size; - - //Splits buffer into 2 sub buffers delimited by null character - for (i = 0; i < size; i++) { - if (data[i] == 0) { - size1 = i; - break; - } - } - if (size1 == size) { - //missing delimiter - return 0; - } - bc = lre_compile(&len, error_msg, sizeof(error_msg), (const char *) data, - size1, 0, NULL); - if (!bc) { - return 0; - } - input = data + size1 + 1; - ret = lre_exec(capture, bc, input, 0, size - (size1 + 1), 0, NULL); - if (ret == 1) { - lre_get_capture_count(bc); - } - free(bc); - - return 0; -} diff --git a/packages/javascript/javascript_android/cxx/quickjs/fuzz/generate_dict.js b/packages/javascript/javascript_android/cxx/quickjs/fuzz/generate_dict.js deleted file mode 100644 index 1366fea..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/fuzz/generate_dict.js +++ /dev/null @@ -1,24 +0,0 @@ -// Function to recursively iterate through built-in names. -function collectBuiltinNames(obj, visited = new Set(), result = new Set()) { - // Check if the object has already been visited to avoid infinite recursion. - if (visited.has(obj)) - return; - - // Add the current object to the set of visited objects - visited.add(obj); - // Get the property names of the current object - const properties = Object.getOwnPropertyNames(obj); - // Iterate through each property - for (var i=0; i < properties.length; i++) { - var property = properties[i]; - if (property != "collectBuiltinNames" && typeof property != "number") - result.add(property); - // Check if the property is an object and if so, recursively iterate through its properties. - if (typeof obj[property] === 'object' && obj[property] !== null) - collectBuiltinNames(obj[property], visited, result); - } - return result; -} - -// Start the recursive iteration with the global object. -console.log(Array.from(collectBuiltinNames(this)).join('\n')); diff --git a/packages/javascript/javascript_android/cxx/quickjs/libregexp-opcode.h b/packages/javascript/javascript_android/cxx/quickjs/libregexp-opcode.h deleted file mode 100644 index ebab751..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/libregexp-opcode.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Regular Expression Engine - * - * Copyright (c) 2017-2018 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifdef DEF - -DEF(invalid, 1) /* never used */ -DEF(char, 3) -DEF(char_i, 3) -DEF(char32, 5) -DEF(char32_i, 5) -DEF(dot, 1) -DEF(any, 1) /* same as dot but match any character including line terminator */ -DEF(line_start, 1) -DEF(line_start_m, 1) -DEF(line_end, 1) -DEF(line_end_m, 1) -DEF(goto, 5) -DEF(split_goto_first, 5) -DEF(split_next_first, 5) -DEF(match, 1) -DEF(save_start, 2) /* save start position */ -DEF(save_end, 2) /* save end position, must come after saved_start */ -DEF(save_reset, 3) /* reset save positions */ -DEF(loop, 5) /* decrement the top the stack and goto if != 0 */ -DEF(push_i32, 5) /* push integer on the stack */ -DEF(drop, 1) -DEF(word_boundary, 1) -DEF(word_boundary_i, 1) -DEF(not_word_boundary, 1) -DEF(not_word_boundary_i, 1) -DEF(back_reference, 2) -DEF(back_reference_i, 2) /* must come after */ -DEF(backward_back_reference, 2) /* must come after */ -DEF(backward_back_reference_i, 2) /* must come after */ -DEF(range, 3) /* variable length */ -DEF(range_i, 3) /* variable length */ -DEF(range32, 3) /* variable length */ -DEF(range32_i, 3) /* variable length */ -DEF(lookahead, 5) -DEF(negative_lookahead, 5) -DEF(push_char_pos, 1) /* push the character position on the stack */ -DEF(check_advance, 1) /* pop one stack element and check that it is different from the character position */ -DEF(prev, 1) /* go to the previous char */ -DEF(simple_greedy_quant, 17) - -#endif /* DEF */ diff --git a/packages/javascript/javascript_android/cxx/quickjs/libregexp.c b/packages/javascript/javascript_android/cxx/quickjs/libregexp.c deleted file mode 100644 index 2b33c86..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/libregexp.c +++ /dev/null @@ -1,3259 +0,0 @@ -/* - * Regular Expression Engine - * - * Copyright (c) 2017-2018 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include -#include -#include -#include -#include -#include - -#include "cutils.h" -#include "libregexp.h" -#include "libunicode.h" - -/* - TODO: - - - Add a lock step execution mode (=linear time execution guaranteed) - when the regular expression is "simple" i.e. no backreference nor - complicated lookahead. The opcodes are designed for this execution - model. -*/ - -#if defined(TEST) -#define DUMP_REOP -#endif - -typedef enum { -#define DEF(id, size) REOP_ ## id, -#include "libregexp-opcode.h" -#undef DEF - REOP_COUNT, -} REOPCodeEnum; - -#define CAPTURE_COUNT_MAX 255 -#define STACK_SIZE_MAX 255 -/* must be large enough to have a negligible runtime cost and small - enough to call the interrupt callback often. */ -#define INTERRUPT_COUNTER_INIT 10000 - -/* unicode code points */ -#define CP_LS 0x2028 -#define CP_PS 0x2029 - -#define TMP_BUF_SIZE 128 - -typedef struct { - DynBuf byte_code; - const uint8_t *buf_ptr; - const uint8_t *buf_end; - const uint8_t *buf_start; - int re_flags; - BOOL is_unicode; - BOOL unicode_sets; /* if set, is_unicode is also set */ - BOOL ignore_case; - BOOL multi_line; - BOOL dotall; - int capture_count; - int total_capture_count; /* -1 = not computed yet */ - int has_named_captures; /* -1 = don't know, 0 = no, 1 = yes */ - void *opaque; - DynBuf group_names; - union { - char error_msg[TMP_BUF_SIZE]; - char tmp_buf[TMP_BUF_SIZE]; - } u; -} REParseState; - -typedef struct { -#ifdef DUMP_REOP - const char *name; -#endif - uint8_t size; -} REOpCode; - -static const REOpCode reopcode_info[REOP_COUNT] = { -#ifdef DUMP_REOP -#define DEF(id, size) { #id, size }, -#else -#define DEF(id, size) { size }, -#endif -#include "libregexp-opcode.h" -#undef DEF -}; - -#define RE_HEADER_FLAGS 0 -#define RE_HEADER_CAPTURE_COUNT 2 -#define RE_HEADER_STACK_SIZE 3 -#define RE_HEADER_BYTECODE_LEN 4 - -#define RE_HEADER_LEN 8 - -static inline int is_digit(int c) { - return c >= '0' && c <= '9'; -} - -/* insert 'len' bytes at position 'pos'. Return < 0 if error. */ -static int dbuf_insert(DynBuf *s, int pos, int len) -{ - if (dbuf_realloc(s, s->size + len)) - return -1; - memmove(s->buf + pos + len, s->buf + pos, s->size - pos); - s->size += len; - return 0; -} - -typedef struct REString { - struct REString *next; - uint32_t hash; - uint32_t len; - uint32_t buf[]; -} REString; - -typedef struct { - /* the string list is the union of 'char_range' and of the strings - in hash_table[]. The strings in hash_table[] have a length != - 1. */ - CharRange cr; - uint32_t n_strings; - uint32_t hash_size; - int hash_bits; - REString **hash_table; -} REStringList; - -static uint32_t re_string_hash(int len, const uint32_t *buf) -{ - int i; - uint32_t h; - h = 1; - for(i = 0; i < len; i++) - h = h * 263 + buf[i]; - return h * 0x61C88647; -} - -static void re_string_list_init(REParseState *s1, REStringList *s) -{ - cr_init(&s->cr, s1->opaque, lre_realloc); - s->n_strings = 0; - s->hash_size = 0; - s->hash_bits = 0; - s->hash_table = NULL; -} - -static void re_string_list_free(REStringList *s) -{ - REString *p, *p_next; - int i; - for(i = 0; i < s->hash_size; i++) { - for(p = s->hash_table[i]; p != NULL; p = p_next) { - p_next = p->next; - lre_realloc(s->cr.mem_opaque, p, 0); - } - } - lre_realloc(s->cr.mem_opaque, s->hash_table, 0); - - cr_free(&s->cr); -} - -static void lre_print_char(int c, BOOL is_range) -{ - if (c == '\'' || c == '\\' || - (is_range && (c == '-' || c == ']'))) { - printf("\\%c", c); - } else if (c >= ' ' && c <= 126) { - printf("%c", c); - } else { - printf("\\u{%04x}", c); - } -} - -static __maybe_unused void re_string_list_dump(const char *str, const REStringList *s) -{ - REString *p; - const CharRange *cr; - int i, j, k; - - printf("%s:\n", str); - printf(" ranges: ["); - cr = &s->cr; - for(i = 0; i < cr->len; i += 2) { - lre_print_char(cr->points[i], TRUE); - if (cr->points[i] != cr->points[i + 1] - 1) { - printf("-"); - lre_print_char(cr->points[i + 1] - 1, TRUE); - } - } - printf("]\n"); - - j = 0; - for(i = 0; i < s->hash_size; i++) { - for(p = s->hash_table[i]; p != NULL; p = p->next) { - printf(" %d/%d: '", j, s->n_strings); - for(k = 0; k < p->len; k++) { - lre_print_char(p->buf[k], FALSE); - } - printf("'\n"); - j++; - } - } -} - -static int re_string_find2(REStringList *s, int len, const uint32_t *buf, - uint32_t h0, BOOL add_flag) -{ - uint32_t h = 0; /* avoid warning */ - REString *p; - if (s->n_strings != 0) { - h = h0 >> (32 - s->hash_bits); - for(p = s->hash_table[h]; p != NULL; p = p->next) { - if (p->hash == h0 && p->len == len && - !memcmp(p->buf, buf, len * sizeof(buf[0]))) { - return 1; - } - } - } - /* not found */ - if (!add_flag) - return 0; - /* increase the size of the hash table if needed */ - if (unlikely((s->n_strings + 1) > s->hash_size)) { - REString **new_hash_table, *p_next; - int new_hash_bits, i; - uint32_t new_hash_size; - new_hash_bits = max_int(s->hash_bits + 1, 4); - new_hash_size = 1 << new_hash_bits; - new_hash_table = lre_realloc(s->cr.mem_opaque, NULL, - sizeof(new_hash_table[0]) * new_hash_size); - if (!new_hash_table) - return -1; - memset(new_hash_table, 0, sizeof(new_hash_table[0]) * new_hash_size); - for(i = 0; i < s->hash_size; i++) { - for(p = s->hash_table[i]; p != NULL; p = p_next) { - p_next = p->next; - h = p->hash >> (32 - new_hash_bits); - p->next = new_hash_table[h]; - new_hash_table[h] = p; - } - } - lre_realloc(s->cr.mem_opaque, s->hash_table, 0); - s->hash_bits = new_hash_bits; - s->hash_size = new_hash_size; - s->hash_table = new_hash_table; - h = h0 >> (32 - s->hash_bits); - } - - p = lre_realloc(s->cr.mem_opaque, NULL, sizeof(REString) + len * sizeof(buf[0])); - if (!p) - return -1; - p->next = s->hash_table[h]; - s->hash_table[h] = p; - s->n_strings++; - p->hash = h0; - p->len = len; - memcpy(p->buf, buf, sizeof(buf[0]) * len); - return 1; -} - -static int re_string_find(REStringList *s, int len, const uint32_t *buf, - BOOL add_flag) -{ - uint32_t h0; - h0 = re_string_hash(len, buf); - return re_string_find2(s, len, buf, h0, add_flag); -} - -/* return -1 if memory error, 0 if OK */ -static int re_string_add(REStringList *s, int len, const uint32_t *buf) -{ - if (len == 1) { - return cr_union_interval(&s->cr, buf[0], buf[0]); - } - if (re_string_find(s, len, buf, TRUE) < 0) - return -1; - return 0; -} - -/* a = a op b */ -static int re_string_list_op(REStringList *a, REStringList *b, int op) -{ - int i, ret; - REString *p, **pp; - - if (cr_op1(&a->cr, b->cr.points, b->cr.len, op)) - return -1; - - switch(op) { - case CR_OP_UNION: - if (b->n_strings != 0) { - for(i = 0; i < b->hash_size; i++) { - for(p = b->hash_table[i]; p != NULL; p = p->next) { - if (re_string_find2(a, p->len, p->buf, p->hash, TRUE) < 0) - return -1; - } - } - } - break; - case CR_OP_INTER: - case CR_OP_SUB: - for(i = 0; i < a->hash_size; i++) { - pp = &a->hash_table[i]; - for(;;) { - p = *pp; - if (p == NULL) - break; - ret = re_string_find2(b, p->len, p->buf, p->hash, FALSE); - if (op == CR_OP_SUB) - ret = !ret; - if (!ret) { - /* remove it */ - *pp = p->next; - a->n_strings--; - lre_realloc(a->cr.mem_opaque, p, 0); - } else { - /* keep it */ - pp = &p->next; - } - } - } - break; - default: - abort(); - } - return 0; -} - -static int re_string_list_canonicalize(REParseState *s1, - REStringList *s, BOOL is_unicode) -{ - if (cr_regexp_canonicalize(&s->cr, is_unicode)) - return -1; - if (s->n_strings != 0) { - REStringList a_s, *a = &a_s; - int i, j; - REString *p; - - /* XXX: simplify */ - re_string_list_init(s1, a); - - a->n_strings = s->n_strings; - a->hash_size = s->hash_size; - a->hash_bits = s->hash_bits; - a->hash_table = s->hash_table; - - s->n_strings = 0; - s->hash_size = 0; - s->hash_bits = 0; - s->hash_table = NULL; - - for(i = 0; i < a->hash_size; i++) { - for(p = a->hash_table[i]; p != NULL; p = p->next) { - for(j = 0; j < p->len; j++) { - p->buf[j] = lre_canonicalize(p->buf[j], is_unicode); - } - if (re_string_add(s, p->len, p->buf)) { - re_string_list_free(a); - return -1; - } - } - } - re_string_list_free(a); - } - return 0; -} - -static const uint16_t char_range_d[] = { - 1, - 0x0030, 0x0039 + 1, -}; - -/* code point ranges for Zs,Zl or Zp property */ -static const uint16_t char_range_s[] = { - 10, - 0x0009, 0x000D + 1, - 0x0020, 0x0020 + 1, - 0x00A0, 0x00A0 + 1, - 0x1680, 0x1680 + 1, - 0x2000, 0x200A + 1, - /* 2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; */ - /* 2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; */ - 0x2028, 0x2029 + 1, - 0x202F, 0x202F + 1, - 0x205F, 0x205F + 1, - 0x3000, 0x3000 + 1, - /* FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; */ - 0xFEFF, 0xFEFF + 1, -}; - -static const uint16_t char_range_w[] = { - 4, - 0x0030, 0x0039 + 1, - 0x0041, 0x005A + 1, - 0x005F, 0x005F + 1, - 0x0061, 0x007A + 1, -}; - -#define CLASS_RANGE_BASE 0x40000000 - -typedef enum { - CHAR_RANGE_d, - CHAR_RANGE_D, - CHAR_RANGE_s, - CHAR_RANGE_S, - CHAR_RANGE_w, - CHAR_RANGE_W, -} CharRangeEnum; - -static const uint16_t * const char_range_table[] = { - char_range_d, - char_range_s, - char_range_w, -}; - -static int cr_init_char_range(REParseState *s, REStringList *cr, uint32_t c) -{ - BOOL invert; - const uint16_t *c_pt; - int len, i; - - invert = c & 1; - c_pt = char_range_table[c >> 1]; - len = *c_pt++; - re_string_list_init(s, cr); - for(i = 0; i < len * 2; i++) { - if (cr_add_point(&cr->cr, c_pt[i])) - goto fail; - } - if (invert) { - if (cr_invert(&cr->cr)) - goto fail; - } - return 0; - fail: - re_string_list_free(cr); - return -1; -} - -#ifdef DUMP_REOP -static __maybe_unused void lre_dump_bytecode(const uint8_t *buf, - int buf_len) -{ - int pos, len, opcode, bc_len, re_flags, i; - uint32_t val; - - assert(buf_len >= RE_HEADER_LEN); - - re_flags = lre_get_flags(buf); - bc_len = get_u32(buf + RE_HEADER_BYTECODE_LEN); - assert(bc_len + RE_HEADER_LEN <= buf_len); - printf("flags: 0x%x capture_count=%d stack_size=%d\n", - re_flags, buf[RE_HEADER_CAPTURE_COUNT], buf[RE_HEADER_STACK_SIZE]); - if (re_flags & LRE_FLAG_NAMED_GROUPS) { - const char *p; - p = (char *)buf + RE_HEADER_LEN + bc_len; - printf("named groups: "); - for(i = 1; i < buf[RE_HEADER_CAPTURE_COUNT]; i++) { - if (i != 1) - printf(","); - printf("<%s>", p); - p += strlen(p) + 1; - } - printf("\n"); - assert(p == (char *)(buf + buf_len)); - } - printf("bytecode_len=%d\n", bc_len); - - buf += RE_HEADER_LEN; - pos = 0; - while (pos < bc_len) { - printf("%5u: ", pos); - opcode = buf[pos]; - len = reopcode_info[opcode].size; - if (opcode >= REOP_COUNT) { - printf(" invalid opcode=0x%02x\n", opcode); - break; - } - if ((pos + len) > bc_len) { - printf(" buffer overflow (opcode=0x%02x)\n", opcode); - break; - } - printf("%s", reopcode_info[opcode].name); - switch(opcode) { - case REOP_char: - case REOP_char_i: - val = get_u16(buf + pos + 1); - if (val >= ' ' && val <= 126) - printf(" '%c'", val); - else - printf(" 0x%04x", val); - break; - case REOP_char32: - case REOP_char32_i: - val = get_u32(buf + pos + 1); - if (val >= ' ' && val <= 126) - printf(" '%c'", val); - else - printf(" 0x%08x", val); - break; - case REOP_goto: - case REOP_split_goto_first: - case REOP_split_next_first: - case REOP_loop: - case REOP_lookahead: - case REOP_negative_lookahead: - val = get_u32(buf + pos + 1); - val += (pos + 5); - printf(" %u", val); - break; - case REOP_simple_greedy_quant: - printf(" %u %u %u %u", - get_u32(buf + pos + 1) + (pos + 17), - get_u32(buf + pos + 1 + 4), - get_u32(buf + pos + 1 + 8), - get_u32(buf + pos + 1 + 12)); - break; - case REOP_save_start: - case REOP_save_end: - case REOP_back_reference: - case REOP_back_reference_i: - case REOP_backward_back_reference: - case REOP_backward_back_reference_i: - printf(" %u", buf[pos + 1]); - break; - case REOP_save_reset: - printf(" %u %u", buf[pos + 1], buf[pos + 2]); - break; - case REOP_push_i32: - val = get_u32(buf + pos + 1); - printf(" %d", val); - break; - case REOP_range: - case REOP_range_i: - { - int n, i; - n = get_u16(buf + pos + 1); - len += n * 4; - for(i = 0; i < n * 2; i++) { - val = get_u16(buf + pos + 3 + i * 2); - printf(" 0x%04x", val); - } - } - break; - case REOP_range32: - case REOP_range32_i: - { - int n, i; - n = get_u16(buf + pos + 1); - len += n * 8; - for(i = 0; i < n * 2; i++) { - val = get_u32(buf + pos + 3 + i * 4); - printf(" 0x%08x", val); - } - } - break; - default: - break; - } - printf("\n"); - pos += len; - } -} -#endif - -static void re_emit_op(REParseState *s, int op) -{ - dbuf_putc(&s->byte_code, op); -} - -/* return the offset of the u32 value */ -static int re_emit_op_u32(REParseState *s, int op, uint32_t val) -{ - int pos; - dbuf_putc(&s->byte_code, op); - pos = s->byte_code.size; - dbuf_put_u32(&s->byte_code, val); - return pos; -} - -static int re_emit_goto(REParseState *s, int op, uint32_t val) -{ - int pos; - dbuf_putc(&s->byte_code, op); - pos = s->byte_code.size; - dbuf_put_u32(&s->byte_code, val - (pos + 4)); - return pos; -} - -static void re_emit_op_u8(REParseState *s, int op, uint32_t val) -{ - dbuf_putc(&s->byte_code, op); - dbuf_putc(&s->byte_code, val); -} - -static void re_emit_op_u16(REParseState *s, int op, uint32_t val) -{ - dbuf_putc(&s->byte_code, op); - dbuf_put_u16(&s->byte_code, val); -} - -static int __attribute__((format(printf, 2, 3))) re_parse_error(REParseState *s, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vsnprintf(s->u.error_msg, sizeof(s->u.error_msg), fmt, ap); - va_end(ap); - return -1; -} - -static int re_parse_out_of_memory(REParseState *s) -{ - return re_parse_error(s, "out of memory"); -} - -/* If allow_overflow is false, return -1 in case of - overflow. Otherwise return INT32_MAX. */ -static int parse_digits(const uint8_t **pp, BOOL allow_overflow) -{ - const uint8_t *p; - uint64_t v; - int c; - - p = *pp; - v = 0; - for(;;) { - c = *p; - if (c < '0' || c > '9') - break; - v = v * 10 + c - '0'; - if (v >= INT32_MAX) { - if (allow_overflow) - v = INT32_MAX; - else - return -1; - } - p++; - } - *pp = p; - return v; -} - -static int re_parse_expect(REParseState *s, const uint8_t **pp, int c) -{ - const uint8_t *p; - p = *pp; - if (*p != c) - return re_parse_error(s, "expecting '%c'", c); - p++; - *pp = p; - return 0; -} - -/* Parse an escape sequence, *pp points after the '\': - allow_utf16 value: - 0 : no UTF-16 escapes allowed - 1 : UTF-16 escapes allowed - 2 : UTF-16 escapes allowed and escapes of surrogate pairs are - converted to a unicode character (unicode regexp case). - - Return the unicode char and update *pp if recognized, - return -1 if malformed escape, - return -2 otherwise. */ -int lre_parse_escape(const uint8_t **pp, int allow_utf16) -{ - const uint8_t *p; - uint32_t c; - - p = *pp; - c = *p++; - switch(c) { - case 'b': - c = '\b'; - break; - case 'f': - c = '\f'; - break; - case 'n': - c = '\n'; - break; - case 'r': - c = '\r'; - break; - case 't': - c = '\t'; - break; - case 'v': - c = '\v'; - break; - case 'x': - case 'u': - { - int h, n, i; - uint32_t c1; - - if (*p == '{' && allow_utf16) { - p++; - c = 0; - for(;;) { - h = from_hex(*p++); - if (h < 0) - return -1; - c = (c << 4) | h; - if (c > 0x10FFFF) - return -1; - if (*p == '}') - break; - } - p++; - } else { - if (c == 'x') { - n = 2; - } else { - n = 4; - } - - c = 0; - for(i = 0; i < n; i++) { - h = from_hex(*p++); - if (h < 0) { - return -1; - } - c = (c << 4) | h; - } - if (is_hi_surrogate(c) && - allow_utf16 == 2 && p[0] == '\\' && p[1] == 'u') { - /* convert an escaped surrogate pair into a - unicode char */ - c1 = 0; - for(i = 0; i < 4; i++) { - h = from_hex(p[2 + i]); - if (h < 0) - break; - c1 = (c1 << 4) | h; - } - if (i == 4 && is_lo_surrogate(c1)) { - p += 6; - c = from_surrogate(c, c1); - } - } - } - } - break; - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - c -= '0'; - if (allow_utf16 == 2) { - /* only accept \0 not followed by digit */ - if (c != 0 || is_digit(*p)) - return -1; - } else { - /* parse a legacy octal sequence */ - uint32_t v; - v = *p - '0'; - if (v > 7) - break; - c = (c << 3) | v; - p++; - if (c >= 32) - break; - v = *p - '0'; - if (v > 7) - break; - c = (c << 3) | v; - p++; - } - break; - default: - return -2; - } - *pp = p; - return c; -} - -#ifdef CONFIG_ALL_UNICODE -/* XXX: we use the same chars for name and value */ -static BOOL is_unicode_char(int c) -{ - return ((c >= '0' && c <= '9') || - (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') || - (c == '_')); -} - -/* XXX: memory error test */ -static void seq_prop_cb(void *opaque, const uint32_t *seq, int seq_len) -{ - REStringList *sl = opaque; - re_string_add(sl, seq_len, seq); -} - -static int parse_unicode_property(REParseState *s, REStringList *cr, - const uint8_t **pp, BOOL is_inv, - BOOL allow_sequence_prop) -{ - const uint8_t *p; - char name[64], value[64]; - char *q; - BOOL script_ext; - int ret; - - p = *pp; - if (*p != '{') - return re_parse_error(s, "expecting '{' after \\p"); - p++; - q = name; - while (is_unicode_char(*p)) { - if ((q - name) >= sizeof(name) - 1) - goto unknown_property_name; - *q++ = *p++; - } - *q = '\0'; - q = value; - if (*p == '=') { - p++; - while (is_unicode_char(*p)) { - if ((q - value) >= sizeof(value) - 1) - return re_parse_error(s, "unknown unicode property value"); - *q++ = *p++; - } - } - *q = '\0'; - if (*p != '}') - return re_parse_error(s, "expecting '}'"); - p++; - // printf("name=%s value=%s\n", name, value); - - if (!strcmp(name, "Script") || !strcmp(name, "sc")) { - script_ext = FALSE; - goto do_script; - } else if (!strcmp(name, "Script_Extensions") || !strcmp(name, "scx")) { - script_ext = TRUE; - do_script: - re_string_list_init(s, cr); - ret = unicode_script(&cr->cr, value, script_ext); - if (ret) { - re_string_list_free(cr); - if (ret == -2) - return re_parse_error(s, "unknown unicode script"); - else - goto out_of_memory; - } - } else if (!strcmp(name, "General_Category") || !strcmp(name, "gc")) { - re_string_list_init(s, cr); - ret = unicode_general_category(&cr->cr, value); - if (ret) { - re_string_list_free(cr); - if (ret == -2) - return re_parse_error(s, "unknown unicode general category"); - else - goto out_of_memory; - } - } else if (value[0] == '\0') { - re_string_list_init(s, cr); - ret = unicode_general_category(&cr->cr, name); - if (ret == -1) { - re_string_list_free(cr); - goto out_of_memory; - } - if (ret < 0) { - ret = unicode_prop(&cr->cr, name); - if (ret == -1) { - re_string_list_free(cr); - goto out_of_memory; - } - } - if (ret < 0 && !is_inv && allow_sequence_prop) { - CharRange cr_tmp; - cr_init(&cr_tmp, s->opaque, lre_realloc); - ret = unicode_sequence_prop(name, seq_prop_cb, cr, &cr_tmp); - cr_free(&cr_tmp); - if (ret == -1) { - re_string_list_free(cr); - goto out_of_memory; - } - } - if (ret < 0) - goto unknown_property_name; - } else { - unknown_property_name: - return re_parse_error(s, "unknown unicode property name"); - } - - /* the ordering of case folding and inversion differs with - unicode_sets. 'unicode_sets' ordering is more consistent */ - /* XXX: the spec seems incorrect, we do it as the other engines - seem to do it. */ - if (s->ignore_case && s->unicode_sets) { - if (re_string_list_canonicalize(s, cr, s->is_unicode)) { - re_string_list_free(cr); - goto out_of_memory; - } - } - if (is_inv) { - if (cr_invert(&cr->cr)) { - re_string_list_free(cr); - goto out_of_memory; - } - } - if (s->ignore_case && !s->unicode_sets) { - if (re_string_list_canonicalize(s, cr, s->is_unicode)) { - re_string_list_free(cr); - goto out_of_memory; - } - } - *pp = p; - return 0; - out_of_memory: - return re_parse_out_of_memory(s); -} -#endif /* CONFIG_ALL_UNICODE */ - -static int get_class_atom(REParseState *s, REStringList *cr, - const uint8_t **pp, BOOL inclass); - -static int parse_class_string_disjunction(REParseState *s, REStringList *cr, - const uint8_t **pp) -{ - const uint8_t *p; - DynBuf str; - int c; - - p = *pp; - if (*p != '{') - return re_parse_error(s, "expecting '{' after \\q"); - - dbuf_init2(&str, s->opaque, lre_realloc); - re_string_list_init(s, cr); - - p++; - for(;;) { - str.size = 0; - while (*p != '}' && *p != '|') { - c = get_class_atom(s, NULL, &p, FALSE); - if (c < 0) - goto fail; - if (dbuf_put_u32(&str, c)) { - re_parse_out_of_memory(s); - goto fail; - } - } - if (re_string_add(cr, str.size / 4, (uint32_t *)str.buf)) { - re_parse_out_of_memory(s); - goto fail; - } - if (*p == '}') - break; - p++; - } - if (s->ignore_case) { - if (re_string_list_canonicalize(s, cr, TRUE)) - goto fail; - } - p++; /* skip the '}' */ - dbuf_free(&str); - *pp = p; - return 0; - fail: - dbuf_free(&str); - re_string_list_free(cr); - return -1; -} - -/* return -1 if error otherwise the character or a class range - (CLASS_RANGE_BASE) if cr != NULL. In case of class range, 'cr' is - initialized. Otherwise, it is ignored. */ -static int get_class_atom(REParseState *s, REStringList *cr, - const uint8_t **pp, BOOL inclass) -{ - const uint8_t *p; - uint32_t c; - int ret; - - p = *pp; - - c = *p; - switch(c) { - case '\\': - p++; - if (p >= s->buf_end) - goto unexpected_end; - c = *p++; - switch(c) { - case 'd': - c = CHAR_RANGE_d; - goto class_range; - case 'D': - c = CHAR_RANGE_D; - goto class_range; - case 's': - c = CHAR_RANGE_s; - goto class_range; - case 'S': - c = CHAR_RANGE_S; - goto class_range; - case 'w': - c = CHAR_RANGE_w; - goto class_range; - case 'W': - c = CHAR_RANGE_W; - class_range: - if (!cr) - goto default_escape; - if (cr_init_char_range(s, cr, c)) - return -1; - c = CLASS_RANGE_BASE; - break; - case 'c': - c = *p; - if ((c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (((c >= '0' && c <= '9') || c == '_') && - inclass && !s->is_unicode)) { /* Annex B.1.4 */ - c &= 0x1f; - p++; - } else if (s->is_unicode) { - goto invalid_escape; - } else { - /* otherwise return '\' and 'c' */ - p--; - c = '\\'; - } - break; - case '-': - if (!inclass && s->is_unicode) - goto invalid_escape; - break; - case '^': - case '$': - case '\\': - case '.': - case '*': - case '+': - case '?': - case '(': - case ')': - case '[': - case ']': - case '{': - case '}': - case '|': - case '/': - /* always valid to escape these characters */ - break; -#ifdef CONFIG_ALL_UNICODE - case 'p': - case 'P': - if (s->is_unicode && cr) { - if (parse_unicode_property(s, cr, &p, (c == 'P'), s->unicode_sets)) - return -1; - c = CLASS_RANGE_BASE; - break; - } - goto default_escape; -#endif - case 'q': - if (s->unicode_sets && cr && inclass) { - if (parse_class_string_disjunction(s, cr, &p)) - return -1; - c = CLASS_RANGE_BASE; - break; - } - goto default_escape; - default: - default_escape: - p--; - ret = lre_parse_escape(&p, s->is_unicode * 2); - if (ret >= 0) { - c = ret; - } else { - if (s->is_unicode) { - invalid_escape: - return re_parse_error(s, "invalid escape sequence in regular expression"); - } else { - /* just ignore the '\' */ - goto normal_char; - } - } - break; - } - break; - case '\0': - if (p >= s->buf_end) { - unexpected_end: - return re_parse_error(s, "unexpected end"); - } - /* fall thru */ - goto normal_char; - - case '&': - case '!': - case '#': - case '$': - case '%': - case '*': - case '+': - case ',': - case '.': - case ':': - case ';': - case '<': - case '=': - case '>': - case '?': - case '@': - case '^': - case '`': - case '~': - if (s->unicode_sets && p[1] == c) { - /* forbidden double characters */ - return re_parse_error(s, "invalid class set operation in regular expression"); - } - goto normal_char; - - case '(': - case ')': - case '[': - case ']': - case '{': - case '}': - case '/': - case '-': - case '|': - if (s->unicode_sets) { - /* invalid characters in unicode sets */ - return re_parse_error(s, "invalid character in class in regular expression"); - } - goto normal_char; - - default: - normal_char: - /* normal char */ - if (c >= 128) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); - if ((unsigned)c > 0xffff && !s->is_unicode) { - /* XXX: should handle non BMP-1 code points */ - return re_parse_error(s, "malformed unicode char"); - } - } else { - p++; - } - break; - } - *pp = p; - return c; -} - -static int re_emit_range(REParseState *s, const CharRange *cr) -{ - int len, i; - uint32_t high; - - len = (unsigned)cr->len / 2; - if (len >= 65535) - return re_parse_error(s, "too many ranges"); - if (len == 0) { - re_emit_op_u32(s, REOP_char32, -1); - } else { - high = cr->points[cr->len - 1]; - if (high == UINT32_MAX) - high = cr->points[cr->len - 2]; - if (high <= 0xffff) { - /* can use 16 bit ranges with the conversion that 0xffff = - infinity */ - re_emit_op_u16(s, s->ignore_case ? REOP_range_i : REOP_range, len); - for(i = 0; i < cr->len; i += 2) { - dbuf_put_u16(&s->byte_code, cr->points[i]); - high = cr->points[i + 1] - 1; - if (high == UINT32_MAX - 1) - high = 0xffff; - dbuf_put_u16(&s->byte_code, high); - } - } else { - re_emit_op_u16(s, s->ignore_case ? REOP_range32_i : REOP_range32, len); - for(i = 0; i < cr->len; i += 2) { - dbuf_put_u32(&s->byte_code, cr->points[i]); - dbuf_put_u32(&s->byte_code, cr->points[i + 1] - 1); - } - } - } - return 0; -} - -static int re_string_cmp_len(const void *a, const void *b, void *arg) -{ - REString *p1 = *(REString **)a; - REString *p2 = *(REString **)b; - return (p1->len < p2->len) - (p1->len > p2->len); -} - -static void re_emit_char(REParseState *s, int c) -{ - if (c <= 0xffff) - re_emit_op_u16(s, s->ignore_case ? REOP_char_i : REOP_char, c); - else - re_emit_op_u32(s, s->ignore_case ? REOP_char32_i : REOP_char32, c); -} - -static int re_emit_string_list(REParseState *s, const REStringList *sl) -{ - REString **tab, *p; - int i, j, split_pos, last_match_pos, n; - BOOL has_empty_string, is_last; - - // re_string_list_dump("sl", sl); - if (sl->n_strings == 0) { - /* simple case: only characters */ - if (re_emit_range(s, &sl->cr)) - return -1; - } else { - /* at least one string list is present : match the longest ones first */ - /* XXX: add a new op_switch opcode to compile as a trie */ - tab = lre_realloc(s->opaque, NULL, sizeof(tab[0]) * sl->n_strings); - if (!tab) { - re_parse_out_of_memory(s); - return -1; - } - has_empty_string = FALSE; - n = 0; - for(i = 0; i < sl->hash_size; i++) { - for(p = sl->hash_table[i]; p != NULL; p = p->next) { - if (p->len == 0) { - has_empty_string = TRUE; - } else { - tab[n++] = p; - } - } - } - assert(n <= sl->n_strings); - - rqsort(tab, n, sizeof(tab[0]), re_string_cmp_len, NULL); - - last_match_pos = -1; - for(i = 0; i < n; i++) { - p = tab[i]; - is_last = !has_empty_string && sl->cr.len == 0 && i == (n - 1); - if (!is_last) - split_pos = re_emit_op_u32(s, REOP_split_next_first, 0); - else - split_pos = 0; - for(j = 0; j < p->len; j++) { - re_emit_char(s, p->buf[j]); - } - if (!is_last) { - last_match_pos = re_emit_op_u32(s, REOP_goto, last_match_pos); - put_u32(s->byte_code.buf + split_pos, s->byte_code.size - (split_pos + 4)); - } - } - - if (sl->cr.len != 0) { - /* char range */ - is_last = !has_empty_string; - if (!is_last) - split_pos = re_emit_op_u32(s, REOP_split_next_first, 0); - else - split_pos = 0; /* not used */ - if (re_emit_range(s, &sl->cr)) { - lre_realloc(s->opaque, tab, 0); - return -1; - } - if (!is_last) - put_u32(s->byte_code.buf + split_pos, s->byte_code.size - (split_pos + 4)); - } - - /* patch the 'goto match' */ - while (last_match_pos != -1) { - int next_pos = get_u32(s->byte_code.buf + last_match_pos); - put_u32(s->byte_code.buf + last_match_pos, s->byte_code.size - (last_match_pos + 4)); - last_match_pos = next_pos; - } - - lre_realloc(s->opaque, tab, 0); - } - return 0; -} - -static int re_parse_nested_class(REParseState *s, REStringList *cr, const uint8_t **pp); - -static int re_parse_class_set_operand(REParseState *s, REStringList *cr, const uint8_t **pp) -{ - int c1; - const uint8_t *p = *pp; - - if (*p == '[') { - if (re_parse_nested_class(s, cr, pp)) - return -1; - } else { - c1 = get_class_atom(s, cr, pp, TRUE); - if (c1 < 0) - return -1; - if (c1 < CLASS_RANGE_BASE) { - /* create a range with a single character */ - re_string_list_init(s, cr); - if (s->ignore_case) - c1 = lre_canonicalize(c1, s->is_unicode); - if (cr_union_interval(&cr->cr, c1, c1)) { - re_string_list_free(cr); - return -1; - } - } - } - return 0; -} - -static int re_parse_nested_class(REParseState *s, REStringList *cr, const uint8_t **pp) -{ - const uint8_t *p; - uint32_t c1, c2; - int ret; - REStringList cr1_s, *cr1 = &cr1_s; - BOOL invert, is_first; - - if (lre_check_stack_overflow(s->opaque, 0)) - return re_parse_error(s, "stack overflow"); - - re_string_list_init(s, cr); - p = *pp; - p++; /* skip '[' */ - - invert = FALSE; - if (*p == '^') { - p++; - invert = TRUE; - } - - /* handle unions */ - is_first = TRUE; - for(;;) { - if (*p == ']') - break; - if (*p == '[' && s->unicode_sets) { - if (re_parse_nested_class(s, cr1, &p)) - goto fail; - goto class_union; - } else { - c1 = get_class_atom(s, cr1, &p, TRUE); - if ((int)c1 < 0) - goto fail; - if (*p == '-' && p[1] != ']') { - const uint8_t *p0 = p + 1; - if (p[1] == '-' && s->unicode_sets && is_first) - goto class_atom; /* first character class followed by '--' */ - if (c1 >= CLASS_RANGE_BASE) { - if (s->is_unicode) { - re_string_list_free(cr1); - goto invalid_class_range; - } - /* Annex B: match '-' character */ - goto class_atom; - } - c2 = get_class_atom(s, cr1, &p0, TRUE); - if ((int)c2 < 0) - goto fail; - if (c2 >= CLASS_RANGE_BASE) { - re_string_list_free(cr1); - if (s->is_unicode) { - goto invalid_class_range; - } - /* Annex B: match '-' character */ - goto class_atom; - } - p = p0; - if (c2 < c1) { - invalid_class_range: - re_parse_error(s, "invalid class range"); - goto fail; - } - if (s->ignore_case) { - CharRange cr2_s, *cr2 = &cr2_s; - cr_init(cr2, s->opaque, lre_realloc); - if (cr_add_interval(cr2, c1, c2 + 1) || - cr_regexp_canonicalize(cr2, s->is_unicode) || - cr_op1(&cr->cr, cr2->points, cr2->len, CR_OP_UNION)) { - cr_free(cr2); - goto memory_error; - } - cr_free(cr2); - } else { - if (cr_union_interval(&cr->cr, c1, c2)) - goto memory_error; - } - is_first = FALSE; /* union operation */ - } else { - class_atom: - if (c1 >= CLASS_RANGE_BASE) { - class_union: - ret = re_string_list_op(cr, cr1, CR_OP_UNION); - re_string_list_free(cr1); - if (ret) - goto memory_error; - } else { - if (s->ignore_case) - c1 = lre_canonicalize(c1, s->is_unicode); - if (cr_union_interval(&cr->cr, c1, c1)) - goto memory_error; - } - } - } - if (s->unicode_sets && is_first) { - if (*p == '&' && p[1] == '&' && p[2] != '&') { - /* handle '&&' */ - for(;;) { - if (*p == ']') { - break; - } else if (*p == '&' && p[1] == '&' && p[2] != '&') { - p += 2; - } else { - goto invalid_operation; - } - if (re_parse_class_set_operand(s, cr1, &p)) - goto fail; - ret = re_string_list_op(cr, cr1, CR_OP_INTER); - re_string_list_free(cr1); - if (ret) - goto memory_error; - } - } else if (*p == '-' && p[1] == '-') { - /* handle '--' */ - for(;;) { - if (*p == ']') { - break; - } else if (*p == '-' && p[1] == '-') { - p += 2; - } else { - invalid_operation: - re_parse_error(s, "invalid operation in regular expression"); - goto fail; - } - if (re_parse_class_set_operand(s, cr1, &p)) - goto fail; - ret = re_string_list_op(cr, cr1, CR_OP_SUB); - re_string_list_free(cr1); - if (ret) - goto memory_error; - } - } - } - is_first = FALSE; - } - - p++; /* skip ']' */ - *pp = p; - if (invert) { - /* XXX: add may_contain_string syntax check to be fully - compliant. The test here accepts more input than the - spec. */ - if (cr->n_strings != 0) { - re_parse_error(s, "negated character class with strings in regular expression debugger eval code"); - goto fail; - } - if (cr_invert(&cr->cr)) - goto memory_error; - } - return 0; - memory_error: - re_parse_out_of_memory(s); - fail: - re_string_list_free(cr); - return -1; -} - -static int re_parse_char_class(REParseState *s, const uint8_t **pp) -{ - REStringList cr_s, *cr = &cr_s; - - if (re_parse_nested_class(s, cr, pp)) - return -1; - if (re_emit_string_list(s, cr)) - goto fail; - re_string_list_free(cr); - return 0; - fail: - re_string_list_free(cr); - return -1; -} - -/* Return: - - true if the opcodes may not advance the char pointer - - false if the opcodes always advance the char pointer -*/ -static BOOL re_need_check_advance(const uint8_t *bc_buf, int bc_buf_len) -{ - int pos, opcode, len; - uint32_t val; - BOOL ret; - - ret = TRUE; - pos = 0; - while (pos < bc_buf_len) { - opcode = bc_buf[pos]; - len = reopcode_info[opcode].size; - switch(opcode) { - case REOP_range: - case REOP_range_i: - val = get_u16(bc_buf + pos + 1); - len += val * 4; - goto simple_char; - case REOP_range32: - case REOP_range32_i: - val = get_u16(bc_buf + pos + 1); - len += val * 8; - goto simple_char; - case REOP_char: - case REOP_char_i: - case REOP_char32: - case REOP_char32_i: - case REOP_dot: - case REOP_any: - simple_char: - ret = FALSE; - break; - case REOP_line_start: - case REOP_line_start_m: - case REOP_line_end: - case REOP_line_end_m: - case REOP_push_i32: - case REOP_push_char_pos: - case REOP_drop: - case REOP_word_boundary: - case REOP_word_boundary_i: - case REOP_not_word_boundary: - case REOP_not_word_boundary_i: - case REOP_prev: - /* no effect */ - break; - case REOP_save_start: - case REOP_save_end: - case REOP_save_reset: - case REOP_back_reference: - case REOP_back_reference_i: - case REOP_backward_back_reference: - case REOP_backward_back_reference_i: - break; - default: - /* safe behavior: we cannot predict the outcome */ - return TRUE; - } - pos += len; - } - return ret; -} - -/* return -1 if a simple quantifier cannot be used. Otherwise return - the number of characters in the atom. */ -static int re_is_simple_quantifier(const uint8_t *bc_buf, int bc_buf_len) -{ - int pos, opcode, len, count; - uint32_t val; - - count = 0; - pos = 0; - while (pos < bc_buf_len) { - opcode = bc_buf[pos]; - len = reopcode_info[opcode].size; - switch(opcode) { - case REOP_range: - case REOP_range_i: - val = get_u16(bc_buf + pos + 1); - len += val * 4; - goto simple_char; - case REOP_range32: - case REOP_range32_i: - val = get_u16(bc_buf + pos + 1); - len += val * 8; - goto simple_char; - case REOP_char: - case REOP_char_i: - case REOP_char32: - case REOP_char32_i: - case REOP_dot: - case REOP_any: - simple_char: - count++; - break; - case REOP_line_start: - case REOP_line_start_m: - case REOP_line_end: - case REOP_line_end_m: - case REOP_word_boundary: - case REOP_word_boundary_i: - case REOP_not_word_boundary: - case REOP_not_word_boundary_i: - break; - default: - return -1; - } - pos += len; - } - return count; -} - -/* '*pp' is the first char after '<' */ -static int re_parse_group_name(char *buf, int buf_size, const uint8_t **pp) -{ - const uint8_t *p, *p1; - uint32_t c, d; - char *q; - - p = *pp; - q = buf; - for(;;) { - c = *p; - if (c == '\\') { - p++; - if (*p != 'u') - return -1; - c = lre_parse_escape(&p, 2); // accept surrogate pairs - } else if (c == '>') { - break; - } else if (c >= 128) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); - if (is_hi_surrogate(c)) { - d = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1); - if (is_lo_surrogate(d)) { - c = from_surrogate(c, d); - p = p1; - } - } - } else { - p++; - } - if (c > 0x10FFFF) - return -1; - if (q == buf) { - if (!lre_js_is_ident_first(c)) - return -1; - } else { - if (!lre_js_is_ident_next(c)) - return -1; - } - if ((q - buf + UTF8_CHAR_LEN_MAX + 1) > buf_size) - return -1; - if (c < 128) { - *q++ = c; - } else { - q += unicode_to_utf8((uint8_t*)q, c); - } - } - if (q == buf) - return -1; - *q = '\0'; - p++; - *pp = p; - return 0; -} - -/* if capture_name = NULL: return the number of captures + 1. - Otherwise, return the capture index corresponding to capture_name - or -1 if none */ -static int re_parse_captures(REParseState *s, int *phas_named_captures, - const char *capture_name) -{ - const uint8_t *p; - int capture_index; - char name[TMP_BUF_SIZE]; - - capture_index = 1; - *phas_named_captures = 0; - for (p = s->buf_start; p < s->buf_end; p++) { - switch (*p) { - case '(': - if (p[1] == '?') { - if (p[2] == '<' && p[3] != '=' && p[3] != '!') { - *phas_named_captures = 1; - /* potential named capture */ - if (capture_name) { - p += 3; - if (re_parse_group_name(name, sizeof(name), &p) == 0) { - if (!strcmp(name, capture_name)) - return capture_index; - } - } - capture_index++; - if (capture_index >= CAPTURE_COUNT_MAX) - goto done; - } - } else { - capture_index++; - if (capture_index >= CAPTURE_COUNT_MAX) - goto done; - } - break; - case '\\': - p++; - break; - case '[': - for (p += 1 + (*p == ']'); p < s->buf_end && *p != ']'; p++) { - if (*p == '\\') - p++; - } - break; - } - } - done: - if (capture_name) - return -1; - else - return capture_index; -} - -static int re_count_captures(REParseState *s) -{ - if (s->total_capture_count < 0) { - s->total_capture_count = re_parse_captures(s, &s->has_named_captures, - NULL); - } - return s->total_capture_count; -} - -static BOOL re_has_named_captures(REParseState *s) -{ - if (s->has_named_captures < 0) - re_count_captures(s); - return s->has_named_captures; -} - -static int find_group_name(REParseState *s, const char *name) -{ - const char *p, *buf_end; - size_t len, name_len; - int capture_index; - - p = (char *)s->group_names.buf; - if (!p) return -1; - buf_end = (char *)s->group_names.buf + s->group_names.size; - name_len = strlen(name); - capture_index = 1; - while (p < buf_end) { - len = strlen(p); - if (len == name_len && memcmp(name, p, name_len) == 0) - return capture_index; - p += len + 1; - capture_index++; - } - return -1; -} - -static int re_parse_disjunction(REParseState *s, BOOL is_backward_dir); - -static int re_parse_modifiers(REParseState *s, const uint8_t **pp) -{ - const uint8_t *p = *pp; - int mask = 0; - int val; - - for(;;) { - if (*p == 'i') { - val = LRE_FLAG_IGNORECASE; - } else if (*p == 'm') { - val = LRE_FLAG_MULTILINE; - } else if (*p == 's') { - val = LRE_FLAG_DOTALL; - } else { - break; - } - if (mask & val) - return re_parse_error(s, "duplicate modifier: '%c'", *p); - mask |= val; - p++; - } - *pp = p; - return mask; -} - -static BOOL update_modifier(BOOL val, int add_mask, int remove_mask, - int mask) -{ - if (add_mask & mask) - val = TRUE; - if (remove_mask & mask) - val = FALSE; - return val; -} - -static int re_parse_term(REParseState *s, BOOL is_backward_dir) -{ - const uint8_t *p; - int c, last_atom_start, quant_min, quant_max, last_capture_count; - BOOL greedy, add_zero_advance_check, is_neg, is_backward_lookahead; - REStringList cr_s, *cr = &cr_s; - - last_atom_start = -1; - last_capture_count = 0; - p = s->buf_ptr; - c = *p; - switch(c) { - case '^': - p++; - re_emit_op(s, s->multi_line ? REOP_line_start_m : REOP_line_start); - break; - case '$': - p++; - re_emit_op(s, s->multi_line ? REOP_line_end_m : REOP_line_end); - break; - case '.': - p++; - last_atom_start = s->byte_code.size; - last_capture_count = s->capture_count; - if (is_backward_dir) - re_emit_op(s, REOP_prev); - re_emit_op(s, s->dotall ? REOP_any : REOP_dot); - if (is_backward_dir) - re_emit_op(s, REOP_prev); - break; - case '{': - if (s->is_unicode) { - return re_parse_error(s, "syntax error"); - } else if (!is_digit(p[1])) { - /* Annex B: we accept '{' not followed by digits as a - normal atom */ - goto parse_class_atom; - } else { - const uint8_t *p1 = p + 1; - /* Annex B: error if it is like a repetition count */ - parse_digits(&p1, TRUE); - if (*p1 == ',') { - p1++; - if (is_digit(*p1)) { - parse_digits(&p1, TRUE); - } - } - if (*p1 != '}') { - goto parse_class_atom; - } - } - /* fall thru */ - case '*': - case '+': - case '?': - return re_parse_error(s, "nothing to repeat"); - case '(': - if (p[1] == '?') { - if (p[2] == ':') { - p += 3; - last_atom_start = s->byte_code.size; - last_capture_count = s->capture_count; - s->buf_ptr = p; - if (re_parse_disjunction(s, is_backward_dir)) - return -1; - p = s->buf_ptr; - if (re_parse_expect(s, &p, ')')) - return -1; - } else if (p[2] == 'i' || p[2] == 'm' || p[2] == 's' || p[2] == '-') { - BOOL saved_ignore_case, saved_multi_line, saved_dotall; - int add_mask, remove_mask; - p += 2; - remove_mask = 0; - add_mask = re_parse_modifiers(s, &p); - if (add_mask < 0) - return -1; - if (*p == '-') { - p++; - remove_mask = re_parse_modifiers(s, &p); - if (remove_mask < 0) - return -1; - } - if ((add_mask == 0 && remove_mask == 0) || - (add_mask & remove_mask) != 0) { - return re_parse_error(s, "invalid modifiers"); - } - if (re_parse_expect(s, &p, ':')) - return -1; - saved_ignore_case = s->ignore_case; - saved_multi_line = s->multi_line; - saved_dotall = s->dotall; - s->ignore_case = update_modifier(s->ignore_case, add_mask, remove_mask, LRE_FLAG_IGNORECASE); - s->multi_line = update_modifier(s->multi_line, add_mask, remove_mask, LRE_FLAG_MULTILINE); - s->dotall = update_modifier(s->dotall, add_mask, remove_mask, LRE_FLAG_DOTALL); - - last_atom_start = s->byte_code.size; - last_capture_count = s->capture_count; - s->buf_ptr = p; - if (re_parse_disjunction(s, is_backward_dir)) - return -1; - p = s->buf_ptr; - if (re_parse_expect(s, &p, ')')) - return -1; - s->ignore_case = saved_ignore_case; - s->multi_line = saved_multi_line; - s->dotall = saved_dotall; - } else if ((p[2] == '=' || p[2] == '!')) { - is_neg = (p[2] == '!'); - is_backward_lookahead = FALSE; - p += 3; - goto lookahead; - } else if (p[2] == '<' && - (p[3] == '=' || p[3] == '!')) { - int pos; - is_neg = (p[3] == '!'); - is_backward_lookahead = TRUE; - p += 4; - /* lookahead */ - lookahead: - /* Annex B allows lookahead to be used as an atom for - the quantifiers */ - if (!s->is_unicode && !is_backward_lookahead) { - last_atom_start = s->byte_code.size; - last_capture_count = s->capture_count; - } - pos = re_emit_op_u32(s, REOP_lookahead + is_neg, 0); - s->buf_ptr = p; - if (re_parse_disjunction(s, is_backward_lookahead)) - return -1; - p = s->buf_ptr; - if (re_parse_expect(s, &p, ')')) - return -1; - re_emit_op(s, REOP_match); - /* jump after the 'match' after the lookahead is successful */ - if (dbuf_error(&s->byte_code)) - return -1; - put_u32(s->byte_code.buf + pos, s->byte_code.size - (pos + 4)); - } else if (p[2] == '<') { - p += 3; - if (re_parse_group_name(s->u.tmp_buf, sizeof(s->u.tmp_buf), - &p)) { - return re_parse_error(s, "invalid group name"); - } - if (find_group_name(s, s->u.tmp_buf) > 0) { - return re_parse_error(s, "duplicate group name"); - } - /* group name with a trailing zero */ - dbuf_put(&s->group_names, (uint8_t *)s->u.tmp_buf, - strlen(s->u.tmp_buf) + 1); - s->has_named_captures = 1; - goto parse_capture; - } else { - return re_parse_error(s, "invalid group"); - } - } else { - int capture_index; - p++; - /* capture without group name */ - dbuf_putc(&s->group_names, 0); - parse_capture: - if (s->capture_count >= CAPTURE_COUNT_MAX) - return re_parse_error(s, "too many captures"); - last_atom_start = s->byte_code.size; - last_capture_count = s->capture_count; - capture_index = s->capture_count++; - re_emit_op_u8(s, REOP_save_start + is_backward_dir, - capture_index); - - s->buf_ptr = p; - if (re_parse_disjunction(s, is_backward_dir)) - return -1; - p = s->buf_ptr; - - re_emit_op_u8(s, REOP_save_start + 1 - is_backward_dir, - capture_index); - - if (re_parse_expect(s, &p, ')')) - return -1; - } - break; - case '\\': - switch(p[1]) { - case 'b': - case 'B': - if (p[1] != 'b') { - re_emit_op(s, s->ignore_case ? REOP_not_word_boundary_i : REOP_not_word_boundary); - } else { - re_emit_op(s, s->ignore_case ? REOP_word_boundary_i : REOP_word_boundary); - } - p += 2; - break; - case 'k': - { - const uint8_t *p1; - int dummy_res; - - p1 = p; - if (p1[2] != '<') { - /* annex B: we tolerate invalid group names in non - unicode mode if there is no named capture - definition */ - if (s->is_unicode || re_has_named_captures(s)) - return re_parse_error(s, "expecting group name"); - else - goto parse_class_atom; - } - p1 += 3; - if (re_parse_group_name(s->u.tmp_buf, sizeof(s->u.tmp_buf), - &p1)) { - if (s->is_unicode || re_has_named_captures(s)) - return re_parse_error(s, "invalid group name"); - else - goto parse_class_atom; - } - c = find_group_name(s, s->u.tmp_buf); - if (c < 0) { - /* no capture name parsed before, try to look - after (inefficient, but hopefully not common */ - c = re_parse_captures(s, &dummy_res, s->u.tmp_buf); - if (c < 0) { - if (s->is_unicode || re_has_named_captures(s)) - return re_parse_error(s, "group name not defined"); - else - goto parse_class_atom; - } - } - p = p1; - } - goto emit_back_reference; - case '0': - p += 2; - c = 0; - if (s->is_unicode) { - if (is_digit(*p)) { - return re_parse_error(s, "invalid decimal escape in regular expression"); - } - } else { - /* Annex B.1.4: accept legacy octal */ - if (*p >= '0' && *p <= '7') { - c = *p++ - '0'; - if (*p >= '0' && *p <= '7') { - c = (c << 3) + *p++ - '0'; - } - } - } - goto normal_char; - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': - case '9': - { - const uint8_t *q = ++p; - - c = parse_digits(&p, FALSE); - if (c < 0 || (c >= s->capture_count && c >= re_count_captures(s))) { - if (!s->is_unicode) { - /* Annex B.1.4: accept legacy octal */ - p = q; - if (*p <= '7') { - c = 0; - if (*p <= '3') - c = *p++ - '0'; - if (*p >= '0' && *p <= '7') { - c = (c << 3) + *p++ - '0'; - if (*p >= '0' && *p <= '7') { - c = (c << 3) + *p++ - '0'; - } - } - } else { - c = *p++; - } - goto normal_char; - } - return re_parse_error(s, "back reference out of range in regular expression"); - } - emit_back_reference: - last_atom_start = s->byte_code.size; - last_capture_count = s->capture_count; - - re_emit_op_u8(s, REOP_back_reference + 2 * is_backward_dir + s->ignore_case, c); - } - break; - default: - goto parse_class_atom; - } - break; - case '[': - last_atom_start = s->byte_code.size; - last_capture_count = s->capture_count; - if (is_backward_dir) - re_emit_op(s, REOP_prev); - if (re_parse_char_class(s, &p)) - return -1; - if (is_backward_dir) - re_emit_op(s, REOP_prev); - break; - case ']': - case '}': - if (s->is_unicode) - return re_parse_error(s, "syntax error"); - goto parse_class_atom; - default: - parse_class_atom: - c = get_class_atom(s, cr, &p, FALSE); - if ((int)c < 0) - return -1; - normal_char: - last_atom_start = s->byte_code.size; - last_capture_count = s->capture_count; - if (is_backward_dir) - re_emit_op(s, REOP_prev); - if (c >= CLASS_RANGE_BASE) { - int ret; - ret = re_emit_string_list(s, cr); - re_string_list_free(cr); - if (ret) - return -1; - } else { - if (s->ignore_case) - c = lre_canonicalize(c, s->is_unicode); - re_emit_char(s, c); - } - if (is_backward_dir) - re_emit_op(s, REOP_prev); - break; - } - - /* quantifier */ - if (last_atom_start >= 0) { - c = *p; - switch(c) { - case '*': - p++; - quant_min = 0; - quant_max = INT32_MAX; - goto quantifier; - case '+': - p++; - quant_min = 1; - quant_max = INT32_MAX; - goto quantifier; - case '?': - p++; - quant_min = 0; - quant_max = 1; - goto quantifier; - case '{': - { - const uint8_t *p1 = p; - /* As an extension (see ES6 annex B), we accept '{' not - followed by digits as a normal atom */ - if (!is_digit(p[1])) { - if (s->is_unicode) - goto invalid_quant_count; - break; - } - p++; - quant_min = parse_digits(&p, TRUE); - quant_max = quant_min; - if (*p == ',') { - p++; - if (is_digit(*p)) { - quant_max = parse_digits(&p, TRUE); - if (quant_max < quant_min) { - invalid_quant_count: - return re_parse_error(s, "invalid repetition count"); - } - } else { - quant_max = INT32_MAX; /* infinity */ - } - } - if (*p != '}' && !s->is_unicode) { - /* Annex B: normal atom if invalid '{' syntax */ - p = p1; - break; - } - if (re_parse_expect(s, &p, '}')) - return -1; - } - quantifier: - greedy = TRUE; - if (*p == '?') { - p++; - greedy = FALSE; - } - if (last_atom_start < 0) { - return re_parse_error(s, "nothing to repeat"); - } - if (greedy) { - int len, pos; - - if (quant_max > 0) { - /* specific optimization for simple quantifiers */ - if (dbuf_error(&s->byte_code)) - goto out_of_memory; - len = re_is_simple_quantifier(s->byte_code.buf + last_atom_start, - s->byte_code.size - last_atom_start); - if (len > 0) { - re_emit_op(s, REOP_match); - - if (dbuf_insert(&s->byte_code, last_atom_start, 17)) - goto out_of_memory; - pos = last_atom_start; - s->byte_code.buf[pos++] = REOP_simple_greedy_quant; - put_u32(&s->byte_code.buf[pos], - s->byte_code.size - last_atom_start - 17); - pos += 4; - put_u32(&s->byte_code.buf[pos], quant_min); - pos += 4; - put_u32(&s->byte_code.buf[pos], quant_max); - pos += 4; - put_u32(&s->byte_code.buf[pos], len); - pos += 4; - goto done; - } - } - - if (dbuf_error(&s->byte_code)) - goto out_of_memory; - } - /* the spec tells that if there is no advance when - running the atom after the first quant_min times, - then there is no match. We remove this test when we - are sure the atom always advances the position. */ - add_zero_advance_check = re_need_check_advance(s->byte_code.buf + last_atom_start, - s->byte_code.size - last_atom_start); - - { - int len, pos; - len = s->byte_code.size - last_atom_start; - if (quant_min == 0) { - /* need to reset the capture in case the atom is - not executed */ - if (last_capture_count != s->capture_count) { - if (dbuf_insert(&s->byte_code, last_atom_start, 3)) - goto out_of_memory; - s->byte_code.buf[last_atom_start++] = REOP_save_reset; - s->byte_code.buf[last_atom_start++] = last_capture_count; - s->byte_code.buf[last_atom_start++] = s->capture_count - 1; - } - if (quant_max == 0) { - s->byte_code.size = last_atom_start; - } else if (quant_max == 1 || quant_max == INT32_MAX) { - BOOL has_goto = (quant_max == INT32_MAX); - if (dbuf_insert(&s->byte_code, last_atom_start, 5 + add_zero_advance_check)) - goto out_of_memory; - s->byte_code.buf[last_atom_start] = REOP_split_goto_first + - greedy; - put_u32(s->byte_code.buf + last_atom_start + 1, - len + 5 * has_goto + add_zero_advance_check * 2); - if (add_zero_advance_check) { - s->byte_code.buf[last_atom_start + 1 + 4] = REOP_push_char_pos; - re_emit_op(s, REOP_check_advance); - } - if (has_goto) - re_emit_goto(s, REOP_goto, last_atom_start); - } else { - if (dbuf_insert(&s->byte_code, last_atom_start, 10 + add_zero_advance_check)) - goto out_of_memory; - pos = last_atom_start; - s->byte_code.buf[pos++] = REOP_push_i32; - put_u32(s->byte_code.buf + pos, quant_max); - pos += 4; - s->byte_code.buf[pos++] = REOP_split_goto_first + greedy; - put_u32(s->byte_code.buf + pos, len + 5 + add_zero_advance_check * 2); - pos += 4; - if (add_zero_advance_check) { - s->byte_code.buf[pos++] = REOP_push_char_pos; - re_emit_op(s, REOP_check_advance); - } - re_emit_goto(s, REOP_loop, last_atom_start + 5); - re_emit_op(s, REOP_drop); - } - } else if (quant_min == 1 && quant_max == INT32_MAX && - !add_zero_advance_check) { - re_emit_goto(s, REOP_split_next_first - greedy, - last_atom_start); - } else { - if (quant_min == 1) { - /* nothing to add */ - } else { - if (dbuf_insert(&s->byte_code, last_atom_start, 5)) - goto out_of_memory; - s->byte_code.buf[last_atom_start] = REOP_push_i32; - put_u32(s->byte_code.buf + last_atom_start + 1, - quant_min); - last_atom_start += 5; - re_emit_goto(s, REOP_loop, last_atom_start); - re_emit_op(s, REOP_drop); - } - if (quant_max == INT32_MAX) { - pos = s->byte_code.size; - re_emit_op_u32(s, REOP_split_goto_first + greedy, - len + 5 + add_zero_advance_check * 2); - if (add_zero_advance_check) - re_emit_op(s, REOP_push_char_pos); - /* copy the atom */ - dbuf_put_self(&s->byte_code, last_atom_start, len); - if (add_zero_advance_check) - re_emit_op(s, REOP_check_advance); - re_emit_goto(s, REOP_goto, pos); - } else if (quant_max > quant_min) { - re_emit_op_u32(s, REOP_push_i32, quant_max - quant_min); - pos = s->byte_code.size; - re_emit_op_u32(s, REOP_split_goto_first + greedy, - len + 5 + add_zero_advance_check * 2); - if (add_zero_advance_check) - re_emit_op(s, REOP_push_char_pos); - /* copy the atom */ - dbuf_put_self(&s->byte_code, last_atom_start, len); - if (add_zero_advance_check) - re_emit_op(s, REOP_check_advance); - re_emit_goto(s, REOP_loop, pos); - re_emit_op(s, REOP_drop); - } - } - last_atom_start = -1; - } - break; - default: - break; - } - } - done: - s->buf_ptr = p; - return 0; - out_of_memory: - return re_parse_out_of_memory(s); -} - -static int re_parse_alternative(REParseState *s, BOOL is_backward_dir) -{ - const uint8_t *p; - int ret; - size_t start, term_start, end, term_size; - - start = s->byte_code.size; - for(;;) { - p = s->buf_ptr; - if (p >= s->buf_end) - break; - if (*p == '|' || *p == ')') - break; - term_start = s->byte_code.size; - ret = re_parse_term(s, is_backward_dir); - if (ret) - return ret; - if (is_backward_dir) { - /* reverse the order of the terms (XXX: inefficient, but - speed is not really critical here) */ - end = s->byte_code.size; - term_size = end - term_start; - if (dbuf_realloc(&s->byte_code, end + term_size)) - return -1; - memmove(s->byte_code.buf + start + term_size, - s->byte_code.buf + start, - end - start); - memcpy(s->byte_code.buf + start, s->byte_code.buf + end, - term_size); - } - } - return 0; -} - -static int re_parse_disjunction(REParseState *s, BOOL is_backward_dir) -{ - int start, len, pos; - - if (lre_check_stack_overflow(s->opaque, 0)) - return re_parse_error(s, "stack overflow"); - - start = s->byte_code.size; - if (re_parse_alternative(s, is_backward_dir)) - return -1; - while (*s->buf_ptr == '|') { - s->buf_ptr++; - - len = s->byte_code.size - start; - - /* insert a split before the first alternative */ - if (dbuf_insert(&s->byte_code, start, 5)) { - return re_parse_out_of_memory(s); - } - s->byte_code.buf[start] = REOP_split_next_first; - put_u32(s->byte_code.buf + start + 1, len + 5); - - pos = re_emit_op_u32(s, REOP_goto, 0); - - if (re_parse_alternative(s, is_backward_dir)) - return -1; - - /* patch the goto */ - len = s->byte_code.size - (pos + 4); - put_u32(s->byte_code.buf + pos, len); - } - return 0; -} - -/* the control flow is recursive so the analysis can be linear */ -static int compute_stack_size(const uint8_t *bc_buf, int bc_buf_len) -{ - int stack_size, stack_size_max, pos, opcode, len; - uint32_t val; - - stack_size = 0; - stack_size_max = 0; - bc_buf += RE_HEADER_LEN; - bc_buf_len -= RE_HEADER_LEN; - pos = 0; - while (pos < bc_buf_len) { - opcode = bc_buf[pos]; - len = reopcode_info[opcode].size; - assert(opcode < REOP_COUNT); - assert((pos + len) <= bc_buf_len); - switch(opcode) { - case REOP_push_i32: - case REOP_push_char_pos: - stack_size++; - if (stack_size > stack_size_max) { - if (stack_size > STACK_SIZE_MAX) - return -1; - stack_size_max = stack_size; - } - break; - case REOP_drop: - case REOP_check_advance: - assert(stack_size > 0); - stack_size--; - break; - case REOP_range: - case REOP_range_i: - val = get_u16(bc_buf + pos + 1); - len += val * 4; - break; - case REOP_range32: - case REOP_range32_i: - val = get_u16(bc_buf + pos + 1); - len += val * 8; - break; - } - pos += len; - } - return stack_size_max; -} - -/* 'buf' must be a zero terminated UTF-8 string of length buf_len. - Return NULL if error and allocate an error message in *perror_msg, - otherwise the compiled bytecode and its length in plen. -*/ -uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, - const char *buf, size_t buf_len, int re_flags, - void *opaque) -{ - REParseState s_s, *s = &s_s; - int stack_size; - BOOL is_sticky; - - memset(s, 0, sizeof(*s)); - s->opaque = opaque; - s->buf_ptr = (const uint8_t *)buf; - s->buf_end = s->buf_ptr + buf_len; - s->buf_start = s->buf_ptr; - s->re_flags = re_flags; - s->is_unicode = ((re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0); - is_sticky = ((re_flags & LRE_FLAG_STICKY) != 0); - s->ignore_case = ((re_flags & LRE_FLAG_IGNORECASE) != 0); - s->multi_line = ((re_flags & LRE_FLAG_MULTILINE) != 0); - s->dotall = ((re_flags & LRE_FLAG_DOTALL) != 0); - s->unicode_sets = ((re_flags & LRE_FLAG_UNICODE_SETS) != 0); - s->capture_count = 1; - s->total_capture_count = -1; - s->has_named_captures = -1; - - dbuf_init2(&s->byte_code, opaque, lre_realloc); - dbuf_init2(&s->group_names, opaque, lre_realloc); - - dbuf_put_u16(&s->byte_code, re_flags); /* first element is the flags */ - dbuf_putc(&s->byte_code, 0); /* second element is the number of captures */ - dbuf_putc(&s->byte_code, 0); /* stack size */ - dbuf_put_u32(&s->byte_code, 0); /* bytecode length */ - - if (!is_sticky) { - /* iterate thru all positions (about the same as .*?( ... ) ) - . We do it without an explicit loop so that lock step - thread execution will be possible in an optimized - implementation */ - re_emit_op_u32(s, REOP_split_goto_first, 1 + 5); - re_emit_op(s, REOP_any); - re_emit_op_u32(s, REOP_goto, -(5 + 1 + 5)); - } - re_emit_op_u8(s, REOP_save_start, 0); - - if (re_parse_disjunction(s, FALSE)) { - error: - dbuf_free(&s->byte_code); - dbuf_free(&s->group_names); - pstrcpy(error_msg, error_msg_size, s->u.error_msg); - *plen = 0; - return NULL; - } - - re_emit_op_u8(s, REOP_save_end, 0); - - re_emit_op(s, REOP_match); - - if (*s->buf_ptr != '\0') { - re_parse_error(s, "extraneous characters at the end"); - goto error; - } - - if (dbuf_error(&s->byte_code)) { - re_parse_out_of_memory(s); - goto error; - } - - stack_size = compute_stack_size(s->byte_code.buf, s->byte_code.size); - if (stack_size < 0) { - re_parse_error(s, "too many imbricated quantifiers"); - goto error; - } - - s->byte_code.buf[RE_HEADER_CAPTURE_COUNT] = s->capture_count; - s->byte_code.buf[RE_HEADER_STACK_SIZE] = stack_size; - put_u32(s->byte_code.buf + RE_HEADER_BYTECODE_LEN, - s->byte_code.size - RE_HEADER_LEN); - - /* add the named groups if needed */ - if (s->group_names.size > (s->capture_count - 1)) { - dbuf_put(&s->byte_code, s->group_names.buf, s->group_names.size); - put_u16(s->byte_code.buf + RE_HEADER_FLAGS, - lre_get_flags(s->byte_code.buf) | LRE_FLAG_NAMED_GROUPS); - } - dbuf_free(&s->group_names); - -#ifdef DUMP_REOP - lre_dump_bytecode(s->byte_code.buf, s->byte_code.size); -#endif - - error_msg[0] = '\0'; - *plen = s->byte_code.size; - return s->byte_code.buf; -} - -static BOOL is_line_terminator(uint32_t c) -{ - return (c == '\n' || c == '\r' || c == CP_LS || c == CP_PS); -} - -static BOOL is_word_char(uint32_t c) -{ - return ((c >= '0' && c <= '9') || - (c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c == '_')); -} - -#define GET_CHAR(c, cptr, cbuf_end, cbuf_type) \ - do { \ - if (cbuf_type == 0) { \ - c = *cptr++; \ - } else { \ - const uint16_t *_p = (const uint16_t *)cptr; \ - const uint16_t *_end = (const uint16_t *)cbuf_end; \ - c = *_p++; \ - if (is_hi_surrogate(c) && cbuf_type == 2) { \ - if (_p < _end && is_lo_surrogate(*_p)) { \ - c = from_surrogate(c, *_p++); \ - } \ - } \ - cptr = (const void *)_p; \ - } \ - } while (0) - -#define PEEK_CHAR(c, cptr, cbuf_end, cbuf_type) \ - do { \ - if (cbuf_type == 0) { \ - c = cptr[0]; \ - } else { \ - const uint16_t *_p = (const uint16_t *)cptr; \ - const uint16_t *_end = (const uint16_t *)cbuf_end; \ - c = *_p++; \ - if (is_hi_surrogate(c) && cbuf_type == 2) { \ - if (_p < _end && is_lo_surrogate(*_p)) { \ - c = from_surrogate(c, *_p); \ - } \ - } \ - } \ - } while (0) - -#define PEEK_PREV_CHAR(c, cptr, cbuf_start, cbuf_type) \ - do { \ - if (cbuf_type == 0) { \ - c = cptr[-1]; \ - } else { \ - const uint16_t *_p = (const uint16_t *)cptr - 1; \ - const uint16_t *_start = (const uint16_t *)cbuf_start; \ - c = *_p; \ - if (is_lo_surrogate(c) && cbuf_type == 2) { \ - if (_p > _start && is_hi_surrogate(_p[-1])) { \ - c = from_surrogate(*--_p, c); \ - } \ - } \ - } \ - } while (0) - -#define GET_PREV_CHAR(c, cptr, cbuf_start, cbuf_type) \ - do { \ - if (cbuf_type == 0) { \ - cptr--; \ - c = cptr[0]; \ - } else { \ - const uint16_t *_p = (const uint16_t *)cptr - 1; \ - const uint16_t *_start = (const uint16_t *)cbuf_start; \ - c = *_p; \ - if (is_lo_surrogate(c) && cbuf_type == 2) { \ - if (_p > _start && is_hi_surrogate(_p[-1])) { \ - c = from_surrogate(*--_p, c); \ - } \ - } \ - cptr = (const void *)_p; \ - } \ - } while (0) - -#define PREV_CHAR(cptr, cbuf_start, cbuf_type) \ - do { \ - if (cbuf_type == 0) { \ - cptr--; \ - } else { \ - const uint16_t *_p = (const uint16_t *)cptr - 1; \ - const uint16_t *_start = (const uint16_t *)cbuf_start; \ - if (is_lo_surrogate(*_p) && cbuf_type == 2) { \ - if (_p > _start && is_hi_surrogate(_p[-1])) { \ - --_p; \ - } \ - } \ - cptr = (const void *)_p; \ - } \ - } while (0) - -typedef uintptr_t StackInt; - -typedef enum { - RE_EXEC_STATE_SPLIT, - RE_EXEC_STATE_LOOKAHEAD, - RE_EXEC_STATE_NEGATIVE_LOOKAHEAD, - RE_EXEC_STATE_GREEDY_QUANT, -} REExecStateEnum; - -typedef struct REExecState { - REExecStateEnum type : 8; - uint8_t stack_len; - size_t count; /* only used for RE_EXEC_STATE_GREEDY_QUANT */ - const uint8_t *cptr; - const uint8_t *pc; - void *buf[0]; -} REExecState; - -typedef struct { - const uint8_t *cbuf; - const uint8_t *cbuf_end; - /* 0 = 8 bit chars, 1 = 16 bit chars, 2 = 16 bit chars, UTF-16 */ - int cbuf_type; - int capture_count; - int stack_size_max; - BOOL is_unicode; - int interrupt_counter; - void *opaque; /* used for stack overflow check */ - - size_t state_size; - uint8_t *state_stack; - size_t state_stack_size; - size_t state_stack_len; -} REExecContext; - -static int push_state(REExecContext *s, - uint8_t **capture, - StackInt *stack, size_t stack_len, - const uint8_t *pc, const uint8_t *cptr, - REExecStateEnum type, size_t count) -{ - REExecState *rs; - uint8_t *new_stack; - size_t new_size, i, n; - StackInt *stack_buf; - - if (unlikely((s->state_stack_len + 1) > s->state_stack_size)) { - /* reallocate the stack */ - new_size = s->state_stack_size * 3 / 2; - if (new_size < 8) - new_size = 8; - new_stack = lre_realloc(s->opaque, s->state_stack, new_size * s->state_size); - if (!new_stack) - return -1; - s->state_stack_size = new_size; - s->state_stack = new_stack; - } - rs = (REExecState *)(s->state_stack + s->state_stack_len * s->state_size); - s->state_stack_len++; - rs->type = type; - rs->count = count; - rs->stack_len = stack_len; - rs->cptr = cptr; - rs->pc = pc; - n = 2 * s->capture_count; - for(i = 0; i < n; i++) - rs->buf[i] = capture[i]; - stack_buf = (StackInt *)(rs->buf + n); - for(i = 0; i < stack_len; i++) - stack_buf[i] = stack[i]; - return 0; -} - -static int lre_poll_timeout(REExecContext *s) -{ - if (unlikely(--s->interrupt_counter <= 0)) { - s->interrupt_counter = INTERRUPT_COUNTER_INIT; - if (lre_check_timeout(s->opaque)) - return LRE_RET_TIMEOUT; - } - return 0; -} - -/* return 1 if match, 0 if not match or < 0 if error. */ -static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture, - StackInt *stack, int stack_len, - const uint8_t *pc, const uint8_t *cptr, - BOOL no_recurse) -{ - int opcode, ret; - int cbuf_type; - uint32_t val, c; - const uint8_t *cbuf_end; - - cbuf_type = s->cbuf_type; - cbuf_end = s->cbuf_end; - - for(;;) { - // printf("top=%p: pc=%d\n", th_list.top, (int)(pc - (bc_buf + RE_HEADER_LEN))); - opcode = *pc++; - switch(opcode) { - case REOP_match: - { - REExecState *rs; - if (no_recurse) - return (intptr_t)cptr; - ret = 1; - goto recurse; - no_match: - if (no_recurse) - return 0; - ret = 0; - recurse: - for(;;) { - if (lre_poll_timeout(s)) - return LRE_RET_TIMEOUT; - if (s->state_stack_len == 0) - return ret; - rs = (REExecState *)(s->state_stack + - (s->state_stack_len - 1) * s->state_size); - if (rs->type == RE_EXEC_STATE_SPLIT) { - if (!ret) { - pop_state: - memcpy(capture, rs->buf, - sizeof(capture[0]) * 2 * s->capture_count); - pop_state1: - pc = rs->pc; - cptr = rs->cptr; - stack_len = rs->stack_len; - memcpy(stack, rs->buf + 2 * s->capture_count, - stack_len * sizeof(stack[0])); - s->state_stack_len--; - break; - } - } else if (rs->type == RE_EXEC_STATE_GREEDY_QUANT) { - if (!ret) { - uint32_t char_count, i; - memcpy(capture, rs->buf, - sizeof(capture[0]) * 2 * s->capture_count); - stack_len = rs->stack_len; - memcpy(stack, rs->buf + 2 * s->capture_count, - stack_len * sizeof(stack[0])); - pc = rs->pc; - cptr = rs->cptr; - /* go backward */ - char_count = get_u32(pc + 12); - for(i = 0; i < char_count; i++) { - PREV_CHAR(cptr, s->cbuf, cbuf_type); - } - pc = (pc + 16) + (int)get_u32(pc); - rs->cptr = cptr; - rs->count--; - if (rs->count == 0) { - s->state_stack_len--; - } - break; - } - } else { - ret = ((rs->type == RE_EXEC_STATE_LOOKAHEAD && ret) || - (rs->type == RE_EXEC_STATE_NEGATIVE_LOOKAHEAD && !ret)); - if (ret) { - /* keep the capture in case of positive lookahead */ - if (rs->type == RE_EXEC_STATE_LOOKAHEAD) - goto pop_state1; - else - goto pop_state; - } - } - s->state_stack_len--; - } - } - break; - case REOP_char32: - case REOP_char32_i: - val = get_u32(pc); - pc += 4; - goto test_char; - case REOP_char: - case REOP_char_i: - val = get_u16(pc); - pc += 2; - test_char: - if (cptr >= cbuf_end) - goto no_match; - GET_CHAR(c, cptr, cbuf_end, cbuf_type); - if (opcode == REOP_char_i || opcode == REOP_char32_i) { - c = lre_canonicalize(c, s->is_unicode); - } - if (val != c) - goto no_match; - break; - case REOP_split_goto_first: - case REOP_split_next_first: - { - const uint8_t *pc1; - - val = get_u32(pc); - pc += 4; - if (opcode == REOP_split_next_first) { - pc1 = pc + (int)val; - } else { - pc1 = pc; - pc = pc + (int)val; - } - ret = push_state(s, capture, stack, stack_len, - pc1, cptr, RE_EXEC_STATE_SPLIT, 0); - if (ret < 0) - return LRE_RET_MEMORY_ERROR; - break; - } - case REOP_lookahead: - case REOP_negative_lookahead: - val = get_u32(pc); - pc += 4; - ret = push_state(s, capture, stack, stack_len, - pc + (int)val, cptr, - RE_EXEC_STATE_LOOKAHEAD + opcode - REOP_lookahead, - 0); - if (ret < 0) - return LRE_RET_MEMORY_ERROR; - break; - - case REOP_goto: - val = get_u32(pc); - pc += 4 + (int)val; - if (lre_poll_timeout(s)) - return LRE_RET_TIMEOUT; - break; - case REOP_line_start: - case REOP_line_start_m: - if (cptr == s->cbuf) - break; - if (opcode == REOP_line_start) - goto no_match; - PEEK_PREV_CHAR(c, cptr, s->cbuf, cbuf_type); - if (!is_line_terminator(c)) - goto no_match; - break; - case REOP_line_end: - case REOP_line_end_m: - if (cptr == cbuf_end) - break; - if (opcode == REOP_line_end) - goto no_match; - PEEK_CHAR(c, cptr, cbuf_end, cbuf_type); - if (!is_line_terminator(c)) - goto no_match; - break; - case REOP_dot: - if (cptr == cbuf_end) - goto no_match; - GET_CHAR(c, cptr, cbuf_end, cbuf_type); - if (is_line_terminator(c)) - goto no_match; - break; - case REOP_any: - if (cptr == cbuf_end) - goto no_match; - GET_CHAR(c, cptr, cbuf_end, cbuf_type); - break; - case REOP_save_start: - case REOP_save_end: - val = *pc++; - assert(val < s->capture_count); - capture[2 * val + opcode - REOP_save_start] = (uint8_t *)cptr; - break; - case REOP_save_reset: - { - uint32_t val2; - val = pc[0]; - val2 = pc[1]; - pc += 2; - assert(val2 < s->capture_count); - while (val <= val2) { - capture[2 * val] = NULL; - capture[2 * val + 1] = NULL; - val++; - } - } - break; - case REOP_push_i32: - val = get_u32(pc); - pc += 4; - stack[stack_len++] = val; - break; - case REOP_drop: - stack_len--; - break; - case REOP_loop: - val = get_u32(pc); - pc += 4; - if (--stack[stack_len - 1] != 0) { - pc += (int)val; - if (lre_poll_timeout(s)) - return LRE_RET_TIMEOUT; - } - break; - case REOP_push_char_pos: - stack[stack_len++] = (uintptr_t)cptr; - break; - case REOP_check_advance: - if (stack[--stack_len] == (uintptr_t)cptr) - goto no_match; - break; - case REOP_word_boundary: - case REOP_word_boundary_i: - case REOP_not_word_boundary: - case REOP_not_word_boundary_i: - { - BOOL v1, v2; - int ignore_case = (opcode == REOP_word_boundary_i || opcode == REOP_not_word_boundary_i); - BOOL is_boundary = (opcode == REOP_word_boundary || opcode == REOP_word_boundary_i); - /* char before */ - if (cptr == s->cbuf) { - v1 = FALSE; - } else { - PEEK_PREV_CHAR(c, cptr, s->cbuf, cbuf_type); - if (ignore_case) - c = lre_canonicalize(c, s->is_unicode); - v1 = is_word_char(c); - } - /* current char */ - if (cptr >= cbuf_end) { - v2 = FALSE; - } else { - PEEK_CHAR(c, cptr, cbuf_end, cbuf_type); - if (ignore_case) - c = lre_canonicalize(c, s->is_unicode); - v2 = is_word_char(c); - } - if (v1 ^ v2 ^ is_boundary) - goto no_match; - } - break; - case REOP_back_reference: - case REOP_back_reference_i: - case REOP_backward_back_reference: - case REOP_backward_back_reference_i: - { - const uint8_t *cptr1, *cptr1_end, *cptr1_start; - uint32_t c1, c2; - - val = *pc++; - if (val >= s->capture_count) - goto no_match; - cptr1_start = capture[2 * val]; - cptr1_end = capture[2 * val + 1]; - if (!cptr1_start || !cptr1_end) - break; - if (opcode == REOP_back_reference || - opcode == REOP_back_reference_i) { - cptr1 = cptr1_start; - while (cptr1 < cptr1_end) { - if (cptr >= cbuf_end) - goto no_match; - GET_CHAR(c1, cptr1, cptr1_end, cbuf_type); - GET_CHAR(c2, cptr, cbuf_end, cbuf_type); - if (opcode == REOP_back_reference_i) { - c1 = lre_canonicalize(c1, s->is_unicode); - c2 = lre_canonicalize(c2, s->is_unicode); - } - if (c1 != c2) - goto no_match; - } - } else { - cptr1 = cptr1_end; - while (cptr1 > cptr1_start) { - if (cptr == s->cbuf) - goto no_match; - GET_PREV_CHAR(c1, cptr1, cptr1_start, cbuf_type); - GET_PREV_CHAR(c2, cptr, s->cbuf, cbuf_type); - if (opcode == REOP_backward_back_reference_i) { - c1 = lre_canonicalize(c1, s->is_unicode); - c2 = lre_canonicalize(c2, s->is_unicode); - } - if (c1 != c2) - goto no_match; - } - } - } - break; - case REOP_range: - case REOP_range_i: - { - int n; - uint32_t low, high, idx_min, idx_max, idx; - - n = get_u16(pc); /* n must be >= 1 */ - pc += 2; - if (cptr >= cbuf_end) - goto no_match; - GET_CHAR(c, cptr, cbuf_end, cbuf_type); - if (opcode == REOP_range_i) { - c = lre_canonicalize(c, s->is_unicode); - } - idx_min = 0; - low = get_u16(pc + 0 * 4); - if (c < low) - goto no_match; - idx_max = n - 1; - high = get_u16(pc + idx_max * 4 + 2); - /* 0xffff in for last value means +infinity */ - if (unlikely(c >= 0xffff) && high == 0xffff) - goto range_match; - if (c > high) - goto no_match; - while (idx_min <= idx_max) { - idx = (idx_min + idx_max) / 2; - low = get_u16(pc + idx * 4); - high = get_u16(pc + idx * 4 + 2); - if (c < low) - idx_max = idx - 1; - else if (c > high) - idx_min = idx + 1; - else - goto range_match; - } - goto no_match; - range_match: - pc += 4 * n; - } - break; - case REOP_range32: - case REOP_range32_i: - { - int n; - uint32_t low, high, idx_min, idx_max, idx; - - n = get_u16(pc); /* n must be >= 1 */ - pc += 2; - if (cptr >= cbuf_end) - goto no_match; - GET_CHAR(c, cptr, cbuf_end, cbuf_type); - if (opcode == REOP_range32_i) { - c = lre_canonicalize(c, s->is_unicode); - } - idx_min = 0; - low = get_u32(pc + 0 * 8); - if (c < low) - goto no_match; - idx_max = n - 1; - high = get_u32(pc + idx_max * 8 + 4); - if (c > high) - goto no_match; - while (idx_min <= idx_max) { - idx = (idx_min + idx_max) / 2; - low = get_u32(pc + idx * 8); - high = get_u32(pc + idx * 8 + 4); - if (c < low) - idx_max = idx - 1; - else if (c > high) - idx_min = idx + 1; - else - goto range32_match; - } - goto no_match; - range32_match: - pc += 8 * n; - } - break; - case REOP_prev: - /* go to the previous char */ - if (cptr == s->cbuf) - goto no_match; - PREV_CHAR(cptr, s->cbuf, cbuf_type); - break; - case REOP_simple_greedy_quant: - { - uint32_t next_pos, quant_min, quant_max; - size_t q; - intptr_t res; - const uint8_t *pc1; - - next_pos = get_u32(pc); - quant_min = get_u32(pc + 4); - quant_max = get_u32(pc + 8); - pc += 16; - pc1 = pc; - pc += (int)next_pos; - - q = 0; - for(;;) { - if (lre_poll_timeout(s)) - return LRE_RET_TIMEOUT; - res = lre_exec_backtrack(s, capture, stack, stack_len, - pc1, cptr, TRUE); - if (res == LRE_RET_MEMORY_ERROR || - res == LRE_RET_TIMEOUT) - return res; - if (!res) - break; - cptr = (uint8_t *)res; - q++; - if (q >= quant_max && quant_max != INT32_MAX) - break; - } - if (q < quant_min) - goto no_match; - if (q > quant_min) { - /* will examine all matches down to quant_min */ - ret = push_state(s, capture, stack, stack_len, - pc1 - 16, cptr, - RE_EXEC_STATE_GREEDY_QUANT, - q - quant_min); - if (ret < 0) - return LRE_RET_MEMORY_ERROR; - } - } - break; - default: - abort(); - } - } -} - -/* Return 1 if match, 0 if not match or < 0 if error (see LRE_RET_x). cindex is the - starting position of the match and must be such as 0 <= cindex <= - clen. */ -int lre_exec(uint8_t **capture, - const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen, - int cbuf_type, void *opaque) -{ - REExecContext s_s, *s = &s_s; - int re_flags, i, alloca_size, ret; - StackInt *stack_buf; - - re_flags = lre_get_flags(bc_buf); - s->is_unicode = (re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0; - s->capture_count = bc_buf[RE_HEADER_CAPTURE_COUNT]; - s->stack_size_max = bc_buf[RE_HEADER_STACK_SIZE]; - s->cbuf = cbuf; - s->cbuf_end = cbuf + (clen << cbuf_type); - s->cbuf_type = cbuf_type; - if (s->cbuf_type == 1 && s->is_unicode) - s->cbuf_type = 2; - s->interrupt_counter = INTERRUPT_COUNTER_INIT; - s->opaque = opaque; - - s->state_size = sizeof(REExecState) + - s->capture_count * sizeof(capture[0]) * 2 + - s->stack_size_max * sizeof(stack_buf[0]); - s->state_stack = NULL; - s->state_stack_len = 0; - s->state_stack_size = 0; - - for(i = 0; i < s->capture_count * 2; i++) - capture[i] = NULL; - alloca_size = s->stack_size_max * sizeof(stack_buf[0]); - stack_buf = alloca(alloca_size); - ret = lre_exec_backtrack(s, capture, stack_buf, 0, bc_buf + RE_HEADER_LEN, - cbuf + (cindex << cbuf_type), FALSE); - lre_realloc(s->opaque, s->state_stack, 0); - return ret; -} - -int lre_get_capture_count(const uint8_t *bc_buf) -{ - return bc_buf[RE_HEADER_CAPTURE_COUNT]; -} - -int lre_get_flags(const uint8_t *bc_buf) -{ - return get_u16(bc_buf + RE_HEADER_FLAGS); -} - -/* Return NULL if no group names. Otherwise, return a pointer to - 'capture_count - 1' zero terminated UTF-8 strings. */ -const char *lre_get_groupnames(const uint8_t *bc_buf) -{ - uint32_t re_bytecode_len; - if ((lre_get_flags(bc_buf) & LRE_FLAG_NAMED_GROUPS) == 0) - return NULL; - re_bytecode_len = get_u32(bc_buf + RE_HEADER_BYTECODE_LEN); - return (const char *)(bc_buf + RE_HEADER_LEN + re_bytecode_len); -} - -#ifdef TEST - -BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size) -{ - return FALSE; -} - -void *lre_realloc(void *opaque, void *ptr, size_t size) -{ - return realloc(ptr, size); -} - -int main(int argc, char **argv) -{ - int len, flags, ret, i; - uint8_t *bc; - char error_msg[64]; - uint8_t *capture[CAPTURE_COUNT_MAX * 2]; - const char *input; - int input_len, capture_count; - - if (argc < 4) { - printf("usage: %s regexp flags input\n", argv[0]); - return 1; - } - flags = atoi(argv[2]); - bc = lre_compile(&len, error_msg, sizeof(error_msg), argv[1], - strlen(argv[1]), flags, NULL); - if (!bc) { - fprintf(stderr, "error: %s\n", error_msg); - exit(1); - } - - input = argv[3]; - input_len = strlen(input); - - ret = lre_exec(capture, bc, (uint8_t *)input, 0, input_len, 0, NULL); - printf("ret=%d\n", ret); - if (ret == 1) { - capture_count = lre_get_capture_count(bc); - for(i = 0; i < 2 * capture_count; i++) { - uint8_t *ptr; - ptr = capture[i]; - printf("%d: ", i); - if (!ptr) - printf(""); - else - printf("%u", (int)(ptr - (uint8_t *)input)); - printf("\n"); - } - } - return 0; -} -#endif diff --git a/packages/javascript/javascript_android/cxx/quickjs/libregexp.h b/packages/javascript/javascript_android/cxx/quickjs/libregexp.h deleted file mode 100644 index da76e4c..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/libregexp.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Regular Expression Engine - * - * Copyright (c) 2017-2018 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef LIBREGEXP_H -#define LIBREGEXP_H - -#include -#include - -#define LRE_FLAG_GLOBAL (1 << 0) -#define LRE_FLAG_IGNORECASE (1 << 1) -#define LRE_FLAG_MULTILINE (1 << 2) -#define LRE_FLAG_DOTALL (1 << 3) -#define LRE_FLAG_UNICODE (1 << 4) -#define LRE_FLAG_STICKY (1 << 5) -#define LRE_FLAG_INDICES (1 << 6) /* Unused by libregexp, just recorded. */ -#define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */ -#define LRE_FLAG_UNICODE_SETS (1 << 8) - -#define LRE_RET_MEMORY_ERROR (-1) -#define LRE_RET_TIMEOUT (-2) - -uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, - const char *buf, size_t buf_len, int re_flags, - void *opaque); -int lre_get_capture_count(const uint8_t *bc_buf); -int lre_get_flags(const uint8_t *bc_buf); -const char *lre_get_groupnames(const uint8_t *bc_buf); -int lre_exec(uint8_t **capture, - const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen, - int cbuf_type, void *opaque); - -int lre_parse_escape(const uint8_t **pp, int allow_utf16); - -/* must be provided by the user, return non zero if overflow */ -int lre_check_stack_overflow(void *opaque, size_t alloca_size); -/* must be provided by the user, return non zero if time out */ -int lre_check_timeout(void *opaque); -void *lre_realloc(void *opaque, void *ptr, size_t size); - -#endif /* LIBREGEXP_H */ diff --git a/packages/javascript/javascript_android/cxx/quickjs/libunicode-table.h b/packages/javascript/javascript_android/cxx/quickjs/libunicode-table.h deleted file mode 100644 index 67df6b3..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/libunicode-table.h +++ /dev/null @@ -1,5149 +0,0 @@ -/* Compressed unicode tables */ -/* Automatically generated file - do not edit */ - -#include - -static const uint32_t case_conv_table1[378] = { - 0x00209a30, 0x00309a00, 0x005a8173, 0x00601730, - 0x006c0730, 0x006f81b3, 0x00701700, 0x007c0700, - 0x007f8100, 0x00803040, 0x009801c3, 0x00988190, - 0x00990640, 0x009c9040, 0x00a481b4, 0x00a52e40, - 0x00bc0130, 0x00bc8640, 0x00bf8170, 0x00c00100, - 0x00c08130, 0x00c10440, 0x00c30130, 0x00c38240, - 0x00c48230, 0x00c58240, 0x00c70130, 0x00c78130, - 0x00c80130, 0x00c88240, 0x00c98130, 0x00ca0130, - 0x00ca8100, 0x00cb0130, 0x00cb8130, 0x00cc0240, - 0x00cd0100, 0x00cd8101, 0x00ce0130, 0x00ce8130, - 0x00cf0100, 0x00cf8130, 0x00d00640, 0x00d30130, - 0x00d38240, 0x00d48130, 0x00d60240, 0x00d70130, - 0x00d78240, 0x00d88230, 0x00d98440, 0x00db8130, - 0x00dc0240, 0x00de0240, 0x00df8100, 0x00e20350, - 0x00e38350, 0x00e50350, 0x00e69040, 0x00ee8100, - 0x00ef1240, 0x00f801b4, 0x00f88350, 0x00fa0240, - 0x00fb0130, 0x00fb8130, 0x00fc2840, 0x01100130, - 0x01111240, 0x011d0131, 0x011d8240, 0x011e8130, - 0x011f0131, 0x011f8201, 0x01208240, 0x01218130, - 0x01220130, 0x01228130, 0x01230a40, 0x01280101, - 0x01288101, 0x01290101, 0x01298100, 0x012a0100, - 0x012b0200, 0x012c8100, 0x012d8100, 0x012e0101, - 0x01300100, 0x01308101, 0x01318100, 0x01320101, - 0x01328101, 0x01330101, 0x01340100, 0x01348100, - 0x01350101, 0x01358101, 0x01360101, 0x01378100, - 0x01388101, 0x01390100, 0x013a8100, 0x013e8101, - 0x01400100, 0x01410101, 0x01418100, 0x01438101, - 0x01440100, 0x01448100, 0x01450200, 0x01460100, - 0x01490100, 0x014e8101, 0x014f0101, 0x01a28173, - 0x01b80440, 0x01bb0240, 0x01bd8300, 0x01bf8130, - 0x01c30130, 0x01c40330, 0x01c60130, 0x01c70230, - 0x01c801d0, 0x01c89130, 0x01d18930, 0x01d60100, - 0x01d68300, 0x01d801d3, 0x01d89100, 0x01e10173, - 0x01e18900, 0x01e60100, 0x01e68200, 0x01e78130, - 0x01e80173, 0x01e88173, 0x01ea8173, 0x01eb0173, - 0x01eb8100, 0x01ec1840, 0x01f80173, 0x01f88173, - 0x01f90100, 0x01f98100, 0x01fa01a0, 0x01fa8173, - 0x01fb8240, 0x01fc8130, 0x01fd0240, 0x01fe8330, - 0x02001030, 0x02082030, 0x02182000, 0x02281000, - 0x02302240, 0x02453640, 0x02600130, 0x02608e40, - 0x02678100, 0x02686040, 0x0298a630, 0x02b0a600, - 0x02c381b5, 0x08502631, 0x08638131, 0x08668131, - 0x08682b00, 0x087e8300, 0x09d05011, 0x09f80610, - 0x09fc0620, 0x0e400174, 0x0e408174, 0x0e410174, - 0x0e418174, 0x0e420174, 0x0e428174, 0x0e430174, - 0x0e438180, 0x0e440180, 0x0e448240, 0x0e482b30, - 0x0e5e8330, 0x0ebc8101, 0x0ebe8101, 0x0ec70101, - 0x0f007e40, 0x0f3f1840, 0x0f4b01b5, 0x0f4b81b6, - 0x0f4c01b6, 0x0f4c81b6, 0x0f4d01b7, 0x0f4d8180, - 0x0f4f0130, 0x0f506040, 0x0f800800, 0x0f840830, - 0x0f880600, 0x0f8c0630, 0x0f900800, 0x0f940830, - 0x0f980800, 0x0f9c0830, 0x0fa00600, 0x0fa40630, - 0x0fa801b0, 0x0fa88100, 0x0fa901d3, 0x0fa98100, - 0x0faa01d3, 0x0faa8100, 0x0fab01d3, 0x0fab8100, - 0x0fac8130, 0x0fad8130, 0x0fae8130, 0x0faf8130, - 0x0fb00800, 0x0fb40830, 0x0fb80200, 0x0fb90400, - 0x0fbb0201, 0x0fbc0201, 0x0fbd0201, 0x0fbe0201, - 0x0fc008b7, 0x0fc40867, 0x0fc808b8, 0x0fcc0868, - 0x0fd008b8, 0x0fd40868, 0x0fd80200, 0x0fd901b9, - 0x0fd981b1, 0x0fda01b9, 0x0fdb01b1, 0x0fdb81d7, - 0x0fdc0230, 0x0fdd0230, 0x0fde0161, 0x0fdf0173, - 0x0fe101b9, 0x0fe181b2, 0x0fe201ba, 0x0fe301b2, - 0x0fe381d8, 0x0fe40430, 0x0fe60162, 0x0fe80201, - 0x0fe901d0, 0x0fe981d0, 0x0feb01b0, 0x0feb81d0, - 0x0fec0230, 0x0fed0230, 0x0ff00201, 0x0ff101d3, - 0x0ff181d3, 0x0ff201ba, 0x0ff28101, 0x0ff301b0, - 0x0ff381d3, 0x0ff40231, 0x0ff50230, 0x0ff60131, - 0x0ff901ba, 0x0ff981b2, 0x0ffa01bb, 0x0ffb01b2, - 0x0ffb81d9, 0x0ffc0230, 0x0ffd0230, 0x0ffe0162, - 0x109301a0, 0x109501a0, 0x109581a0, 0x10990131, - 0x10a70101, 0x10b01031, 0x10b81001, 0x10c18240, - 0x125b1a31, 0x12681a01, 0x16003031, 0x16183001, - 0x16300240, 0x16310130, 0x16318130, 0x16320130, - 0x16328100, 0x16330100, 0x16338640, 0x16368130, - 0x16370130, 0x16378130, 0x16380130, 0x16390240, - 0x163a8240, 0x163f0230, 0x16406440, 0x16758440, - 0x16790240, 0x16802600, 0x16938100, 0x16968100, - 0x53202e40, 0x53401c40, 0x53910e40, 0x53993e40, - 0x53bc8440, 0x53be8130, 0x53bf0a40, 0x53c58240, - 0x53c68130, 0x53c80440, 0x53ca0101, 0x53cb1440, - 0x53d50130, 0x53d58130, 0x53d60130, 0x53d68130, - 0x53d70130, 0x53d80130, 0x53d88130, 0x53d90130, - 0x53d98131, 0x53da1040, 0x53e20131, 0x53e28130, - 0x53e30130, 0x53e38440, 0x53e58130, 0x53e60240, - 0x53e80240, 0x53eb0640, 0x53ee0130, 0x53fa8240, - 0x55a98101, 0x55b85020, 0x7d8001b2, 0x7d8081b2, - 0x7d8101b2, 0x7d8181da, 0x7d8201da, 0x7d8281b3, - 0x7d8301b3, 0x7d8981bb, 0x7d8a01bb, 0x7d8a81bb, - 0x7d8b01bc, 0x7d8b81bb, 0x7f909a31, 0x7fa09a01, - 0x82002831, 0x82142801, 0x82582431, 0x826c2401, - 0x82b80b31, 0x82be0f31, 0x82c60731, 0x82ca0231, - 0x82cb8b01, 0x82d18f01, 0x82d98701, 0x82dd8201, - 0x86403331, 0x86603301, 0x86a81631, 0x86b81601, - 0x8c502031, 0x8c602001, 0xb7202031, 0xb7302001, - 0xf4802231, 0xf4912201, -}; - -static const uint8_t case_conv_table2[378] = { - 0x01, 0x00, 0x9c, 0x06, 0x07, 0x4d, 0x03, 0x04, - 0x10, 0x00, 0x8f, 0x0b, 0x00, 0x00, 0x11, 0x00, - 0x08, 0x00, 0x53, 0x4b, 0x52, 0x00, 0x53, 0x00, - 0x54, 0x00, 0x3b, 0x55, 0x56, 0x00, 0x58, 0x5a, - 0x40, 0x5f, 0x5e, 0x00, 0x47, 0x52, 0x63, 0x65, - 0x43, 0x66, 0x00, 0x68, 0x00, 0x6a, 0x00, 0x6c, - 0x00, 0x6e, 0x00, 0x70, 0x00, 0x00, 0x41, 0x00, - 0x00, 0x00, 0x00, 0x1a, 0x00, 0x93, 0x00, 0x00, - 0x20, 0x36, 0x00, 0x28, 0x00, 0x24, 0x00, 0x24, - 0x25, 0x2d, 0x00, 0x13, 0x6d, 0x6f, 0x00, 0x29, - 0x27, 0x2a, 0x14, 0x16, 0x18, 0x1b, 0x1c, 0x41, - 0x1e, 0x42, 0x1f, 0x4e, 0x3c, 0x40, 0x22, 0x21, - 0x44, 0x21, 0x43, 0x26, 0x28, 0x27, 0x29, 0x23, - 0x2b, 0x4b, 0x2d, 0x46, 0x2f, 0x4c, 0x31, 0x4d, - 0x33, 0x47, 0x45, 0x99, 0x00, 0x00, 0x97, 0x91, - 0x7f, 0x80, 0x85, 0x86, 0x12, 0x82, 0x84, 0x78, - 0x79, 0x12, 0x7d, 0xa3, 0x7e, 0x7a, 0x7b, 0x8c, - 0x92, 0x98, 0xa6, 0xa0, 0x87, 0x00, 0x9a, 0xa1, - 0x95, 0x77, 0x33, 0x95, 0x00, 0x90, 0x00, 0x76, - 0x9b, 0x9a, 0x99, 0x98, 0x00, 0x00, 0xa0, 0x00, - 0x9e, 0x00, 0xa3, 0xa2, 0x15, 0x31, 0x32, 0x33, - 0xb7, 0xb8, 0x55, 0xac, 0xab, 0x12, 0x14, 0x1e, - 0x21, 0x22, 0x22, 0x2a, 0x34, 0x35, 0x00, 0xa8, - 0xa9, 0x39, 0x22, 0x4c, 0x00, 0x00, 0x97, 0x01, - 0x5a, 0xda, 0x1d, 0x36, 0x05, 0x00, 0xc7, 0xc6, - 0xc9, 0xc8, 0xcb, 0xca, 0xcd, 0xcc, 0xcf, 0xce, - 0xc4, 0xd8, 0x45, 0xd9, 0x42, 0xda, 0x46, 0xdb, - 0xd1, 0xd3, 0xd5, 0xd7, 0xdd, 0xdc, 0xf1, 0xf9, - 0x01, 0x11, 0x0a, 0x12, 0x80, 0x9f, 0x00, 0x21, - 0x80, 0xa3, 0xf0, 0x00, 0xc0, 0x40, 0xc6, 0x60, - 0xea, 0xde, 0xe6, 0x99, 0xc0, 0x00, 0x00, 0x06, - 0x60, 0xdf, 0x29, 0x00, 0x15, 0x12, 0x06, 0x16, - 0xfb, 0xe0, 0x09, 0x15, 0x12, 0x84, 0x0b, 0xc6, - 0x16, 0x02, 0xe2, 0x06, 0xc0, 0x40, 0x00, 0x46, - 0x60, 0xe1, 0xe3, 0x6d, 0x37, 0x38, 0x39, 0x18, - 0x17, 0x1a, 0x19, 0x00, 0x1d, 0x1c, 0x1f, 0x1e, - 0x00, 0x61, 0xba, 0x67, 0x45, 0x48, 0x00, 0x50, - 0x64, 0x4f, 0x51, 0x00, 0x00, 0x49, 0x00, 0x00, - 0x00, 0xa5, 0xa6, 0xa7, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xb9, 0x00, 0x00, 0x5c, 0x00, 0x4a, 0x00, - 0x5d, 0x57, 0x59, 0x62, 0x60, 0x72, 0x6b, 0x71, - 0x54, 0x00, 0x3e, 0x69, 0xbb, 0x00, 0x5b, 0x00, - 0x00, 0x00, 0x25, 0x00, 0x48, 0xaa, 0x8a, 0x8b, - 0x8c, 0xab, 0xac, 0x58, 0x58, 0xaf, 0x94, 0xb0, - 0x6f, 0xb2, 0x63, 0x62, 0x65, 0x64, 0x67, 0x66, - 0x6c, 0x6d, 0x6e, 0x6f, 0x68, 0x69, 0x6a, 0x6b, - 0x71, 0x70, 0x73, 0x72, 0x75, 0x74, 0x77, 0x76, - 0x79, 0x78, -}; - -static const uint16_t case_conv_ext[58] = { - 0x0399, 0x0308, 0x0301, 0x03a5, 0x0313, 0x0300, 0x0342, 0x0391, - 0x0397, 0x03a9, 0x0046, 0x0049, 0x004c, 0x0053, 0x0069, 0x0307, - 0x02bc, 0x004e, 0x004a, 0x030c, 0x0535, 0x0552, 0x0048, 0x0331, - 0x0054, 0x0057, 0x030a, 0x0059, 0x0041, 0x02be, 0x1f08, 0x1f80, - 0x1f28, 0x1f90, 0x1f68, 0x1fa0, 0x1fba, 0x0386, 0x1fb3, 0x1fca, - 0x0389, 0x1fc3, 0x03a1, 0x1ffa, 0x038f, 0x1ff3, 0x0544, 0x0546, - 0x053b, 0x054e, 0x053d, 0x03b8, 0x0462, 0xa64a, 0x1e60, 0x03c9, - 0x006b, 0x00e5, -}; - -static const uint8_t unicode_prop_Cased1_table[193] = { - 0x40, 0xa9, 0x80, 0x8e, 0x80, 0xfc, 0x80, 0xd3, - 0x80, 0x9b, 0x81, 0x8d, 0x02, 0x80, 0xe1, 0x80, - 0x91, 0x85, 0x9a, 0x01, 0x00, 0x01, 0x11, 0x03, - 0x04, 0x08, 0x01, 0x08, 0x30, 0x08, 0x01, 0x15, - 0x20, 0x00, 0x39, 0x99, 0x31, 0x9d, 0x84, 0x40, - 0x94, 0x80, 0xd6, 0x82, 0xa6, 0x80, 0x41, 0x62, - 0x80, 0xa6, 0x80, 0x4b, 0x72, 0x80, 0x4c, 0x02, - 0xf8, 0x02, 0x80, 0x8f, 0x80, 0xb0, 0x40, 0xdb, - 0x08, 0x80, 0x41, 0xd0, 0x80, 0x8c, 0x80, 0x8f, - 0x8c, 0xe4, 0x03, 0x01, 0x89, 0x00, 0x14, 0x28, - 0x10, 0x11, 0x02, 0x01, 0x18, 0x0b, 0x24, 0x4b, - 0x26, 0x01, 0x01, 0x86, 0xe5, 0x80, 0x60, 0x79, - 0xb6, 0x81, 0x40, 0x91, 0x81, 0xbd, 0x88, 0x94, - 0x05, 0x80, 0x98, 0x80, 0xa2, 0x00, 0x80, 0x9b, - 0x12, 0x82, 0x43, 0x34, 0xa2, 0x06, 0x80, 0x8d, - 0x60, 0x5c, 0x15, 0x01, 0x10, 0xa9, 0x80, 0x88, - 0x60, 0xcc, 0x44, 0xd4, 0x80, 0xc6, 0x01, 0x08, - 0x09, 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, - 0x03, 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, - 0x16, 0x80, 0x41, 0x53, 0x81, 0x98, 0x80, 0x98, - 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, - 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, - 0x07, 0x47, 0x33, 0x89, 0x80, 0x93, 0x2d, 0x41, - 0x04, 0xbd, 0x50, 0xc1, 0x99, 0x85, 0x99, 0x85, - 0x99, -}; - -static const uint8_t unicode_prop_Cased1_index[18] = { - 0xb9, 0x02, 0x80, // 002B9 at 36 - 0xa0, 0x1e, 0x40, // 01EA0 at 66 - 0x9e, 0xa6, 0x40, // 0A69E at 98 - 0xbb, 0x07, 0x01, // 107BB at 128 - 0xdb, 0xd6, 0x01, // 1D6DB at 160 - 0x8a, 0xf1, 0x01, // 1F18A at 192 (upper bound) -}; - -static const uint8_t unicode_prop_Case_Ignorable_table[764] = { - 0xa6, 0x05, 0x80, 0x8a, 0x80, 0xa2, 0x00, 0x80, - 0xc6, 0x03, 0x00, 0x03, 0x01, 0x81, 0x41, 0xf6, - 0x40, 0xbf, 0x19, 0x18, 0x88, 0x08, 0x80, 0x40, - 0xfa, 0x86, 0x40, 0xce, 0x04, 0x80, 0xb0, 0xac, - 0x00, 0x01, 0x01, 0x00, 0xab, 0x80, 0x8a, 0x85, - 0x89, 0x8a, 0x00, 0xa2, 0x80, 0x89, 0x94, 0x8f, - 0x80, 0xe4, 0x38, 0x89, 0x03, 0xa0, 0x00, 0x80, - 0x9d, 0x9a, 0xda, 0x8a, 0xb9, 0x8a, 0x18, 0x08, - 0x97, 0x97, 0xaa, 0x82, 0xab, 0x06, 0x0c, 0x88, - 0xa8, 0xb9, 0xb6, 0x00, 0x03, 0x3b, 0x02, 0x86, - 0x89, 0x81, 0x8c, 0x80, 0x8e, 0x80, 0xb9, 0x03, - 0x1f, 0x80, 0x93, 0x81, 0x99, 0x01, 0x81, 0xb8, - 0x03, 0x0b, 0x09, 0x12, 0x80, 0x9d, 0x0a, 0x80, - 0x8a, 0x81, 0xb8, 0x03, 0x20, 0x0b, 0x80, 0x93, - 0x81, 0x95, 0x28, 0x80, 0xb9, 0x01, 0x00, 0x1f, - 0x06, 0x81, 0x8a, 0x81, 0x9d, 0x80, 0xbc, 0x80, - 0x8b, 0x80, 0xb1, 0x02, 0x80, 0xb6, 0x00, 0x14, - 0x10, 0x1e, 0x81, 0x8a, 0x81, 0x9c, 0x80, 0xb9, - 0x01, 0x05, 0x04, 0x81, 0x93, 0x81, 0x9b, 0x81, - 0xb8, 0x0b, 0x1f, 0x80, 0x93, 0x81, 0x9c, 0x80, - 0xc7, 0x06, 0x10, 0x80, 0xd9, 0x01, 0x86, 0x8a, - 0x88, 0xe1, 0x01, 0x88, 0x88, 0x00, 0x86, 0xc8, - 0x81, 0x9a, 0x00, 0x00, 0x80, 0xb6, 0x8d, 0x04, - 0x01, 0x84, 0x8a, 0x80, 0xa3, 0x88, 0x80, 0xe5, - 0x18, 0x28, 0x09, 0x81, 0x98, 0x0b, 0x82, 0x8f, - 0x83, 0x8c, 0x01, 0x0d, 0x80, 0x8e, 0x80, 0xdd, - 0x80, 0x42, 0x5f, 0x82, 0x43, 0xb1, 0x82, 0x9c, - 0x81, 0x9d, 0x81, 0x9d, 0x81, 0xbf, 0x08, 0x37, - 0x01, 0x8a, 0x10, 0x20, 0xac, 0x84, 0xb2, 0x80, - 0xc0, 0x81, 0xa1, 0x80, 0xf5, 0x13, 0x81, 0x88, - 0x05, 0x82, 0x40, 0xda, 0x09, 0x80, 0xb9, 0x00, - 0x30, 0x00, 0x01, 0x3d, 0x89, 0x08, 0xa6, 0x07, - 0x9e, 0xb0, 0x83, 0xaf, 0x00, 0x20, 0x04, 0x80, - 0xa7, 0x88, 0x8b, 0x81, 0x9f, 0x19, 0x08, 0x82, - 0xb7, 0x00, 0x0a, 0x00, 0x82, 0xb9, 0x39, 0x81, - 0xbf, 0x85, 0xd1, 0x10, 0x8c, 0x06, 0x18, 0x28, - 0x11, 0xb1, 0xbe, 0x8c, 0x80, 0xa1, 0xe4, 0x41, - 0xbc, 0x00, 0x82, 0x8a, 0x82, 0x8c, 0x82, 0x8c, - 0x82, 0x8c, 0x81, 0x8b, 0x27, 0x81, 0x89, 0x01, - 0x01, 0x84, 0xb0, 0x20, 0x89, 0x00, 0x8c, 0x80, - 0x8f, 0x8c, 0xb2, 0xa0, 0x4b, 0x8a, 0x81, 0xf0, - 0x82, 0xfc, 0x80, 0x8e, 0x80, 0xdf, 0x9f, 0xae, - 0x80, 0x41, 0xd4, 0x80, 0xa3, 0x1a, 0x24, 0x80, - 0xdc, 0x85, 0xdc, 0x82, 0x60, 0x6f, 0x15, 0x80, - 0x44, 0xe1, 0x85, 0x41, 0x0d, 0x80, 0xe1, 0x18, - 0x89, 0x00, 0x9b, 0x83, 0xcf, 0x81, 0x8d, 0xa1, - 0xcd, 0x80, 0x96, 0x82, 0xe6, 0x12, 0x0f, 0x02, - 0x03, 0x80, 0x98, 0x0c, 0x80, 0x40, 0x96, 0x81, - 0x99, 0x91, 0x8c, 0x80, 0xa5, 0x87, 0x98, 0x8a, - 0xad, 0x82, 0xaf, 0x01, 0x19, 0x81, 0x90, 0x80, - 0x94, 0x81, 0xc1, 0x29, 0x09, 0x81, 0x8b, 0x07, - 0x80, 0xa2, 0x80, 0x8a, 0x80, 0xb2, 0x00, 0x11, - 0x0c, 0x08, 0x80, 0x9a, 0x80, 0x8d, 0x0c, 0x08, - 0x80, 0xe3, 0x84, 0x88, 0x82, 0xf8, 0x01, 0x03, - 0x80, 0x60, 0x4f, 0x2f, 0x80, 0x40, 0x92, 0x90, - 0x42, 0x3c, 0x8f, 0x10, 0x8b, 0x8f, 0xa1, 0x01, - 0x80, 0x40, 0xa8, 0x06, 0x05, 0x80, 0x8a, 0x80, - 0xa2, 0x00, 0x80, 0xae, 0x80, 0xac, 0x81, 0xc2, - 0x80, 0x94, 0x82, 0x42, 0x00, 0x80, 0x40, 0xe1, - 0x80, 0x40, 0x94, 0x84, 0x44, 0x04, 0x28, 0xa9, - 0x80, 0x88, 0x42, 0x45, 0x10, 0x0c, 0x83, 0xa7, - 0x13, 0x80, 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x83, - 0xa5, 0x80, 0x99, 0x20, 0x80, 0x41, 0x3a, 0x81, - 0xce, 0x83, 0xc5, 0x8a, 0xb0, 0x83, 0xfa, 0x80, - 0xb5, 0x8e, 0xa8, 0x01, 0x81, 0x89, 0x82, 0xb0, - 0x19, 0x09, 0x03, 0x80, 0x89, 0x80, 0xb1, 0x82, - 0xa3, 0x20, 0x87, 0xbd, 0x80, 0x8b, 0x81, 0xb3, - 0x88, 0x89, 0x19, 0x80, 0xde, 0x11, 0x00, 0x0d, - 0x01, 0x80, 0x40, 0x9c, 0x02, 0x87, 0x94, 0x81, - 0xb8, 0x0a, 0x80, 0xa4, 0x32, 0x84, 0xc5, 0x85, - 0x8c, 0x00, 0x00, 0x80, 0x8d, 0x81, 0xd4, 0x39, - 0x10, 0x80, 0x96, 0x80, 0xd3, 0x28, 0x03, 0x08, - 0x81, 0x40, 0xed, 0x1d, 0x08, 0x81, 0x9a, 0x81, - 0xd4, 0x39, 0x00, 0x81, 0xe9, 0x00, 0x01, 0x28, - 0x80, 0xe4, 0x00, 0x01, 0x18, 0x84, 0x41, 0x02, - 0x88, 0x01, 0x40, 0xff, 0x08, 0x03, 0x80, 0x40, - 0x8f, 0x19, 0x0b, 0x80, 0x9f, 0x89, 0xa7, 0x29, - 0x1f, 0x80, 0x88, 0x29, 0x82, 0xad, 0x8c, 0x01, - 0x41, 0x95, 0x30, 0x28, 0x80, 0xd1, 0x95, 0x0e, - 0x01, 0x01, 0xf9, 0x2a, 0x00, 0x08, 0x30, 0x80, - 0xc7, 0x0a, 0x00, 0x80, 0x41, 0x5a, 0x81, 0x8a, - 0x81, 0xb3, 0x24, 0x00, 0x80, 0x96, 0x80, 0x54, - 0xd4, 0x90, 0x85, 0x8e, 0x60, 0x2c, 0xc7, 0x8b, - 0x12, 0x49, 0xbf, 0x84, 0xba, 0x86, 0x88, 0x83, - 0x41, 0xfb, 0x82, 0xa7, 0x81, 0x41, 0xe1, 0x80, - 0xbe, 0x90, 0xbf, 0x08, 0x81, 0x60, 0x40, 0x0a, - 0x18, 0x30, 0x81, 0x4c, 0x9d, 0x08, 0x83, 0x52, - 0x5b, 0xad, 0x81, 0x96, 0x42, 0x1f, 0x82, 0x88, - 0x8f, 0x0e, 0x9d, 0x83, 0x40, 0x93, 0x82, 0x47, - 0xba, 0xb6, 0x83, 0xb1, 0x38, 0x8d, 0x80, 0x95, - 0x20, 0x8e, 0x45, 0x4f, 0x30, 0x90, 0x0e, 0x01, - 0x04, 0x84, 0xbd, 0xa0, 0x80, 0x40, 0x9f, 0x8d, - 0x41, 0x6f, 0x80, 0xbc, 0x83, 0x41, 0xfa, 0x84, - 0x40, 0xfd, 0x81, 0x42, 0xdf, 0x86, 0xec, 0x87, - 0x4a, 0xae, 0x84, 0x6c, 0x0c, 0x00, 0x80, 0x9d, - 0xdf, 0xff, 0x40, 0xef, -}; - -static const uint8_t unicode_prop_Case_Ignorable_index[72] = { - 0xbe, 0x05, 0x00, // 005BE at 32 - 0xfe, 0x07, 0x00, // 007FE at 64 - 0x52, 0x0a, 0xa0, // 00A52 at 101 - 0xc1, 0x0b, 0x00, // 00BC1 at 128 - 0x82, 0x0d, 0x00, // 00D82 at 160 - 0x3f, 0x10, 0x80, // 0103F at 196 - 0xd4, 0x17, 0x40, // 017D4 at 226 - 0xcf, 0x1a, 0x20, // 01ACF at 257 - 0xf5, 0x1c, 0x00, // 01CF5 at 288 - 0x80, 0x20, 0x00, // 02080 at 320 - 0x16, 0xa0, 0x00, // 0A016 at 352 - 0xc6, 0xa8, 0x00, // 0A8C6 at 384 - 0xc2, 0xaa, 0x60, // 0AAC2 at 419 - 0x56, 0xfe, 0x20, // 0FE56 at 449 - 0xb1, 0x07, 0x01, // 107B1 at 480 - 0x02, 0x10, 0x01, // 11002 at 512 - 0x42, 0x12, 0x41, // 11242 at 546 - 0xc4, 0x14, 0x21, // 114C4 at 577 - 0xe1, 0x19, 0x81, // 119E1 at 612 - 0x48, 0x1d, 0x01, // 11D48 at 640 - 0x44, 0x6b, 0x01, // 16B44 at 672 - 0x83, 0xd1, 0x21, // 1D183 at 705 - 0x3e, 0xe1, 0x01, // 1E13E at 736 - 0xf0, 0x01, 0x0e, // E01F0 at 768 (upper bound) -}; - -static const uint8_t unicode_prop_ID_Start_table[1133] = { - 0xc0, 0x99, 0x85, 0x99, 0xae, 0x80, 0x89, 0x03, - 0x04, 0x96, 0x80, 0x9e, 0x80, 0x41, 0xc9, 0x83, - 0x8b, 0x8d, 0x26, 0x00, 0x80, 0x40, 0x80, 0x20, - 0x09, 0x18, 0x05, 0x00, 0x10, 0x00, 0x93, 0x80, - 0xd2, 0x80, 0x40, 0x8a, 0x87, 0x40, 0xa5, 0x80, - 0xa5, 0x08, 0x85, 0xa8, 0xc6, 0x9a, 0x1b, 0xac, - 0xaa, 0xa2, 0x08, 0xe2, 0x00, 0x8e, 0x0e, 0x81, - 0x89, 0x11, 0x80, 0x8f, 0x00, 0x9d, 0x9c, 0xd8, - 0x8a, 0x80, 0x97, 0xa0, 0x88, 0x0b, 0x04, 0x95, - 0x18, 0x88, 0x02, 0x80, 0x96, 0x98, 0x86, 0x8a, - 0x84, 0x97, 0x05, 0x90, 0xa9, 0xb9, 0xb5, 0x10, - 0x91, 0x06, 0x89, 0x8e, 0x8f, 0x1f, 0x09, 0x81, - 0x95, 0x06, 0x00, 0x13, 0x10, 0x8f, 0x80, 0x8c, - 0x08, 0x82, 0x8d, 0x81, 0x89, 0x07, 0x2b, 0x09, - 0x95, 0x06, 0x01, 0x01, 0x01, 0x9e, 0x18, 0x80, - 0x92, 0x82, 0x8f, 0x88, 0x02, 0x80, 0x95, 0x06, - 0x01, 0x04, 0x10, 0x91, 0x80, 0x8e, 0x81, 0x96, - 0x80, 0x8a, 0x39, 0x09, 0x95, 0x06, 0x01, 0x04, - 0x10, 0x9d, 0x08, 0x82, 0x8e, 0x80, 0x90, 0x00, - 0x2a, 0x10, 0x1a, 0x08, 0x00, 0x0a, 0x0a, 0x12, - 0x8b, 0x95, 0x80, 0xb3, 0x38, 0x10, 0x96, 0x80, - 0x8f, 0x10, 0x99, 0x11, 0x01, 0x81, 0x9d, 0x03, - 0x38, 0x10, 0x96, 0x80, 0x89, 0x04, 0x10, 0x9e, - 0x08, 0x81, 0x8e, 0x81, 0x90, 0x88, 0x02, 0x80, - 0xa8, 0x08, 0x8f, 0x04, 0x17, 0x82, 0x97, 0x2c, - 0x91, 0x82, 0x97, 0x80, 0x88, 0x00, 0x0e, 0xb9, - 0xaf, 0x01, 0x8b, 0x86, 0xb9, 0x08, 0x00, 0x20, - 0x97, 0x00, 0x80, 0x89, 0x01, 0x88, 0x01, 0x20, - 0x80, 0x94, 0x83, 0x9f, 0x80, 0xbe, 0x38, 0xa3, - 0x9a, 0x84, 0xf2, 0xaa, 0x93, 0x80, 0x8f, 0x2b, - 0x1a, 0x02, 0x0e, 0x13, 0x8c, 0x8b, 0x80, 0x90, - 0xa5, 0x00, 0x20, 0x81, 0xaa, 0x80, 0x41, 0x4c, - 0x03, 0x0e, 0x00, 0x03, 0x81, 0xa8, 0x03, 0x81, - 0xa0, 0x03, 0x0e, 0x00, 0x03, 0x81, 0x8e, 0x80, - 0xb8, 0x03, 0x81, 0xc2, 0xa4, 0x8f, 0x8f, 0xd5, - 0x0d, 0x82, 0x42, 0x6b, 0x81, 0x90, 0x80, 0x99, - 0x84, 0xca, 0x82, 0x8a, 0x86, 0x91, 0x8c, 0x92, - 0x8d, 0x91, 0x8d, 0x8c, 0x02, 0x8e, 0xb3, 0xa2, - 0x03, 0x80, 0xc2, 0xd8, 0x86, 0xa8, 0x00, 0x84, - 0xc5, 0x89, 0x9e, 0xb0, 0x9d, 0x0c, 0x8a, 0xab, - 0x83, 0x99, 0xb5, 0x96, 0x88, 0xb4, 0xd1, 0x80, - 0xdc, 0xae, 0x90, 0x87, 0xb5, 0x9d, 0x8c, 0x81, - 0x89, 0xab, 0x99, 0xa3, 0xa8, 0x82, 0x89, 0xa3, - 0x81, 0x8a, 0x84, 0xaa, 0x0a, 0xa8, 0x18, 0x28, - 0x0a, 0x04, 0x40, 0xbf, 0xbf, 0x41, 0x15, 0x0d, - 0x81, 0xa5, 0x0d, 0x0f, 0x00, 0x00, 0x00, 0x80, - 0x9e, 0x81, 0xb4, 0x06, 0x00, 0x12, 0x06, 0x13, - 0x0d, 0x83, 0x8c, 0x22, 0x06, 0xf3, 0x80, 0x8c, - 0x80, 0x8f, 0x8c, 0xe4, 0x03, 0x01, 0x89, 0x00, - 0x0d, 0x28, 0x00, 0x00, 0x80, 0x8f, 0x0b, 0x24, - 0x18, 0x90, 0xa8, 0x4a, 0x76, 0x40, 0xe4, 0x2b, - 0x11, 0x8b, 0xa5, 0x00, 0x20, 0x81, 0xb7, 0x30, - 0x8f, 0x96, 0x88, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x86, 0x42, 0x25, 0x82, 0x98, 0x88, - 0x34, 0x0c, 0x83, 0xd5, 0x1c, 0x80, 0xd9, 0x03, - 0x84, 0xaa, 0x80, 0xdd, 0x90, 0x9f, 0xaf, 0x8f, - 0x41, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x56, 0x8c, - 0xc2, 0xad, 0x81, 0x41, 0x0c, 0x82, 0x8f, 0x89, - 0x81, 0x93, 0xae, 0x8f, 0x9e, 0x81, 0xcf, 0xa6, - 0x88, 0x81, 0xe6, 0x81, 0xc2, 0x09, 0x00, 0x07, - 0x94, 0x8f, 0x02, 0x03, 0x80, 0x96, 0x9c, 0xb3, - 0x8d, 0xb1, 0xbd, 0x2a, 0x00, 0x81, 0x8a, 0x9b, - 0x89, 0x96, 0x98, 0x9c, 0x86, 0xae, 0x9b, 0x80, - 0x8f, 0x20, 0x89, 0x89, 0x20, 0xa8, 0x96, 0x10, - 0x87, 0x93, 0x96, 0x10, 0x82, 0xb1, 0x00, 0x11, - 0x0c, 0x08, 0x00, 0x97, 0x11, 0x8a, 0x32, 0x8b, - 0x29, 0x29, 0x85, 0x88, 0x30, 0x30, 0xaa, 0x80, - 0x8d, 0x85, 0xf2, 0x9c, 0x60, 0x2b, 0xa3, 0x8b, - 0x96, 0x83, 0xb0, 0x60, 0x21, 0x03, 0x41, 0x6d, - 0x81, 0xe9, 0xa5, 0x86, 0x8b, 0x24, 0x00, 0x89, - 0x80, 0x8c, 0x04, 0x00, 0x01, 0x01, 0x80, 0xeb, - 0xa0, 0x41, 0x6a, 0x91, 0xbf, 0x81, 0xb5, 0xa7, - 0x8b, 0xf3, 0x20, 0x40, 0x86, 0xa3, 0x99, 0x85, - 0x99, 0x8a, 0xd8, 0x15, 0x0d, 0x0d, 0x0a, 0xa2, - 0x8b, 0x80, 0x99, 0x80, 0x92, 0x01, 0x80, 0x8e, - 0x81, 0x8d, 0xa1, 0xfa, 0xc4, 0xb4, 0x41, 0x0a, - 0x9c, 0x82, 0xb0, 0xae, 0x9f, 0x8c, 0x9d, 0x84, - 0xa5, 0x89, 0x9d, 0x81, 0xa3, 0x1f, 0x04, 0xa9, - 0x40, 0x9d, 0x91, 0xa3, 0x83, 0xa3, 0x83, 0xa7, - 0x87, 0xb3, 0x8b, 0x8a, 0x80, 0x8e, 0x06, 0x01, - 0x80, 0x8a, 0x80, 0x8e, 0x06, 0x01, 0x82, 0xb3, - 0x8b, 0x41, 0x36, 0x88, 0x95, 0x89, 0x87, 0x97, - 0x28, 0xa9, 0x80, 0x88, 0xc4, 0x29, 0x00, 0xab, - 0x01, 0x10, 0x81, 0x96, 0x89, 0x96, 0x88, 0x9e, - 0xc0, 0x92, 0x01, 0x89, 0x95, 0x89, 0x99, 0xc5, - 0xb7, 0x29, 0xbf, 0x80, 0x8e, 0x18, 0x10, 0x9c, - 0xa9, 0x9c, 0x82, 0x9c, 0xa2, 0x38, 0x9b, 0x9a, - 0xb5, 0x89, 0x95, 0x89, 0x92, 0x8c, 0x91, 0xed, - 0xc8, 0xb6, 0xb2, 0x8c, 0xb2, 0x8c, 0xa3, 0xa5, - 0x9b, 0x88, 0x96, 0x40, 0xf9, 0xa9, 0x29, 0x8f, - 0x82, 0xba, 0x9c, 0x89, 0x07, 0x95, 0xa9, 0x91, - 0xad, 0x94, 0x9a, 0x96, 0x8b, 0xb4, 0xb8, 0x09, - 0x80, 0x8c, 0xac, 0x9f, 0x98, 0x99, 0xa3, 0x9c, - 0x01, 0x07, 0xa2, 0x10, 0x8b, 0xaf, 0x8d, 0x83, - 0x94, 0x00, 0x80, 0xa2, 0x91, 0x80, 0x98, 0x92, - 0x81, 0xbe, 0x30, 0x00, 0x18, 0x8e, 0x80, 0x89, - 0x86, 0xae, 0xa5, 0x39, 0x09, 0x95, 0x06, 0x01, - 0x04, 0x10, 0x91, 0x80, 0x8b, 0x84, 0x9d, 0x89, - 0x00, 0x08, 0x80, 0xa5, 0x00, 0x98, 0x00, 0x80, - 0xab, 0xb4, 0x91, 0x83, 0x93, 0x82, 0x9d, 0xaf, - 0x93, 0x08, 0x80, 0x40, 0xb7, 0xae, 0xa8, 0x83, - 0xa3, 0xaf, 0x93, 0x80, 0xba, 0xaa, 0x8c, 0x80, - 0xc6, 0x9a, 0xa4, 0x86, 0x40, 0xb8, 0xab, 0xf3, - 0xbf, 0x9e, 0x39, 0x01, 0x38, 0x08, 0x97, 0x8e, - 0x00, 0x80, 0xdd, 0x39, 0xa6, 0x8f, 0x00, 0x80, - 0x9b, 0x80, 0x89, 0xa7, 0x30, 0x94, 0x80, 0x8a, - 0xad, 0x92, 0x80, 0x91, 0xc8, 0x40, 0xc6, 0xa0, - 0x9e, 0x88, 0x80, 0xa4, 0x90, 0x80, 0xb0, 0x9d, - 0xef, 0x30, 0x08, 0xa5, 0x94, 0x80, 0x98, 0x28, - 0x08, 0x9f, 0x8d, 0x80, 0x41, 0x46, 0x92, 0x8e, - 0x00, 0x8c, 0x80, 0xa1, 0xfb, 0x80, 0xce, 0x43, - 0x99, 0xe5, 0xee, 0x90, 0x40, 0xc3, 0x4a, 0x4b, - 0xe0, 0x8e, 0x44, 0x2f, 0x90, 0x85, 0x98, 0x4f, - 0x9a, 0x84, 0x42, 0x46, 0x5a, 0xb8, 0x9d, 0x46, - 0xe1, 0x42, 0x38, 0x86, 0x9e, 0x90, 0xce, 0x90, - 0x9d, 0x91, 0xaf, 0x8f, 0x83, 0x9e, 0x94, 0x84, - 0x92, 0x41, 0xaf, 0xac, 0x40, 0xd2, 0xbf, 0xff, - 0xca, 0x20, 0xc1, 0x8c, 0xbf, 0x08, 0x80, 0x9b, - 0x57, 0xf7, 0x87, 0x44, 0xd5, 0xa8, 0x89, 0x60, - 0x22, 0xe6, 0x18, 0x30, 0x08, 0x41, 0x22, 0x8e, - 0x80, 0x9c, 0x11, 0x80, 0x8d, 0x1f, 0x41, 0x8b, - 0x49, 0x03, 0xea, 0x84, 0x8c, 0x82, 0x88, 0x86, - 0x89, 0x57, 0x65, 0xd4, 0x80, 0xc6, 0x01, 0x08, - 0x09, 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, - 0x03, 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, - 0x16, 0x80, 0x41, 0x53, 0x81, 0x98, 0x80, 0x98, - 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, - 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, - 0x07, 0x47, 0x33, 0x9e, 0x2d, 0x41, 0x04, 0xbd, - 0x40, 0x91, 0xac, 0x89, 0x86, 0x8f, 0x80, 0x41, - 0x40, 0x9d, 0x91, 0xab, 0x41, 0xe3, 0x9b, 0x40, - 0xe3, 0x9d, 0x08, 0x41, 0xee, 0x30, 0x18, 0x08, - 0x8e, 0x80, 0x40, 0xc4, 0xba, 0xc3, 0x30, 0x44, - 0xb3, 0x18, 0x9a, 0x01, 0x00, 0x08, 0x80, 0x89, - 0x03, 0x00, 0x00, 0x28, 0x18, 0x00, 0x00, 0x02, - 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00, 0x80, 0x89, - 0x80, 0x90, 0x22, 0x04, 0x80, 0x90, 0x51, 0x43, - 0x60, 0xa6, 0xdf, 0x9f, 0x50, 0x39, 0x85, 0x40, - 0xdd, 0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x8e, - 0x42, 0x6d, 0x49, 0xa1, 0x42, 0x1d, 0x45, 0xe1, - 0x53, 0x4a, 0x84, 0x50, 0x5f, -}; - -static const uint8_t unicode_prop_ID_Start_index[108] = { - 0xf6, 0x03, 0x20, // 003F6 at 33 - 0xa6, 0x07, 0x00, // 007A6 at 64 - 0xa9, 0x09, 0x20, // 009A9 at 97 - 0xb1, 0x0a, 0x00, // 00AB1 at 128 - 0xba, 0x0b, 0x20, // 00BBA at 161 - 0x3b, 0x0d, 0x20, // 00D3B at 193 - 0xc7, 0x0e, 0x20, // 00EC7 at 225 - 0x49, 0x12, 0x00, // 01249 at 256 - 0x9b, 0x16, 0x00, // 0169B at 288 - 0xac, 0x19, 0x00, // 019AC at 320 - 0xc0, 0x1d, 0x80, // 01DC0 at 356 - 0x80, 0x20, 0x20, // 02080 at 385 - 0x70, 0x2d, 0x00, // 02D70 at 416 - 0x00, 0x32, 0x00, // 03200 at 448 - 0xdd, 0xa7, 0x00, // 0A7DD at 480 - 0x4c, 0xaa, 0x20, // 0AA4C at 513 - 0xc7, 0xd7, 0x20, // 0D7C7 at 545 - 0xfc, 0xfd, 0x20, // 0FDFC at 577 - 0x9d, 0x02, 0x21, // 1029D at 609 - 0x96, 0x05, 0x01, // 10596 at 640 - 0x9f, 0x08, 0x01, // 1089F at 672 - 0x49, 0x0c, 0x21, // 10C49 at 705 - 0x76, 0x10, 0x21, // 11076 at 737 - 0xa9, 0x12, 0x01, // 112A9 at 768 - 0xb0, 0x14, 0x01, // 114B0 at 800 - 0x42, 0x19, 0x41, // 11942 at 834 - 0x90, 0x1c, 0x01, // 11C90 at 864 - 0xf1, 0x2f, 0x21, // 12FF1 at 897 - 0x90, 0x6b, 0x21, // 16B90 at 929 - 0x33, 0xb1, 0x21, // 1B133 at 961 - 0x06, 0xd5, 0x01, // 1D506 at 992 - 0xc3, 0xd7, 0x01, // 1D7C3 at 1024 - 0xff, 0xe7, 0x21, // 1E7FF at 1057 - 0x63, 0xee, 0x01, // 1EE63 at 1088 - 0x5e, 0xee, 0x42, // 2EE5E at 1122 - 0xb0, 0x23, 0x03, // 323B0 at 1152 (upper bound) -}; - -static const uint8_t unicode_prop_ID_Continue1_table[695] = { - 0xaf, 0x89, 0xa4, 0x80, 0xd6, 0x80, 0x42, 0x47, - 0xef, 0x96, 0x80, 0x40, 0xfa, 0x84, 0x41, 0x08, - 0xac, 0x00, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xaf, - 0x9e, 0x28, 0xe4, 0x31, 0x29, 0x08, 0x19, 0x89, - 0x96, 0x80, 0x9d, 0x9a, 0xda, 0x8a, 0x8e, 0x89, - 0xa0, 0x88, 0x88, 0x80, 0x97, 0x18, 0x88, 0x02, - 0x04, 0xaa, 0x82, 0xba, 0x88, 0xa9, 0x97, 0x80, - 0xa0, 0xb5, 0x10, 0x91, 0x06, 0x89, 0x09, 0x89, - 0x90, 0x82, 0xb7, 0x00, 0x31, 0x09, 0x82, 0x88, - 0x80, 0x89, 0x09, 0x89, 0x8d, 0x01, 0x82, 0xb7, - 0x00, 0x23, 0x09, 0x12, 0x80, 0x93, 0x8b, 0x10, - 0x8a, 0x82, 0xb7, 0x00, 0x38, 0x10, 0x82, 0x93, - 0x09, 0x89, 0x89, 0x28, 0x82, 0xb7, 0x00, 0x31, - 0x09, 0x16, 0x82, 0x89, 0x09, 0x89, 0x91, 0x80, - 0xba, 0x22, 0x10, 0x83, 0x88, 0x80, 0x8d, 0x89, - 0x8f, 0x84, 0xb6, 0x00, 0x30, 0x10, 0x1e, 0x81, - 0x8a, 0x09, 0x89, 0x90, 0x82, 0xb7, 0x00, 0x30, - 0x10, 0x1e, 0x81, 0x8a, 0x09, 0x89, 0x10, 0x8b, - 0x83, 0xb6, 0x08, 0x30, 0x10, 0x83, 0x88, 0x80, - 0x89, 0x09, 0x89, 0x90, 0x82, 0xc5, 0x03, 0x28, - 0x00, 0x3d, 0x89, 0x09, 0xbc, 0x01, 0x86, 0x8b, - 0x38, 0x89, 0xd6, 0x01, 0x88, 0x8a, 0x30, 0x89, - 0xbd, 0x0d, 0x89, 0x8a, 0x00, 0x00, 0x03, 0x81, - 0xb0, 0x93, 0x01, 0x84, 0x8a, 0x80, 0xa3, 0x88, - 0x80, 0xe3, 0x93, 0x80, 0x89, 0x8b, 0x1b, 0x10, - 0x11, 0x32, 0x83, 0x8c, 0x8b, 0x80, 0x8e, 0x42, - 0xbe, 0x82, 0x88, 0x88, 0x43, 0x9f, 0x83, 0x9b, - 0x82, 0x9c, 0x81, 0x9d, 0x81, 0xbf, 0x9f, 0x88, - 0x01, 0x89, 0xa0, 0x10, 0x8a, 0x40, 0x8e, 0x80, - 0xf5, 0x8b, 0x83, 0x8b, 0x89, 0x89, 0xff, 0x8a, - 0xbb, 0x84, 0xb8, 0x89, 0x80, 0x9c, 0x81, 0x8a, - 0x85, 0x89, 0x95, 0x8d, 0x80, 0x8f, 0xb0, 0x84, - 0xae, 0x90, 0x8a, 0x89, 0x90, 0x88, 0x8b, 0x82, - 0x9d, 0x8c, 0x81, 0x89, 0xab, 0x8d, 0xaf, 0x93, - 0x87, 0x89, 0x85, 0x89, 0xf5, 0x10, 0x94, 0x18, - 0x28, 0x0a, 0x40, 0xc5, 0xbf, 0x42, 0x0b, 0x81, - 0xb0, 0x81, 0x92, 0x80, 0xfa, 0x8c, 0x18, 0x82, - 0x8b, 0x4b, 0xfd, 0x82, 0x40, 0x8c, 0x80, 0xdf, - 0x9f, 0x42, 0x29, 0x85, 0xe8, 0x81, 0xdf, 0x80, - 0x60, 0x75, 0x23, 0x89, 0xc4, 0x03, 0x89, 0x9f, - 0x81, 0xcf, 0x81, 0x41, 0x0f, 0x02, 0x03, 0x80, - 0x96, 0x23, 0x80, 0xd2, 0x81, 0xb1, 0x91, 0x89, - 0x89, 0x85, 0x91, 0x8c, 0x8a, 0x9b, 0x87, 0x98, - 0x8c, 0xab, 0x83, 0xae, 0x8d, 0x8e, 0x89, 0x8a, - 0x80, 0x89, 0x89, 0xae, 0x8d, 0x8b, 0x07, 0x09, - 0x89, 0xa0, 0x82, 0xb1, 0x00, 0x11, 0x0c, 0x08, - 0x80, 0xa8, 0x24, 0x81, 0x40, 0xeb, 0x38, 0x09, - 0x89, 0x60, 0x4f, 0x23, 0x80, 0x42, 0xe0, 0x8f, - 0x8f, 0x8f, 0x11, 0x97, 0x82, 0x40, 0xbf, 0x89, - 0xa4, 0x80, 0xa4, 0x80, 0x42, 0x96, 0x80, 0x40, - 0xe1, 0x80, 0x40, 0x94, 0x84, 0x41, 0x24, 0x89, - 0x45, 0x56, 0x10, 0x0c, 0x83, 0xa7, 0x13, 0x80, - 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x1f, 0x89, 0x85, - 0x89, 0x9e, 0x84, 0x41, 0x3c, 0x81, 0xce, 0x83, - 0xc5, 0x8a, 0xb0, 0x83, 0xf9, 0x82, 0xb4, 0x8e, - 0x9e, 0x8a, 0x09, 0x89, 0x83, 0xac, 0x8a, 0x30, - 0xac, 0x89, 0x2a, 0xa3, 0x8d, 0x80, 0x89, 0x21, - 0xab, 0x80, 0x8b, 0x82, 0xaf, 0x8d, 0x3b, 0x80, - 0x8b, 0xd1, 0x8b, 0x28, 0x08, 0x40, 0x9c, 0x8b, - 0x84, 0x89, 0x2b, 0xb6, 0x08, 0x31, 0x09, 0x82, - 0x88, 0x80, 0x89, 0x09, 0x32, 0x84, 0xc2, 0x88, - 0x00, 0x08, 0x03, 0x04, 0x00, 0x8d, 0x81, 0xd1, - 0x91, 0x88, 0x89, 0x18, 0xd0, 0x93, 0x8b, 0x89, - 0x40, 0xd4, 0x31, 0x88, 0x9a, 0x81, 0xd1, 0x90, - 0x8e, 0x89, 0xd0, 0x8c, 0x87, 0x89, 0x85, 0x93, - 0xb8, 0x8e, 0x83, 0x89, 0x40, 0xf1, 0x8e, 0x40, - 0xa4, 0x89, 0xc5, 0x28, 0x09, 0x18, 0x00, 0x81, - 0x8b, 0x89, 0xf6, 0x31, 0x32, 0x80, 0x9b, 0x89, - 0xa7, 0x30, 0x1f, 0x80, 0x88, 0x8a, 0xad, 0x8f, - 0x41, 0x55, 0x89, 0xb4, 0x38, 0x87, 0x8f, 0x89, - 0xb7, 0x95, 0x80, 0x8d, 0xf9, 0x2a, 0x00, 0x08, - 0x30, 0x07, 0x89, 0xaf, 0x20, 0x08, 0x27, 0x89, - 0x41, 0x48, 0x83, 0x88, 0x08, 0x80, 0xaf, 0x32, - 0x84, 0x8c, 0x8a, 0x54, 0xe4, 0x05, 0x8e, 0x60, - 0x2c, 0xc7, 0x9b, 0x49, 0x25, 0x89, 0xd5, 0x89, - 0xa5, 0x84, 0xba, 0x86, 0x98, 0x89, 0x42, 0x15, - 0x89, 0x41, 0xd4, 0x00, 0xb6, 0x33, 0xd0, 0x80, - 0x8a, 0x81, 0x60, 0x4c, 0xaa, 0x81, 0x50, 0x50, - 0x89, 0x42, 0x05, 0xad, 0x81, 0x96, 0x42, 0x1d, - 0x22, 0x2f, 0x39, 0x86, 0x9d, 0x83, 0x40, 0x93, - 0x82, 0x45, 0x88, 0xb1, 0x41, 0xff, 0xb6, 0x83, - 0xb1, 0x38, 0x8d, 0x80, 0x95, 0x20, 0x8e, 0x45, - 0x4f, 0x30, 0x90, 0x0e, 0x01, 0x04, 0xe3, 0x80, - 0x40, 0x9f, 0x86, 0x88, 0x89, 0x41, 0x63, 0x80, - 0xbc, 0x8d, 0x41, 0xf1, 0x8d, 0x40, 0xf3, 0x08, - 0x89, 0x42, 0xd4, 0x86, 0xec, 0x34, 0x89, 0x52, - 0x95, 0x89, 0x6c, 0x05, 0x05, 0x40, 0xef, -}; - -static const uint8_t unicode_prop_ID_Continue1_index[66] = { - 0xfa, 0x06, 0x00, // 006FA at 32 - 0x70, 0x09, 0x00, // 00970 at 64 - 0xf0, 0x0a, 0x40, // 00AF0 at 98 - 0x57, 0x0c, 0x00, // 00C57 at 128 - 0xf0, 0x0d, 0x60, // 00DF0 at 163 - 0xc7, 0x0f, 0x20, // 00FC7 at 193 - 0xea, 0x17, 0x40, // 017EA at 226 - 0x05, 0x1b, 0x00, // 01B05 at 256 - 0x0e, 0x20, 0x00, // 0200E at 288 - 0xa0, 0xa6, 0x20, // 0A6A0 at 321 - 0xe6, 0xa9, 0x20, // 0A9E6 at 353 - 0x10, 0xfe, 0x00, // 0FE10 at 384 - 0x40, 0x0a, 0x01, // 10A40 at 416 - 0xc3, 0x10, 0x01, // 110C3 at 448 - 0x4e, 0x13, 0x01, // 1134E at 480 - 0x41, 0x16, 0x01, // 11641 at 512 - 0x0b, 0x1a, 0x01, // 11A0B at 544 - 0xaa, 0x1d, 0x01, // 11DAA at 576 - 0x7a, 0x6d, 0x21, // 16D7A at 609 - 0x45, 0xd2, 0x21, // 1D245 at 641 - 0xaf, 0xe2, 0x01, // 1E2AF at 672 - 0xf0, 0x01, 0x0e, // E01F0 at 704 (upper bound) -}; - -#ifdef CONFIG_ALL_UNICODE - -static const uint8_t unicode_cc_table[916] = { - 0xb2, 0xcf, 0xd4, 0x00, 0xe8, 0x03, 0xdc, 0x00, - 0xe8, 0x00, 0xd8, 0x04, 0xdc, 0x01, 0xca, 0x03, - 0xdc, 0x01, 0xca, 0x0a, 0xdc, 0x04, 0x01, 0x03, - 0xdc, 0xc7, 0x00, 0xf0, 0xc0, 0x02, 0xdc, 0xc2, - 0x01, 0xdc, 0x80, 0xc2, 0x03, 0xdc, 0xc0, 0x00, - 0xe8, 0x01, 0xdc, 0xc0, 0x41, 0xe9, 0x00, 0xea, - 0x41, 0xe9, 0x00, 0xea, 0x00, 0xe9, 0xcc, 0xb0, - 0xe2, 0xc4, 0xb0, 0xd8, 0x00, 0xdc, 0xc3, 0x00, - 0xdc, 0xc2, 0x00, 0xde, 0x00, 0xdc, 0xc5, 0x05, - 0xdc, 0xc1, 0x00, 0xdc, 0xc1, 0x00, 0xde, 0x00, - 0xe4, 0xc0, 0x49, 0x0a, 0x43, 0x13, 0x80, 0x00, - 0x17, 0x80, 0x41, 0x18, 0x80, 0xc0, 0x00, 0xdc, - 0x80, 0x00, 0x12, 0xb0, 0x17, 0xc7, 0x42, 0x1e, - 0xaf, 0x47, 0x1b, 0xc1, 0x01, 0xdc, 0xc4, 0x00, - 0xdc, 0xc1, 0x00, 0xdc, 0x8f, 0x00, 0x23, 0xb0, - 0x34, 0xc6, 0x81, 0xc3, 0x00, 0xdc, 0xc0, 0x81, - 0xc1, 0x80, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xa2, - 0x00, 0x24, 0x9d, 0xc0, 0x00, 0xdc, 0xc1, 0x00, - 0xdc, 0xc1, 0x02, 0xdc, 0xc0, 0x01, 0xdc, 0xc0, - 0x00, 0xdc, 0xc2, 0x00, 0xdc, 0xc0, 0x00, 0xdc, - 0xc0, 0x00, 0xdc, 0xc0, 0x00, 0xdc, 0xc1, 0xb0, - 0x6f, 0xc6, 0x00, 0xdc, 0xc0, 0x88, 0x00, 0xdc, - 0x97, 0xc3, 0x80, 0xc8, 0x80, 0xc2, 0x80, 0xc4, - 0xaa, 0x02, 0xdc, 0xb0, 0x0a, 0xc1, 0x02, 0xdc, - 0xc3, 0xa9, 0xc4, 0x04, 0xdc, 0xcd, 0x80, 0x00, - 0xdc, 0xc1, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xc2, - 0x02, 0xdc, 0x42, 0x1b, 0xc2, 0x00, 0xdc, 0xc1, - 0x01, 0xdc, 0xc4, 0xb0, 0x0b, 0x00, 0x07, 0x8f, - 0x00, 0x09, 0x82, 0xc0, 0x00, 0xdc, 0xc1, 0xb0, - 0x36, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xaf, 0xc0, - 0xb0, 0x0c, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0, - 0x3d, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0, 0x3d, - 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0, 0x4e, 0x00, - 0x09, 0xb0, 0x3d, 0x00, 0x07, 0x8f, 0x00, 0x09, - 0x86, 0x00, 0x54, 0x00, 0x5b, 0xb0, 0x34, 0x00, - 0x07, 0x8f, 0x00, 0x09, 0xb0, 0x3c, 0x01, 0x09, - 0x8f, 0x00, 0x09, 0xb0, 0x4b, 0x00, 0x09, 0xb0, - 0x3c, 0x01, 0x67, 0x00, 0x09, 0x8c, 0x03, 0x6b, - 0xb0, 0x3b, 0x01, 0x76, 0x00, 0x09, 0x8c, 0x03, - 0x7a, 0xb0, 0x1b, 0x01, 0xdc, 0x9a, 0x00, 0xdc, - 0x80, 0x00, 0xdc, 0x80, 0x00, 0xd8, 0xb0, 0x06, - 0x41, 0x81, 0x80, 0x00, 0x84, 0x84, 0x03, 0x82, - 0x81, 0x00, 0x82, 0x80, 0xc1, 0x00, 0x09, 0x80, - 0xc1, 0xb0, 0x0d, 0x00, 0xdc, 0xb0, 0x3f, 0x00, - 0x07, 0x80, 0x01, 0x09, 0xb0, 0x21, 0x00, 0xdc, - 0xb2, 0x9e, 0xc2, 0xb3, 0x83, 0x01, 0x09, 0x9d, - 0x00, 0x09, 0xb0, 0x6c, 0x00, 0x09, 0x89, 0xc0, - 0xb0, 0x9a, 0x00, 0xe4, 0xb0, 0x5e, 0x00, 0xde, - 0xc0, 0x00, 0xdc, 0xb0, 0xaa, 0xc0, 0x00, 0xdc, - 0xb0, 0x16, 0x00, 0x09, 0x93, 0xc7, 0x81, 0x00, - 0xdc, 0xaf, 0xc4, 0x05, 0xdc, 0xc1, 0x00, 0xdc, - 0x80, 0x01, 0xdc, 0xc1, 0x01, 0xdc, 0xc4, 0x00, - 0xdc, 0xc3, 0xb0, 0x34, 0x00, 0x07, 0x8e, 0x00, - 0x09, 0xa5, 0xc0, 0x00, 0xdc, 0xc6, 0xb0, 0x05, - 0x01, 0x09, 0xb0, 0x09, 0x00, 0x07, 0x8a, 0x01, - 0x09, 0xb0, 0x12, 0x00, 0x07, 0xb0, 0x67, 0xc2, - 0x41, 0x00, 0x04, 0xdc, 0xc1, 0x03, 0xdc, 0xc0, - 0x41, 0x00, 0x05, 0x01, 0x83, 0x00, 0xdc, 0x85, - 0xc0, 0x82, 0xc1, 0xb0, 0x95, 0xc1, 0x00, 0xdc, - 0xc6, 0x00, 0xdc, 0xc1, 0x00, 0xea, 0x00, 0xd6, - 0x00, 0xdc, 0x00, 0xca, 0xe4, 0x00, 0xe8, 0x01, - 0xe4, 0x00, 0xdc, 0x00, 0xda, 0xc0, 0x00, 0xe9, - 0x00, 0xdc, 0xc0, 0x00, 0xdc, 0xb2, 0x9f, 0xc1, - 0x01, 0x01, 0xc3, 0x02, 0x01, 0xc1, 0x83, 0xc0, - 0x82, 0x01, 0x01, 0xc0, 0x00, 0xdc, 0xc0, 0x01, - 0x01, 0x03, 0xdc, 0xc0, 0xb8, 0x03, 0xcd, 0xc2, - 0xb0, 0x5c, 0x00, 0x09, 0xb0, 0x2f, 0xdf, 0xb1, - 0xf9, 0x00, 0xda, 0x00, 0xe4, 0x00, 0xe8, 0x00, - 0xde, 0x01, 0xe0, 0xb0, 0x38, 0x01, 0x08, 0xb8, - 0x6d, 0xa3, 0xc0, 0x83, 0xc9, 0x9f, 0xc1, 0xb0, - 0x1f, 0xc1, 0xb0, 0xe3, 0x00, 0x09, 0xa4, 0x00, - 0x09, 0xb0, 0x66, 0x00, 0x09, 0x9a, 0xd1, 0xb0, - 0x08, 0x02, 0xdc, 0xa4, 0x00, 0x09, 0xb0, 0x2e, - 0x00, 0x07, 0x8b, 0x00, 0x09, 0xb0, 0xbe, 0xc0, - 0x80, 0xc1, 0x00, 0xdc, 0x81, 0xc1, 0x84, 0xc1, - 0x80, 0xc0, 0xb0, 0x03, 0x00, 0x09, 0xb0, 0xc5, - 0x00, 0x09, 0xb8, 0x46, 0xff, 0x00, 0x1a, 0xb2, - 0xd0, 0xc6, 0x06, 0xdc, 0xc1, 0xb3, 0x9c, 0x00, - 0xdc, 0xb0, 0xb1, 0x00, 0xdc, 0xb0, 0x64, 0xc4, - 0xb6, 0x61, 0x00, 0xdc, 0x80, 0xc0, 0xa7, 0xc0, - 0x00, 0x01, 0x00, 0xdc, 0x83, 0x00, 0x09, 0xb0, - 0x74, 0xc0, 0x00, 0xdc, 0xb2, 0x0c, 0xc3, 0xb0, - 0x10, 0xc4, 0xb1, 0x0c, 0xc1, 0xb0, 0x1f, 0x02, - 0xdc, 0xb0, 0x15, 0x01, 0xdc, 0xc2, 0x00, 0xdc, - 0xc0, 0x03, 0xdc, 0xb0, 0x00, 0xc0, 0x00, 0xdc, - 0xc0, 0x00, 0xdc, 0xb0, 0x8f, 0x00, 0x09, 0xa8, - 0x00, 0x09, 0x8d, 0x00, 0x09, 0xb0, 0x08, 0x00, - 0x09, 0x00, 0x07, 0xb0, 0x14, 0xc2, 0xaf, 0x01, - 0x09, 0xb0, 0x0d, 0x00, 0x07, 0xb0, 0x1b, 0x00, - 0x09, 0x88, 0x00, 0x07, 0xb0, 0x39, 0x00, 0x09, - 0x00, 0x07, 0xb0, 0x81, 0x00, 0x07, 0x00, 0x09, - 0xb0, 0x1f, 0x01, 0x07, 0x8f, 0x00, 0x09, 0x97, - 0xc6, 0x82, 0xc4, 0xb0, 0x28, 0x02, 0x09, 0xb0, - 0x40, 0x00, 0x09, 0x82, 0x00, 0x07, 0x96, 0xc0, - 0xb0, 0x32, 0x00, 0x09, 0x00, 0x07, 0xb0, 0xca, - 0x00, 0x09, 0x00, 0x07, 0xb0, 0x4d, 0x00, 0x09, - 0xb0, 0x45, 0x00, 0x09, 0x00, 0x07, 0xb0, 0x42, - 0x00, 0x09, 0xb0, 0xdc, 0x00, 0x09, 0x00, 0x07, - 0xb0, 0xd1, 0x01, 0x09, 0x83, 0x00, 0x07, 0xb0, - 0x6b, 0x00, 0x09, 0xb0, 0x22, 0x00, 0x09, 0x91, - 0x00, 0x09, 0xb0, 0x20, 0x00, 0x09, 0xb1, 0x74, - 0x00, 0x09, 0xb0, 0xd1, 0x00, 0x07, 0x80, 0x01, - 0x09, 0xb0, 0x20, 0x00, 0x09, 0xb1, 0x78, 0x01, - 0x09, 0xb8, 0x39, 0xbb, 0x00, 0x09, 0xb8, 0x01, - 0x8f, 0x04, 0x01, 0xb0, 0x0a, 0xc6, 0xb4, 0x88, - 0x01, 0x06, 0xb8, 0x44, 0x7b, 0x00, 0x01, 0xb8, - 0x0c, 0x95, 0x01, 0xd8, 0x02, 0x01, 0x82, 0x00, - 0xe2, 0x04, 0xd8, 0x87, 0x07, 0xdc, 0x81, 0xc4, - 0x01, 0xdc, 0x9d, 0xc3, 0xb0, 0x63, 0xc2, 0xb8, - 0x05, 0x8a, 0xc6, 0x80, 0xd0, 0x81, 0xc6, 0x80, - 0xc1, 0x80, 0xc4, 0xb0, 0x33, 0xc0, 0xb0, 0x6f, - 0xc6, 0xb1, 0x46, 0xc0, 0xb0, 0x0c, 0xc3, 0xb1, - 0xcb, 0x01, 0xe8, 0x00, 0xdc, 0xc0, 0xb0, 0xcd, - 0xc0, 0x00, 0xdc, 0xb2, 0xaf, 0x06, 0xdc, 0xb0, - 0x3c, 0xc5, 0x00, 0x07, -}; - -static const uint8_t unicode_cc_index[87] = { - 0x4d, 0x03, 0x00, // 0034D at 32 - 0x97, 0x05, 0x20, // 00597 at 65 - 0xc6, 0x05, 0x00, // 005C6 at 96 - 0xe7, 0x06, 0x00, // 006E7 at 128 - 0x45, 0x07, 0x00, // 00745 at 160 - 0x9c, 0x08, 0x00, // 0089C at 192 - 0x4d, 0x09, 0x00, // 0094D at 224 - 0x3c, 0x0b, 0x00, // 00B3C at 256 - 0x3d, 0x0d, 0x00, // 00D3D at 288 - 0x36, 0x0f, 0x00, // 00F36 at 320 - 0x38, 0x10, 0x20, // 01038 at 353 - 0x3a, 0x19, 0x00, // 0193A at 384 - 0xcb, 0x1a, 0x20, // 01ACB at 417 - 0xd3, 0x1c, 0x00, // 01CD3 at 448 - 0xcf, 0x1d, 0x00, // 01DCF at 480 - 0xe2, 0x20, 0x00, // 020E2 at 512 - 0x2e, 0x30, 0x20, // 0302E at 545 - 0x2b, 0xa9, 0x20, // 0A92B at 577 - 0xed, 0xab, 0x00, // 0ABED at 608 - 0x39, 0x0a, 0x01, // 10A39 at 640 - 0x4c, 0x0f, 0x01, // 10F4C at 672 - 0x35, 0x11, 0x21, // 11135 at 705 - 0x66, 0x13, 0x01, // 11366 at 736 - 0x40, 0x16, 0x01, // 11640 at 768 - 0x47, 0x1a, 0x01, // 11A47 at 800 - 0xf0, 0x6a, 0x21, // 16AF0 at 833 - 0x8a, 0xd1, 0x01, // 1D18A at 864 - 0xec, 0xe4, 0x21, // 1E4EC at 897 - 0x4b, 0xe9, 0x01, // 1E94B at 928 (upper bound) -}; - -static const uint32_t unicode_decomp_table1[709] = { - 0x00280081, 0x002a0097, 0x002a8081, 0x002bc097, - 0x002c8115, 0x002d0097, 0x002d4081, 0x002e0097, - 0x002e4115, 0x002f0199, 0x00302016, 0x00400842, - 0x00448a42, 0x004a0442, 0x004c0096, 0x004c8117, - 0x004d0242, 0x004e4342, 0x004fc12f, 0x0050c342, - 0x005240bf, 0x00530342, 0x00550942, 0x005a0842, - 0x005e0096, 0x005e4342, 0x005fc081, 0x00680142, - 0x006bc142, 0x00710185, 0x0071c317, 0x00734844, - 0x00778344, 0x00798342, 0x007b02be, 0x007c4197, - 0x007d0142, 0x007e0444, 0x00800e42, 0x00878142, - 0x00898744, 0x00ac0483, 0x00b60317, 0x00b80283, - 0x00d00214, 0x00d10096, 0x00dd0080, 0x00de8097, - 0x00df8080, 0x00e10097, 0x00e1413e, 0x00e1c080, - 0x00e204be, 0x00ea83ae, 0x00f282ae, 0x00f401ad, - 0x00f4c12e, 0x00f54103, 0x00fc0303, 0x00fe4081, - 0x0100023e, 0x0101c0be, 0x010301be, 0x010640be, - 0x010e40be, 0x0114023e, 0x0115c0be, 0x011701be, - 0x011d8144, 0x01304144, 0x01340244, 0x01358144, - 0x01368344, 0x01388344, 0x013a8644, 0x013e0144, - 0x0161c085, 0x018882ae, 0x019d422f, 0x01b00184, - 0x01b4c084, 0x024a4084, 0x024c4084, 0x024d0084, - 0x0256042e, 0x0272c12e, 0x02770120, 0x0277c084, - 0x028cc084, 0x028d8084, 0x029641ae, 0x02978084, - 0x02d20084, 0x02d2c12e, 0x02d70120, 0x02e50084, - 0x02f281ae, 0x03120084, 0x03300084, 0x0331c122, - 0x0332812e, 0x035281ae, 0x03768084, 0x037701ae, - 0x038cc085, 0x03acc085, 0x03b7012f, 0x03c30081, - 0x03d0c084, 0x03d34084, 0x03d48084, 0x03d5c084, - 0x03d70084, 0x03da4084, 0x03dcc084, 0x03dd412e, - 0x03ddc085, 0x03de0084, 0x03de4085, 0x03e04084, - 0x03e4c084, 0x03e74084, 0x03e88084, 0x03e9c084, - 0x03eb0084, 0x03ee4084, 0x04098084, 0x043f0081, - 0x06c18484, 0x06c48084, 0x06cec184, 0x06d00120, - 0x06d0c084, 0x074b0383, 0x074cc41f, 0x074f1783, - 0x075e0081, 0x0766d283, 0x07801d44, 0x078e8942, - 0x07931844, 0x079f0d42, 0x07a58216, 0x07a68085, - 0x07a6c0be, 0x07a80d44, 0x07aea044, 0x07c00122, - 0x07c08344, 0x07c20122, 0x07c28344, 0x07c40122, - 0x07c48244, 0x07c60122, 0x07c68244, 0x07c8113e, - 0x07d08244, 0x07d20122, 0x07d28244, 0x07d40122, - 0x07d48344, 0x07d64c3e, 0x07dc4080, 0x07dc80be, - 0x07dcc080, 0x07dd00be, 0x07dd4080, 0x07dd80be, - 0x07ddc080, 0x07de00be, 0x07de4080, 0x07de80be, - 0x07dec080, 0x07df00be, 0x07df4080, 0x07e00820, - 0x07e40820, 0x07e80820, 0x07ec05be, 0x07eec080, - 0x07ef00be, 0x07ef4097, 0x07ef8080, 0x07efc117, - 0x07f0443e, 0x07f24080, 0x07f280be, 0x07f2c080, - 0x07f303be, 0x07f4c080, 0x07f582ae, 0x07f6c080, - 0x07f7433e, 0x07f8c080, 0x07f903ae, 0x07fac080, - 0x07fb013e, 0x07fb8102, 0x07fc83be, 0x07fe4080, - 0x07fe80be, 0x07fec080, 0x07ff00be, 0x07ff4080, - 0x07ff8097, 0x0800011e, 0x08008495, 0x08044081, - 0x0805c097, 0x08090081, 0x08094097, 0x08098099, - 0x080bc081, 0x080cc085, 0x080d00b1, 0x080d8085, - 0x080dc0b1, 0x080f0197, 0x0811c197, 0x0815c0b3, - 0x0817c081, 0x081c0595, 0x081ec081, 0x081f0215, - 0x0820051f, 0x08228583, 0x08254415, 0x082a0097, - 0x08400119, 0x08408081, 0x0840c0bf, 0x08414119, - 0x0841c081, 0x084240bf, 0x0842852d, 0x08454081, - 0x08458097, 0x08464295, 0x08480097, 0x08484099, - 0x08488097, 0x08490081, 0x08498080, 0x084a0081, - 0x084a8102, 0x084b0495, 0x084d421f, 0x084e4081, - 0x084ec099, 0x084f0283, 0x08514295, 0x08540119, - 0x0854809b, 0x0854c619, 0x0857c097, 0x08580081, - 0x08584097, 0x08588099, 0x0858c097, 0x08590081, - 0x08594097, 0x08598099, 0x0859c09b, 0x085a0097, - 0x085a4081, 0x085a8097, 0x085ac099, 0x085b0295, - 0x085c4097, 0x085c8099, 0x085cc097, 0x085d0081, - 0x085d4097, 0x085d8099, 0x085dc09b, 0x085e0097, - 0x085e4081, 0x085e8097, 0x085ec099, 0x085f0215, - 0x08624099, 0x0866813e, 0x086b80be, 0x087341be, - 0x088100be, 0x088240be, 0x088300be, 0x088901be, - 0x088b0085, 0x088b40b1, 0x088bc085, 0x088c00b1, - 0x089040be, 0x089100be, 0x0891c1be, 0x089801be, - 0x089b42be, 0x089d0144, 0x089e0144, 0x08a00144, - 0x08a10144, 0x08a20144, 0x08ab023e, 0x08b80244, - 0x08ba8220, 0x08ca411e, 0x0918049f, 0x091a4523, - 0x091cc097, 0x091d04a5, 0x091f452b, 0x0921c09b, - 0x092204a1, 0x09244525, 0x0926c099, 0x09270d25, - 0x092d8d1f, 0x09340d1f, 0x093a8081, 0x0a8300b3, - 0x0a9d0099, 0x0a9d4097, 0x0a9d8099, 0x0ab700be, - 0x0b1f0115, 0x0b5bc081, 0x0ba7c081, 0x0bbcc081, - 0x0bc004ad, 0x0bc244ad, 0x0bc484ad, 0x0bc6f383, - 0x0be0852d, 0x0be31d03, 0x0bf1882d, 0x0c000081, - 0x0c0d8283, 0x0c130b84, 0x0c194284, 0x0c1c0122, - 0x0c1cc122, 0x0c1d8122, 0x0c1e4122, 0x0c1f0122, - 0x0c250084, 0x0c26c123, 0x0c278084, 0x0c27c085, - 0x0c2b0b84, 0x0c314284, 0x0c340122, 0x0c34c122, - 0x0c358122, 0x0c364122, 0x0c370122, 0x0c3d0084, - 0x0c3dc220, 0x0c3f8084, 0x0c3fc085, 0x0c4c4a2d, - 0x0c51451f, 0x0c53ca9f, 0x0c5915ad, 0x0c648703, - 0x0c800741, 0x0c838089, 0x0c83c129, 0x0c8441a9, - 0x0c850089, 0x0c854129, 0x0c85c2a9, 0x0c870089, - 0x0c87408f, 0x0c87808d, 0x0c881241, 0x0c910203, - 0x0c940099, 0x0c9444a3, 0x0c968323, 0x0c98072d, - 0x0c9b84af, 0x0c9dc2a1, 0x0c9f00b5, 0x0c9f40b3, - 0x0c9f8085, 0x0ca01883, 0x0cac4223, 0x0cad4523, - 0x0cafc097, 0x0cb004a1, 0x0cb241a5, 0x0cb30097, - 0x0cb34099, 0x0cb38097, 0x0cb3c099, 0x0cb417ad, - 0x0cbfc085, 0x0cc001b3, 0x0cc0c0b1, 0x0cc100b3, - 0x0cc14131, 0x0cc1c0b5, 0x0cc200b3, 0x0cc241b1, - 0x0cc30133, 0x0cc38131, 0x0cc40085, 0x0cc440b1, - 0x0cc48133, 0x0cc50085, 0x0cc540b5, 0x0cc580b7, - 0x0cc5c0b5, 0x0cc600b1, 0x0cc64135, 0x0cc6c0b3, - 0x0cc701b1, 0x0cc7c0b3, 0x0cc800b5, 0x0cc840b3, - 0x0cc881b1, 0x0cc9422f, 0x0cca4131, 0x0ccac0b5, - 0x0ccb00b1, 0x0ccb40b3, 0x0ccb80b5, 0x0ccbc0b1, - 0x0ccc012f, 0x0ccc80b5, 0x0cccc0b3, 0x0ccd00b5, - 0x0ccd40b1, 0x0ccd80b5, 0x0ccdc085, 0x0cce02b1, - 0x0ccf40b3, 0x0ccf80b1, 0x0ccfc085, 0x0cd001b1, - 0x0cd0c0b3, 0x0cd101b1, 0x0cd1c0b5, 0x0cd200b3, - 0x0cd24085, 0x0cd280b5, 0x0cd2c085, 0x0cd30133, - 0x0cd381b1, 0x0cd440b3, 0x0cd48085, 0x0cd4c0b1, - 0x0cd500b3, 0x0cd54085, 0x0cd580b5, 0x0cd5c0b1, - 0x0cd60521, 0x0cd88525, 0x0cdb02a5, 0x0cdc4099, - 0x0cdc8117, 0x0cdd0099, 0x0cdd4197, 0x0cde0127, - 0x0cde8285, 0x0cdfc089, 0x0ce0043f, 0x0ce20099, - 0x0ce2409b, 0x0ce283bf, 0x0ce44219, 0x0ce54205, - 0x0ce6433f, 0x0ce7c131, 0x0ce84085, 0x0ce881b1, - 0x0ce94085, 0x0ce98107, 0x0cea0089, 0x0cea4097, - 0x0cea8219, 0x0ceb809d, 0x0cebc08d, 0x0cec083f, - 0x0cf00105, 0x0cf0809b, 0x0cf0c197, 0x0cf1809b, - 0x0cf1c099, 0x0cf20517, 0x0cf48099, 0x0cf4c117, - 0x0cf54119, 0x0cf5c097, 0x0cf6009b, 0x0cf64099, - 0x0cf68217, 0x0cf78119, 0x0cf804a1, 0x0cfa4525, - 0x0cfcc525, 0x0cff4125, 0x0cffc099, 0x29a70103, - 0x29dc0081, 0x29fc8195, 0x29fe0103, 0x2ad70203, - 0x2ada4081, 0x3e401482, 0x3e4a7f82, 0x3e6a3f82, - 0x3e8aa102, 0x3e9b0110, 0x3e9c2f82, 0x3eb3c590, - 0x3ec00197, 0x3ec0c119, 0x3ec1413f, 0x3ec4c2af, - 0x3ec74184, 0x3ec804ad, 0x3eca4081, 0x3eca8304, - 0x3ecc03a0, 0x3ece02a0, 0x3ecf8084, 0x3ed00120, - 0x3ed0c120, 0x3ed184ae, 0x3ed3c085, 0x3ed4312d, - 0x3ef4cbad, 0x3efa892f, 0x3eff022d, 0x3f002f2f, - 0x3f1782a5, 0x3f18c0b1, 0x3f1907af, 0x3f1cffaf, - 0x3f3c81a5, 0x3f3d64af, 0x3f542031, 0x3f649b31, - 0x3f7c0131, 0x3f7c83b3, 0x3f7e40b1, 0x3f7e80bd, - 0x3f7ec0bb, 0x3f7f00b3, 0x3f840503, 0x3f8c01ad, - 0x3f8cc315, 0x3f8e462d, 0x3f91cc03, 0x3f97c695, - 0x3f9c01af, 0x3f9d0085, 0x3f9d852f, 0x3fa03aad, - 0x3fbd442f, 0x3fc06f1f, 0x3fd7c11f, 0x3fd85fad, - 0x3fe80081, 0x3fe84f1f, 0x3ff0831f, 0x3ff2831f, - 0x3ff4831f, 0x3ff6819f, 0x3ff80783, 0x41724092, - 0x41790092, 0x41e04d83, 0x41e70f91, 0x44268192, - 0x442ac092, 0x444b8112, 0x44d2c112, 0x44e0c192, - 0x44e38092, 0x44e44092, 0x44f14212, 0x452ec212, - 0x456e8112, 0x464e0092, 0x58484412, 0x5b5a0192, - 0x73358d1f, 0x733c051f, 0x74578392, 0x746ec312, - 0x75000d1f, 0x75068d1f, 0x750d0d1f, 0x7513839f, - 0x7515891f, 0x751a0d1f, 0x75208d1f, 0x75271015, - 0x752f439f, 0x7531459f, 0x75340d1f, 0x753a8d1f, - 0x75410395, 0x7543441f, 0x7545839f, 0x75478d1f, - 0x754e0795, 0x7552839f, 0x75548d1f, 0x755b0d1f, - 0x75618d1f, 0x75680d1f, 0x756e8d1f, 0x75750d1f, - 0x757b8d1f, 0x75820d1f, 0x75888d1f, 0x758f0d1f, - 0x75958d1f, 0x759c0d1f, 0x75a28d1f, 0x75a90103, - 0x75aa089f, 0x75ae4081, 0x75ae839f, 0x75b04081, - 0x75b08c9f, 0x75b6c081, 0x75b7032d, 0x75b8889f, - 0x75bcc081, 0x75bd039f, 0x75bec081, 0x75bf0c9f, - 0x75c54081, 0x75c5832d, 0x75c7089f, 0x75cb4081, - 0x75cb839f, 0x75cd4081, 0x75cd8c9f, 0x75d3c081, - 0x75d4032d, 0x75d5889f, 0x75d9c081, 0x75da039f, - 0x75dbc081, 0x75dc0c9f, 0x75e24081, 0x75e2832d, - 0x75e4089f, 0x75e84081, 0x75e8839f, 0x75ea4081, - 0x75ea8c9f, 0x75f0c081, 0x75f1042d, 0x75f3851f, - 0x75f6051f, 0x75f8851f, 0x75fb051f, 0x75fd851f, - 0x780c049f, 0x780e419f, 0x780f059f, 0x7811c203, - 0x7812d0ad, 0x781b0103, 0x7b80022d, 0x7b814dad, - 0x7b884203, 0x7b89c081, 0x7b8a452d, 0x7b8d0403, - 0x7b908081, 0x7b91dc03, 0x7ba0052d, 0x7ba2c8ad, - 0x7ba84483, 0x7baac8ad, 0x7c400097, 0x7c404521, - 0x7c440d25, 0x7c4a8087, 0x7c4ac115, 0x7c4b4117, - 0x7c4c0d1f, 0x7c528217, 0x7c538099, 0x7c53c097, - 0x7c5a8197, 0x7c640097, 0x7c80012f, 0x7c808081, - 0x7c841603, 0x7c9004c1, 0x7c940103, 0x7efc051f, - 0xbe0001ac, 0xbe00d110, 0xbe0947ac, 0xbe0d3910, - 0xbe29872c, 0xbe2d022c, 0xbe2e3790, 0xbe49ff90, - 0xbe69bc10, -}; - -static const uint16_t unicode_decomp_table2[709] = { - 0x0020, 0x0000, 0x0061, 0x0002, 0x0004, 0x0006, 0x03bc, 0x0008, - 0x000a, 0x000c, 0x0015, 0x0095, 0x00a5, 0x00b9, 0x00c1, 0x00c3, - 0x00c7, 0x00cb, 0x00d1, 0x00d7, 0x00dd, 0x00e0, 0x00e6, 0x00f8, - 0x0108, 0x010a, 0x0073, 0x0110, 0x0112, 0x0114, 0x0120, 0x012c, - 0x0144, 0x014d, 0x0153, 0x0162, 0x0168, 0x016a, 0x0176, 0x0192, - 0x0194, 0x01a9, 0x01bb, 0x01c7, 0x01d1, 0x01d5, 0x02b9, 0x01d7, - 0x003b, 0x01d9, 0x01db, 0x00b7, 0x01e1, 0x01fc, 0x020c, 0x0218, - 0x021d, 0x0223, 0x0227, 0x03a3, 0x0233, 0x023f, 0x0242, 0x024b, - 0x024e, 0x0251, 0x025d, 0x0260, 0x0269, 0x026c, 0x026f, 0x0275, - 0x0278, 0x0281, 0x028a, 0x029c, 0x029f, 0x02a3, 0x02af, 0x02b9, - 0x02c5, 0x02c9, 0x02cd, 0x02d1, 0x02d5, 0x02e7, 0x02ed, 0x02f1, - 0x02f5, 0x02f9, 0x02fd, 0x0305, 0x0309, 0x030d, 0x0313, 0x0317, - 0x031b, 0x0323, 0x0327, 0x032b, 0x032f, 0x0335, 0x033d, 0x0341, - 0x0349, 0x034d, 0x0351, 0x0f0b, 0x0357, 0x035b, 0x035f, 0x0363, - 0x0367, 0x036b, 0x036f, 0x0373, 0x0379, 0x037d, 0x0381, 0x0385, - 0x0389, 0x038d, 0x0391, 0x0395, 0x0399, 0x039d, 0x03a1, 0x10dc, - 0x03a5, 0x03c9, 0x03cd, 0x03d9, 0x03dd, 0x03e1, 0x03ef, 0x03f1, - 0x043d, 0x044f, 0x0499, 0x04f0, 0x0502, 0x054a, 0x0564, 0x056c, - 0x0570, 0x0573, 0x059a, 0x05fa, 0x05fe, 0x0607, 0x060b, 0x0614, - 0x0618, 0x061e, 0x0622, 0x0628, 0x068e, 0x0694, 0x0698, 0x069e, - 0x06a2, 0x06ab, 0x03ac, 0x06f3, 0x03ad, 0x06f6, 0x03ae, 0x06f9, - 0x03af, 0x06fc, 0x03cc, 0x06ff, 0x03cd, 0x0702, 0x03ce, 0x0705, - 0x0709, 0x070d, 0x0711, 0x0386, 0x0732, 0x0735, 0x03b9, 0x0737, - 0x073b, 0x0388, 0x0753, 0x0389, 0x0756, 0x0390, 0x076b, 0x038a, - 0x0777, 0x03b0, 0x0789, 0x038e, 0x0799, 0x079f, 0x07a3, 0x038c, - 0x07b8, 0x038f, 0x07bb, 0x00b4, 0x07be, 0x07c0, 0x07c2, 0x2010, - 0x07cb, 0x002e, 0x07cd, 0x07cf, 0x0020, 0x07d2, 0x07d6, 0x07db, - 0x07df, 0x07e4, 0x07ea, 0x07f0, 0x0020, 0x07f6, 0x2212, 0x0801, - 0x0805, 0x0807, 0x081d, 0x0825, 0x0827, 0x0043, 0x082d, 0x0830, - 0x0190, 0x0836, 0x0839, 0x004e, 0x0845, 0x0847, 0x084c, 0x084e, - 0x0851, 0x005a, 0x03a9, 0x005a, 0x0853, 0x0857, 0x0860, 0x0069, - 0x0862, 0x0865, 0x086f, 0x0874, 0x087a, 0x087e, 0x08a2, 0x0049, - 0x08a4, 0x08a6, 0x08a9, 0x0056, 0x08ab, 0x08ad, 0x08b0, 0x08b4, - 0x0058, 0x08b6, 0x08b8, 0x08bb, 0x08c0, 0x08c2, 0x08c5, 0x0076, - 0x08c7, 0x08c9, 0x08cc, 0x08d0, 0x0078, 0x08d2, 0x08d4, 0x08d7, - 0x08db, 0x08de, 0x08e4, 0x08e7, 0x08f0, 0x08f3, 0x08f6, 0x08f9, - 0x0902, 0x0906, 0x090b, 0x090f, 0x0914, 0x0917, 0x091a, 0x0923, - 0x092c, 0x093b, 0x093e, 0x0941, 0x0944, 0x0947, 0x094a, 0x0956, - 0x095c, 0x0960, 0x0962, 0x0964, 0x0968, 0x096a, 0x0970, 0x0978, - 0x097c, 0x0980, 0x0986, 0x0989, 0x098f, 0x0991, 0x0030, 0x0993, - 0x0999, 0x099c, 0x099e, 0x09a1, 0x09a4, 0x2d61, 0x6bcd, 0x9f9f, - 0x09a6, 0x09b1, 0x09bc, 0x09c7, 0x0a95, 0x0aa1, 0x0b15, 0x0020, - 0x0b27, 0x0b31, 0x0b8d, 0x0ba1, 0x0ba5, 0x0ba9, 0x0bad, 0x0bb1, - 0x0bb5, 0x0bb9, 0x0bbd, 0x0bc1, 0x0bc5, 0x0c21, 0x0c35, 0x0c39, - 0x0c3d, 0x0c41, 0x0c45, 0x0c49, 0x0c4d, 0x0c51, 0x0c55, 0x0c59, - 0x0c6f, 0x0c71, 0x0c73, 0x0ca0, 0x0cbc, 0x0cdc, 0x0ce4, 0x0cec, - 0x0cf4, 0x0cfc, 0x0d04, 0x0d0c, 0x0d14, 0x0d22, 0x0d2e, 0x0d7a, - 0x0d82, 0x0d85, 0x0d89, 0x0d8d, 0x0d9d, 0x0db1, 0x0db5, 0x0dbc, - 0x0dc2, 0x0dc6, 0x0e28, 0x0e2c, 0x0e30, 0x0e32, 0x0e36, 0x0e3c, - 0x0e3e, 0x0e41, 0x0e43, 0x0e46, 0x0e77, 0x0e7b, 0x0e89, 0x0e8e, - 0x0e94, 0x0e9c, 0x0ea3, 0x0ea9, 0x0eb4, 0x0ebe, 0x0ec6, 0x0eca, - 0x0ecf, 0x0ed9, 0x0edd, 0x0ee4, 0x0eec, 0x0ef3, 0x0ef8, 0x0f04, - 0x0f0a, 0x0f15, 0x0f1b, 0x0f22, 0x0f28, 0x0f33, 0x0f3d, 0x0f45, - 0x0f4c, 0x0f51, 0x0f57, 0x0f5e, 0x0f63, 0x0f69, 0x0f70, 0x0f76, - 0x0f7d, 0x0f82, 0x0f89, 0x0f8d, 0x0f9e, 0x0fa4, 0x0fa9, 0x0fad, - 0x0fb8, 0x0fbe, 0x0fc9, 0x0fd0, 0x0fd6, 0x0fda, 0x0fe1, 0x0fe5, - 0x0fef, 0x0ffa, 0x1000, 0x1004, 0x1009, 0x100f, 0x1013, 0x101a, - 0x101f, 0x1023, 0x1029, 0x102f, 0x1032, 0x1036, 0x1039, 0x103f, - 0x1045, 0x1059, 0x1061, 0x1079, 0x107c, 0x1080, 0x1095, 0x10a1, - 0x10b1, 0x10c3, 0x10cb, 0x10cf, 0x10da, 0x10de, 0x10ea, 0x10f2, - 0x10f4, 0x1100, 0x1105, 0x1111, 0x1141, 0x1149, 0x114d, 0x1153, - 0x1157, 0x115a, 0x116e, 0x1171, 0x1175, 0x117b, 0x117d, 0x1181, - 0x1184, 0x118c, 0x1192, 0x1196, 0x119c, 0x11a2, 0x11a8, 0x11ab, - 0xa76f, 0x11af, 0x11b2, 0x11b6, 0x028d, 0x11be, 0x1210, 0x130e, - 0x140c, 0x1490, 0x1495, 0x1553, 0x156c, 0x1572, 0x1578, 0x157e, - 0x158a, 0x1596, 0x002b, 0x15a1, 0x15b9, 0x15bd, 0x15c1, 0x15c5, - 0x15c9, 0x15cd, 0x15e1, 0x15e5, 0x1649, 0x1662, 0x1688, 0x168e, - 0x174c, 0x1752, 0x1757, 0x1777, 0x1877, 0x187d, 0x1911, 0x19d3, - 0x1a77, 0x1a7f, 0x1a9d, 0x1aa2, 0x1ab6, 0x1ac0, 0x1ac6, 0x1ada, - 0x1adf, 0x1ae5, 0x1af3, 0x1b23, 0x1b30, 0x1b38, 0x1b3c, 0x1b52, - 0x1bc9, 0x1bdb, 0x1bdd, 0x1bdf, 0x3164, 0x1c20, 0x1c22, 0x1c24, - 0x1c26, 0x1c28, 0x1c2a, 0x1c48, 0x1c4d, 0x1c52, 0x1c88, 0x1cce, - 0x1cdc, 0x1ce1, 0x1cea, 0x1cf3, 0x1d01, 0x1d06, 0x1d0b, 0x1d1d, - 0x1d2f, 0x1d38, 0x1d3d, 0x1d61, 0x1d6f, 0x1d71, 0x1d73, 0x1d93, - 0x1dae, 0x1db0, 0x1db2, 0x1db4, 0x1db6, 0x1db8, 0x1dba, 0x1dbc, - 0x1ddc, 0x1dde, 0x1de0, 0x1de2, 0x1de4, 0x1deb, 0x1ded, 0x1def, - 0x1df1, 0x1e00, 0x1e02, 0x1e04, 0x1e06, 0x1e08, 0x1e0a, 0x1e0c, - 0x1e0e, 0x1e10, 0x1e12, 0x1e14, 0x1e16, 0x1e18, 0x1e1a, 0x1e1c, - 0x1e20, 0x03f4, 0x1e22, 0x2207, 0x1e24, 0x2202, 0x1e26, 0x1e2e, - 0x03f4, 0x1e30, 0x2207, 0x1e32, 0x2202, 0x1e34, 0x1e3c, 0x03f4, - 0x1e3e, 0x2207, 0x1e40, 0x2202, 0x1e42, 0x1e4a, 0x03f4, 0x1e4c, - 0x2207, 0x1e4e, 0x2202, 0x1e50, 0x1e58, 0x03f4, 0x1e5a, 0x2207, - 0x1e5c, 0x2202, 0x1e5e, 0x1e68, 0x1e6a, 0x1e6c, 0x1e6e, 0x1e70, - 0x1e72, 0x1e74, 0x1e76, 0x1e78, 0x1e80, 0x1ea3, 0x1ea7, 0x1ead, - 0x1eca, 0x062d, 0x1ed2, 0x1ede, 0x062c, 0x1eee, 0x1f5e, 0x1f6a, - 0x1f7d, 0x1f8f, 0x1fa2, 0x1fa4, 0x1fa8, 0x1fae, 0x1fb4, 0x1fb6, - 0x1fba, 0x1fbc, 0x1fc4, 0x1fc7, 0x1fc9, 0x1fcf, 0x1fd1, 0x30b5, - 0x1fd7, 0x202f, 0x2045, 0x2049, 0x204b, 0x2050, 0x209d, 0x20ae, - 0x21af, 0x21bf, 0x21c5, 0x22bf, 0x23dd, -}; - -static const uint8_t unicode_decomp_data[9451] = { - 0x20, 0x88, 0x20, 0x84, 0x32, 0x33, 0x20, 0x81, - 0x20, 0xa7, 0x31, 0x6f, 0x31, 0xd0, 0x34, 0x31, - 0xd0, 0x32, 0x33, 0xd0, 0x34, 0x41, 0x80, 0x41, - 0x81, 0x41, 0x82, 0x41, 0x83, 0x41, 0x88, 0x41, - 0x8a, 0x00, 0x00, 0x43, 0xa7, 0x45, 0x80, 0x45, - 0x81, 0x45, 0x82, 0x45, 0x88, 0x49, 0x80, 0x49, - 0x81, 0x49, 0x82, 0x49, 0x88, 0x00, 0x00, 0x4e, - 0x83, 0x4f, 0x80, 0x4f, 0x81, 0x4f, 0x82, 0x4f, - 0x83, 0x4f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x55, - 0x80, 0x55, 0x81, 0x55, 0x82, 0x55, 0x88, 0x59, - 0x81, 0x00, 0x00, 0x00, 0x00, 0x61, 0x80, 0x61, - 0x81, 0x61, 0x82, 0x61, 0x83, 0x61, 0x88, 0x61, - 0x8a, 0x00, 0x00, 0x63, 0xa7, 0x65, 0x80, 0x65, - 0x81, 0x65, 0x82, 0x65, 0x88, 0x69, 0x80, 0x69, - 0x81, 0x69, 0x82, 0x69, 0x88, 0x00, 0x00, 0x6e, - 0x83, 0x6f, 0x80, 0x6f, 0x81, 0x6f, 0x82, 0x6f, - 0x83, 0x6f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x75, - 0x80, 0x75, 0x81, 0x75, 0x82, 0x75, 0x88, 0x79, - 0x81, 0x00, 0x00, 0x79, 0x88, 0x41, 0x84, 0x41, - 0x86, 0x41, 0xa8, 0x43, 0x81, 0x43, 0x82, 0x43, - 0x87, 0x43, 0x8c, 0x44, 0x8c, 0x45, 0x84, 0x45, - 0x86, 0x45, 0x87, 0x45, 0xa8, 0x45, 0x8c, 0x47, - 0x82, 0x47, 0x86, 0x47, 0x87, 0x47, 0xa7, 0x48, - 0x82, 0x49, 0x83, 0x49, 0x84, 0x49, 0x86, 0x49, - 0xa8, 0x49, 0x87, 0x49, 0x4a, 0x69, 0x6a, 0x4a, - 0x82, 0x4b, 0xa7, 0x4c, 0x81, 0x4c, 0xa7, 0x4c, - 0x8c, 0x4c, 0x00, 0x00, 0x6b, 0x20, 0x6b, 0x4e, - 0x81, 0x4e, 0xa7, 0x4e, 0x8c, 0xbc, 0x02, 0x6e, - 0x4f, 0x84, 0x4f, 0x86, 0x4f, 0x8b, 0x52, 0x81, - 0x52, 0xa7, 0x52, 0x8c, 0x53, 0x81, 0x53, 0x82, - 0x53, 0xa7, 0x53, 0x8c, 0x54, 0xa7, 0x54, 0x8c, - 0x55, 0x83, 0x55, 0x84, 0x55, 0x86, 0x55, 0x8a, - 0x55, 0x8b, 0x55, 0xa8, 0x57, 0x82, 0x59, 0x82, - 0x59, 0x88, 0x5a, 0x81, 0x5a, 0x87, 0x5a, 0x8c, - 0x4f, 0x9b, 0x55, 0x9b, 0x44, 0x00, 0x7d, 0x01, - 0x44, 0x00, 0x7e, 0x01, 0x64, 0x00, 0x7e, 0x01, - 0x4c, 0x4a, 0x4c, 0x6a, 0x6c, 0x6a, 0x4e, 0x4a, - 0x4e, 0x6a, 0x6e, 0x6a, 0x41, 0x00, 0x8c, 0x49, - 0x00, 0x8c, 0x4f, 0x00, 0x8c, 0x55, 0x00, 0x8c, - 0xdc, 0x00, 0x84, 0xdc, 0x00, 0x81, 0xdc, 0x00, - 0x8c, 0xdc, 0x00, 0x80, 0xc4, 0x00, 0x84, 0x26, - 0x02, 0x84, 0xc6, 0x00, 0x84, 0x47, 0x8c, 0x4b, - 0x8c, 0x4f, 0xa8, 0xea, 0x01, 0x84, 0xeb, 0x01, - 0x84, 0xb7, 0x01, 0x8c, 0x92, 0x02, 0x8c, 0x6a, - 0x00, 0x8c, 0x44, 0x5a, 0x44, 0x7a, 0x64, 0x7a, - 0x47, 0x81, 0x4e, 0x00, 0x80, 0xc5, 0x00, 0x81, - 0xc6, 0x00, 0x81, 0xd8, 0x00, 0x81, 0x41, 0x8f, - 0x41, 0x91, 0x45, 0x8f, 0x45, 0x91, 0x49, 0x8f, - 0x49, 0x91, 0x4f, 0x8f, 0x4f, 0x91, 0x52, 0x8f, - 0x52, 0x91, 0x55, 0x8f, 0x55, 0x91, 0x53, 0xa6, - 0x54, 0xa6, 0x48, 0x8c, 0x41, 0x00, 0x87, 0x45, - 0x00, 0xa7, 0xd6, 0x00, 0x84, 0xd5, 0x00, 0x84, - 0x4f, 0x00, 0x87, 0x2e, 0x02, 0x84, 0x59, 0x00, - 0x84, 0x68, 0x00, 0x66, 0x02, 0x6a, 0x00, 0x72, - 0x00, 0x79, 0x02, 0x7b, 0x02, 0x81, 0x02, 0x77, - 0x00, 0x79, 0x00, 0x20, 0x86, 0x20, 0x87, 0x20, - 0x8a, 0x20, 0xa8, 0x20, 0x83, 0x20, 0x8b, 0x63, - 0x02, 0x6c, 0x00, 0x73, 0x00, 0x78, 0x00, 0x95, - 0x02, 0x80, 0x81, 0x00, 0x93, 0x88, 0x81, 0x20, - 0xc5, 0x20, 0x81, 0xa8, 0x00, 0x81, 0x91, 0x03, - 0x81, 0x95, 0x03, 0x81, 0x97, 0x03, 0x81, 0x99, - 0x03, 0x81, 0x00, 0x00, 0x00, 0x9f, 0x03, 0x81, - 0x00, 0x00, 0x00, 0xa5, 0x03, 0x81, 0xa9, 0x03, - 0x81, 0xca, 0x03, 0x81, 0x01, 0x03, 0x98, 0x07, - 0xa4, 0x07, 0xb0, 0x00, 0xb4, 0x00, 0xb6, 0x00, - 0xb8, 0x00, 0xca, 0x00, 0x01, 0x03, 0xb8, 0x07, - 0xc4, 0x07, 0xbe, 0x00, 0xc4, 0x00, 0xc8, 0x00, - 0xa5, 0x03, 0x0d, 0x13, 0x00, 0x01, 0x03, 0xd1, - 0x00, 0xd1, 0x07, 0xc6, 0x03, 0xc0, 0x03, 0xba, - 0x03, 0xc1, 0x03, 0xc2, 0x03, 0x00, 0x00, 0x98, - 0x03, 0xb5, 0x03, 0x15, 0x04, 0x80, 0x15, 0x04, - 0x88, 0x00, 0x00, 0x00, 0x13, 0x04, 0x81, 0x06, - 0x04, 0x88, 0x1a, 0x04, 0x81, 0x18, 0x04, 0x80, - 0x23, 0x04, 0x86, 0x18, 0x04, 0x86, 0x38, 0x04, - 0x86, 0x35, 0x04, 0x80, 0x35, 0x04, 0x88, 0x00, - 0x00, 0x00, 0x33, 0x04, 0x81, 0x56, 0x04, 0x88, - 0x3a, 0x04, 0x81, 0x38, 0x04, 0x80, 0x43, 0x04, - 0x86, 0x74, 0x04, 0x8f, 0x16, 0x04, 0x86, 0x10, - 0x04, 0x86, 0x10, 0x04, 0x88, 0x15, 0x04, 0x86, - 0xd8, 0x04, 0x88, 0x16, 0x04, 0x88, 0x17, 0x04, - 0x88, 0x18, 0x04, 0x84, 0x18, 0x04, 0x88, 0x1e, - 0x04, 0x88, 0xe8, 0x04, 0x88, 0x2d, 0x04, 0x88, - 0x23, 0x04, 0x84, 0x23, 0x04, 0x88, 0x23, 0x04, - 0x8b, 0x27, 0x04, 0x88, 0x2b, 0x04, 0x88, 0x65, - 0x05, 0x82, 0x05, 0x27, 0x06, 0x00, 0x2c, 0x00, - 0x2d, 0x21, 0x2d, 0x00, 0x2e, 0x23, 0x2d, 0x27, - 0x06, 0x00, 0x4d, 0x21, 0x4d, 0xa0, 0x4d, 0x23, - 0x4d, 0xd5, 0x06, 0x54, 0x06, 0x00, 0x00, 0x00, - 0x00, 0xc1, 0x06, 0x54, 0x06, 0xd2, 0x06, 0x54, - 0x06, 0x28, 0x09, 0x3c, 0x09, 0x30, 0x09, 0x3c, - 0x09, 0x33, 0x09, 0x3c, 0x09, 0x15, 0x09, 0x00, - 0x27, 0x01, 0x27, 0x02, 0x27, 0x07, 0x27, 0x0c, - 0x27, 0x0d, 0x27, 0x16, 0x27, 0x1a, 0x27, 0xbe, - 0x09, 0x09, 0x00, 0x09, 0x19, 0xa1, 0x09, 0xbc, - 0x09, 0xaf, 0x09, 0xbc, 0x09, 0x32, 0x0a, 0x3c, - 0x0a, 0x38, 0x0a, 0x3c, 0x0a, 0x16, 0x0a, 0x00, - 0x26, 0x01, 0x26, 0x06, 0x26, 0x2b, 0x0a, 0x3c, - 0x0a, 0x47, 0x0b, 0x56, 0x0b, 0x3e, 0x0b, 0x09, - 0x00, 0x09, 0x19, 0x21, 0x0b, 0x3c, 0x0b, 0x92, - 0x0b, 0xd7, 0x0b, 0xbe, 0x0b, 0x08, 0x00, 0x09, - 0x00, 0x08, 0x19, 0x46, 0x0c, 0x56, 0x0c, 0xbf, - 0x0c, 0xd5, 0x0c, 0xc6, 0x0c, 0xd5, 0x0c, 0xc2, - 0x0c, 0x04, 0x00, 0x08, 0x13, 0x3e, 0x0d, 0x08, - 0x00, 0x09, 0x00, 0x08, 0x19, 0xd9, 0x0d, 0xca, - 0x0d, 0xca, 0x0d, 0x0f, 0x05, 0x12, 0x00, 0x0f, - 0x15, 0x4d, 0x0e, 0x32, 0x0e, 0xcd, 0x0e, 0xb2, - 0x0e, 0x99, 0x0e, 0x12, 0x00, 0x12, 0x08, 0x42, - 0x0f, 0xb7, 0x0f, 0x4c, 0x0f, 0xb7, 0x0f, 0x51, - 0x0f, 0xb7, 0x0f, 0x56, 0x0f, 0xb7, 0x0f, 0x5b, - 0x0f, 0xb7, 0x0f, 0x40, 0x0f, 0xb5, 0x0f, 0x71, - 0x0f, 0x72, 0x0f, 0x71, 0x0f, 0x00, 0x03, 0x41, - 0x0f, 0xb2, 0x0f, 0x81, 0x0f, 0xb3, 0x0f, 0x80, - 0x0f, 0xb3, 0x0f, 0x81, 0x0f, 0x71, 0x0f, 0x80, - 0x0f, 0x92, 0x0f, 0xb7, 0x0f, 0x9c, 0x0f, 0xb7, - 0x0f, 0xa1, 0x0f, 0xb7, 0x0f, 0xa6, 0x0f, 0xb7, - 0x0f, 0xab, 0x0f, 0xb7, 0x0f, 0x90, 0x0f, 0xb5, - 0x0f, 0x25, 0x10, 0x2e, 0x10, 0x05, 0x1b, 0x35, - 0x1b, 0x00, 0x00, 0x00, 0x00, 0x07, 0x1b, 0x35, - 0x1b, 0x00, 0x00, 0x00, 0x00, 0x09, 0x1b, 0x35, - 0x1b, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x1b, 0x35, - 0x1b, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x1b, 0x35, - 0x1b, 0x11, 0x1b, 0x35, 0x1b, 0x3a, 0x1b, 0x35, - 0x1b, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1b, 0x35, - 0x1b, 0x3e, 0x1b, 0x35, 0x1b, 0x42, 0x1b, 0x35, - 0x1b, 0x41, 0x00, 0xc6, 0x00, 0x42, 0x00, 0x00, - 0x00, 0x44, 0x00, 0x45, 0x00, 0x8e, 0x01, 0x47, - 0x00, 0x4f, 0x00, 0x22, 0x02, 0x50, 0x00, 0x52, - 0x00, 0x54, 0x00, 0x55, 0x00, 0x57, 0x00, 0x61, - 0x00, 0x50, 0x02, 0x51, 0x02, 0x02, 0x1d, 0x62, - 0x00, 0x64, 0x00, 0x65, 0x00, 0x59, 0x02, 0x5b, - 0x02, 0x5c, 0x02, 0x67, 0x00, 0x00, 0x00, 0x6b, - 0x00, 0x6d, 0x00, 0x4b, 0x01, 0x6f, 0x00, 0x54, - 0x02, 0x16, 0x1d, 0x17, 0x1d, 0x70, 0x00, 0x74, - 0x00, 0x75, 0x00, 0x1d, 0x1d, 0x6f, 0x02, 0x76, - 0x00, 0x25, 0x1d, 0xb2, 0x03, 0xb3, 0x03, 0xb4, - 0x03, 0xc6, 0x03, 0xc7, 0x03, 0x69, 0x00, 0x72, - 0x00, 0x75, 0x00, 0x76, 0x00, 0xb2, 0x03, 0xb3, - 0x03, 0xc1, 0x03, 0xc6, 0x03, 0xc7, 0x03, 0x52, - 0x02, 0x63, 0x00, 0x55, 0x02, 0xf0, 0x00, 0x5c, - 0x02, 0x66, 0x00, 0x5f, 0x02, 0x61, 0x02, 0x65, - 0x02, 0x68, 0x02, 0x69, 0x02, 0x6a, 0x02, 0x7b, - 0x1d, 0x9d, 0x02, 0x6d, 0x02, 0x85, 0x1d, 0x9f, - 0x02, 0x71, 0x02, 0x70, 0x02, 0x72, 0x02, 0x73, - 0x02, 0x74, 0x02, 0x75, 0x02, 0x78, 0x02, 0x82, - 0x02, 0x83, 0x02, 0xab, 0x01, 0x89, 0x02, 0x8a, - 0x02, 0x1c, 0x1d, 0x8b, 0x02, 0x8c, 0x02, 0x7a, - 0x00, 0x90, 0x02, 0x91, 0x02, 0x92, 0x02, 0xb8, - 0x03, 0x41, 0x00, 0xa5, 0x42, 0x00, 0x87, 0x42, - 0x00, 0xa3, 0x42, 0x00, 0xb1, 0xc7, 0x00, 0x81, - 0x44, 0x00, 0x87, 0x44, 0x00, 0xa3, 0x44, 0x00, - 0xb1, 0x44, 0x00, 0xa7, 0x44, 0x00, 0xad, 0x12, - 0x01, 0x80, 0x12, 0x01, 0x81, 0x45, 0x00, 0xad, - 0x45, 0x00, 0xb0, 0x28, 0x02, 0x86, 0x46, 0x00, - 0x87, 0x47, 0x00, 0x84, 0x48, 0x00, 0x87, 0x48, - 0x00, 0xa3, 0x48, 0x00, 0x88, 0x48, 0x00, 0xa7, - 0x48, 0x00, 0xae, 0x49, 0x00, 0xb0, 0xcf, 0x00, - 0x81, 0x4b, 0x00, 0x81, 0x4b, 0x00, 0xa3, 0x4b, - 0x00, 0xb1, 0x4c, 0x00, 0xa3, 0x36, 0x1e, 0x84, - 0x4c, 0xb1, 0x4c, 0xad, 0x4d, 0x81, 0x4d, 0x87, - 0x4d, 0xa3, 0x4e, 0x87, 0x4e, 0xa3, 0x4e, 0xb1, - 0x4e, 0xad, 0xd5, 0x00, 0x81, 0xd5, 0x00, 0x88, - 0x4c, 0x01, 0x80, 0x4c, 0x01, 0x81, 0x50, 0x00, - 0x81, 0x50, 0x00, 0x87, 0x52, 0x00, 0x87, 0x52, - 0x00, 0xa3, 0x5a, 0x1e, 0x84, 0x52, 0x00, 0xb1, - 0x53, 0x00, 0x87, 0x53, 0x00, 0xa3, 0x5a, 0x01, - 0x87, 0x60, 0x01, 0x87, 0x62, 0x1e, 0x87, 0x54, - 0x00, 0x87, 0x54, 0x00, 0xa3, 0x54, 0x00, 0xb1, - 0x54, 0x00, 0xad, 0x55, 0x00, 0xa4, 0x55, 0x00, - 0xb0, 0x55, 0x00, 0xad, 0x68, 0x01, 0x81, 0x6a, - 0x01, 0x88, 0x56, 0x83, 0x56, 0xa3, 0x57, 0x80, - 0x57, 0x81, 0x57, 0x88, 0x57, 0x87, 0x57, 0xa3, - 0x58, 0x87, 0x58, 0x88, 0x59, 0x87, 0x5a, 0x82, - 0x5a, 0xa3, 0x5a, 0xb1, 0x68, 0xb1, 0x74, 0x88, - 0x77, 0x8a, 0x79, 0x8a, 0x61, 0x00, 0xbe, 0x02, - 0x7f, 0x01, 0x87, 0x41, 0x00, 0xa3, 0x41, 0x00, - 0x89, 0xc2, 0x00, 0x81, 0xc2, 0x00, 0x80, 0xc2, - 0x00, 0x89, 0xc2, 0x00, 0x83, 0xa0, 0x1e, 0x82, - 0x02, 0x01, 0x81, 0x02, 0x01, 0x80, 0x02, 0x01, - 0x89, 0x02, 0x01, 0x83, 0xa0, 0x1e, 0x86, 0x45, - 0x00, 0xa3, 0x45, 0x00, 0x89, 0x45, 0x00, 0x83, - 0xca, 0x00, 0x81, 0xca, 0x00, 0x80, 0xca, 0x00, - 0x89, 0xca, 0x00, 0x83, 0xb8, 0x1e, 0x82, 0x49, - 0x00, 0x89, 0x49, 0x00, 0xa3, 0x4f, 0x00, 0xa3, - 0x4f, 0x00, 0x89, 0xd4, 0x00, 0x81, 0xd4, 0x00, - 0x80, 0xd4, 0x00, 0x89, 0xd4, 0x00, 0x83, 0xcc, - 0x1e, 0x82, 0xa0, 0x01, 0x81, 0xa0, 0x01, 0x80, - 0xa0, 0x01, 0x89, 0xa0, 0x01, 0x83, 0xa0, 0x01, - 0xa3, 0x55, 0x00, 0xa3, 0x55, 0x00, 0x89, 0xaf, - 0x01, 0x81, 0xaf, 0x01, 0x80, 0xaf, 0x01, 0x89, - 0xaf, 0x01, 0x83, 0xaf, 0x01, 0xa3, 0x59, 0x00, - 0x80, 0x59, 0x00, 0xa3, 0x59, 0x00, 0x89, 0x59, - 0x00, 0x83, 0xb1, 0x03, 0x13, 0x03, 0x00, 0x1f, - 0x80, 0x00, 0x1f, 0x81, 0x00, 0x1f, 0xc2, 0x91, - 0x03, 0x13, 0x03, 0x08, 0x1f, 0x80, 0x08, 0x1f, - 0x81, 0x08, 0x1f, 0xc2, 0xb5, 0x03, 0x13, 0x03, - 0x10, 0x1f, 0x80, 0x10, 0x1f, 0x81, 0x95, 0x03, - 0x13, 0x03, 0x18, 0x1f, 0x80, 0x18, 0x1f, 0x81, - 0xb7, 0x03, 0x93, 0xb7, 0x03, 0x94, 0x20, 0x1f, - 0x80, 0x21, 0x1f, 0x80, 0x20, 0x1f, 0x81, 0x21, - 0x1f, 0x81, 0x20, 0x1f, 0xc2, 0x21, 0x1f, 0xc2, - 0x97, 0x03, 0x93, 0x97, 0x03, 0x94, 0x28, 0x1f, - 0x80, 0x29, 0x1f, 0x80, 0x28, 0x1f, 0x81, 0x29, - 0x1f, 0x81, 0x28, 0x1f, 0xc2, 0x29, 0x1f, 0xc2, - 0xb9, 0x03, 0x93, 0xb9, 0x03, 0x94, 0x30, 0x1f, - 0x80, 0x31, 0x1f, 0x80, 0x30, 0x1f, 0x81, 0x31, - 0x1f, 0x81, 0x30, 0x1f, 0xc2, 0x31, 0x1f, 0xc2, - 0x99, 0x03, 0x93, 0x99, 0x03, 0x94, 0x38, 0x1f, - 0x80, 0x39, 0x1f, 0x80, 0x38, 0x1f, 0x81, 0x39, - 0x1f, 0x81, 0x38, 0x1f, 0xc2, 0x39, 0x1f, 0xc2, - 0xbf, 0x03, 0x93, 0xbf, 0x03, 0x94, 0x40, 0x1f, - 0x80, 0x40, 0x1f, 0x81, 0x9f, 0x03, 0x13, 0x03, - 0x48, 0x1f, 0x80, 0x48, 0x1f, 0x81, 0xc5, 0x03, - 0x13, 0x03, 0x50, 0x1f, 0x80, 0x50, 0x1f, 0x81, - 0x50, 0x1f, 0xc2, 0xa5, 0x03, 0x94, 0x00, 0x00, - 0x00, 0x59, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x59, - 0x1f, 0x81, 0x00, 0x00, 0x00, 0x59, 0x1f, 0xc2, - 0xc9, 0x03, 0x93, 0xc9, 0x03, 0x94, 0x60, 0x1f, - 0x80, 0x61, 0x1f, 0x80, 0x60, 0x1f, 0x81, 0x61, - 0x1f, 0x81, 0x60, 0x1f, 0xc2, 0x61, 0x1f, 0xc2, - 0xa9, 0x03, 0x93, 0xa9, 0x03, 0x94, 0x68, 0x1f, - 0x80, 0x69, 0x1f, 0x80, 0x68, 0x1f, 0x81, 0x69, - 0x1f, 0x81, 0x68, 0x1f, 0xc2, 0x69, 0x1f, 0xc2, - 0xb1, 0x03, 0x80, 0xb5, 0x03, 0x80, 0xb7, 0x03, - 0x80, 0xb9, 0x03, 0x80, 0xbf, 0x03, 0x80, 0xc5, - 0x03, 0x80, 0xc9, 0x03, 0x80, 0x00, 0x1f, 0x45, - 0x03, 0x20, 0x1f, 0x45, 0x03, 0x60, 0x1f, 0x45, - 0x03, 0xb1, 0x03, 0x86, 0xb1, 0x03, 0x84, 0x70, - 0x1f, 0xc5, 0xb1, 0x03, 0xc5, 0xac, 0x03, 0xc5, - 0x00, 0x00, 0x00, 0xb1, 0x03, 0xc2, 0xb6, 0x1f, - 0xc5, 0x91, 0x03, 0x86, 0x91, 0x03, 0x84, 0x91, - 0x03, 0x80, 0x91, 0x03, 0xc5, 0x20, 0x93, 0x20, - 0x93, 0x20, 0xc2, 0xa8, 0x00, 0xc2, 0x74, 0x1f, - 0xc5, 0xb7, 0x03, 0xc5, 0xae, 0x03, 0xc5, 0x00, - 0x00, 0x00, 0xb7, 0x03, 0xc2, 0xc6, 0x1f, 0xc5, - 0x95, 0x03, 0x80, 0x97, 0x03, 0x80, 0x97, 0x03, - 0xc5, 0xbf, 0x1f, 0x80, 0xbf, 0x1f, 0x81, 0xbf, - 0x1f, 0xc2, 0xb9, 0x03, 0x86, 0xb9, 0x03, 0x84, - 0xca, 0x03, 0x80, 0x00, 0x03, 0xb9, 0x42, 0xca, - 0x42, 0x99, 0x06, 0x99, 0x04, 0x99, 0x00, 0xfe, - 0x1f, 0x80, 0xfe, 0x1f, 0x81, 0xfe, 0x1f, 0xc2, - 0xc5, 0x03, 0x86, 0xc5, 0x03, 0x84, 0xcb, 0x03, - 0x80, 0x00, 0x03, 0xc1, 0x13, 0xc1, 0x14, 0xc5, - 0x42, 0xcb, 0x42, 0xa5, 0x06, 0xa5, 0x04, 0xa5, - 0x00, 0xa1, 0x03, 0x94, 0xa8, 0x00, 0x80, 0x85, - 0x03, 0x60, 0x00, 0x7c, 0x1f, 0xc5, 0xc9, 0x03, - 0xc5, 0xce, 0x03, 0xc5, 0x00, 0x00, 0x00, 0xc9, - 0x03, 0xc2, 0xf6, 0x1f, 0xc5, 0x9f, 0x03, 0x80, - 0xa9, 0x03, 0x80, 0xa9, 0x03, 0xc5, 0x20, 0x94, - 0x02, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0xb3, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x32, 0x20, 0x32, 0x20, 0x32, 0x20, - 0x00, 0x00, 0x00, 0x35, 0x20, 0x35, 0x20, 0x35, - 0x20, 0x00, 0x00, 0x00, 0x21, 0x21, 0x00, 0x00, - 0x20, 0x85, 0x3f, 0x3f, 0x3f, 0x21, 0x21, 0x3f, - 0x32, 0x20, 0x00, 0x00, 0x00, 0x00, 0x30, 0x69, - 0x00, 0x00, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x2b, 0x3d, 0x28, 0x29, 0x6e, 0x30, 0x00, 0x2b, - 0x00, 0x12, 0x22, 0x3d, 0x00, 0x28, 0x00, 0x29, - 0x00, 0x00, 0x00, 0x61, 0x00, 0x65, 0x00, 0x6f, - 0x00, 0x78, 0x00, 0x59, 0x02, 0x68, 0x6b, 0x6c, - 0x6d, 0x6e, 0x70, 0x73, 0x74, 0x52, 0x73, 0x61, - 0x2f, 0x63, 0x61, 0x2f, 0x73, 0xb0, 0x00, 0x43, - 0x63, 0x2f, 0x6f, 0x63, 0x2f, 0x75, 0xb0, 0x00, - 0x46, 0x48, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, - 0xdf, 0x01, 0x01, 0x04, 0x24, 0x4e, 0x6f, 0x50, - 0x51, 0x52, 0x52, 0x52, 0x53, 0x4d, 0x54, 0x45, - 0x4c, 0x54, 0x4d, 0x4b, 0x00, 0xc5, 0x00, 0x42, - 0x43, 0x00, 0x65, 0x45, 0x46, 0x00, 0x4d, 0x6f, - 0xd0, 0x05, 0x46, 0x41, 0x58, 0xc0, 0x03, 0xb3, - 0x03, 0x93, 0x03, 0xa0, 0x03, 0x11, 0x22, 0x44, - 0x64, 0x65, 0x69, 0x6a, 0x31, 0xd0, 0x37, 0x31, - 0xd0, 0x39, 0x31, 0xd0, 0x31, 0x30, 0x31, 0xd0, - 0x33, 0x32, 0xd0, 0x33, 0x31, 0xd0, 0x35, 0x32, - 0xd0, 0x35, 0x33, 0xd0, 0x35, 0x34, 0xd0, 0x35, - 0x31, 0xd0, 0x36, 0x35, 0xd0, 0x36, 0x31, 0xd0, - 0x38, 0x33, 0xd0, 0x38, 0x35, 0xd0, 0x38, 0x37, - 0xd0, 0x38, 0x31, 0xd0, 0x49, 0x49, 0x49, 0x49, - 0x49, 0x49, 0x56, 0x56, 0x49, 0x56, 0x49, 0x49, - 0x56, 0x49, 0x49, 0x49, 0x49, 0x58, 0x58, 0x49, - 0x58, 0x49, 0x49, 0x4c, 0x43, 0x44, 0x4d, 0x69, - 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x76, 0x76, - 0x69, 0x76, 0x69, 0x69, 0x76, 0x69, 0x69, 0x69, - 0x69, 0x78, 0x78, 0x69, 0x78, 0x69, 0x69, 0x6c, - 0x63, 0x64, 0x6d, 0x30, 0xd0, 0x33, 0x90, 0x21, - 0xb8, 0x92, 0x21, 0xb8, 0x94, 0x21, 0xb8, 0xd0, - 0x21, 0xb8, 0xd4, 0x21, 0xb8, 0xd2, 0x21, 0xb8, - 0x03, 0x22, 0xb8, 0x08, 0x22, 0xb8, 0x0b, 0x22, - 0xb8, 0x23, 0x22, 0xb8, 0x00, 0x00, 0x00, 0x25, - 0x22, 0xb8, 0x2b, 0x22, 0x2b, 0x22, 0x2b, 0x22, - 0x00, 0x00, 0x00, 0x2e, 0x22, 0x2e, 0x22, 0x2e, - 0x22, 0x00, 0x00, 0x00, 0x3c, 0x22, 0xb8, 0x43, - 0x22, 0xb8, 0x45, 0x22, 0xb8, 0x00, 0x00, 0x00, - 0x48, 0x22, 0xb8, 0x3d, 0x00, 0xb8, 0x00, 0x00, - 0x00, 0x61, 0x22, 0xb8, 0x4d, 0x22, 0xb8, 0x3c, - 0x00, 0xb8, 0x3e, 0x00, 0xb8, 0x64, 0x22, 0xb8, - 0x65, 0x22, 0xb8, 0x72, 0x22, 0xb8, 0x76, 0x22, - 0xb8, 0x7a, 0x22, 0xb8, 0x82, 0x22, 0xb8, 0x86, - 0x22, 0xb8, 0xa2, 0x22, 0xb8, 0xa8, 0x22, 0xb8, - 0xa9, 0x22, 0xb8, 0xab, 0x22, 0xb8, 0x7c, 0x22, - 0xb8, 0x91, 0x22, 0xb8, 0xb2, 0x22, 0x38, 0x03, - 0x08, 0x30, 0x31, 0x00, 0x31, 0x00, 0x30, 0x00, - 0x32, 0x30, 0x28, 0x00, 0x31, 0x00, 0x29, 0x00, - 0x28, 0x00, 0x31, 0x00, 0x30, 0x00, 0x29, 0x00, - 0x28, 0x32, 0x30, 0x29, 0x31, 0x00, 0x2e, 0x00, - 0x31, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x32, 0x30, - 0x2e, 0x28, 0x00, 0x61, 0x00, 0x29, 0x00, 0x41, - 0x00, 0x61, 0x00, 0x2b, 0x22, 0x00, 0x00, 0x00, - 0x00, 0x3a, 0x3a, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0xdd, 0x2a, 0xb8, 0x6a, 0x56, 0x00, 0x4e, - 0x00, 0x28, 0x36, 0x3f, 0x59, 0x85, 0x8c, 0xa0, - 0xba, 0x3f, 0x51, 0x00, 0x26, 0x2c, 0x43, 0x57, - 0x6c, 0xa1, 0xb6, 0xc1, 0x9b, 0x52, 0x00, 0x5e, - 0x7a, 0x7f, 0x9d, 0xa6, 0xc1, 0xce, 0xe7, 0xb6, - 0x53, 0xc8, 0x53, 0xe3, 0x53, 0xd7, 0x56, 0x1f, - 0x57, 0xeb, 0x58, 0x02, 0x59, 0x0a, 0x59, 0x15, - 0x59, 0x27, 0x59, 0x73, 0x59, 0x50, 0x5b, 0x80, - 0x5b, 0xf8, 0x5b, 0x0f, 0x5c, 0x22, 0x5c, 0x38, - 0x5c, 0x6e, 0x5c, 0x71, 0x5c, 0xdb, 0x5d, 0xe5, - 0x5d, 0xf1, 0x5d, 0xfe, 0x5d, 0x72, 0x5e, 0x7a, - 0x5e, 0x7f, 0x5e, 0xf4, 0x5e, 0xfe, 0x5e, 0x0b, - 0x5f, 0x13, 0x5f, 0x50, 0x5f, 0x61, 0x5f, 0x73, - 0x5f, 0xc3, 0x5f, 0x08, 0x62, 0x36, 0x62, 0x4b, - 0x62, 0x2f, 0x65, 0x34, 0x65, 0x87, 0x65, 0x97, - 0x65, 0xa4, 0x65, 0xb9, 0x65, 0xe0, 0x65, 0xe5, - 0x65, 0xf0, 0x66, 0x08, 0x67, 0x28, 0x67, 0x20, - 0x6b, 0x62, 0x6b, 0x79, 0x6b, 0xb3, 0x6b, 0xcb, - 0x6b, 0xd4, 0x6b, 0xdb, 0x6b, 0x0f, 0x6c, 0x14, - 0x6c, 0x34, 0x6c, 0x6b, 0x70, 0x2a, 0x72, 0x36, - 0x72, 0x3b, 0x72, 0x3f, 0x72, 0x47, 0x72, 0x59, - 0x72, 0x5b, 0x72, 0xac, 0x72, 0x84, 0x73, 0x89, - 0x73, 0xdc, 0x74, 0xe6, 0x74, 0x18, 0x75, 0x1f, - 0x75, 0x28, 0x75, 0x30, 0x75, 0x8b, 0x75, 0x92, - 0x75, 0x76, 0x76, 0x7d, 0x76, 0xae, 0x76, 0xbf, - 0x76, 0xee, 0x76, 0xdb, 0x77, 0xe2, 0x77, 0xf3, - 0x77, 0x3a, 0x79, 0xb8, 0x79, 0xbe, 0x79, 0x74, - 0x7a, 0xcb, 0x7a, 0xf9, 0x7a, 0x73, 0x7c, 0xf8, - 0x7c, 0x36, 0x7f, 0x51, 0x7f, 0x8a, 0x7f, 0xbd, - 0x7f, 0x01, 0x80, 0x0c, 0x80, 0x12, 0x80, 0x33, - 0x80, 0x7f, 0x80, 0x89, 0x80, 0xe3, 0x81, 0x00, - 0x07, 0x10, 0x19, 0x29, 0x38, 0x3c, 0x8b, 0x8f, - 0x95, 0x4d, 0x86, 0x6b, 0x86, 0x40, 0x88, 0x4c, - 0x88, 0x63, 0x88, 0x7e, 0x89, 0x8b, 0x89, 0xd2, - 0x89, 0x00, 0x8a, 0x37, 0x8c, 0x46, 0x8c, 0x55, - 0x8c, 0x78, 0x8c, 0x9d, 0x8c, 0x64, 0x8d, 0x70, - 0x8d, 0xb3, 0x8d, 0xab, 0x8e, 0xca, 0x8e, 0x9b, - 0x8f, 0xb0, 0x8f, 0xb5, 0x8f, 0x91, 0x90, 0x49, - 0x91, 0xc6, 0x91, 0xcc, 0x91, 0xd1, 0x91, 0x77, - 0x95, 0x80, 0x95, 0x1c, 0x96, 0xb6, 0x96, 0xb9, - 0x96, 0xe8, 0x96, 0x51, 0x97, 0x5e, 0x97, 0x62, - 0x97, 0x69, 0x97, 0xcb, 0x97, 0xed, 0x97, 0xf3, - 0x97, 0x01, 0x98, 0xa8, 0x98, 0xdb, 0x98, 0xdf, - 0x98, 0x96, 0x99, 0x99, 0x99, 0xac, 0x99, 0xa8, - 0x9a, 0xd8, 0x9a, 0xdf, 0x9a, 0x25, 0x9b, 0x2f, - 0x9b, 0x32, 0x9b, 0x3c, 0x9b, 0x5a, 0x9b, 0xe5, - 0x9c, 0x75, 0x9e, 0x7f, 0x9e, 0xa5, 0x9e, 0x00, - 0x16, 0x1e, 0x28, 0x2c, 0x54, 0x58, 0x69, 0x6e, - 0x7b, 0x96, 0xa5, 0xad, 0xe8, 0xf7, 0xfb, 0x12, - 0x30, 0x00, 0x00, 0x41, 0x53, 0x44, 0x53, 0x45, - 0x53, 0x4b, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x4d, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x4f, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x51, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x53, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x55, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x57, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x59, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x5b, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x5d, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x5f, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x61, 0x30, 0x99, 0x30, 0x64, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x66, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x68, 0x30, 0x99, - 0x30, 0x6f, 0x30, 0x99, 0x30, 0x72, 0x30, 0x99, - 0x30, 0x75, 0x30, 0x99, 0x30, 0x78, 0x30, 0x99, - 0x30, 0x7b, 0x30, 0x99, 0x30, 0x46, 0x30, 0x99, - 0x30, 0x20, 0x00, 0x99, 0x30, 0x9d, 0x30, 0x99, - 0x30, 0x88, 0x30, 0x8a, 0x30, 0xab, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xad, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xb5, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x30, 0x99, - 0x30, 0xc4, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0xc6, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0xc8, 0x30, 0x99, 0x30, 0xcf, 0x30, 0x99, - 0x30, 0xd2, 0x30, 0x99, 0x30, 0xd5, 0x30, 0x99, - 0x30, 0xd8, 0x30, 0x99, 0x30, 0xdb, 0x30, 0x99, - 0x30, 0xa6, 0x30, 0x99, 0x30, 0xef, 0x30, 0x99, - 0x30, 0xfd, 0x30, 0x99, 0x30, 0xb3, 0x30, 0xc8, - 0x30, 0x00, 0x11, 0x00, 0x01, 0xaa, 0x02, 0xac, - 0xad, 0x03, 0x04, 0x05, 0xb0, 0xb1, 0xb2, 0xb3, - 0xb4, 0xb5, 0x1a, 0x06, 0x07, 0x08, 0x21, 0x09, - 0x11, 0x61, 0x11, 0x14, 0x11, 0x4c, 0x00, 0x01, - 0xb3, 0xb4, 0xb8, 0xba, 0xbf, 0xc3, 0xc5, 0x08, - 0xc9, 0xcb, 0x09, 0x0a, 0x0c, 0x0e, 0x0f, 0x13, - 0x15, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x22, - 0x2c, 0x33, 0x38, 0xdd, 0xde, 0x43, 0x44, 0x45, - 0x70, 0x71, 0x74, 0x7d, 0x7e, 0x80, 0x8a, 0x8d, - 0x00, 0x4e, 0x8c, 0x4e, 0x09, 0x4e, 0xdb, 0x56, - 0x0a, 0x4e, 0x2d, 0x4e, 0x0b, 0x4e, 0x32, 0x75, - 0x59, 0x4e, 0x19, 0x4e, 0x01, 0x4e, 0x29, 0x59, - 0x30, 0x57, 0xba, 0x4e, 0x28, 0x00, 0x29, 0x00, - 0x00, 0x11, 0x02, 0x11, 0x03, 0x11, 0x05, 0x11, - 0x06, 0x11, 0x07, 0x11, 0x09, 0x11, 0x0b, 0x11, - 0x0c, 0x11, 0x0e, 0x11, 0x0f, 0x11, 0x10, 0x11, - 0x11, 0x11, 0x12, 0x11, 0x28, 0x00, 0x00, 0x11, - 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x02, 0x11, - 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x05, 0x11, - 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x09, 0x11, - 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11, - 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0e, 0x11, - 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0c, 0x11, - 0x6e, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11, - 0x69, 0x11, 0x0c, 0x11, 0x65, 0x11, 0xab, 0x11, - 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11, 0x69, 0x11, - 0x12, 0x11, 0x6e, 0x11, 0x29, 0x00, 0x28, 0x00, - 0x29, 0x00, 0x00, 0x4e, 0x8c, 0x4e, 0x09, 0x4e, - 0xdb, 0x56, 0x94, 0x4e, 0x6d, 0x51, 0x03, 0x4e, - 0x6b, 0x51, 0x5d, 0x4e, 0x41, 0x53, 0x08, 0x67, - 0x6b, 0x70, 0x34, 0x6c, 0x28, 0x67, 0xd1, 0x91, - 0x1f, 0x57, 0xe5, 0x65, 0x2a, 0x68, 0x09, 0x67, - 0x3e, 0x79, 0x0d, 0x54, 0x79, 0x72, 0xa1, 0x8c, - 0x5d, 0x79, 0xb4, 0x52, 0xe3, 0x4e, 0x7c, 0x54, - 0x66, 0x5b, 0xe3, 0x76, 0x01, 0x4f, 0xc7, 0x8c, - 0x54, 0x53, 0x6d, 0x79, 0x11, 0x4f, 0xea, 0x81, - 0xf3, 0x81, 0x4f, 0x55, 0x7c, 0x5e, 0x87, 0x65, - 0x8f, 0x7b, 0x50, 0x54, 0x45, 0x32, 0x00, 0x31, - 0x00, 0x33, 0x00, 0x30, 0x00, 0x00, 0x11, 0x00, - 0x02, 0x03, 0x05, 0x06, 0x07, 0x09, 0x0b, 0x0c, - 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x00, 0x11, 0x00, - 0x61, 0x02, 0x61, 0x03, 0x61, 0x05, 0x61, 0x06, - 0x61, 0x07, 0x61, 0x09, 0x61, 0x0b, 0x61, 0x0c, - 0x61, 0x0e, 0x11, 0x61, 0x11, 0x00, 0x11, 0x0e, - 0x61, 0xb7, 0x00, 0x69, 0x0b, 0x11, 0x01, 0x63, - 0x00, 0x69, 0x0b, 0x11, 0x6e, 0x11, 0x00, 0x4e, - 0x8c, 0x4e, 0x09, 0x4e, 0xdb, 0x56, 0x94, 0x4e, - 0x6d, 0x51, 0x03, 0x4e, 0x6b, 0x51, 0x5d, 0x4e, - 0x41, 0x53, 0x08, 0x67, 0x6b, 0x70, 0x34, 0x6c, - 0x28, 0x67, 0xd1, 0x91, 0x1f, 0x57, 0xe5, 0x65, - 0x2a, 0x68, 0x09, 0x67, 0x3e, 0x79, 0x0d, 0x54, - 0x79, 0x72, 0xa1, 0x8c, 0x5d, 0x79, 0xb4, 0x52, - 0xd8, 0x79, 0x37, 0x75, 0x73, 0x59, 0x69, 0x90, - 0x2a, 0x51, 0x70, 0x53, 0xe8, 0x6c, 0x05, 0x98, - 0x11, 0x4f, 0x99, 0x51, 0x63, 0x6b, 0x0a, 0x4e, - 0x2d, 0x4e, 0x0b, 0x4e, 0xe6, 0x5d, 0xf3, 0x53, - 0x3b, 0x53, 0x97, 0x5b, 0x66, 0x5b, 0xe3, 0x76, - 0x01, 0x4f, 0xc7, 0x8c, 0x54, 0x53, 0x1c, 0x59, - 0x33, 0x00, 0x36, 0x00, 0x34, 0x00, 0x30, 0x00, - 0x35, 0x30, 0x31, 0x00, 0x08, 0x67, 0x31, 0x00, - 0x30, 0x00, 0x08, 0x67, 0x48, 0x67, 0x65, 0x72, - 0x67, 0x65, 0x56, 0x4c, 0x54, 0x44, 0xa2, 0x30, - 0x00, 0x02, 0x04, 0x06, 0x08, 0x09, 0x0b, 0x0d, - 0x0f, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1b, 0x1d, - 0x1f, 0x22, 0x24, 0x26, 0x28, 0x29, 0x2a, 0x2b, - 0x2c, 0x2d, 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3d, - 0x3e, 0x3f, 0x40, 0x42, 0x44, 0x46, 0x47, 0x48, - 0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0xe4, - 0x4e, 0x8c, 0x54, 0xa1, 0x30, 0x01, 0x30, 0x5b, - 0x27, 0x01, 0x4a, 0x34, 0x00, 0x01, 0x52, 0x39, - 0x01, 0xa2, 0x30, 0x00, 0x5a, 0x49, 0xa4, 0x30, - 0x00, 0x27, 0x4f, 0x0c, 0xa4, 0x30, 0x00, 0x4f, - 0x1d, 0x02, 0x05, 0x4f, 0xa8, 0x30, 0x00, 0x11, - 0x07, 0x54, 0x21, 0xa8, 0x30, 0x00, 0x54, 0x03, - 0x54, 0xa4, 0x30, 0x06, 0x4f, 0x15, 0x06, 0x58, - 0x3c, 0x07, 0x00, 0x46, 0xab, 0x30, 0x00, 0x3e, - 0x18, 0x1d, 0x00, 0x42, 0x3f, 0x51, 0xac, 0x30, - 0x00, 0x41, 0x47, 0x00, 0x47, 0x32, 0xae, 0x30, - 0xac, 0x30, 0xae, 0x30, 0x00, 0x1d, 0x4e, 0xad, - 0x30, 0x00, 0x38, 0x3d, 0x4f, 0x01, 0x3e, 0x13, - 0x4f, 0xad, 0x30, 0xed, 0x30, 0xad, 0x30, 0x00, - 0x40, 0x03, 0x3c, 0x33, 0xad, 0x30, 0x00, 0x40, - 0x34, 0x4f, 0x1b, 0x3e, 0xad, 0x30, 0x00, 0x40, - 0x42, 0x16, 0x1b, 0xb0, 0x30, 0x00, 0x39, 0x30, - 0xa4, 0x30, 0x0c, 0x45, 0x3c, 0x24, 0x4f, 0x0b, - 0x47, 0x18, 0x00, 0x49, 0xaf, 0x30, 0x00, 0x3e, - 0x4d, 0x1e, 0xb1, 0x30, 0x00, 0x4b, 0x08, 0x02, - 0x3a, 0x19, 0x02, 0x4b, 0x2c, 0xa4, 0x30, 0x11, - 0x00, 0x0b, 0x47, 0xb5, 0x30, 0x00, 0x3e, 0x0c, - 0x47, 0x2b, 0xb0, 0x30, 0x07, 0x3a, 0x43, 0x00, - 0xb9, 0x30, 0x02, 0x3a, 0x08, 0x02, 0x3a, 0x0f, - 0x07, 0x43, 0x00, 0xb7, 0x30, 0x10, 0x00, 0x12, - 0x34, 0x11, 0x3c, 0x13, 0x17, 0xa4, 0x30, 0x2a, - 0x1f, 0x24, 0x2b, 0x00, 0x20, 0xbb, 0x30, 0x16, - 0x41, 0x00, 0x38, 0x0d, 0xc4, 0x30, 0x0d, 0x38, - 0x00, 0xd0, 0x30, 0x00, 0x2c, 0x1c, 0x1b, 0xa2, - 0x30, 0x32, 0x00, 0x17, 0x26, 0x49, 0xaf, 0x30, - 0x25, 0x00, 0x3c, 0xb3, 0x30, 0x21, 0x00, 0x20, - 0x38, 0xa1, 0x30, 0x34, 0x00, 0x48, 0x22, 0x28, - 0xa3, 0x30, 0x32, 0x00, 0x59, 0x25, 0xa7, 0x30, - 0x2f, 0x1c, 0x10, 0x00, 0x44, 0xd5, 0x30, 0x00, - 0x14, 0x1e, 0xaf, 0x30, 0x29, 0x00, 0x10, 0x4d, - 0x3c, 0xda, 0x30, 0xbd, 0x30, 0xb8, 0x30, 0x22, - 0x13, 0x1a, 0x20, 0x33, 0x0c, 0x22, 0x3b, 0x01, - 0x22, 0x44, 0x00, 0x21, 0x44, 0x07, 0xa4, 0x30, - 0x39, 0x00, 0x4f, 0x24, 0xc8, 0x30, 0x14, 0x23, - 0x00, 0xdb, 0x30, 0xf3, 0x30, 0xc9, 0x30, 0x14, - 0x2a, 0x00, 0x12, 0x33, 0x22, 0x12, 0x33, 0x2a, - 0xa4, 0x30, 0x3a, 0x00, 0x0b, 0x49, 0xa4, 0x30, - 0x3a, 0x00, 0x47, 0x3a, 0x1f, 0x2b, 0x3a, 0x47, - 0x0b, 0xb7, 0x30, 0x27, 0x3c, 0x00, 0x30, 0x3c, - 0xaf, 0x30, 0x30, 0x00, 0x3e, 0x44, 0xdf, 0x30, - 0xea, 0x30, 0xd0, 0x30, 0x0f, 0x1a, 0x00, 0x2c, - 0x1b, 0xe1, 0x30, 0xac, 0x30, 0xac, 0x30, 0x35, - 0x00, 0x1c, 0x47, 0x35, 0x50, 0x1c, 0x3f, 0xa2, - 0x30, 0x42, 0x5a, 0x27, 0x42, 0x5a, 0x49, 0x44, - 0x00, 0x51, 0xc3, 0x30, 0x27, 0x00, 0x05, 0x28, - 0xea, 0x30, 0xe9, 0x30, 0xd4, 0x30, 0x17, 0x00, - 0x28, 0xd6, 0x30, 0x15, 0x26, 0x00, 0x15, 0xec, - 0x30, 0xe0, 0x30, 0xb2, 0x30, 0x3a, 0x41, 0x16, - 0x00, 0x41, 0xc3, 0x30, 0x2c, 0x00, 0x05, 0x30, - 0x00, 0xb9, 0x70, 0x31, 0x00, 0x30, 0x00, 0xb9, - 0x70, 0x32, 0x00, 0x30, 0x00, 0xb9, 0x70, 0x68, - 0x50, 0x61, 0x64, 0x61, 0x41, 0x55, 0x62, 0x61, - 0x72, 0x6f, 0x56, 0x70, 0x63, 0x64, 0x6d, 0x64, - 0x00, 0x6d, 0x00, 0xb2, 0x00, 0x49, 0x00, 0x55, - 0x00, 0x73, 0x5e, 0x10, 0x62, 0x2d, 0x66, 0x8c, - 0x54, 0x27, 0x59, 0x63, 0x6b, 0x0e, 0x66, 0xbb, - 0x6c, 0x2a, 0x68, 0x0f, 0x5f, 0x1a, 0x4f, 0x3e, - 0x79, 0x70, 0x00, 0x41, 0x6e, 0x00, 0x41, 0xbc, - 0x03, 0x41, 0x6d, 0x00, 0x41, 0x6b, 0x00, 0x41, - 0x4b, 0x00, 0x42, 0x4d, 0x00, 0x42, 0x47, 0x00, - 0x42, 0x63, 0x61, 0x6c, 0x6b, 0x63, 0x61, 0x6c, - 0x70, 0x00, 0x46, 0x6e, 0x00, 0x46, 0xbc, 0x03, - 0x46, 0xbc, 0x03, 0x67, 0x6d, 0x00, 0x67, 0x6b, - 0x00, 0x67, 0x48, 0x00, 0x7a, 0x6b, 0x48, 0x7a, - 0x4d, 0x48, 0x7a, 0x47, 0x48, 0x7a, 0x54, 0x48, - 0x7a, 0xbc, 0x03, 0x13, 0x21, 0x6d, 0x00, 0x13, - 0x21, 0x64, 0x00, 0x13, 0x21, 0x6b, 0x00, 0x13, - 0x21, 0x66, 0x00, 0x6d, 0x6e, 0x00, 0x6d, 0xbc, - 0x03, 0x6d, 0x6d, 0x00, 0x6d, 0x63, 0x00, 0x6d, - 0x6b, 0x00, 0x6d, 0x63, 0x00, 0x0a, 0x0a, 0x4f, - 0x00, 0x0a, 0x4f, 0x6d, 0x00, 0xb2, 0x00, 0x63, - 0x00, 0x08, 0x0a, 0x4f, 0x0a, 0x0a, 0x50, 0x00, - 0x0a, 0x50, 0x6d, 0x00, 0xb3, 0x00, 0x6b, 0x00, - 0x6d, 0x00, 0xb3, 0x00, 0x6d, 0x00, 0x15, 0x22, - 0x73, 0x00, 0x6d, 0x00, 0x15, 0x22, 0x73, 0x00, - 0xb2, 0x00, 0x50, 0x61, 0x6b, 0x50, 0x61, 0x4d, - 0x50, 0x61, 0x47, 0x50, 0x61, 0x72, 0x61, 0x64, - 0x72, 0x61, 0x64, 0xd1, 0x73, 0x72, 0x00, 0x61, - 0x00, 0x64, 0x00, 0x15, 0x22, 0x73, 0x00, 0xb2, - 0x00, 0x70, 0x00, 0x73, 0x6e, 0x00, 0x73, 0xbc, - 0x03, 0x73, 0x6d, 0x00, 0x73, 0x70, 0x00, 0x56, - 0x6e, 0x00, 0x56, 0xbc, 0x03, 0x56, 0x6d, 0x00, - 0x56, 0x6b, 0x00, 0x56, 0x4d, 0x00, 0x56, 0x70, - 0x00, 0x57, 0x6e, 0x00, 0x57, 0xbc, 0x03, 0x57, - 0x6d, 0x00, 0x57, 0x6b, 0x00, 0x57, 0x4d, 0x00, - 0x57, 0x6b, 0x00, 0xa9, 0x03, 0x4d, 0x00, 0xa9, - 0x03, 0x61, 0x2e, 0x6d, 0x2e, 0x42, 0x71, 0x63, - 0x63, 0x63, 0x64, 0x43, 0xd1, 0x6b, 0x67, 0x43, - 0x6f, 0x2e, 0x64, 0x42, 0x47, 0x79, 0x68, 0x61, - 0x48, 0x50, 0x69, 0x6e, 0x4b, 0x4b, 0x4b, 0x4d, - 0x6b, 0x74, 0x6c, 0x6d, 0x6c, 0x6e, 0x6c, 0x6f, - 0x67, 0x6c, 0x78, 0x6d, 0x62, 0x6d, 0x69, 0x6c, - 0x6d, 0x6f, 0x6c, 0x50, 0x48, 0x70, 0x2e, 0x6d, - 0x2e, 0x50, 0x50, 0x4d, 0x50, 0x52, 0x73, 0x72, - 0x53, 0x76, 0x57, 0x62, 0x56, 0xd1, 0x6d, 0x41, - 0xd1, 0x6d, 0x31, 0x00, 0xe5, 0x65, 0x31, 0x00, - 0x30, 0x00, 0xe5, 0x65, 0x32, 0x00, 0x30, 0x00, - 0xe5, 0x65, 0x33, 0x00, 0x30, 0x00, 0xe5, 0x65, - 0x67, 0x61, 0x6c, 0x4a, 0x04, 0x4c, 0x04, 0x43, - 0x46, 0x51, 0x26, 0x01, 0x53, 0x01, 0x27, 0xa7, - 0x37, 0xab, 0x6b, 0x02, 0x52, 0xab, 0x48, 0x8c, - 0xf4, 0x66, 0xca, 0x8e, 0xc8, 0x8c, 0xd1, 0x6e, - 0x32, 0x4e, 0xe5, 0x53, 0x9c, 0x9f, 0x9c, 0x9f, - 0x51, 0x59, 0xd1, 0x91, 0x87, 0x55, 0x48, 0x59, - 0xf6, 0x61, 0x69, 0x76, 0x85, 0x7f, 0x3f, 0x86, - 0xba, 0x87, 0xf8, 0x88, 0x8f, 0x90, 0x02, 0x6a, - 0x1b, 0x6d, 0xd9, 0x70, 0xde, 0x73, 0x3d, 0x84, - 0x6a, 0x91, 0xf1, 0x99, 0x82, 0x4e, 0x75, 0x53, - 0x04, 0x6b, 0x1b, 0x72, 0x2d, 0x86, 0x1e, 0x9e, - 0x50, 0x5d, 0xeb, 0x6f, 0xcd, 0x85, 0x64, 0x89, - 0xc9, 0x62, 0xd8, 0x81, 0x1f, 0x88, 0xca, 0x5e, - 0x17, 0x67, 0x6a, 0x6d, 0xfc, 0x72, 0xce, 0x90, - 0x86, 0x4f, 0xb7, 0x51, 0xde, 0x52, 0xc4, 0x64, - 0xd3, 0x6a, 0x10, 0x72, 0xe7, 0x76, 0x01, 0x80, - 0x06, 0x86, 0x5c, 0x86, 0xef, 0x8d, 0x32, 0x97, - 0x6f, 0x9b, 0xfa, 0x9d, 0x8c, 0x78, 0x7f, 0x79, - 0xa0, 0x7d, 0xc9, 0x83, 0x04, 0x93, 0x7f, 0x9e, - 0xd6, 0x8a, 0xdf, 0x58, 0x04, 0x5f, 0x60, 0x7c, - 0x7e, 0x80, 0x62, 0x72, 0xca, 0x78, 0xc2, 0x8c, - 0xf7, 0x96, 0xd8, 0x58, 0x62, 0x5c, 0x13, 0x6a, - 0xda, 0x6d, 0x0f, 0x6f, 0x2f, 0x7d, 0x37, 0x7e, - 0x4b, 0x96, 0xd2, 0x52, 0x8b, 0x80, 0xdc, 0x51, - 0xcc, 0x51, 0x1c, 0x7a, 0xbe, 0x7d, 0xf1, 0x83, - 0x75, 0x96, 0x80, 0x8b, 0xcf, 0x62, 0x02, 0x6a, - 0xfe, 0x8a, 0x39, 0x4e, 0xe7, 0x5b, 0x12, 0x60, - 0x87, 0x73, 0x70, 0x75, 0x17, 0x53, 0xfb, 0x78, - 0xbf, 0x4f, 0xa9, 0x5f, 0x0d, 0x4e, 0xcc, 0x6c, - 0x78, 0x65, 0x22, 0x7d, 0xc3, 0x53, 0x5e, 0x58, - 0x01, 0x77, 0x49, 0x84, 0xaa, 0x8a, 0xba, 0x6b, - 0xb0, 0x8f, 0x88, 0x6c, 0xfe, 0x62, 0xe5, 0x82, - 0xa0, 0x63, 0x65, 0x75, 0xae, 0x4e, 0x69, 0x51, - 0xc9, 0x51, 0x81, 0x68, 0xe7, 0x7c, 0x6f, 0x82, - 0xd2, 0x8a, 0xcf, 0x91, 0xf5, 0x52, 0x42, 0x54, - 0x73, 0x59, 0xec, 0x5e, 0xc5, 0x65, 0xfe, 0x6f, - 0x2a, 0x79, 0xad, 0x95, 0x6a, 0x9a, 0x97, 0x9e, - 0xce, 0x9e, 0x9b, 0x52, 0xc6, 0x66, 0x77, 0x6b, - 0x62, 0x8f, 0x74, 0x5e, 0x90, 0x61, 0x00, 0x62, - 0x9a, 0x64, 0x23, 0x6f, 0x49, 0x71, 0x89, 0x74, - 0xca, 0x79, 0xf4, 0x7d, 0x6f, 0x80, 0x26, 0x8f, - 0xee, 0x84, 0x23, 0x90, 0x4a, 0x93, 0x17, 0x52, - 0xa3, 0x52, 0xbd, 0x54, 0xc8, 0x70, 0xc2, 0x88, - 0xaa, 0x8a, 0xc9, 0x5e, 0xf5, 0x5f, 0x7b, 0x63, - 0xae, 0x6b, 0x3e, 0x7c, 0x75, 0x73, 0xe4, 0x4e, - 0xf9, 0x56, 0xe7, 0x5b, 0xba, 0x5d, 0x1c, 0x60, - 0xb2, 0x73, 0x69, 0x74, 0x9a, 0x7f, 0x46, 0x80, - 0x34, 0x92, 0xf6, 0x96, 0x48, 0x97, 0x18, 0x98, - 0x8b, 0x4f, 0xae, 0x79, 0xb4, 0x91, 0xb8, 0x96, - 0xe1, 0x60, 0x86, 0x4e, 0xda, 0x50, 0xee, 0x5b, - 0x3f, 0x5c, 0x99, 0x65, 0x02, 0x6a, 0xce, 0x71, - 0x42, 0x76, 0xfc, 0x84, 0x7c, 0x90, 0x8d, 0x9f, - 0x88, 0x66, 0x2e, 0x96, 0x89, 0x52, 0x7b, 0x67, - 0xf3, 0x67, 0x41, 0x6d, 0x9c, 0x6e, 0x09, 0x74, - 0x59, 0x75, 0x6b, 0x78, 0x10, 0x7d, 0x5e, 0x98, - 0x6d, 0x51, 0x2e, 0x62, 0x78, 0x96, 0x2b, 0x50, - 0x19, 0x5d, 0xea, 0x6d, 0x2a, 0x8f, 0x8b, 0x5f, - 0x44, 0x61, 0x17, 0x68, 0x87, 0x73, 0x86, 0x96, - 0x29, 0x52, 0x0f, 0x54, 0x65, 0x5c, 0x13, 0x66, - 0x4e, 0x67, 0xa8, 0x68, 0xe5, 0x6c, 0x06, 0x74, - 0xe2, 0x75, 0x79, 0x7f, 0xcf, 0x88, 0xe1, 0x88, - 0xcc, 0x91, 0xe2, 0x96, 0x3f, 0x53, 0xba, 0x6e, - 0x1d, 0x54, 0xd0, 0x71, 0x98, 0x74, 0xfa, 0x85, - 0xa3, 0x96, 0x57, 0x9c, 0x9f, 0x9e, 0x97, 0x67, - 0xcb, 0x6d, 0xe8, 0x81, 0xcb, 0x7a, 0x20, 0x7b, - 0x92, 0x7c, 0xc0, 0x72, 0x99, 0x70, 0x58, 0x8b, - 0xc0, 0x4e, 0x36, 0x83, 0x3a, 0x52, 0x07, 0x52, - 0xa6, 0x5e, 0xd3, 0x62, 0xd6, 0x7c, 0x85, 0x5b, - 0x1e, 0x6d, 0xb4, 0x66, 0x3b, 0x8f, 0x4c, 0x88, - 0x4d, 0x96, 0x8b, 0x89, 0xd3, 0x5e, 0x40, 0x51, - 0xc0, 0x55, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x58, - 0x00, 0x00, 0x74, 0x66, 0x00, 0x00, 0x00, 0x00, - 0xde, 0x51, 0x2a, 0x73, 0xca, 0x76, 0x3c, 0x79, - 0x5e, 0x79, 0x65, 0x79, 0x8f, 0x79, 0x56, 0x97, - 0xbe, 0x7c, 0xbd, 0x7f, 0x00, 0x00, 0x12, 0x86, - 0x00, 0x00, 0xf8, 0x8a, 0x00, 0x00, 0x00, 0x00, - 0x38, 0x90, 0xfd, 0x90, 0xef, 0x98, 0xfc, 0x98, - 0x28, 0x99, 0xb4, 0x9d, 0xde, 0x90, 0xb7, 0x96, - 0xae, 0x4f, 0xe7, 0x50, 0x4d, 0x51, 0xc9, 0x52, - 0xe4, 0x52, 0x51, 0x53, 0x9d, 0x55, 0x06, 0x56, - 0x68, 0x56, 0x40, 0x58, 0xa8, 0x58, 0x64, 0x5c, - 0x6e, 0x5c, 0x94, 0x60, 0x68, 0x61, 0x8e, 0x61, - 0xf2, 0x61, 0x4f, 0x65, 0xe2, 0x65, 0x91, 0x66, - 0x85, 0x68, 0x77, 0x6d, 0x1a, 0x6e, 0x22, 0x6f, - 0x6e, 0x71, 0x2b, 0x72, 0x22, 0x74, 0x91, 0x78, - 0x3e, 0x79, 0x49, 0x79, 0x48, 0x79, 0x50, 0x79, - 0x56, 0x79, 0x5d, 0x79, 0x8d, 0x79, 0x8e, 0x79, - 0x40, 0x7a, 0x81, 0x7a, 0xc0, 0x7b, 0xf4, 0x7d, - 0x09, 0x7e, 0x41, 0x7e, 0x72, 0x7f, 0x05, 0x80, - 0xed, 0x81, 0x79, 0x82, 0x79, 0x82, 0x57, 0x84, - 0x10, 0x89, 0x96, 0x89, 0x01, 0x8b, 0x39, 0x8b, - 0xd3, 0x8c, 0x08, 0x8d, 0xb6, 0x8f, 0x38, 0x90, - 0xe3, 0x96, 0xff, 0x97, 0x3b, 0x98, 0x75, 0x60, - 0xee, 0x42, 0x18, 0x82, 0x02, 0x26, 0x4e, 0xb5, - 0x51, 0x68, 0x51, 0x80, 0x4f, 0x45, 0x51, 0x80, - 0x51, 0xc7, 0x52, 0xfa, 0x52, 0x9d, 0x55, 0x55, - 0x55, 0x99, 0x55, 0xe2, 0x55, 0x5a, 0x58, 0xb3, - 0x58, 0x44, 0x59, 0x54, 0x59, 0x62, 0x5a, 0x28, - 0x5b, 0xd2, 0x5e, 0xd9, 0x5e, 0x69, 0x5f, 0xad, - 0x5f, 0xd8, 0x60, 0x4e, 0x61, 0x08, 0x61, 0x8e, - 0x61, 0x60, 0x61, 0xf2, 0x61, 0x34, 0x62, 0xc4, - 0x63, 0x1c, 0x64, 0x52, 0x64, 0x56, 0x65, 0x74, - 0x66, 0x17, 0x67, 0x1b, 0x67, 0x56, 0x67, 0x79, - 0x6b, 0xba, 0x6b, 0x41, 0x6d, 0xdb, 0x6e, 0xcb, - 0x6e, 0x22, 0x6f, 0x1e, 0x70, 0x6e, 0x71, 0xa7, - 0x77, 0x35, 0x72, 0xaf, 0x72, 0x2a, 0x73, 0x71, - 0x74, 0x06, 0x75, 0x3b, 0x75, 0x1d, 0x76, 0x1f, - 0x76, 0xca, 0x76, 0xdb, 0x76, 0xf4, 0x76, 0x4a, - 0x77, 0x40, 0x77, 0xcc, 0x78, 0xb1, 0x7a, 0xc0, - 0x7b, 0x7b, 0x7c, 0x5b, 0x7d, 0xf4, 0x7d, 0x3e, - 0x7f, 0x05, 0x80, 0x52, 0x83, 0xef, 0x83, 0x79, - 0x87, 0x41, 0x89, 0x86, 0x89, 0x96, 0x89, 0xbf, - 0x8a, 0xf8, 0x8a, 0xcb, 0x8a, 0x01, 0x8b, 0xfe, - 0x8a, 0xed, 0x8a, 0x39, 0x8b, 0x8a, 0x8b, 0x08, - 0x8d, 0x38, 0x8f, 0x72, 0x90, 0x99, 0x91, 0x76, - 0x92, 0x7c, 0x96, 0xe3, 0x96, 0x56, 0x97, 0xdb, - 0x97, 0xff, 0x97, 0x0b, 0x98, 0x3b, 0x98, 0x12, - 0x9b, 0x9c, 0x9f, 0x4a, 0x28, 0x44, 0x28, 0xd5, - 0x33, 0x9d, 0x3b, 0x18, 0x40, 0x39, 0x40, 0x49, - 0x52, 0xd0, 0x5c, 0xd3, 0x7e, 0x43, 0x9f, 0x8e, - 0x9f, 0x2a, 0xa0, 0x02, 0x66, 0x66, 0x66, 0x69, - 0x66, 0x6c, 0x66, 0x66, 0x69, 0x66, 0x66, 0x6c, - 0x7f, 0x01, 0x74, 0x73, 0x00, 0x74, 0x65, 0x05, - 0x0f, 0x11, 0x0f, 0x00, 0x0f, 0x06, 0x19, 0x11, - 0x0f, 0x08, 0xd9, 0x05, 0xb4, 0x05, 0x00, 0x00, - 0x00, 0x00, 0xf2, 0x05, 0xb7, 0x05, 0xd0, 0x05, - 0x12, 0x00, 0x03, 0x04, 0x0b, 0x0c, 0x0d, 0x18, - 0x1a, 0xe9, 0x05, 0xc1, 0x05, 0xe9, 0x05, 0xc2, - 0x05, 0x49, 0xfb, 0xc1, 0x05, 0x49, 0xfb, 0xc2, - 0x05, 0xd0, 0x05, 0xb7, 0x05, 0xd0, 0x05, 0xb8, - 0x05, 0xd0, 0x05, 0xbc, 0x05, 0xd8, 0x05, 0xbc, - 0x05, 0xde, 0x05, 0xbc, 0x05, 0xe0, 0x05, 0xbc, - 0x05, 0xe3, 0x05, 0xbc, 0x05, 0xb9, 0x05, 0x2d, - 0x03, 0x2e, 0x03, 0x2f, 0x03, 0x30, 0x03, 0x31, - 0x03, 0x1c, 0x00, 0x18, 0x06, 0x22, 0x06, 0x2b, - 0x06, 0xd0, 0x05, 0xdc, 0x05, 0x71, 0x06, 0x00, - 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0f, 0x0f, 0x0f, 0x0f, 0x09, 0x09, 0x09, - 0x09, 0x0e, 0x0e, 0x0e, 0x0e, 0x08, 0x08, 0x08, - 0x08, 0x33, 0x33, 0x33, 0x33, 0x35, 0x35, 0x35, - 0x35, 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, 0x12, - 0x12, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, - 0x16, 0x1c, 0x1c, 0x1b, 0x1b, 0x1d, 0x1d, 0x17, - 0x17, 0x27, 0x27, 0x20, 0x20, 0x38, 0x38, 0x38, - 0x38, 0x3e, 0x3e, 0x3e, 0x3e, 0x42, 0x42, 0x42, - 0x42, 0x40, 0x40, 0x40, 0x40, 0x49, 0x49, 0x4a, - 0x4a, 0x4a, 0x4a, 0x4f, 0x4f, 0x50, 0x50, 0x50, - 0x50, 0x4d, 0x4d, 0x4d, 0x4d, 0x61, 0x61, 0x62, - 0x62, 0x49, 0x06, 0x64, 0x64, 0x64, 0x64, 0x7e, - 0x7e, 0x7d, 0x7d, 0x7f, 0x7f, 0x2e, 0x82, 0x82, - 0x7c, 0x7c, 0x80, 0x80, 0x87, 0x87, 0x87, 0x87, - 0x00, 0x00, 0x26, 0x06, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xaf, 0x00, 0xaf, 0x00, 0x22, 0x00, 0x22, - 0x00, 0xa1, 0x00, 0xa1, 0x00, 0xa0, 0x00, 0xa0, - 0x00, 0xa2, 0x00, 0xa2, 0x00, 0xaa, 0x00, 0xaa, - 0x00, 0xaa, 0x00, 0x23, 0x00, 0x23, 0x00, 0x23, - 0xcc, 0x06, 0x00, 0x00, 0x00, 0x00, 0x26, 0x06, - 0x00, 0x06, 0x00, 0x07, 0x00, 0x1f, 0x00, 0x23, - 0x00, 0x24, 0x02, 0x06, 0x02, 0x07, 0x02, 0x08, - 0x02, 0x1f, 0x02, 0x23, 0x02, 0x24, 0x04, 0x06, - 0x04, 0x07, 0x04, 0x08, 0x04, 0x1f, 0x04, 0x23, - 0x04, 0x24, 0x05, 0x06, 0x05, 0x1f, 0x05, 0x23, - 0x05, 0x24, 0x06, 0x07, 0x06, 0x1f, 0x07, 0x06, - 0x07, 0x1f, 0x08, 0x06, 0x08, 0x07, 0x08, 0x1f, - 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x08, 0x0d, 0x1f, - 0x0f, 0x07, 0x0f, 0x1f, 0x10, 0x06, 0x10, 0x07, - 0x10, 0x08, 0x10, 0x1f, 0x11, 0x07, 0x11, 0x1f, - 0x12, 0x1f, 0x13, 0x06, 0x13, 0x1f, 0x14, 0x06, - 0x14, 0x1f, 0x1b, 0x06, 0x1b, 0x07, 0x1b, 0x08, - 0x1b, 0x1f, 0x1b, 0x23, 0x1b, 0x24, 0x1c, 0x07, - 0x1c, 0x1f, 0x1c, 0x23, 0x1c, 0x24, 0x1d, 0x01, - 0x1d, 0x06, 0x1d, 0x07, 0x1d, 0x08, 0x1d, 0x1e, - 0x1d, 0x1f, 0x1d, 0x23, 0x1d, 0x24, 0x1e, 0x06, - 0x1e, 0x07, 0x1e, 0x08, 0x1e, 0x1f, 0x1e, 0x23, - 0x1e, 0x24, 0x1f, 0x06, 0x1f, 0x07, 0x1f, 0x08, - 0x1f, 0x1f, 0x1f, 0x23, 0x1f, 0x24, 0x20, 0x06, - 0x20, 0x07, 0x20, 0x08, 0x20, 0x1f, 0x20, 0x23, - 0x20, 0x24, 0x21, 0x06, 0x21, 0x1f, 0x21, 0x23, - 0x21, 0x24, 0x24, 0x06, 0x24, 0x07, 0x24, 0x08, - 0x24, 0x1f, 0x24, 0x23, 0x24, 0x24, 0x0a, 0x4a, - 0x0b, 0x4a, 0x23, 0x4a, 0x20, 0x00, 0x4c, 0x06, - 0x51, 0x06, 0x51, 0x06, 0xff, 0x00, 0x1f, 0x26, - 0x06, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x1f, 0x00, - 0x20, 0x00, 0x23, 0x00, 0x24, 0x02, 0x0b, 0x02, - 0x0c, 0x02, 0x1f, 0x02, 0x20, 0x02, 0x23, 0x02, - 0x24, 0x04, 0x0b, 0x04, 0x0c, 0x04, 0x1f, 0x26, - 0x06, 0x04, 0x20, 0x04, 0x23, 0x04, 0x24, 0x05, - 0x0b, 0x05, 0x0c, 0x05, 0x1f, 0x05, 0x20, 0x05, - 0x23, 0x05, 0x24, 0x1b, 0x23, 0x1b, 0x24, 0x1c, - 0x23, 0x1c, 0x24, 0x1d, 0x01, 0x1d, 0x1e, 0x1d, - 0x1f, 0x1d, 0x23, 0x1d, 0x24, 0x1e, 0x1f, 0x1e, - 0x23, 0x1e, 0x24, 0x1f, 0x01, 0x1f, 0x1f, 0x20, - 0x0b, 0x20, 0x0c, 0x20, 0x1f, 0x20, 0x20, 0x20, - 0x23, 0x20, 0x24, 0x23, 0x4a, 0x24, 0x0b, 0x24, - 0x0c, 0x24, 0x1f, 0x24, 0x20, 0x24, 0x23, 0x24, - 0x24, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, - 0x1f, 0x00, 0x21, 0x02, 0x06, 0x02, 0x07, 0x02, - 0x08, 0x02, 0x1f, 0x02, 0x21, 0x04, 0x06, 0x04, - 0x07, 0x04, 0x08, 0x04, 0x1f, 0x04, 0x21, 0x05, - 0x1f, 0x06, 0x07, 0x06, 0x1f, 0x07, 0x06, 0x07, - 0x1f, 0x08, 0x06, 0x08, 0x1f, 0x0d, 0x06, 0x0d, - 0x07, 0x0d, 0x08, 0x0d, 0x1f, 0x0f, 0x07, 0x0f, - 0x08, 0x0f, 0x1f, 0x10, 0x06, 0x10, 0x07, 0x10, - 0x08, 0x10, 0x1f, 0x11, 0x07, 0x12, 0x1f, 0x13, - 0x06, 0x13, 0x1f, 0x14, 0x06, 0x14, 0x1f, 0x1b, - 0x06, 0x1b, 0x07, 0x1b, 0x08, 0x1b, 0x1f, 0x1c, - 0x07, 0x1c, 0x1f, 0x1d, 0x06, 0x1d, 0x07, 0x1d, - 0x08, 0x1d, 0x1e, 0x1d, 0x1f, 0x1e, 0x06, 0x1e, - 0x07, 0x1e, 0x08, 0x1e, 0x1f, 0x1e, 0x21, 0x1f, - 0x06, 0x1f, 0x07, 0x1f, 0x08, 0x1f, 0x1f, 0x20, - 0x06, 0x20, 0x07, 0x20, 0x08, 0x20, 0x1f, 0x20, - 0x21, 0x21, 0x06, 0x21, 0x1f, 0x21, 0x4a, 0x24, - 0x06, 0x24, 0x07, 0x24, 0x08, 0x24, 0x1f, 0x24, - 0x21, 0x00, 0x1f, 0x00, 0x21, 0x02, 0x1f, 0x02, - 0x21, 0x04, 0x1f, 0x04, 0x21, 0x05, 0x1f, 0x05, - 0x21, 0x0d, 0x1f, 0x0d, 0x21, 0x0e, 0x1f, 0x0e, - 0x21, 0x1d, 0x1e, 0x1d, 0x1f, 0x1e, 0x1f, 0x20, - 0x1f, 0x20, 0x21, 0x24, 0x1f, 0x24, 0x21, 0x40, - 0x06, 0x4e, 0x06, 0x51, 0x06, 0x27, 0x06, 0x10, - 0x22, 0x10, 0x23, 0x12, 0x22, 0x12, 0x23, 0x13, - 0x22, 0x13, 0x23, 0x0c, 0x22, 0x0c, 0x23, 0x0d, - 0x22, 0x0d, 0x23, 0x06, 0x22, 0x06, 0x23, 0x05, - 0x22, 0x05, 0x23, 0x07, 0x22, 0x07, 0x23, 0x0e, - 0x22, 0x0e, 0x23, 0x0f, 0x22, 0x0f, 0x23, 0x0d, - 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e, 0x0d, - 0x0a, 0x0c, 0x0a, 0x0e, 0x0a, 0x0f, 0x0a, 0x10, - 0x22, 0x10, 0x23, 0x12, 0x22, 0x12, 0x23, 0x13, - 0x22, 0x13, 0x23, 0x0c, 0x22, 0x0c, 0x23, 0x0d, - 0x22, 0x0d, 0x23, 0x06, 0x22, 0x06, 0x23, 0x05, - 0x22, 0x05, 0x23, 0x07, 0x22, 0x07, 0x23, 0x0e, - 0x22, 0x0e, 0x23, 0x0f, 0x22, 0x0f, 0x23, 0x0d, - 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e, 0x0d, - 0x0a, 0x0c, 0x0a, 0x0e, 0x0a, 0x0f, 0x0a, 0x0d, - 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e, 0x0c, - 0x20, 0x0d, 0x20, 0x10, 0x1e, 0x0c, 0x05, 0x0c, - 0x06, 0x0c, 0x07, 0x0d, 0x05, 0x0d, 0x06, 0x0d, - 0x07, 0x10, 0x1e, 0x11, 0x1e, 0x00, 0x24, 0x00, - 0x24, 0x2a, 0x06, 0x00, 0x02, 0x1b, 0x00, 0x03, - 0x02, 0x00, 0x03, 0x02, 0x00, 0x03, 0x1b, 0x00, - 0x04, 0x1b, 0x00, 0x1b, 0x02, 0x00, 0x1b, 0x03, - 0x00, 0x1b, 0x04, 0x02, 0x1b, 0x03, 0x02, 0x1b, - 0x03, 0x03, 0x1b, 0x20, 0x03, 0x1b, 0x1f, 0x09, - 0x03, 0x02, 0x09, 0x02, 0x03, 0x09, 0x02, 0x1f, - 0x09, 0x1b, 0x03, 0x09, 0x1b, 0x03, 0x09, 0x1b, - 0x02, 0x09, 0x1b, 0x1b, 0x09, 0x1b, 0x1b, 0x0b, - 0x03, 0x03, 0x0b, 0x03, 0x03, 0x0b, 0x1b, 0x1b, - 0x0a, 0x03, 0x1b, 0x0a, 0x03, 0x1b, 0x0a, 0x02, - 0x20, 0x0a, 0x1b, 0x04, 0x0a, 0x1b, 0x04, 0x0a, - 0x1b, 0x1b, 0x0a, 0x1b, 0x1b, 0x0c, 0x03, 0x1f, - 0x0c, 0x04, 0x1b, 0x0c, 0x04, 0x1b, 0x0d, 0x1b, - 0x03, 0x0d, 0x1b, 0x03, 0x0d, 0x1b, 0x1b, 0x0d, - 0x1b, 0x20, 0x0f, 0x02, 0x1b, 0x0f, 0x1b, 0x1b, - 0x0f, 0x1b, 0x1b, 0x0f, 0x1b, 0x1f, 0x10, 0x1b, - 0x1b, 0x10, 0x1b, 0x20, 0x10, 0x1b, 0x1f, 0x17, - 0x04, 0x1b, 0x17, 0x04, 0x1b, 0x18, 0x1b, 0x03, - 0x18, 0x1b, 0x1b, 0x1a, 0x03, 0x1b, 0x1a, 0x03, - 0x20, 0x1a, 0x03, 0x1f, 0x1a, 0x02, 0x02, 0x1a, - 0x02, 0x02, 0x1a, 0x04, 0x1b, 0x1a, 0x04, 0x1b, - 0x1a, 0x1b, 0x03, 0x1a, 0x1b, 0x03, 0x1b, 0x03, - 0x02, 0x1b, 0x03, 0x1b, 0x1b, 0x03, 0x20, 0x1b, - 0x02, 0x03, 0x1b, 0x02, 0x1b, 0x1b, 0x04, 0x02, - 0x1b, 0x04, 0x1b, 0x28, 0x06, 0x1d, 0x04, 0x06, - 0x1f, 0x1d, 0x04, 0x1f, 0x1d, 0x1d, 0x1e, 0x05, - 0x1d, 0x1e, 0x05, 0x21, 0x1e, 0x04, 0x1d, 0x1e, - 0x04, 0x1d, 0x1e, 0x04, 0x21, 0x1e, 0x1d, 0x22, - 0x1e, 0x1d, 0x21, 0x22, 0x1d, 0x1d, 0x22, 0x1d, - 0x1d, 0x00, 0x06, 0x22, 0x02, 0x04, 0x22, 0x02, - 0x04, 0x21, 0x02, 0x06, 0x22, 0x02, 0x06, 0x21, - 0x02, 0x1d, 0x22, 0x02, 0x1d, 0x21, 0x04, 0x1d, - 0x22, 0x04, 0x05, 0x21, 0x04, 0x1d, 0x21, 0x0b, - 0x06, 0x21, 0x0d, 0x05, 0x22, 0x0c, 0x05, 0x22, - 0x0e, 0x05, 0x22, 0x1c, 0x04, 0x22, 0x1c, 0x1d, - 0x22, 0x22, 0x05, 0x22, 0x22, 0x04, 0x22, 0x22, - 0x1d, 0x22, 0x1d, 0x1d, 0x22, 0x1a, 0x1d, 0x22, - 0x1e, 0x05, 0x22, 0x1a, 0x1d, 0x05, 0x1c, 0x05, - 0x1d, 0x11, 0x1d, 0x22, 0x1b, 0x1d, 0x22, 0x1e, - 0x04, 0x05, 0x1d, 0x06, 0x22, 0x1c, 0x04, 0x1d, - 0x1b, 0x1d, 0x1d, 0x1c, 0x04, 0x1d, 0x1e, 0x04, - 0x05, 0x04, 0x05, 0x22, 0x05, 0x04, 0x22, 0x1d, - 0x04, 0x22, 0x19, 0x1d, 0x22, 0x00, 0x05, 0x22, - 0x1b, 0x1d, 0x1d, 0x11, 0x04, 0x1d, 0x0d, 0x1d, - 0x1d, 0x0b, 0x06, 0x22, 0x1e, 0x04, 0x22, 0x35, - 0x06, 0x00, 0x0f, 0x9d, 0x0d, 0x0f, 0x9d, 0x27, - 0x06, 0x00, 0x1d, 0x1d, 0x20, 0x00, 0x1c, 0x01, - 0x0a, 0x1e, 0x06, 0x1e, 0x08, 0x0e, 0x1d, 0x12, - 0x1e, 0x0a, 0x0c, 0x21, 0x1d, 0x12, 0x1d, 0x23, - 0x20, 0x21, 0x0c, 0x1d, 0x1e, 0x35, 0x06, 0x00, - 0x0f, 0x14, 0x27, 0x06, 0x0e, 0x1d, 0x22, 0xff, - 0x00, 0x1d, 0x1d, 0x20, 0xff, 0x12, 0x1d, 0x23, - 0x20, 0xff, 0x21, 0x0c, 0x1d, 0x1e, 0x27, 0x06, - 0x05, 0x1d, 0xff, 0x05, 0x1d, 0x00, 0x1d, 0x20, - 0x27, 0x06, 0x0a, 0xa5, 0x00, 0x1d, 0x2c, 0x00, - 0x01, 0x30, 0x02, 0x30, 0x3a, 0x00, 0x3b, 0x00, - 0x21, 0x00, 0x3f, 0x00, 0x16, 0x30, 0x17, 0x30, - 0x26, 0x20, 0x13, 0x20, 0x12, 0x01, 0x00, 0x5f, - 0x5f, 0x28, 0x29, 0x7b, 0x7d, 0x08, 0x30, 0x0c, - 0x0d, 0x08, 0x09, 0x02, 0x03, 0x00, 0x01, 0x04, - 0x05, 0x06, 0x07, 0x5b, 0x00, 0x5d, 0x00, 0x3e, - 0x20, 0x3e, 0x20, 0x3e, 0x20, 0x3e, 0x20, 0x5f, - 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x2c, 0x00, 0x01, - 0x30, 0x2e, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x3a, - 0x00, 0x3f, 0x00, 0x21, 0x00, 0x14, 0x20, 0x28, - 0x00, 0x29, 0x00, 0x7b, 0x00, 0x7d, 0x00, 0x14, - 0x30, 0x15, 0x30, 0x23, 0x26, 0x2a, 0x2b, 0x2d, - 0x3c, 0x3e, 0x3d, 0x00, 0x5c, 0x24, 0x25, 0x40, - 0x40, 0x06, 0xff, 0x0b, 0x00, 0x0b, 0xff, 0x0c, - 0x20, 0x00, 0x4d, 0x06, 0x40, 0x06, 0xff, 0x0e, - 0x00, 0x0e, 0xff, 0x0f, 0x00, 0x0f, 0xff, 0x10, - 0x00, 0x10, 0xff, 0x11, 0x00, 0x11, 0xff, 0x12, - 0x00, 0x12, 0x21, 0x06, 0x00, 0x01, 0x01, 0x02, - 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x05, - 0x05, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, - 0x08, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, - 0x0f, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x12, - 0x12, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, - 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, - 0x16, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, - 0x18, 0x19, 0x19, 0x19, 0x19, 0x20, 0x20, 0x20, - 0x20, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, - 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, - 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26, - 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29, 0x29, - 0x29, 0x22, 0x06, 0x22, 0x00, 0x22, 0x00, 0x22, - 0x01, 0x22, 0x01, 0x22, 0x03, 0x22, 0x03, 0x22, - 0x05, 0x22, 0x05, 0x21, 0x00, 0x85, 0x29, 0x01, - 0x30, 0x01, 0x0b, 0x0c, 0x00, 0xfa, 0xf1, 0xa0, - 0xa2, 0xa4, 0xa6, 0xa8, 0xe2, 0xe4, 0xe6, 0xc2, - 0xfb, 0xa1, 0xa3, 0xa5, 0xa7, 0xa9, 0xaa, 0xac, - 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, - 0xbe, 0xc0, 0xc3, 0xc5, 0xc7, 0xc9, 0xca, 0xcb, - 0xcc, 0xcd, 0xce, 0xd1, 0xd4, 0xd7, 0xda, 0xdd, - 0xde, 0xdf, 0xe0, 0xe1, 0xe3, 0xe5, 0xe7, 0xe8, - 0xe9, 0xea, 0xeb, 0xec, 0xee, 0xf2, 0x98, 0x99, - 0x31, 0x31, 0x4f, 0x31, 0x55, 0x31, 0x5b, 0x31, - 0x61, 0x31, 0xa2, 0x00, 0xa3, 0x00, 0xac, 0x00, - 0xaf, 0x00, 0xa6, 0x00, 0xa5, 0x00, 0xa9, 0x20, - 0x00, 0x00, 0x02, 0x25, 0x90, 0x21, 0x91, 0x21, - 0x92, 0x21, 0x93, 0x21, 0xa0, 0x25, 0xcb, 0x25, - 0xd2, 0x05, 0x07, 0x03, 0x01, 0xda, 0x05, 0x07, - 0x03, 0x01, 0xd0, 0x02, 0xd1, 0x02, 0xe6, 0x00, - 0x99, 0x02, 0x53, 0x02, 0x00, 0x00, 0xa3, 0x02, - 0x66, 0xab, 0xa5, 0x02, 0xa4, 0x02, 0x56, 0x02, - 0x57, 0x02, 0x91, 0x1d, 0x58, 0x02, 0x5e, 0x02, - 0xa9, 0x02, 0x64, 0x02, 0x62, 0x02, 0x60, 0x02, - 0x9b, 0x02, 0x27, 0x01, 0x9c, 0x02, 0x67, 0x02, - 0x84, 0x02, 0xaa, 0x02, 0xab, 0x02, 0x6c, 0x02, - 0x04, 0xdf, 0x8e, 0xa7, 0x6e, 0x02, 0x05, 0xdf, - 0x8e, 0x02, 0x06, 0xdf, 0xf8, 0x00, 0x76, 0x02, - 0x77, 0x02, 0x71, 0x00, 0x7a, 0x02, 0x08, 0xdf, - 0x7d, 0x02, 0x7e, 0x02, 0x80, 0x02, 0xa8, 0x02, - 0xa6, 0x02, 0x67, 0xab, 0xa7, 0x02, 0x88, 0x02, - 0x71, 0x2c, 0x00, 0x00, 0x8f, 0x02, 0xa1, 0x02, - 0xa2, 0x02, 0x98, 0x02, 0xc0, 0x01, 0xc1, 0x01, - 0xc2, 0x01, 0x0a, 0xdf, 0x1e, 0xdf, 0x41, 0x04, - 0x40, 0x00, 0x00, 0x00, 0x00, 0x14, 0x99, 0x10, - 0xba, 0x10, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x10, - 0xba, 0x10, 0x05, 0x05, 0xa5, 0x10, 0xba, 0x10, - 0x05, 0x31, 0x11, 0x27, 0x11, 0x32, 0x11, 0x27, - 0x11, 0x55, 0x47, 0x13, 0x3e, 0x13, 0x47, 0x13, - 0x57, 0x13, 0x55, 0x82, 0x13, 0xc9, 0x13, 0x00, - 0x00, 0x00, 0x00, 0x84, 0x13, 0xbb, 0x13, 0x05, - 0x05, 0x8b, 0x13, 0xc2, 0x13, 0x05, 0x90, 0x13, - 0xc9, 0x13, 0x05, 0xc2, 0x13, 0xc2, 0x13, 0x00, - 0x00, 0x00, 0x00, 0xc2, 0x13, 0xb8, 0x13, 0xc2, - 0x13, 0xc9, 0x13, 0x05, 0x55, 0xb9, 0x14, 0xba, - 0x14, 0xb9, 0x14, 0xb0, 0x14, 0x00, 0x00, 0x00, - 0x00, 0xb9, 0x14, 0xbd, 0x14, 0x55, 0x50, 0xb8, - 0x15, 0xaf, 0x15, 0xb9, 0x15, 0xaf, 0x15, 0x55, - 0x35, 0x19, 0x30, 0x19, 0x05, 0x1e, 0x61, 0x1e, - 0x61, 0x1e, 0x61, 0x29, 0x61, 0x1e, 0x61, 0x1f, - 0x61, 0x29, 0x61, 0x1f, 0x61, 0x1e, 0x61, 0x20, - 0x61, 0x21, 0x61, 0x1f, 0x61, 0x22, 0x61, 0x1f, - 0x61, 0x21, 0x61, 0x20, 0x61, 0x55, 0x55, 0x55, - 0x55, 0x67, 0x6d, 0x67, 0x6d, 0x63, 0x6d, 0x67, - 0x6d, 0x69, 0x6d, 0x67, 0x6d, 0x55, 0x05, 0x41, - 0x00, 0x30, 0x00, 0x57, 0xd1, 0x65, 0xd1, 0x58, - 0xd1, 0x65, 0xd1, 0x5f, 0xd1, 0x6e, 0xd1, 0x5f, - 0xd1, 0x6f, 0xd1, 0x5f, 0xd1, 0x70, 0xd1, 0x5f, - 0xd1, 0x71, 0xd1, 0x5f, 0xd1, 0x72, 0xd1, 0x55, - 0x55, 0x55, 0x05, 0xb9, 0xd1, 0x65, 0xd1, 0xba, - 0xd1, 0x65, 0xd1, 0xbb, 0xd1, 0x6e, 0xd1, 0xbc, - 0xd1, 0x6e, 0xd1, 0xbb, 0xd1, 0x6f, 0xd1, 0xbc, - 0xd1, 0x6f, 0xd1, 0x55, 0x55, 0x55, 0x41, 0x00, - 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x69, 0x00, - 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x43, 0x44, - 0x00, 0x00, 0x47, 0x00, 0x00, 0x4a, 0x4b, 0x00, - 0x00, 0x4e, 0x4f, 0x50, 0x51, 0x00, 0x53, 0x54, - 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, - 0x63, 0x64, 0x00, 0x66, 0x68, 0x00, 0x70, 0x00, - 0x41, 0x00, 0x61, 0x00, 0x41, 0x42, 0x00, 0x44, - 0x45, 0x46, 0x47, 0x4a, 0x00, 0x53, 0x00, 0x61, - 0x00, 0x41, 0x42, 0x00, 0x44, 0x45, 0x46, 0x47, - 0x00, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x00, 0x4f, - 0x53, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, - 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, - 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, - 0x41, 0x00, 0x61, 0x00, 0x31, 0x01, 0x37, 0x02, - 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, - 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x91, 0x03, - 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00, - 0x1f, 0x04, 0x20, 0x05, 0x91, 0x03, 0xa3, 0x03, - 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00, 0x1f, 0x04, - 0x20, 0x05, 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, - 0xd1, 0x03, 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, - 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, - 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x0b, 0x0c, - 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, - 0x30, 0x00, 0x30, 0x04, 0x3a, 0x04, 0x3e, 0x04, - 0x4b, 0x04, 0x4d, 0x04, 0x4e, 0x04, 0x89, 0xa6, - 0x30, 0x04, 0xa9, 0x26, 0x28, 0xb9, 0x7f, 0x9f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x0a, 0x0b, 0x0e, 0x0f, 0x11, 0x13, 0x14, - 0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x61, 0x26, - 0x25, 0x2f, 0x7b, 0x51, 0xa6, 0xb1, 0x04, 0x27, - 0x06, 0x00, 0x01, 0x05, 0x08, 0x2a, 0x06, 0x1e, - 0x08, 0x03, 0x0d, 0x20, 0x19, 0x1a, 0x1b, 0x1c, - 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00, - 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, 0x44, 0x90, - 0x77, 0x45, 0x28, 0x06, 0x2c, 0x06, 0x00, 0x00, - 0x47, 0x06, 0x33, 0x06, 0x17, 0x10, 0x11, 0x12, - 0x13, 0x00, 0x06, 0x0e, 0x02, 0x0f, 0x34, 0x06, - 0x2a, 0x06, 0x2b, 0x06, 0x2e, 0x06, 0x00, 0x00, - 0x36, 0x06, 0x00, 0x00, 0x3a, 0x06, 0x2d, 0x06, - 0x00, 0x00, 0x4a, 0x06, 0x00, 0x00, 0x44, 0x06, - 0x00, 0x00, 0x46, 0x06, 0x33, 0x06, 0x39, 0x06, - 0x00, 0x00, 0x35, 0x06, 0x42, 0x06, 0x00, 0x00, - 0x34, 0x06, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x06, - 0x00, 0x00, 0x36, 0x06, 0x00, 0x00, 0x3a, 0x06, - 0x00, 0x00, 0xba, 0x06, 0x00, 0x00, 0x6f, 0x06, - 0x00, 0x00, 0x28, 0x06, 0x2c, 0x06, 0x00, 0x00, - 0x47, 0x06, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x06, - 0x37, 0x06, 0x4a, 0x06, 0x43, 0x06, 0x00, 0x00, - 0x45, 0x06, 0x46, 0x06, 0x33, 0x06, 0x39, 0x06, - 0x41, 0x06, 0x35, 0x06, 0x42, 0x06, 0x00, 0x00, - 0x34, 0x06, 0x2a, 0x06, 0x2b, 0x06, 0x2e, 0x06, - 0x00, 0x00, 0x36, 0x06, 0x38, 0x06, 0x3a, 0x06, - 0x6e, 0x06, 0x00, 0x00, 0xa1, 0x06, 0x27, 0x06, - 0x00, 0x01, 0x05, 0x08, 0x20, 0x21, 0x0b, 0x06, - 0x10, 0x23, 0x2a, 0x06, 0x1a, 0x1b, 0x1c, 0x09, - 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00, 0x01, - 0x04, 0x06, 0x0c, 0x0e, 0x10, 0x28, 0x06, 0x2c, - 0x06, 0x2f, 0x06, 0x00, 0x00, 0x48, 0x06, 0x32, - 0x06, 0x2d, 0x06, 0x37, 0x06, 0x4a, 0x06, 0x2a, - 0x06, 0x1a, 0x1b, 0x1c, 0x09, 0x0f, 0x17, 0x0b, - 0x18, 0x07, 0x0a, 0x00, 0x01, 0x04, 0x06, 0x0c, - 0x0e, 0x10, 0x30, 0x2e, 0x30, 0x00, 0x2c, 0x00, - 0x28, 0x00, 0x41, 0x00, 0x29, 0x00, 0x14, 0x30, - 0x53, 0x00, 0x15, 0x30, 0x43, 0x52, 0x43, 0x44, - 0x57, 0x5a, 0x41, 0x00, 0x48, 0x56, 0x4d, 0x56, - 0x53, 0x44, 0x53, 0x53, 0x50, 0x50, 0x56, 0x57, - 0x43, 0x4d, 0x43, 0x4d, 0x44, 0x4d, 0x52, 0x44, - 0x4a, 0x4b, 0x30, 0x30, 0x00, 0x68, 0x68, 0x4b, - 0x62, 0x57, 0x5b, 0xcc, 0x53, 0xc7, 0x30, 0x8c, - 0x4e, 0x1a, 0x59, 0xe3, 0x89, 0x29, 0x59, 0xa4, - 0x4e, 0x20, 0x66, 0x21, 0x71, 0x99, 0x65, 0x4d, - 0x52, 0x8c, 0x5f, 0x8d, 0x51, 0xb0, 0x65, 0x1d, - 0x52, 0x42, 0x7d, 0x1f, 0x75, 0xa9, 0x8c, 0xf0, - 0x58, 0x39, 0x54, 0x14, 0x6f, 0x95, 0x62, 0x55, - 0x63, 0x00, 0x4e, 0x09, 0x4e, 0x4a, 0x90, 0xe6, - 0x5d, 0x2d, 0x4e, 0xf3, 0x53, 0x07, 0x63, 0x70, - 0x8d, 0x53, 0x62, 0x81, 0x79, 0x7a, 0x7a, 0x08, - 0x54, 0x80, 0x6e, 0x09, 0x67, 0x08, 0x67, 0x33, - 0x75, 0x72, 0x52, 0xb6, 0x55, 0x4d, 0x91, 0x14, - 0x30, 0x15, 0x30, 0x2c, 0x67, 0x09, 0x4e, 0x8c, - 0x4e, 0x89, 0x5b, 0xb9, 0x70, 0x53, 0x62, 0xd7, - 0x76, 0xdd, 0x52, 0x57, 0x65, 0x97, 0x5f, 0xef, - 0x53, 0x30, 0x00, 0x38, 0x4e, 0x05, 0x00, 0x09, - 0x22, 0x01, 0x60, 0x4f, 0xae, 0x4f, 0xbb, 0x4f, - 0x02, 0x50, 0x7a, 0x50, 0x99, 0x50, 0xe7, 0x50, - 0xcf, 0x50, 0x9e, 0x34, 0x3a, 0x06, 0x4d, 0x51, - 0x54, 0x51, 0x64, 0x51, 0x77, 0x51, 0x1c, 0x05, - 0xb9, 0x34, 0x67, 0x51, 0x8d, 0x51, 0x4b, 0x05, - 0x97, 0x51, 0xa4, 0x51, 0xcc, 0x4e, 0xac, 0x51, - 0xb5, 0x51, 0xdf, 0x91, 0xf5, 0x51, 0x03, 0x52, - 0xdf, 0x34, 0x3b, 0x52, 0x46, 0x52, 0x72, 0x52, - 0x77, 0x52, 0x15, 0x35, 0x02, 0x00, 0x20, 0x80, - 0x80, 0x00, 0x08, 0x00, 0x00, 0xc7, 0x52, 0x00, - 0x02, 0x1d, 0x33, 0x3e, 0x3f, 0x50, 0x82, 0x8a, - 0x93, 0xac, 0xb6, 0xb8, 0xb8, 0xb8, 0x2c, 0x0a, - 0x70, 0x70, 0xca, 0x53, 0xdf, 0x53, 0x63, 0x0b, - 0xeb, 0x53, 0xf1, 0x53, 0x06, 0x54, 0x9e, 0x54, - 0x38, 0x54, 0x48, 0x54, 0x68, 0x54, 0xa2, 0x54, - 0xf6, 0x54, 0x10, 0x55, 0x53, 0x55, 0x63, 0x55, - 0x84, 0x55, 0x84, 0x55, 0x99, 0x55, 0xab, 0x55, - 0xb3, 0x55, 0xc2, 0x55, 0x16, 0x57, 0x06, 0x56, - 0x17, 0x57, 0x51, 0x56, 0x74, 0x56, 0x07, 0x52, - 0xee, 0x58, 0xce, 0x57, 0xf4, 0x57, 0x0d, 0x58, - 0x8b, 0x57, 0x32, 0x58, 0x31, 0x58, 0xac, 0x58, - 0xe4, 0x14, 0xf2, 0x58, 0xf7, 0x58, 0x06, 0x59, - 0x1a, 0x59, 0x22, 0x59, 0x62, 0x59, 0xa8, 0x16, - 0xea, 0x16, 0xec, 0x59, 0x1b, 0x5a, 0x27, 0x5a, - 0xd8, 0x59, 0x66, 0x5a, 0xee, 0x36, 0xfc, 0x36, - 0x08, 0x5b, 0x3e, 0x5b, 0x3e, 0x5b, 0xc8, 0x19, - 0xc3, 0x5b, 0xd8, 0x5b, 0xe7, 0x5b, 0xf3, 0x5b, - 0x18, 0x1b, 0xff, 0x5b, 0x06, 0x5c, 0x53, 0x5f, - 0x22, 0x5c, 0x81, 0x37, 0x60, 0x5c, 0x6e, 0x5c, - 0xc0, 0x5c, 0x8d, 0x5c, 0xe4, 0x1d, 0x43, 0x5d, - 0xe6, 0x1d, 0x6e, 0x5d, 0x6b, 0x5d, 0x7c, 0x5d, - 0xe1, 0x5d, 0xe2, 0x5d, 0x2f, 0x38, 0xfd, 0x5d, - 0x28, 0x5e, 0x3d, 0x5e, 0x69, 0x5e, 0x62, 0x38, - 0x83, 0x21, 0x7c, 0x38, 0xb0, 0x5e, 0xb3, 0x5e, - 0xb6, 0x5e, 0xca, 0x5e, 0x92, 0xa3, 0xfe, 0x5e, - 0x31, 0x23, 0x31, 0x23, 0x01, 0x82, 0x22, 0x5f, - 0x22, 0x5f, 0xc7, 0x38, 0xb8, 0x32, 0xda, 0x61, - 0x62, 0x5f, 0x6b, 0x5f, 0xe3, 0x38, 0x9a, 0x5f, - 0xcd, 0x5f, 0xd7, 0x5f, 0xf9, 0x5f, 0x81, 0x60, - 0x3a, 0x39, 0x1c, 0x39, 0x94, 0x60, 0xd4, 0x26, - 0xc7, 0x60, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, - 0x02, 0x08, 0x00, 0x80, 0x08, 0x00, 0x00, 0x08, - 0x80, 0x28, 0x80, 0x02, 0x00, 0x00, 0x02, 0x48, - 0x61, 0x00, 0x04, 0x06, 0x04, 0x32, 0x46, 0x6a, - 0x5c, 0x67, 0x96, 0xaa, 0xae, 0xc8, 0xd3, 0x5d, - 0x62, 0x00, 0x54, 0x77, 0xf3, 0x0c, 0x2b, 0x3d, - 0x63, 0xfc, 0x62, 0x68, 0x63, 0x83, 0x63, 0xe4, - 0x63, 0xf1, 0x2b, 0x22, 0x64, 0xc5, 0x63, 0xa9, - 0x63, 0x2e, 0x3a, 0x69, 0x64, 0x7e, 0x64, 0x9d, - 0x64, 0x77, 0x64, 0x6c, 0x3a, 0x4f, 0x65, 0x6c, - 0x65, 0x0a, 0x30, 0xe3, 0x65, 0xf8, 0x66, 0x49, - 0x66, 0x19, 0x3b, 0x91, 0x66, 0x08, 0x3b, 0xe4, - 0x3a, 0x92, 0x51, 0x95, 0x51, 0x00, 0x67, 0x9c, - 0x66, 0xad, 0x80, 0xd9, 0x43, 0x17, 0x67, 0x1b, - 0x67, 0x21, 0x67, 0x5e, 0x67, 0x53, 0x67, 0xc3, - 0x33, 0x49, 0x3b, 0xfa, 0x67, 0x85, 0x67, 0x52, - 0x68, 0x85, 0x68, 0x6d, 0x34, 0x8e, 0x68, 0x1f, - 0x68, 0x14, 0x69, 0x9d, 0x3b, 0x42, 0x69, 0xa3, - 0x69, 0xea, 0x69, 0xa8, 0x6a, 0xa3, 0x36, 0xdb, - 0x6a, 0x18, 0x3c, 0x21, 0x6b, 0xa7, 0x38, 0x54, - 0x6b, 0x4e, 0x3c, 0x72, 0x6b, 0x9f, 0x6b, 0xba, - 0x6b, 0xbb, 0x6b, 0x8d, 0x3a, 0x0b, 0x1d, 0xfa, - 0x3a, 0x4e, 0x6c, 0xbc, 0x3c, 0xbf, 0x6c, 0xcd, - 0x6c, 0x67, 0x6c, 0x16, 0x6d, 0x3e, 0x6d, 0x77, - 0x6d, 0x41, 0x6d, 0x69, 0x6d, 0x78, 0x6d, 0x85, - 0x6d, 0x1e, 0x3d, 0x34, 0x6d, 0x2f, 0x6e, 0x6e, - 0x6e, 0x33, 0x3d, 0xcb, 0x6e, 0xc7, 0x6e, 0xd1, - 0x3e, 0xf9, 0x6d, 0x6e, 0x6f, 0x5e, 0x3f, 0x8e, - 0x3f, 0xc6, 0x6f, 0x39, 0x70, 0x1e, 0x70, 0x1b, - 0x70, 0x96, 0x3d, 0x4a, 0x70, 0x7d, 0x70, 0x77, - 0x70, 0xad, 0x70, 0x25, 0x05, 0x45, 0x71, 0x63, - 0x42, 0x9c, 0x71, 0xab, 0x43, 0x28, 0x72, 0x35, - 0x72, 0x50, 0x72, 0x08, 0x46, 0x80, 0x72, 0x95, - 0x72, 0x35, 0x47, 0x02, 0x20, 0x00, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, - 0x02, 0x02, 0x80, 0x8a, 0x00, 0x00, 0x20, 0x00, - 0x08, 0x0a, 0x00, 0x80, 0x88, 0x80, 0x20, 0x14, - 0x48, 0x7a, 0x73, 0x8b, 0x73, 0xac, 0x3e, 0xa5, - 0x73, 0xb8, 0x3e, 0xb8, 0x3e, 0x47, 0x74, 0x5c, - 0x74, 0x71, 0x74, 0x85, 0x74, 0xca, 0x74, 0x1b, - 0x3f, 0x24, 0x75, 0x36, 0x4c, 0x3e, 0x75, 0x92, - 0x4c, 0x70, 0x75, 0x9f, 0x21, 0x10, 0x76, 0xa1, - 0x4f, 0xb8, 0x4f, 0x44, 0x50, 0xfc, 0x3f, 0x08, - 0x40, 0xf4, 0x76, 0xf3, 0x50, 0xf2, 0x50, 0x19, - 0x51, 0x33, 0x51, 0x1e, 0x77, 0x1f, 0x77, 0x1f, - 0x77, 0x4a, 0x77, 0x39, 0x40, 0x8b, 0x77, 0x46, - 0x40, 0x96, 0x40, 0x1d, 0x54, 0x4e, 0x78, 0x8c, - 0x78, 0xcc, 0x78, 0xe3, 0x40, 0x26, 0x56, 0x56, - 0x79, 0x9a, 0x56, 0xc5, 0x56, 0x8f, 0x79, 0xeb, - 0x79, 0x2f, 0x41, 0x40, 0x7a, 0x4a, 0x7a, 0x4f, - 0x7a, 0x7c, 0x59, 0xa7, 0x5a, 0xa7, 0x5a, 0xee, - 0x7a, 0x02, 0x42, 0xab, 0x5b, 0xc6, 0x7b, 0xc9, - 0x7b, 0x27, 0x42, 0x80, 0x5c, 0xd2, 0x7c, 0xa0, - 0x42, 0xe8, 0x7c, 0xe3, 0x7c, 0x00, 0x7d, 0x86, - 0x5f, 0x63, 0x7d, 0x01, 0x43, 0xc7, 0x7d, 0x02, - 0x7e, 0x45, 0x7e, 0x34, 0x43, 0x28, 0x62, 0x47, - 0x62, 0x59, 0x43, 0xd9, 0x62, 0x7a, 0x7f, 0x3e, - 0x63, 0x95, 0x7f, 0xfa, 0x7f, 0x05, 0x80, 0xda, - 0x64, 0x23, 0x65, 0x60, 0x80, 0xa8, 0x65, 0x70, - 0x80, 0x5f, 0x33, 0xd5, 0x43, 0xb2, 0x80, 0x03, - 0x81, 0x0b, 0x44, 0x3e, 0x81, 0xb5, 0x5a, 0xa7, - 0x67, 0xb5, 0x67, 0x93, 0x33, 0x9c, 0x33, 0x01, - 0x82, 0x04, 0x82, 0x9e, 0x8f, 0x6b, 0x44, 0x91, - 0x82, 0x8b, 0x82, 0x9d, 0x82, 0xb3, 0x52, 0xb1, - 0x82, 0xb3, 0x82, 0xbd, 0x82, 0xe6, 0x82, 0x3c, - 0x6b, 0xe5, 0x82, 0x1d, 0x83, 0x63, 0x83, 0xad, - 0x83, 0x23, 0x83, 0xbd, 0x83, 0xe7, 0x83, 0x57, - 0x84, 0x53, 0x83, 0xca, 0x83, 0xcc, 0x83, 0xdc, - 0x83, 0x36, 0x6c, 0x6b, 0x6d, 0x02, 0x00, 0x00, - 0x20, 0x22, 0x2a, 0xa0, 0x0a, 0x00, 0x20, 0x80, - 0x28, 0x00, 0xa8, 0x20, 0x20, 0x00, 0x02, 0x80, - 0x22, 0x02, 0x8a, 0x08, 0x00, 0xaa, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x00, 0x28, 0xd5, 0x6c, 0x2b, - 0x45, 0xf1, 0x84, 0xf3, 0x84, 0x16, 0x85, 0xca, - 0x73, 0x64, 0x85, 0x2c, 0x6f, 0x5d, 0x45, 0x61, - 0x45, 0xb1, 0x6f, 0xd2, 0x70, 0x6b, 0x45, 0x50, - 0x86, 0x5c, 0x86, 0x67, 0x86, 0x69, 0x86, 0xa9, - 0x86, 0x88, 0x86, 0x0e, 0x87, 0xe2, 0x86, 0x79, - 0x87, 0x28, 0x87, 0x6b, 0x87, 0x86, 0x87, 0xd7, - 0x45, 0xe1, 0x87, 0x01, 0x88, 0xf9, 0x45, 0x60, - 0x88, 0x63, 0x88, 0x67, 0x76, 0xd7, 0x88, 0xde, - 0x88, 0x35, 0x46, 0xfa, 0x88, 0xbb, 0x34, 0xae, - 0x78, 0x66, 0x79, 0xbe, 0x46, 0xc7, 0x46, 0xa0, - 0x8a, 0xed, 0x8a, 0x8a, 0x8b, 0x55, 0x8c, 0xa8, - 0x7c, 0xab, 0x8c, 0xc1, 0x8c, 0x1b, 0x8d, 0x77, - 0x8d, 0x2f, 0x7f, 0x04, 0x08, 0xcb, 0x8d, 0xbc, - 0x8d, 0xf0, 0x8d, 0xde, 0x08, 0xd4, 0x8e, 0x38, - 0x8f, 0xd2, 0x85, 0xed, 0x85, 0x94, 0x90, 0xf1, - 0x90, 0x11, 0x91, 0x2e, 0x87, 0x1b, 0x91, 0x38, - 0x92, 0xd7, 0x92, 0xd8, 0x92, 0x7c, 0x92, 0xf9, - 0x93, 0x15, 0x94, 0xfa, 0x8b, 0x8b, 0x95, 0x95, - 0x49, 0xb7, 0x95, 0x77, 0x8d, 0xe6, 0x49, 0xc3, - 0x96, 0xb2, 0x5d, 0x23, 0x97, 0x45, 0x91, 0x1a, - 0x92, 0x6e, 0x4a, 0x76, 0x4a, 0xe0, 0x97, 0x0a, - 0x94, 0xb2, 0x4a, 0x96, 0x94, 0x0b, 0x98, 0x0b, - 0x98, 0x29, 0x98, 0xb6, 0x95, 0xe2, 0x98, 0x33, - 0x4b, 0x29, 0x99, 0xa7, 0x99, 0xc2, 0x99, 0xfe, - 0x99, 0xce, 0x4b, 0x30, 0x9b, 0x12, 0x9b, 0x40, - 0x9c, 0xfd, 0x9c, 0xce, 0x4c, 0xed, 0x4c, 0x67, - 0x9d, 0xce, 0xa0, 0xf8, 0x4c, 0x05, 0xa1, 0x0e, - 0xa2, 0x91, 0xa2, 0xbb, 0x9e, 0x56, 0x4d, 0xf9, - 0x9e, 0xfe, 0x9e, 0x05, 0x9f, 0x0f, 0x9f, 0x16, - 0x9f, 0x3b, 0x9f, 0x00, 0xa6, 0x02, 0x88, 0xa0, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x28, 0x00, - 0x08, 0xa0, 0x80, 0xa0, 0x80, 0x00, 0x80, 0x80, - 0x00, 0x0a, 0x88, 0x80, 0x00, 0x80, 0x00, 0x20, - 0x2a, 0x00, 0x80, -}; - -static const uint16_t unicode_comp_table[965] = { - 0x4a01, 0x49c0, 0x4a02, 0x0280, 0x0281, 0x0282, 0x0283, 0x02c0, - 0x02c2, 0x0a00, 0x0284, 0x2442, 0x0285, 0x07c0, 0x0980, 0x0982, - 0x2440, 0x2280, 0x02c4, 0x2282, 0x2284, 0x2286, 0x02c6, 0x02c8, - 0x02ca, 0x02cc, 0x0287, 0x228a, 0x02ce, 0x228c, 0x2290, 0x2292, - 0x228e, 0x0288, 0x0289, 0x028a, 0x2482, 0x0300, 0x0302, 0x0304, - 0x028b, 0x2480, 0x0308, 0x0984, 0x0986, 0x2458, 0x0a02, 0x0306, - 0x2298, 0x229a, 0x229e, 0x0900, 0x030a, 0x22a0, 0x030c, 0x030e, - 0x0840, 0x0310, 0x0312, 0x22a2, 0x22a6, 0x09c0, 0x22a4, 0x22a8, - 0x22aa, 0x028c, 0x028d, 0x028e, 0x0340, 0x0342, 0x0344, 0x0380, - 0x028f, 0x248e, 0x07c2, 0x0988, 0x098a, 0x2490, 0x0346, 0x22ac, - 0x0400, 0x22b0, 0x0842, 0x22b2, 0x0402, 0x22b4, 0x0440, 0x0444, - 0x22b6, 0x0442, 0x22c2, 0x22c0, 0x22c4, 0x22c6, 0x22c8, 0x0940, - 0x04c0, 0x0291, 0x22ca, 0x04c4, 0x22cc, 0x04c2, 0x22d0, 0x22ce, - 0x0292, 0x0293, 0x0294, 0x0295, 0x0540, 0x0542, 0x0a08, 0x0296, - 0x2494, 0x0544, 0x07c4, 0x098c, 0x098e, 0x06c0, 0x2492, 0x0844, - 0x2308, 0x230a, 0x0580, 0x230c, 0x0584, 0x0990, 0x0992, 0x230e, - 0x0582, 0x2312, 0x0586, 0x0588, 0x2314, 0x058c, 0x2316, 0x0998, - 0x058a, 0x231e, 0x0590, 0x2320, 0x099a, 0x058e, 0x2324, 0x2322, - 0x0299, 0x029a, 0x029b, 0x05c0, 0x05c2, 0x05c4, 0x029c, 0x24ac, - 0x05c6, 0x05c8, 0x07c6, 0x0994, 0x0996, 0x0700, 0x24aa, 0x2326, - 0x05ca, 0x232a, 0x2328, 0x2340, 0x2342, 0x2344, 0x2346, 0x05cc, - 0x234a, 0x2348, 0x234c, 0x234e, 0x2350, 0x24b8, 0x029d, 0x05ce, - 0x24be, 0x0a0c, 0x2352, 0x0600, 0x24bc, 0x24ba, 0x0640, 0x2354, - 0x0642, 0x0644, 0x2356, 0x2358, 0x02a0, 0x02a1, 0x02a2, 0x02a3, - 0x02c1, 0x02c3, 0x0a01, 0x02a4, 0x2443, 0x02a5, 0x07c1, 0x0981, - 0x0983, 0x2441, 0x2281, 0x02c5, 0x2283, 0x2285, 0x2287, 0x02c7, - 0x02c9, 0x02cb, 0x02cd, 0x02a7, 0x228b, 0x02cf, 0x228d, 0x2291, - 0x2293, 0x228f, 0x02a8, 0x02a9, 0x02aa, 0x2483, 0x0301, 0x0303, - 0x0305, 0x02ab, 0x2481, 0x0309, 0x0985, 0x0987, 0x2459, 0x0a03, - 0x0307, 0x2299, 0x229b, 0x229f, 0x0901, 0x030b, 0x22a1, 0x030d, - 0x030f, 0x0841, 0x0311, 0x0313, 0x22a3, 0x22a7, 0x09c1, 0x22a5, - 0x22a9, 0x22ab, 0x2380, 0x02ac, 0x02ad, 0x02ae, 0x0341, 0x0343, - 0x0345, 0x02af, 0x248f, 0x07c3, 0x0989, 0x098b, 0x2491, 0x0347, - 0x22ad, 0x0401, 0x0884, 0x22b1, 0x0843, 0x22b3, 0x0403, 0x22b5, - 0x0441, 0x0445, 0x22b7, 0x0443, 0x22c3, 0x22c1, 0x22c5, 0x22c7, - 0x22c9, 0x0941, 0x04c1, 0x02b1, 0x22cb, 0x04c5, 0x22cd, 0x04c3, - 0x22d1, 0x22cf, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x0541, 0x0543, - 0x0a09, 0x02b6, 0x2495, 0x0545, 0x07c5, 0x098d, 0x098f, 0x06c1, - 0x2493, 0x0845, 0x2309, 0x230b, 0x0581, 0x230d, 0x0585, 0x0991, - 0x0993, 0x230f, 0x0583, 0x2313, 0x0587, 0x0589, 0x2315, 0x058d, - 0x2317, 0x0999, 0x058b, 0x231f, 0x2381, 0x0591, 0x2321, 0x099b, - 0x058f, 0x2325, 0x2323, 0x02b9, 0x02ba, 0x02bb, 0x05c1, 0x05c3, - 0x05c5, 0x02bc, 0x24ad, 0x05c7, 0x05c9, 0x07c7, 0x0995, 0x0997, - 0x0701, 0x24ab, 0x2327, 0x05cb, 0x232b, 0x2329, 0x2341, 0x2343, - 0x2345, 0x2347, 0x05cd, 0x234b, 0x2349, 0x2382, 0x234d, 0x234f, - 0x2351, 0x24b9, 0x02bd, 0x05cf, 0x24bf, 0x0a0d, 0x2353, 0x02bf, - 0x24bd, 0x2383, 0x24bb, 0x0641, 0x2355, 0x0643, 0x0645, 0x2357, - 0x2359, 0x3101, 0x0c80, 0x2e00, 0x2446, 0x2444, 0x244a, 0x2448, - 0x0800, 0x0942, 0x0944, 0x0804, 0x2288, 0x2486, 0x2484, 0x248a, - 0x2488, 0x22ae, 0x2498, 0x2496, 0x249c, 0x249a, 0x2300, 0x0a06, - 0x2302, 0x0a04, 0x0946, 0x07ce, 0x07ca, 0x07c8, 0x07cc, 0x2447, - 0x2445, 0x244b, 0x2449, 0x0801, 0x0943, 0x0945, 0x0805, 0x2289, - 0x2487, 0x2485, 0x248b, 0x2489, 0x22af, 0x2499, 0x2497, 0x249d, - 0x249b, 0x2301, 0x0a07, 0x2303, 0x0a05, 0x0947, 0x07cf, 0x07cb, - 0x07c9, 0x07cd, 0x2450, 0x244e, 0x2454, 0x2452, 0x2451, 0x244f, - 0x2455, 0x2453, 0x2294, 0x2296, 0x2295, 0x2297, 0x2304, 0x2306, - 0x2305, 0x2307, 0x2318, 0x2319, 0x231a, 0x231b, 0x232c, 0x232d, - 0x232e, 0x232f, 0x2400, 0x24a2, 0x24a0, 0x24a6, 0x24a4, 0x24a8, - 0x24a3, 0x24a1, 0x24a7, 0x24a5, 0x24a9, 0x24b0, 0x24ae, 0x24b4, - 0x24b2, 0x24b6, 0x24b1, 0x24af, 0x24b5, 0x24b3, 0x24b7, 0x0882, - 0x0880, 0x0881, 0x0802, 0x0803, 0x229c, 0x229d, 0x0a0a, 0x0a0b, - 0x0883, 0x0b40, 0x2c8a, 0x0c81, 0x2c89, 0x2c88, 0x2540, 0x2541, - 0x2d00, 0x2e07, 0x0d00, 0x2640, 0x2641, 0x2e80, 0x0d01, 0x26c8, - 0x26c9, 0x2f00, 0x2f84, 0x0d02, 0x2f83, 0x2f82, 0x0d40, 0x26d8, - 0x26d9, 0x3186, 0x0d04, 0x2740, 0x2741, 0x3100, 0x3086, 0x0d06, - 0x3085, 0x3084, 0x0d41, 0x2840, 0x3200, 0x0d07, 0x284f, 0x2850, - 0x3280, 0x2c84, 0x2e03, 0x2857, 0x0d42, 0x2c81, 0x2c80, 0x24c0, - 0x24c1, 0x2c86, 0x2c83, 0x28c0, 0x0d43, 0x25c0, 0x25c1, 0x2940, - 0x0d44, 0x26c0, 0x26c1, 0x2e05, 0x2e02, 0x29c0, 0x0d45, 0x2f05, - 0x2f04, 0x0d80, 0x26d0, 0x26d1, 0x2f80, 0x2a40, 0x0d82, 0x26e0, - 0x26e1, 0x3080, 0x3081, 0x2ac0, 0x0d83, 0x3004, 0x3003, 0x0d81, - 0x27c0, 0x27c1, 0x3082, 0x2b40, 0x0d84, 0x2847, 0x2848, 0x3184, - 0x3181, 0x2f06, 0x0d08, 0x2f81, 0x3005, 0x0d46, 0x3083, 0x3182, - 0x0e00, 0x0e01, 0x0f40, 0x1180, 0x1182, 0x0f03, 0x0f00, 0x11c0, - 0x0f01, 0x1140, 0x1202, 0x1204, 0x0f81, 0x1240, 0x0fc0, 0x1242, - 0x0f80, 0x1244, 0x1284, 0x0f82, 0x1286, 0x1288, 0x128a, 0x12c0, - 0x1282, 0x1181, 0x1183, 0x1043, 0x1040, 0x11c1, 0x1041, 0x1141, - 0x1203, 0x1205, 0x10c1, 0x1241, 0x1000, 0x1243, 0x10c0, 0x1245, - 0x1285, 0x10c2, 0x1287, 0x1289, 0x128b, 0x12c1, 0x1283, 0x1080, - 0x1100, 0x1101, 0x1200, 0x1201, 0x1280, 0x1281, 0x1340, 0x1341, - 0x1343, 0x1342, 0x1344, 0x13c2, 0x1400, 0x13c0, 0x1440, 0x1480, - 0x14c0, 0x1540, 0x1541, 0x1740, 0x1700, 0x1741, 0x17c0, 0x1800, - 0x1802, 0x1801, 0x1840, 0x1880, 0x1900, 0x18c0, 0x18c1, 0x1901, - 0x1940, 0x1942, 0x1941, 0x1980, 0x19c0, 0x19c2, 0x19c1, 0x1c80, - 0x1cc0, 0x1dc0, 0x1f80, 0x2000, 0x2002, 0x2004, 0x2006, 0x2008, - 0x2040, 0x2080, 0x2082, 0x20c0, 0x20c1, 0x2100, 0x22b8, 0x22b9, - 0x2310, 0x2311, 0x231c, 0x231d, 0x244c, 0x2456, 0x244d, 0x2457, - 0x248c, 0x248d, 0x249e, 0x249f, 0x2500, 0x2502, 0x2504, 0x2bc0, - 0x2501, 0x2503, 0x2505, 0x2bc1, 0x2bc2, 0x2bc3, 0x2bc4, 0x2bc5, - 0x2bc6, 0x2bc7, 0x2580, 0x2582, 0x2584, 0x2bc8, 0x2581, 0x2583, - 0x2585, 0x2bc9, 0x2bca, 0x2bcb, 0x2bcc, 0x2bcd, 0x2bce, 0x2bcf, - 0x2600, 0x2602, 0x2601, 0x2603, 0x2680, 0x2682, 0x2681, 0x2683, - 0x26c2, 0x26c4, 0x26c6, 0x2c00, 0x26c3, 0x26c5, 0x26c7, 0x2c01, - 0x2c02, 0x2c03, 0x2c04, 0x2c05, 0x2c06, 0x2c07, 0x26ca, 0x26cc, - 0x26ce, 0x2c08, 0x26cb, 0x26cd, 0x26cf, 0x2c09, 0x2c0a, 0x2c0b, - 0x2c0c, 0x2c0d, 0x2c0e, 0x2c0f, 0x26d2, 0x26d4, 0x26d6, 0x26d3, - 0x26d5, 0x26d7, 0x26da, 0x26dc, 0x26de, 0x26db, 0x26dd, 0x26df, - 0x2700, 0x2702, 0x2701, 0x2703, 0x2780, 0x2782, 0x2781, 0x2783, - 0x2800, 0x2802, 0x2804, 0x2801, 0x2803, 0x2805, 0x2842, 0x2844, - 0x2846, 0x2849, 0x284b, 0x284d, 0x2c40, 0x284a, 0x284c, 0x284e, - 0x2c41, 0x2c42, 0x2c43, 0x2c44, 0x2c45, 0x2c46, 0x2c47, 0x2851, - 0x2853, 0x2855, 0x2c48, 0x2852, 0x2854, 0x2856, 0x2c49, 0x2c4a, - 0x2c4b, 0x2c4c, 0x2c4d, 0x2c4e, 0x2c4f, 0x2c82, 0x2e01, 0x3180, - 0x2c87, 0x2f01, 0x2f02, 0x2f03, 0x2e06, 0x3185, 0x3000, 0x3001, - 0x3002, 0x4640, 0x4641, 0x4680, 0x46c0, 0x46c2, 0x46c1, 0x4700, - 0x4740, 0x4780, 0x47c0, 0x47c2, 0x4900, 0x4940, 0x4980, 0x4982, - 0x4a00, 0x49c2, 0x4a03, 0x4a04, 0x4a40, 0x4a41, 0x4a80, 0x4a81, - 0x4ac0, 0x4ac1, 0x4bc0, 0x4bc1, 0x4b00, 0x4b01, 0x4b40, 0x4b41, - 0x4bc2, 0x4bc3, 0x4b80, 0x4b81, 0x4b82, 0x4b83, 0x4c00, 0x4c01, - 0x4c02, 0x4c03, 0x5600, 0x5440, 0x5442, 0x5444, 0x5446, 0x5448, - 0x544a, 0x544c, 0x544e, 0x5450, 0x5452, 0x5454, 0x5456, 0x5480, - 0x5482, 0x5484, 0x54c0, 0x54c1, 0x5500, 0x5501, 0x5540, 0x5541, - 0x5580, 0x5581, 0x55c0, 0x55c1, 0x5680, 0x58c0, 0x5700, 0x5702, - 0x5704, 0x5706, 0x5708, 0x570a, 0x570c, 0x570e, 0x5710, 0x5712, - 0x5714, 0x5716, 0x5740, 0x5742, 0x5744, 0x5780, 0x5781, 0x57c0, - 0x57c1, 0x5800, 0x5801, 0x5840, 0x5841, 0x5880, 0x5881, 0x5900, - 0x5901, 0x5902, 0x5903, 0x5940, 0x8ec0, 0x8f00, 0x8fc0, 0x8fc2, - 0x9000, 0x9040, 0x9041, 0x9080, 0x9081, 0x90c0, 0x90c2, 0x9100, - 0x9140, 0x9182, 0x9180, 0x9183, 0x91c1, 0x91c0, 0x91c3, 0x9200, - 0x9201, 0x9240, 0x9280, 0x9282, 0x9284, 0x9281, 0x9285, 0x9287, - 0x9286, 0x9283, 0x92c1, 0x92c0, 0x92c2, -}; - -typedef enum { - UNICODE_GC_Cn, - UNICODE_GC_Lu, - UNICODE_GC_Ll, - UNICODE_GC_Lt, - UNICODE_GC_Lm, - UNICODE_GC_Lo, - UNICODE_GC_Mn, - UNICODE_GC_Mc, - UNICODE_GC_Me, - UNICODE_GC_Nd, - UNICODE_GC_Nl, - UNICODE_GC_No, - UNICODE_GC_Sm, - UNICODE_GC_Sc, - UNICODE_GC_Sk, - UNICODE_GC_So, - UNICODE_GC_Pc, - UNICODE_GC_Pd, - UNICODE_GC_Ps, - UNICODE_GC_Pe, - UNICODE_GC_Pi, - UNICODE_GC_Pf, - UNICODE_GC_Po, - UNICODE_GC_Zs, - UNICODE_GC_Zl, - UNICODE_GC_Zp, - UNICODE_GC_Cc, - UNICODE_GC_Cf, - UNICODE_GC_Cs, - UNICODE_GC_Co, - UNICODE_GC_LC, - UNICODE_GC_L, - UNICODE_GC_M, - UNICODE_GC_N, - UNICODE_GC_S, - UNICODE_GC_P, - UNICODE_GC_Z, - UNICODE_GC_C, - UNICODE_GC_COUNT, -} UnicodeGCEnum; - -static const char unicode_gc_name_table[] = - "Cn,Unassigned" "\0" - "Lu,Uppercase_Letter" "\0" - "Ll,Lowercase_Letter" "\0" - "Lt,Titlecase_Letter" "\0" - "Lm,Modifier_Letter" "\0" - "Lo,Other_Letter" "\0" - "Mn,Nonspacing_Mark" "\0" - "Mc,Spacing_Mark" "\0" - "Me,Enclosing_Mark" "\0" - "Nd,Decimal_Number,digit" "\0" - "Nl,Letter_Number" "\0" - "No,Other_Number" "\0" - "Sm,Math_Symbol" "\0" - "Sc,Currency_Symbol" "\0" - "Sk,Modifier_Symbol" "\0" - "So,Other_Symbol" "\0" - "Pc,Connector_Punctuation" "\0" - "Pd,Dash_Punctuation" "\0" - "Ps,Open_Punctuation" "\0" - "Pe,Close_Punctuation" "\0" - "Pi,Initial_Punctuation" "\0" - "Pf,Final_Punctuation" "\0" - "Po,Other_Punctuation" "\0" - "Zs,Space_Separator" "\0" - "Zl,Line_Separator" "\0" - "Zp,Paragraph_Separator" "\0" - "Cc,Control,cntrl" "\0" - "Cf,Format" "\0" - "Cs,Surrogate" "\0" - "Co,Private_Use" "\0" - "LC,Cased_Letter" "\0" - "L,Letter" "\0" - "M,Mark,Combining_Mark" "\0" - "N,Number" "\0" - "S,Symbol" "\0" - "P,Punctuation,punct" "\0" - "Z,Separator" "\0" - "C,Other" "\0" -; - -static const uint8_t unicode_gc_table[4070] = { - 0xfa, 0x18, 0x17, 0x56, 0x0d, 0x56, 0x12, 0x13, - 0x16, 0x0c, 0x16, 0x11, 0x36, 0xe9, 0x02, 0x36, - 0x4c, 0x36, 0xe1, 0x12, 0x12, 0x16, 0x13, 0x0e, - 0x10, 0x0e, 0xe2, 0x12, 0x12, 0x0c, 0x13, 0x0c, - 0xfa, 0x19, 0x17, 0x16, 0x6d, 0x0f, 0x16, 0x0e, - 0x0f, 0x05, 0x14, 0x0c, 0x1b, 0x0f, 0x0e, 0x0f, - 0x0c, 0x2b, 0x0e, 0x02, 0x36, 0x0e, 0x0b, 0x05, - 0x15, 0x4b, 0x16, 0xe1, 0x0f, 0x0c, 0xc1, 0xe2, - 0x10, 0x0c, 0xe2, 0x00, 0xff, 0x30, 0x02, 0xff, - 0x08, 0x02, 0xff, 0x27, 0xbf, 0x22, 0x21, 0x02, - 0x5f, 0x5f, 0x21, 0x22, 0x61, 0x02, 0x21, 0x02, - 0x41, 0x42, 0x21, 0x02, 0x21, 0x02, 0x9f, 0x7f, - 0x02, 0x5f, 0x5f, 0x21, 0x02, 0x5f, 0x3f, 0x02, - 0x05, 0x3f, 0x22, 0x65, 0x01, 0x03, 0x02, 0x01, - 0x03, 0x02, 0x01, 0x03, 0x02, 0xff, 0x08, 0x02, - 0xff, 0x0a, 0x02, 0x01, 0x03, 0x02, 0x5f, 0x21, - 0x02, 0xff, 0x32, 0xa2, 0x21, 0x02, 0x21, 0x22, - 0x5f, 0x41, 0x02, 0xff, 0x00, 0xe2, 0x3c, 0x05, - 0xe2, 0x13, 0xe4, 0x0a, 0x6e, 0xe4, 0x04, 0xee, - 0x06, 0x84, 0xce, 0x04, 0x0e, 0x04, 0xee, 0x09, - 0xe6, 0x68, 0x7f, 0x04, 0x0e, 0x3f, 0x20, 0x04, - 0x42, 0x16, 0x01, 0x60, 0x2e, 0x01, 0x16, 0x41, - 0x00, 0x01, 0x00, 0x21, 0x02, 0xe1, 0x09, 0x00, - 0xe1, 0x01, 0xe2, 0x1b, 0x3f, 0x02, 0x41, 0x42, - 0xff, 0x10, 0x62, 0x3f, 0x0c, 0x5f, 0x3f, 0x02, - 0xe1, 0x2b, 0xe2, 0x28, 0xff, 0x1a, 0x0f, 0x86, - 0x28, 0xff, 0x2f, 0xff, 0x06, 0x02, 0xff, 0x58, - 0x00, 0xe1, 0x1e, 0x20, 0x04, 0xb6, 0xe2, 0x21, - 0x16, 0x11, 0x20, 0x2f, 0x0d, 0x00, 0xe6, 0x25, - 0x11, 0x06, 0x16, 0x26, 0x16, 0x26, 0x16, 0x06, - 0xe0, 0x00, 0xe5, 0x13, 0x60, 0x65, 0x36, 0xe0, - 0x03, 0xbb, 0x4c, 0x36, 0x0d, 0x36, 0x2f, 0xe6, - 0x03, 0x16, 0x1b, 0x56, 0xe5, 0x18, 0x04, 0xe5, - 0x02, 0xe6, 0x0d, 0xe9, 0x02, 0x76, 0x25, 0x06, - 0xe5, 0x5b, 0x16, 0x05, 0xc6, 0x1b, 0x0f, 0xa6, - 0x24, 0x26, 0x0f, 0x66, 0x25, 0xe9, 0x02, 0x45, - 0x2f, 0x05, 0xf6, 0x06, 0x00, 0x1b, 0x05, 0x06, - 0xe5, 0x16, 0xe6, 0x13, 0x20, 0xe5, 0x51, 0xe6, - 0x03, 0x05, 0xe0, 0x06, 0xe9, 0x02, 0xe5, 0x19, - 0xe6, 0x01, 0x24, 0x0f, 0x56, 0x04, 0x20, 0x06, - 0x2d, 0xe5, 0x0e, 0x66, 0x04, 0xe6, 0x01, 0x04, - 0x46, 0x04, 0x86, 0x20, 0xf6, 0x07, 0x00, 0xe5, - 0x11, 0x46, 0x20, 0x16, 0x00, 0xe5, 0x03, 0x80, - 0xe5, 0x10, 0x0e, 0xa5, 0x00, 0x3b, 0x80, 0xe6, - 0x01, 0xe5, 0x21, 0x04, 0xe6, 0x10, 0x1b, 0xe6, - 0x18, 0x07, 0xe5, 0x2e, 0x06, 0x07, 0x06, 0x05, - 0x47, 0xe6, 0x00, 0x67, 0x06, 0x27, 0x05, 0xc6, - 0xe5, 0x02, 0x26, 0x36, 0xe9, 0x02, 0x16, 0x04, - 0xe5, 0x07, 0x06, 0x27, 0x00, 0xe5, 0x00, 0x20, - 0x25, 0x20, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x05, - 0x40, 0x65, 0x20, 0x06, 0x05, 0x47, 0x66, 0x20, - 0x27, 0x20, 0x27, 0x06, 0x05, 0xe0, 0x00, 0x07, - 0x60, 0x25, 0x00, 0x45, 0x26, 0x20, 0xe9, 0x02, - 0x25, 0x2d, 0xab, 0x0f, 0x0d, 0x05, 0x16, 0x06, - 0x20, 0x26, 0x07, 0x00, 0xa5, 0x60, 0x25, 0x20, - 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00, 0x25, - 0x00, 0x25, 0x20, 0x06, 0x00, 0x47, 0x26, 0x60, - 0x26, 0x20, 0x46, 0x40, 0x06, 0xc0, 0x65, 0x00, - 0x05, 0xc0, 0xe9, 0x02, 0x26, 0x45, 0x06, 0x16, - 0xe0, 0x02, 0x26, 0x07, 0x00, 0xe5, 0x01, 0x00, - 0x45, 0x00, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, - 0x00, 0x85, 0x20, 0x06, 0x05, 0x47, 0x86, 0x00, - 0x26, 0x07, 0x00, 0x27, 0x06, 0x20, 0x05, 0xe0, - 0x07, 0x25, 0x26, 0x20, 0xe9, 0x02, 0x16, 0x0d, - 0xc0, 0x05, 0xa6, 0x00, 0x06, 0x27, 0x00, 0xe5, - 0x00, 0x20, 0x25, 0x20, 0xe5, 0x0e, 0x00, 0xc5, - 0x00, 0x25, 0x00, 0x85, 0x20, 0x06, 0x05, 0x07, - 0x06, 0x07, 0x66, 0x20, 0x27, 0x20, 0x27, 0x06, - 0xc0, 0x26, 0x07, 0x60, 0x25, 0x00, 0x45, 0x26, - 0x20, 0xe9, 0x02, 0x0f, 0x05, 0xab, 0xe0, 0x02, - 0x06, 0x05, 0x00, 0xa5, 0x40, 0x45, 0x00, 0x65, - 0x40, 0x25, 0x00, 0x05, 0x00, 0x25, 0x40, 0x25, - 0x40, 0x45, 0x40, 0xe5, 0x04, 0x60, 0x27, 0x06, - 0x27, 0x40, 0x47, 0x00, 0x47, 0x06, 0x20, 0x05, - 0xa0, 0x07, 0xe0, 0x06, 0xe9, 0x02, 0x4b, 0xaf, - 0x0d, 0x0f, 0x80, 0x06, 0x47, 0x06, 0xe5, 0x00, - 0x00, 0x45, 0x00, 0xe5, 0x0f, 0x00, 0xe5, 0x08, - 0x20, 0x06, 0x05, 0x46, 0x67, 0x00, 0x46, 0x00, - 0x66, 0xc0, 0x26, 0x00, 0x45, 0x20, 0x05, 0x20, - 0x25, 0x26, 0x20, 0xe9, 0x02, 0xc0, 0x16, 0xcb, - 0x0f, 0x05, 0x06, 0x27, 0x16, 0xe5, 0x00, 0x00, - 0x45, 0x00, 0xe5, 0x0f, 0x00, 0xe5, 0x02, 0x00, - 0x85, 0x20, 0x06, 0x05, 0x07, 0x06, 0x87, 0x00, - 0x06, 0x27, 0x00, 0x27, 0x26, 0xc0, 0x27, 0xa0, - 0x25, 0x00, 0x25, 0x26, 0x20, 0xe9, 0x02, 0x00, - 0x25, 0x07, 0xe0, 0x04, 0x26, 0x27, 0xe5, 0x01, - 0x00, 0x45, 0x00, 0xe5, 0x21, 0x26, 0x05, 0x47, - 0x66, 0x00, 0x47, 0x00, 0x47, 0x06, 0x05, 0x0f, - 0x60, 0x45, 0x07, 0xcb, 0x45, 0x26, 0x20, 0xe9, - 0x02, 0xeb, 0x01, 0x0f, 0xa5, 0x00, 0x06, 0x27, - 0x00, 0xe5, 0x0a, 0x40, 0xe5, 0x10, 0x00, 0xe5, - 0x01, 0x00, 0x05, 0x20, 0xc5, 0x40, 0x06, 0x60, - 0x47, 0x46, 0x00, 0x06, 0x00, 0xe7, 0x00, 0xa0, - 0xe9, 0x02, 0x20, 0x27, 0x16, 0xe0, 0x04, 0xe5, - 0x28, 0x06, 0x25, 0xc6, 0x60, 0x0d, 0xa5, 0x04, - 0xe6, 0x00, 0x16, 0xe9, 0x02, 0x36, 0xe0, 0x1d, - 0x25, 0x00, 0x05, 0x00, 0x85, 0x00, 0xe5, 0x10, - 0x00, 0x05, 0x00, 0xe5, 0x02, 0x06, 0x25, 0xe6, - 0x01, 0x05, 0x20, 0x85, 0x00, 0x04, 0x00, 0xc6, - 0x00, 0xe9, 0x02, 0x20, 0x65, 0xe0, 0x18, 0x05, - 0x4f, 0xf6, 0x07, 0x0f, 0x16, 0x4f, 0x26, 0xaf, - 0xe9, 0x02, 0xeb, 0x02, 0x0f, 0x06, 0x0f, 0x06, - 0x0f, 0x06, 0x12, 0x13, 0x12, 0x13, 0x27, 0xe5, - 0x00, 0x00, 0xe5, 0x1c, 0x60, 0xe6, 0x06, 0x07, - 0x86, 0x16, 0x26, 0x85, 0xe6, 0x03, 0x00, 0xe6, - 0x1c, 0x00, 0xef, 0x00, 0x06, 0xaf, 0x00, 0x2f, - 0x96, 0x6f, 0x36, 0xe0, 0x1d, 0xe5, 0x23, 0x27, - 0x66, 0x07, 0xa6, 0x07, 0x26, 0x27, 0x26, 0x05, - 0xe9, 0x02, 0xb6, 0xa5, 0x27, 0x26, 0x65, 0x46, - 0x05, 0x47, 0x25, 0xc7, 0x45, 0x66, 0xe5, 0x05, - 0x06, 0x27, 0x26, 0xa7, 0x06, 0x05, 0x07, 0xe9, - 0x02, 0x47, 0x06, 0x2f, 0xe1, 0x1e, 0x00, 0x01, - 0x80, 0x01, 0x20, 0xe2, 0x23, 0x16, 0x04, 0x42, - 0xe5, 0x80, 0xc1, 0x00, 0x65, 0x20, 0xc5, 0x00, - 0x05, 0x00, 0x65, 0x20, 0xe5, 0x21, 0x00, 0x65, - 0x20, 0xe5, 0x19, 0x00, 0x65, 0x20, 0xc5, 0x00, - 0x05, 0x00, 0x65, 0x20, 0xe5, 0x07, 0x00, 0xe5, - 0x31, 0x00, 0x65, 0x20, 0xe5, 0x3b, 0x20, 0x46, - 0xf6, 0x01, 0xeb, 0x0c, 0x40, 0xe5, 0x08, 0xef, - 0x02, 0xa0, 0xe1, 0x4e, 0x20, 0xa2, 0x20, 0x11, - 0xe5, 0x81, 0xe4, 0x0f, 0x16, 0xe5, 0x09, 0x17, - 0xe5, 0x12, 0x12, 0x13, 0x40, 0xe5, 0x43, 0x56, - 0x4a, 0xe5, 0x00, 0xc0, 0xe5, 0x0a, 0x46, 0x07, - 0xe0, 0x01, 0xe5, 0x0b, 0x26, 0x07, 0x36, 0xe0, - 0x01, 0xe5, 0x0a, 0x26, 0xe0, 0x04, 0xe5, 0x05, - 0x00, 0x45, 0x00, 0x26, 0xe0, 0x04, 0xe5, 0x2c, - 0x26, 0x07, 0xc6, 0xe7, 0x00, 0x06, 0x27, 0xe6, - 0x03, 0x56, 0x04, 0x56, 0x0d, 0x05, 0x06, 0x20, - 0xe9, 0x02, 0xa0, 0xeb, 0x02, 0xa0, 0xb6, 0x11, - 0x76, 0x46, 0x1b, 0x06, 0xe9, 0x02, 0xa0, 0xe5, - 0x1b, 0x04, 0xe5, 0x2d, 0xc0, 0x85, 0x26, 0xe5, - 0x1a, 0x06, 0x05, 0x80, 0xe5, 0x3e, 0xe0, 0x02, - 0xe5, 0x17, 0x00, 0x46, 0x67, 0x26, 0x47, 0x60, - 0x27, 0x06, 0xa7, 0x46, 0x60, 0x0f, 0x40, 0x36, - 0xe9, 0x02, 0xe5, 0x16, 0x20, 0x85, 0xe0, 0x03, - 0xe5, 0x24, 0x60, 0xe5, 0x12, 0xa0, 0xe9, 0x02, - 0x0b, 0x40, 0xef, 0x1a, 0xe5, 0x0f, 0x26, 0x27, - 0x06, 0x20, 0x36, 0xe5, 0x2d, 0x07, 0x06, 0x07, - 0xc6, 0x00, 0x06, 0x07, 0x06, 0x27, 0xe6, 0x00, - 0xa7, 0xe6, 0x02, 0x20, 0x06, 0xe9, 0x02, 0xa0, - 0xe9, 0x02, 0xa0, 0xd6, 0x04, 0xb6, 0x20, 0xe6, - 0x06, 0x08, 0xe6, 0x08, 0xe0, 0x29, 0x66, 0x07, - 0xe5, 0x27, 0x06, 0x07, 0x86, 0x07, 0x06, 0x87, - 0x06, 0x27, 0xe5, 0x00, 0x00, 0x36, 0xe9, 0x02, - 0xd6, 0xef, 0x02, 0xe6, 0x01, 0xef, 0x01, 0x56, - 0x26, 0x07, 0xe5, 0x16, 0x07, 0x66, 0x27, 0x26, - 0x07, 0x46, 0x25, 0xe9, 0x02, 0xe5, 0x24, 0x06, - 0x07, 0x26, 0x47, 0x06, 0x07, 0x46, 0x27, 0xe0, - 0x00, 0x76, 0xe5, 0x1c, 0xe7, 0x00, 0xe6, 0x00, - 0x27, 0x26, 0x40, 0x96, 0xe9, 0x02, 0x40, 0x45, - 0xe9, 0x02, 0xe5, 0x16, 0xa4, 0x36, 0xe2, 0x01, - 0x3f, 0x80, 0xe1, 0x23, 0x20, 0x41, 0xf6, 0x00, - 0xe0, 0x00, 0x46, 0x16, 0xe6, 0x05, 0x07, 0xc6, - 0x65, 0x06, 0xa5, 0x06, 0x25, 0x07, 0x26, 0x05, - 0x80, 0xe2, 0x24, 0xe4, 0x37, 0xe2, 0x05, 0x04, - 0xe2, 0x1a, 0xe4, 0x1d, 0xe6, 0x38, 0xff, 0x80, - 0x0e, 0xe2, 0x00, 0xff, 0x5a, 0xe2, 0x00, 0xe1, - 0x00, 0xa2, 0x20, 0xa1, 0x20, 0xe2, 0x00, 0xe1, - 0x00, 0xe2, 0x00, 0xe1, 0x00, 0xa2, 0x20, 0xa1, - 0x20, 0xe2, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x3f, 0xc2, 0xe1, 0x00, 0xe2, 0x06, - 0x20, 0xe2, 0x00, 0xe3, 0x00, 0xe2, 0x00, 0xe3, - 0x00, 0xe2, 0x00, 0xe3, 0x00, 0x82, 0x00, 0x22, - 0x61, 0x03, 0x0e, 0x02, 0x4e, 0x42, 0x00, 0x22, - 0x61, 0x03, 0x4e, 0x62, 0x20, 0x22, 0x61, 0x00, - 0x4e, 0xe2, 0x00, 0x81, 0x4e, 0x20, 0x42, 0x00, - 0x22, 0x61, 0x03, 0x2e, 0x00, 0xf7, 0x03, 0x9b, - 0xb1, 0x36, 0x14, 0x15, 0x12, 0x34, 0x15, 0x12, - 0x14, 0xf6, 0x00, 0x18, 0x19, 0x9b, 0x17, 0xf6, - 0x01, 0x14, 0x15, 0x76, 0x30, 0x56, 0x0c, 0x12, - 0x13, 0xf6, 0x03, 0x0c, 0x16, 0x10, 0xf6, 0x02, - 0x17, 0x9b, 0x00, 0xfb, 0x02, 0x0b, 0x04, 0x20, - 0xab, 0x4c, 0x12, 0x13, 0x04, 0xeb, 0x02, 0x4c, - 0x12, 0x13, 0x00, 0xe4, 0x05, 0x40, 0xed, 0x19, - 0xe0, 0x07, 0xe6, 0x05, 0x68, 0x06, 0x48, 0xe6, - 0x04, 0xe0, 0x07, 0x2f, 0x01, 0x6f, 0x01, 0x2f, - 0x02, 0x41, 0x22, 0x41, 0x02, 0x0f, 0x01, 0x2f, - 0x0c, 0x81, 0xaf, 0x01, 0x0f, 0x01, 0x0f, 0x01, - 0x0f, 0x61, 0x0f, 0x02, 0x61, 0x02, 0x65, 0x02, - 0x2f, 0x22, 0x21, 0x8c, 0x3f, 0x42, 0x0f, 0x0c, - 0x2f, 0x02, 0x0f, 0xeb, 0x08, 0xea, 0x1b, 0x3f, - 0x6a, 0x0b, 0x2f, 0x60, 0x8c, 0x8f, 0x2c, 0x6f, - 0x0c, 0x2f, 0x0c, 0x2f, 0x0c, 0xcf, 0x0c, 0xef, - 0x17, 0x2c, 0x2f, 0x0c, 0x0f, 0x0c, 0xef, 0x17, - 0xec, 0x80, 0x84, 0xef, 0x00, 0x12, 0x13, 0x12, - 0x13, 0xef, 0x0c, 0x2c, 0xcf, 0x12, 0x13, 0xef, - 0x49, 0x0c, 0xef, 0x16, 0xec, 0x11, 0xef, 0x20, - 0xac, 0xef, 0x40, 0xe0, 0x0e, 0xef, 0x03, 0xe0, - 0x0d, 0xeb, 0x34, 0xef, 0x46, 0xeb, 0x0e, 0xef, - 0x80, 0x2f, 0x0c, 0xef, 0x01, 0x0c, 0xef, 0x2e, - 0xec, 0x00, 0xef, 0x67, 0x0c, 0xef, 0x80, 0x70, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0xeb, 0x16, - 0xef, 0x24, 0x8c, 0x12, 0x13, 0xec, 0x17, 0x12, - 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, - 0x13, 0xec, 0x08, 0xef, 0x80, 0x78, 0xec, 0x7b, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0xec, 0x37, - 0x12, 0x13, 0x12, 0x13, 0xec, 0x18, 0x12, 0x13, - 0xec, 0x80, 0x7a, 0xef, 0x28, 0xec, 0x0d, 0x2f, - 0xac, 0xef, 0x1f, 0x20, 0xef, 0x18, 0x00, 0xef, - 0x61, 0xe1, 0x28, 0xe2, 0x28, 0x5f, 0x21, 0x22, - 0xdf, 0x41, 0x02, 0x3f, 0x02, 0x3f, 0x82, 0x24, - 0x41, 0x02, 0xff, 0x5a, 0x02, 0xaf, 0x7f, 0x46, - 0x3f, 0x80, 0x76, 0x0b, 0x36, 0xe2, 0x1e, 0x00, - 0x02, 0x80, 0x02, 0x20, 0xe5, 0x30, 0xc0, 0x04, - 0x16, 0xe0, 0x06, 0x06, 0xe5, 0x0f, 0xe0, 0x01, - 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, - 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, - 0xe6, 0x18, 0x36, 0x14, 0x15, 0x14, 0x15, 0x56, - 0x14, 0x15, 0x16, 0x14, 0x15, 0xf6, 0x01, 0x11, - 0x36, 0x11, 0x16, 0x14, 0x15, 0x36, 0x14, 0x15, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, - 0x96, 0x04, 0xf6, 0x02, 0x31, 0x76, 0x11, 0x16, - 0x12, 0xf6, 0x05, 0x2f, 0x56, 0x12, 0x13, 0x12, - 0x13, 0x12, 0x13, 0x12, 0x13, 0x11, 0xe0, 0x1a, - 0xef, 0x12, 0x00, 0xef, 0x51, 0xe0, 0x04, 0xef, - 0x80, 0x4e, 0xe0, 0x12, 0xef, 0x08, 0x17, 0x56, - 0x0f, 0x04, 0x05, 0x0a, 0x12, 0x13, 0x12, 0x13, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x2f, 0x12, - 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x11, - 0x12, 0x33, 0x0f, 0xea, 0x01, 0x66, 0x27, 0x11, - 0x84, 0x2f, 0x4a, 0x04, 0x05, 0x16, 0x2f, 0x00, - 0xe5, 0x4e, 0x20, 0x26, 0x2e, 0x24, 0x05, 0x11, - 0xe5, 0x52, 0x16, 0x44, 0x05, 0x80, 0xe5, 0x23, - 0x00, 0xe5, 0x56, 0x00, 0x2f, 0x6b, 0xef, 0x02, - 0xe5, 0x18, 0xef, 0x1e, 0xe0, 0x01, 0x0f, 0xe5, - 0x08, 0xef, 0x17, 0x00, 0xeb, 0x02, 0xef, 0x16, - 0xeb, 0x00, 0x0f, 0xeb, 0x07, 0xef, 0x18, 0xeb, - 0x02, 0xef, 0x1f, 0xeb, 0x07, 0xef, 0x80, 0xb8, - 0xe5, 0x99, 0x38, 0xef, 0x38, 0xe5, 0xc0, 0x11, - 0x8d, 0x04, 0xe5, 0x83, 0xef, 0x40, 0xef, 0x2f, - 0xe0, 0x01, 0xe5, 0x20, 0xa4, 0x36, 0xe5, 0x80, - 0x84, 0x04, 0x56, 0xe5, 0x08, 0xe9, 0x02, 0x25, - 0xe0, 0x0c, 0xff, 0x26, 0x05, 0x06, 0x48, 0x16, - 0xe6, 0x02, 0x16, 0x04, 0xff, 0x14, 0x24, 0x26, - 0xe5, 0x3e, 0xea, 0x02, 0x26, 0xb6, 0xe0, 0x00, - 0xee, 0x0f, 0xe4, 0x01, 0x2e, 0xff, 0x06, 0x22, - 0xff, 0x36, 0x04, 0xe2, 0x00, 0x9f, 0xff, 0x02, - 0x04, 0x2e, 0x7f, 0x05, 0x7f, 0x22, 0xff, 0x0d, - 0x61, 0x02, 0x81, 0x02, 0xff, 0x07, 0x41, 0x02, - 0x5f, 0x3f, 0x20, 0x3f, 0x00, 0x02, 0x00, 0x02, - 0xdf, 0xe0, 0x0d, 0x44, 0x3f, 0x05, 0x24, 0x02, - 0xc5, 0x06, 0x45, 0x06, 0x65, 0x06, 0xe5, 0x0f, - 0x27, 0x26, 0x07, 0x6f, 0x06, 0x40, 0xab, 0x2f, - 0x0d, 0x0f, 0xa0, 0xe5, 0x2c, 0x76, 0xe0, 0x00, - 0x27, 0xe5, 0x2a, 0xe7, 0x08, 0x26, 0xe0, 0x00, - 0x36, 0xe9, 0x02, 0xa0, 0xe6, 0x0a, 0xa5, 0x56, - 0x05, 0x16, 0x25, 0x06, 0xe9, 0x02, 0xe5, 0x14, - 0xe6, 0x00, 0x36, 0xe5, 0x0f, 0xe6, 0x03, 0x27, - 0xe0, 0x03, 0x16, 0xe5, 0x15, 0x40, 0x46, 0x07, - 0xe5, 0x27, 0x06, 0x27, 0x66, 0x27, 0x26, 0x47, - 0xf6, 0x05, 0x00, 0x04, 0xe9, 0x02, 0x60, 0x36, - 0x85, 0x06, 0x04, 0xe5, 0x01, 0xe9, 0x02, 0x85, - 0x00, 0xe5, 0x21, 0xa6, 0x27, 0x26, 0x27, 0x26, - 0xe0, 0x01, 0x45, 0x06, 0xe5, 0x00, 0x06, 0x07, - 0x20, 0xe9, 0x02, 0x20, 0x76, 0xe5, 0x08, 0x04, - 0xa5, 0x4f, 0x05, 0x07, 0x06, 0x07, 0xe5, 0x2a, - 0x06, 0x05, 0x46, 0x25, 0x26, 0x85, 0x26, 0x05, - 0x06, 0x05, 0xe0, 0x10, 0x25, 0x04, 0x36, 0xe5, - 0x03, 0x07, 0x26, 0x27, 0x36, 0x05, 0x24, 0x07, - 0x06, 0xe0, 0x02, 0xa5, 0x20, 0xa5, 0x20, 0xa5, - 0xe0, 0x01, 0xc5, 0x00, 0xc5, 0x00, 0xe2, 0x23, - 0x0e, 0x64, 0xe2, 0x01, 0x04, 0x2e, 0x60, 0xe2, - 0x48, 0xe5, 0x1b, 0x27, 0x06, 0x27, 0x06, 0x27, - 0x16, 0x07, 0x06, 0x20, 0xe9, 0x02, 0xa0, 0xe5, - 0xab, 0x1c, 0xe0, 0x04, 0xe5, 0x0f, 0x60, 0xe5, - 0x29, 0x60, 0xfc, 0x87, 0x78, 0xfd, 0x98, 0x78, - 0xe5, 0x80, 0xe6, 0x20, 0xe5, 0x62, 0xe0, 0x1e, - 0xc2, 0xe0, 0x04, 0x82, 0x80, 0x05, 0x06, 0xe5, - 0x02, 0x0c, 0xe5, 0x05, 0x00, 0x85, 0x00, 0x05, - 0x00, 0x25, 0x00, 0x25, 0x00, 0xe5, 0x64, 0xee, - 0x09, 0xe0, 0x08, 0xe5, 0x80, 0xe3, 0x13, 0x12, - 0xef, 0x08, 0xe5, 0x38, 0x20, 0xe5, 0x2e, 0xc0, - 0x0f, 0xe0, 0x18, 0xe5, 0x04, 0x0d, 0x4f, 0xe6, - 0x08, 0xd6, 0x12, 0x13, 0x16, 0xa0, 0xe6, 0x08, - 0x16, 0x31, 0x30, 0x12, 0x13, 0x12, 0x13, 0x12, - 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, - 0x13, 0x12, 0x13, 0x36, 0x12, 0x13, 0x76, 0x50, - 0x56, 0x00, 0x76, 0x11, 0x12, 0x13, 0x12, 0x13, - 0x12, 0x13, 0x56, 0x0c, 0x11, 0x4c, 0x00, 0x16, - 0x0d, 0x36, 0x60, 0x85, 0x00, 0xe5, 0x7f, 0x20, - 0x1b, 0x00, 0x56, 0x0d, 0x56, 0x12, 0x13, 0x16, - 0x0c, 0x16, 0x11, 0x36, 0xe9, 0x02, 0x36, 0x4c, - 0x36, 0xe1, 0x12, 0x12, 0x16, 0x13, 0x0e, 0x10, - 0x0e, 0xe2, 0x12, 0x12, 0x0c, 0x13, 0x0c, 0x12, - 0x13, 0x16, 0x12, 0x13, 0x36, 0xe5, 0x02, 0x04, - 0xe5, 0x25, 0x24, 0xe5, 0x17, 0x40, 0xa5, 0x20, - 0xa5, 0x20, 0xa5, 0x20, 0x45, 0x40, 0x2d, 0x0c, - 0x0e, 0x0f, 0x2d, 0x00, 0x0f, 0x6c, 0x2f, 0xe0, - 0x02, 0x5b, 0x2f, 0x20, 0xe5, 0x04, 0x00, 0xe5, - 0x12, 0x00, 0xe5, 0x0b, 0x00, 0x25, 0x00, 0xe5, - 0x07, 0x20, 0xe5, 0x06, 0xe0, 0x1a, 0xe5, 0x73, - 0x80, 0x56, 0x60, 0xeb, 0x25, 0x40, 0xef, 0x01, - 0xea, 0x2d, 0x6b, 0xef, 0x09, 0x2b, 0x4f, 0x00, - 0xef, 0x05, 0x40, 0x0f, 0xe0, 0x27, 0xef, 0x25, - 0x06, 0xe0, 0x7a, 0xe5, 0x15, 0x40, 0xe5, 0x29, - 0xe0, 0x07, 0x06, 0xeb, 0x13, 0x60, 0xe5, 0x18, - 0x6b, 0xe0, 0x01, 0xe5, 0x0c, 0x0a, 0xe5, 0x00, - 0x0a, 0x80, 0xe5, 0x1e, 0x86, 0x80, 0xe5, 0x16, - 0x00, 0x16, 0xe5, 0x1c, 0x60, 0xe5, 0x00, 0x16, - 0x8a, 0xe0, 0x22, 0xe1, 0x20, 0xe2, 0x20, 0xe5, - 0x46, 0x20, 0xe9, 0x02, 0xa0, 0xe1, 0x1c, 0x60, - 0xe2, 0x1c, 0x60, 0xe5, 0x20, 0xe0, 0x00, 0xe5, - 0x2c, 0xe0, 0x03, 0x16, 0xe1, 0x03, 0x00, 0xe1, - 0x07, 0x00, 0xc1, 0x00, 0x21, 0x00, 0xe2, 0x03, - 0x00, 0xe2, 0x07, 0x00, 0xc2, 0x00, 0x22, 0x40, - 0xe5, 0x2c, 0xe0, 0x04, 0xe5, 0x80, 0xaf, 0xe0, - 0x01, 0xe5, 0x0e, 0xe0, 0x02, 0xe5, 0x00, 0xe0, - 0x10, 0xa4, 0x00, 0xe4, 0x22, 0x00, 0xe4, 0x01, - 0xe0, 0x3d, 0xa5, 0x20, 0x05, 0x00, 0xe5, 0x24, - 0x00, 0x25, 0x40, 0x05, 0x20, 0xe5, 0x0f, 0x00, - 0x16, 0xeb, 0x00, 0xe5, 0x0f, 0x2f, 0xcb, 0xe5, - 0x17, 0xe0, 0x00, 0xeb, 0x01, 0xe0, 0x28, 0xe5, - 0x0b, 0x00, 0x25, 0x80, 0x8b, 0xe5, 0x0e, 0xab, - 0x40, 0x16, 0xe5, 0x12, 0x80, 0x16, 0xe0, 0x38, - 0xe5, 0x30, 0x60, 0x2b, 0x25, 0xeb, 0x08, 0x20, - 0xeb, 0x26, 0x05, 0x46, 0x00, 0x26, 0x80, 0x66, - 0x65, 0x00, 0x45, 0x00, 0xe5, 0x15, 0x20, 0x46, - 0x60, 0x06, 0xeb, 0x01, 0xc0, 0xf6, 0x01, 0xc0, - 0xe5, 0x15, 0x2b, 0x16, 0xe5, 0x15, 0x4b, 0xe0, - 0x18, 0xe5, 0x00, 0x0f, 0xe5, 0x14, 0x26, 0x60, - 0x8b, 0xd6, 0xe0, 0x01, 0xe5, 0x2e, 0x40, 0xd6, - 0xe5, 0x0e, 0x20, 0xeb, 0x00, 0xe5, 0x0b, 0x80, - 0xeb, 0x00, 0xe5, 0x0a, 0xc0, 0x76, 0xe0, 0x04, - 0xcb, 0xe0, 0x48, 0xe5, 0x41, 0xe0, 0x2f, 0xe1, - 0x2b, 0xe0, 0x05, 0xe2, 0x2b, 0xc0, 0xab, 0xe5, - 0x1c, 0x66, 0xe0, 0x00, 0xe9, 0x02, 0xa0, 0xe9, - 0x02, 0x65, 0x04, 0x05, 0xe1, 0x0e, 0x40, 0x86, - 0x11, 0x04, 0xe2, 0x0e, 0xe0, 0x00, 0x2c, 0xe0, - 0x80, 0x48, 0xeb, 0x17, 0x00, 0xe5, 0x22, 0x00, - 0x26, 0x11, 0x20, 0x25, 0xe0, 0x08, 0x45, 0xe0, - 0x2f, 0x66, 0xe5, 0x15, 0xeb, 0x02, 0x05, 0xe0, - 0x00, 0xe5, 0x0e, 0xe6, 0x03, 0x6b, 0x96, 0xe0, - 0x0e, 0xe5, 0x0a, 0x66, 0x76, 0xe0, 0x1e, 0xe5, - 0x0d, 0xcb, 0xe0, 0x0c, 0xe5, 0x0f, 0xe0, 0x01, - 0x07, 0x06, 0x07, 0xe5, 0x2d, 0xe6, 0x07, 0xd6, - 0x60, 0xeb, 0x0c, 0xe9, 0x02, 0x06, 0x25, 0x26, - 0x05, 0xe0, 0x01, 0x46, 0x07, 0xe5, 0x25, 0x47, - 0x66, 0x27, 0x26, 0x36, 0x1b, 0x76, 0x06, 0xe0, - 0x02, 0x1b, 0x20, 0xe5, 0x11, 0xc0, 0xe9, 0x02, - 0xa0, 0x46, 0xe5, 0x1c, 0x86, 0x07, 0xe6, 0x00, - 0x00, 0xe9, 0x02, 0x76, 0x05, 0x27, 0x05, 0xe0, - 0x00, 0xe5, 0x1b, 0x06, 0x36, 0x05, 0xe0, 0x01, - 0x26, 0x07, 0xe5, 0x28, 0x47, 0xe6, 0x01, 0x27, - 0x65, 0x76, 0x66, 0x16, 0x07, 0x06, 0xe9, 0x02, - 0x05, 0x16, 0x05, 0x56, 0x00, 0xeb, 0x0c, 0xe0, - 0x03, 0xe5, 0x0a, 0x00, 0xe5, 0x11, 0x47, 0x46, - 0x27, 0x06, 0x07, 0x26, 0xb6, 0x06, 0x25, 0x06, - 0xe0, 0x36, 0xc5, 0x00, 0x05, 0x00, 0x65, 0x00, - 0xe5, 0x07, 0x00, 0xe5, 0x02, 0x16, 0xa0, 0xe5, - 0x27, 0x06, 0x47, 0xe6, 0x00, 0x80, 0xe9, 0x02, - 0xa0, 0x26, 0x27, 0x00, 0xe5, 0x00, 0x20, 0x25, - 0x20, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00, - 0x85, 0x00, 0x26, 0x05, 0x27, 0x06, 0x67, 0x20, - 0x27, 0x20, 0x47, 0x20, 0x05, 0xa0, 0x07, 0x80, - 0x85, 0x27, 0x20, 0xc6, 0x40, 0x86, 0xe0, 0x03, - 0xe5, 0x02, 0x00, 0x05, 0x20, 0x05, 0x00, 0xe5, - 0x1e, 0x00, 0x05, 0x47, 0xa6, 0x00, 0x07, 0x20, - 0x07, 0x00, 0x67, 0x00, 0x27, 0x06, 0x07, 0x06, - 0x05, 0x06, 0x05, 0x36, 0x00, 0x36, 0xe0, 0x00, - 0x26, 0xe0, 0x15, 0xe5, 0x2d, 0x47, 0xe6, 0x00, - 0x27, 0x46, 0x07, 0x06, 0x65, 0x96, 0xe9, 0x02, - 0x36, 0x00, 0x16, 0x06, 0x45, 0xe0, 0x16, 0xe5, - 0x28, 0x47, 0xa6, 0x07, 0x06, 0x67, 0x26, 0x07, - 0x26, 0x25, 0x16, 0x05, 0xe0, 0x00, 0xe9, 0x02, - 0xe0, 0x80, 0x1e, 0xe5, 0x27, 0x47, 0x66, 0x20, - 0x67, 0x26, 0x07, 0x26, 0xf6, 0x0f, 0x65, 0x26, - 0xe0, 0x1a, 0xe5, 0x28, 0x47, 0xe6, 0x00, 0x27, - 0x06, 0x07, 0x26, 0x56, 0x05, 0xe0, 0x03, 0xe9, - 0x02, 0xa0, 0xf6, 0x05, 0xe0, 0x0b, 0xe5, 0x23, - 0x06, 0x07, 0x06, 0x27, 0xa6, 0x07, 0x06, 0x05, - 0x16, 0xa0, 0xe9, 0x02, 0xa0, 0xe9, 0x0c, 0xe0, - 0x14, 0xe5, 0x13, 0x20, 0x06, 0x07, 0x06, 0x27, - 0x66, 0x07, 0x86, 0x60, 0xe9, 0x02, 0x2b, 0x56, - 0x0f, 0xc5, 0xe0, 0x80, 0x31, 0xe5, 0x24, 0x47, - 0xe6, 0x01, 0x07, 0x26, 0x16, 0xe0, 0x5c, 0xe1, - 0x18, 0xe2, 0x18, 0xe9, 0x02, 0xeb, 0x01, 0xe0, - 0x04, 0xe5, 0x00, 0x20, 0x05, 0x20, 0xe5, 0x00, - 0x00, 0x25, 0x00, 0xe5, 0x10, 0xa7, 0x00, 0x27, - 0x20, 0x26, 0x07, 0x06, 0x05, 0x07, 0x05, 0x07, - 0x06, 0x56, 0xe0, 0x01, 0xe9, 0x02, 0xe0, 0x3e, - 0xe5, 0x00, 0x20, 0xe5, 0x1f, 0x47, 0x66, 0x20, - 0x26, 0x67, 0x06, 0x05, 0x16, 0x05, 0x07, 0xe0, - 0x13, 0x05, 0xe6, 0x02, 0xe5, 0x20, 0xa6, 0x07, - 0x05, 0x66, 0xf6, 0x00, 0x06, 0xe0, 0x00, 0x05, - 0xa6, 0x27, 0x46, 0xe5, 0x26, 0xe6, 0x05, 0x07, - 0x26, 0x56, 0x05, 0x96, 0xe0, 0x05, 0xe5, 0x41, - 0xc0, 0xf6, 0x02, 0xe0, 0x80, 0x2e, 0xe5, 0x19, - 0x16, 0xe0, 0x06, 0xe9, 0x02, 0xa0, 0xe5, 0x01, - 0x00, 0xe5, 0x1d, 0x07, 0xc6, 0x00, 0xa6, 0x07, - 0x06, 0x05, 0x96, 0xe0, 0x02, 0xe9, 0x02, 0xeb, - 0x0b, 0x40, 0x36, 0xe5, 0x16, 0x20, 0xe6, 0x0e, - 0x00, 0x07, 0xc6, 0x07, 0x26, 0x07, 0x26, 0xe0, - 0x41, 0xc5, 0x00, 0x25, 0x00, 0xe5, 0x1e, 0xa6, - 0x40, 0x06, 0x00, 0x26, 0x00, 0xc6, 0x05, 0x06, - 0xe0, 0x00, 0xe9, 0x02, 0xa0, 0xa5, 0x00, 0x25, - 0x00, 0xe5, 0x18, 0x87, 0x00, 0x26, 0x00, 0x27, - 0x06, 0x07, 0x06, 0x05, 0xc0, 0xe9, 0x02, 0xe0, - 0x80, 0xae, 0xe5, 0x0b, 0x26, 0x27, 0x36, 0xc0, - 0x26, 0x05, 0x07, 0xe5, 0x05, 0x00, 0xe5, 0x1a, - 0x27, 0x86, 0x40, 0x27, 0x06, 0x07, 0x06, 0xf6, - 0x05, 0xe9, 0x02, 0x06, 0xe0, 0x4d, 0x05, 0xe0, - 0x07, 0xeb, 0x0d, 0xef, 0x00, 0x6d, 0xef, 0x09, - 0xe0, 0x05, 0x16, 0xe5, 0x83, 0x12, 0xe0, 0x5e, - 0xea, 0x67, 0x00, 0x96, 0xe0, 0x03, 0xe5, 0x80, - 0x3c, 0xe0, 0x89, 0xc4, 0xe5, 0x59, 0x36, 0xe0, - 0x05, 0xe5, 0x83, 0xa8, 0xfb, 0x08, 0x06, 0xa5, - 0xe6, 0x07, 0xe0, 0x02, 0xe5, 0x8f, 0x13, 0x80, - 0xe5, 0x81, 0xbf, 0xe0, 0x9a, 0x31, 0xe5, 0x16, - 0xe6, 0x04, 0x47, 0x46, 0xe9, 0x02, 0xe0, 0x86, - 0x3e, 0xe5, 0x81, 0xb1, 0xc0, 0xe5, 0x17, 0x00, - 0xe9, 0x02, 0x60, 0x36, 0xe5, 0x47, 0x00, 0xe9, - 0x02, 0xa0, 0xe5, 0x16, 0x20, 0x86, 0x16, 0xe0, - 0x02, 0xe5, 0x28, 0xc6, 0x96, 0x6f, 0x64, 0x16, - 0x0f, 0xe0, 0x02, 0xe9, 0x02, 0x00, 0xcb, 0x00, - 0xe5, 0x0d, 0x80, 0xe5, 0x0b, 0xe0, 0x81, 0x28, - 0x44, 0xe5, 0x20, 0x24, 0x56, 0xe9, 0x02, 0xe0, - 0x80, 0x3e, 0xe1, 0x18, 0xe2, 0x18, 0xeb, 0x0f, - 0x76, 0xe0, 0x5d, 0xe5, 0x43, 0x60, 0x06, 0x05, - 0xe7, 0x2f, 0xc0, 0x66, 0xe4, 0x05, 0xe0, 0x38, - 0x24, 0x16, 0x04, 0x06, 0xe0, 0x03, 0x27, 0xe0, - 0x06, 0xe5, 0x97, 0x70, 0xe0, 0x00, 0xe5, 0x84, - 0x4e, 0xe0, 0x21, 0xe5, 0x02, 0xe0, 0xa2, 0x5f, - 0x64, 0x00, 0xc4, 0x00, 0x24, 0x00, 0xe5, 0x80, - 0x9b, 0xe0, 0x07, 0x05, 0xe0, 0x15, 0x45, 0x20, - 0x05, 0xe0, 0x06, 0x65, 0xe0, 0x00, 0xe5, 0x81, - 0x04, 0xe0, 0x88, 0x7c, 0xe5, 0x63, 0x80, 0xe5, - 0x05, 0x40, 0xe5, 0x01, 0xc0, 0xe5, 0x02, 0x20, - 0x0f, 0x26, 0x16, 0x7b, 0xe0, 0x8e, 0xd4, 0xef, - 0x80, 0x68, 0xe9, 0x02, 0xa0, 0xef, 0x81, 0x2c, - 0xe0, 0x44, 0xe6, 0x26, 0x20, 0xe6, 0x0f, 0xe0, - 0x01, 0xef, 0x6c, 0xe0, 0x34, 0xef, 0x80, 0x6e, - 0xe0, 0x02, 0xef, 0x1f, 0x20, 0xef, 0x34, 0x27, - 0x46, 0x4f, 0xa7, 0xfb, 0x00, 0xe6, 0x00, 0x2f, - 0xc6, 0xef, 0x16, 0x66, 0xef, 0x35, 0xe0, 0x0d, - 0xef, 0x3a, 0x46, 0x0f, 0xe0, 0x72, 0xeb, 0x0c, - 0xe0, 0x04, 0xeb, 0x0c, 0xe0, 0x04, 0xef, 0x4f, - 0xe0, 0x01, 0xeb, 0x11, 0xe0, 0x7f, 0xe1, 0x12, - 0xe2, 0x12, 0xe1, 0x12, 0xc2, 0x00, 0xe2, 0x0a, - 0xe1, 0x12, 0xe2, 0x12, 0x01, 0x00, 0x21, 0x20, - 0x01, 0x20, 0x21, 0x20, 0x61, 0x00, 0xe1, 0x00, - 0x62, 0x00, 0x02, 0x00, 0xc2, 0x00, 0xe2, 0x03, - 0xe1, 0x12, 0xe2, 0x12, 0x21, 0x00, 0x61, 0x20, - 0xe1, 0x00, 0x00, 0xc1, 0x00, 0xe2, 0x12, 0x21, - 0x00, 0x61, 0x00, 0x81, 0x00, 0x01, 0x40, 0xc1, - 0x00, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, - 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, - 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, - 0x12, 0xe2, 0x14, 0x20, 0xe1, 0x11, 0x0c, 0xe2, - 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11, - 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, - 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, - 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0x3f, - 0x20, 0xe9, 0x2a, 0xef, 0x81, 0x78, 0xe6, 0x2f, - 0x6f, 0xe6, 0x2a, 0xef, 0x00, 0x06, 0xef, 0x06, - 0x06, 0x2f, 0x96, 0xe0, 0x07, 0x86, 0x00, 0xe6, - 0x07, 0xe0, 0x83, 0xc8, 0xe2, 0x02, 0x05, 0xe2, - 0x0c, 0xa0, 0xa2, 0xe0, 0x80, 0x4d, 0xc6, 0x00, - 0xe6, 0x09, 0x20, 0xc6, 0x00, 0x26, 0x00, 0x86, - 0x80, 0xe4, 0x36, 0xe0, 0x19, 0x06, 0xe0, 0x68, - 0xe5, 0x25, 0x40, 0xc6, 0xc4, 0x20, 0xe9, 0x02, - 0x60, 0x05, 0x0f, 0xe0, 0x80, 0xb8, 0xe5, 0x16, - 0x06, 0xe0, 0x09, 0xe5, 0x24, 0x66, 0xe9, 0x02, - 0x80, 0x0d, 0xe0, 0x81, 0x48, 0xe5, 0x13, 0x04, - 0x66, 0xe9, 0x02, 0xe0, 0x80, 0x4e, 0xe5, 0x16, - 0x26, 0x05, 0xe9, 0x02, 0x60, 0x16, 0xe0, 0x81, - 0x58, 0xc5, 0x00, 0x65, 0x00, 0x25, 0x00, 0xe5, - 0x07, 0x00, 0xe5, 0x80, 0x3d, 0x20, 0xeb, 0x01, - 0xc6, 0xe0, 0x21, 0xe1, 0x1a, 0xe2, 0x1a, 0xc6, - 0x04, 0x60, 0xe9, 0x02, 0x60, 0x36, 0xe0, 0x82, - 0x89, 0xeb, 0x33, 0x0f, 0x4b, 0x0d, 0x6b, 0xe0, - 0x44, 0xeb, 0x25, 0x0f, 0xeb, 0x07, 0xe0, 0x80, - 0x3a, 0x65, 0x00, 0xe5, 0x13, 0x00, 0x25, 0x00, - 0x05, 0x20, 0x05, 0x00, 0xe5, 0x02, 0x00, 0x65, - 0x00, 0x05, 0x00, 0x05, 0xa0, 0x05, 0x60, 0x05, - 0x00, 0x05, 0x00, 0x05, 0x00, 0x45, 0x00, 0x25, - 0x00, 0x05, 0x20, 0x05, 0x00, 0x05, 0x00, 0x05, - 0x00, 0x05, 0x00, 0x05, 0x00, 0x25, 0x00, 0x05, - 0x20, 0x65, 0x00, 0xc5, 0x00, 0x65, 0x00, 0x65, - 0x00, 0x05, 0x00, 0xe5, 0x02, 0x00, 0xe5, 0x09, - 0x80, 0x45, 0x00, 0x85, 0x00, 0xe5, 0x09, 0xe0, - 0x2c, 0x2c, 0xe0, 0x80, 0x86, 0xef, 0x24, 0x60, - 0xef, 0x5c, 0xe0, 0x04, 0xef, 0x07, 0x20, 0xef, - 0x07, 0x00, 0xef, 0x07, 0x00, 0xef, 0x1d, 0xe0, - 0x02, 0xeb, 0x05, 0xef, 0x80, 0x19, 0xe0, 0x30, - 0xef, 0x15, 0xe0, 0x05, 0xef, 0x24, 0x60, 0xef, - 0x01, 0xc0, 0x2f, 0xe0, 0x06, 0xaf, 0xe0, 0x80, - 0x12, 0xef, 0x80, 0x73, 0x8e, 0xef, 0x82, 0x50, - 0x60, 0xef, 0x09, 0x40, 0xef, 0x05, 0x40, 0xef, - 0x6f, 0x60, 0xef, 0x57, 0xa0, 0xef, 0x04, 0x60, - 0x0f, 0xe0, 0x07, 0xef, 0x04, 0x60, 0xef, 0x30, - 0xe0, 0x00, 0xef, 0x02, 0xa0, 0xef, 0x20, 0xe0, - 0x00, 0xef, 0x16, 0x20, 0xef, 0x04, 0x60, 0x2f, - 0xe0, 0x36, 0xef, 0x80, 0xcc, 0xe0, 0x04, 0xef, - 0x06, 0x20, 0xef, 0x05, 0x40, 0xef, 0x02, 0x80, - 0xef, 0x30, 0xc0, 0xef, 0x07, 0x20, 0xef, 0x03, - 0xa0, 0xef, 0x01, 0xc0, 0xef, 0x80, 0x0b, 0x00, - 0xef, 0x54, 0xe9, 0x02, 0xe0, 0x83, 0x7e, 0xe5, - 0xc0, 0x66, 0x58, 0xe0, 0x18, 0xe5, 0x8f, 0xb2, - 0xa0, 0xe5, 0x80, 0x56, 0x20, 0xe5, 0x95, 0xfa, - 0xe0, 0x06, 0xe5, 0x9c, 0xa9, 0xe0, 0x07, 0xe5, - 0x81, 0xe6, 0xe0, 0x89, 0x1a, 0xe5, 0x81, 0x96, - 0xe0, 0x85, 0x5a, 0xe5, 0x92, 0xc3, 0x80, 0xe5, - 0x8f, 0xd8, 0xe0, 0xca, 0x9b, 0xc9, 0x1b, 0xe0, - 0x16, 0xfb, 0x58, 0xe0, 0x78, 0xe6, 0x80, 0x68, - 0xe0, 0xc0, 0xbd, 0x88, 0xfd, 0xc0, 0xbf, 0x76, - 0x20, 0xfd, 0xc0, 0xbf, 0x76, 0x20, -}; - -typedef enum { - UNICODE_SCRIPT_Unknown, - UNICODE_SCRIPT_Adlam, - UNICODE_SCRIPT_Ahom, - UNICODE_SCRIPT_Anatolian_Hieroglyphs, - UNICODE_SCRIPT_Arabic, - UNICODE_SCRIPT_Armenian, - UNICODE_SCRIPT_Avestan, - UNICODE_SCRIPT_Balinese, - UNICODE_SCRIPT_Bamum, - UNICODE_SCRIPT_Bassa_Vah, - UNICODE_SCRIPT_Batak, - UNICODE_SCRIPT_Bengali, - UNICODE_SCRIPT_Bhaiksuki, - UNICODE_SCRIPT_Bopomofo, - UNICODE_SCRIPT_Brahmi, - UNICODE_SCRIPT_Braille, - UNICODE_SCRIPT_Buginese, - UNICODE_SCRIPT_Buhid, - UNICODE_SCRIPT_Canadian_Aboriginal, - UNICODE_SCRIPT_Carian, - UNICODE_SCRIPT_Caucasian_Albanian, - UNICODE_SCRIPT_Chakma, - UNICODE_SCRIPT_Cham, - UNICODE_SCRIPT_Cherokee, - UNICODE_SCRIPT_Chorasmian, - UNICODE_SCRIPT_Common, - UNICODE_SCRIPT_Coptic, - UNICODE_SCRIPT_Cuneiform, - UNICODE_SCRIPT_Cypriot, - UNICODE_SCRIPT_Cyrillic, - UNICODE_SCRIPT_Cypro_Minoan, - UNICODE_SCRIPT_Deseret, - UNICODE_SCRIPT_Devanagari, - UNICODE_SCRIPT_Dives_Akuru, - UNICODE_SCRIPT_Dogra, - UNICODE_SCRIPT_Duployan, - UNICODE_SCRIPT_Egyptian_Hieroglyphs, - UNICODE_SCRIPT_Elbasan, - UNICODE_SCRIPT_Elymaic, - UNICODE_SCRIPT_Ethiopic, - UNICODE_SCRIPT_Garay, - UNICODE_SCRIPT_Georgian, - UNICODE_SCRIPT_Glagolitic, - UNICODE_SCRIPT_Gothic, - UNICODE_SCRIPT_Grantha, - UNICODE_SCRIPT_Greek, - UNICODE_SCRIPT_Gujarati, - UNICODE_SCRIPT_Gunjala_Gondi, - UNICODE_SCRIPT_Gurmukhi, - UNICODE_SCRIPT_Gurung_Khema, - UNICODE_SCRIPT_Han, - UNICODE_SCRIPT_Hangul, - UNICODE_SCRIPT_Hanifi_Rohingya, - UNICODE_SCRIPT_Hanunoo, - UNICODE_SCRIPT_Hatran, - UNICODE_SCRIPT_Hebrew, - UNICODE_SCRIPT_Hiragana, - UNICODE_SCRIPT_Imperial_Aramaic, - UNICODE_SCRIPT_Inherited, - UNICODE_SCRIPT_Inscriptional_Pahlavi, - UNICODE_SCRIPT_Inscriptional_Parthian, - UNICODE_SCRIPT_Javanese, - UNICODE_SCRIPT_Kaithi, - UNICODE_SCRIPT_Kannada, - UNICODE_SCRIPT_Katakana, - UNICODE_SCRIPT_Kawi, - UNICODE_SCRIPT_Kayah_Li, - UNICODE_SCRIPT_Kharoshthi, - UNICODE_SCRIPT_Khmer, - UNICODE_SCRIPT_Khojki, - UNICODE_SCRIPT_Khitan_Small_Script, - UNICODE_SCRIPT_Khudawadi, - UNICODE_SCRIPT_Kirat_Rai, - UNICODE_SCRIPT_Lao, - UNICODE_SCRIPT_Latin, - UNICODE_SCRIPT_Lepcha, - UNICODE_SCRIPT_Limbu, - UNICODE_SCRIPT_Linear_A, - UNICODE_SCRIPT_Linear_B, - UNICODE_SCRIPT_Lisu, - UNICODE_SCRIPT_Lycian, - UNICODE_SCRIPT_Lydian, - UNICODE_SCRIPT_Makasar, - UNICODE_SCRIPT_Mahajani, - UNICODE_SCRIPT_Malayalam, - UNICODE_SCRIPT_Mandaic, - UNICODE_SCRIPT_Manichaean, - UNICODE_SCRIPT_Marchen, - UNICODE_SCRIPT_Masaram_Gondi, - UNICODE_SCRIPT_Medefaidrin, - UNICODE_SCRIPT_Meetei_Mayek, - UNICODE_SCRIPT_Mende_Kikakui, - UNICODE_SCRIPT_Meroitic_Cursive, - UNICODE_SCRIPT_Meroitic_Hieroglyphs, - UNICODE_SCRIPT_Miao, - UNICODE_SCRIPT_Modi, - UNICODE_SCRIPT_Mongolian, - UNICODE_SCRIPT_Mro, - UNICODE_SCRIPT_Multani, - UNICODE_SCRIPT_Myanmar, - UNICODE_SCRIPT_Nabataean, - UNICODE_SCRIPT_Nag_Mundari, - UNICODE_SCRIPT_Nandinagari, - UNICODE_SCRIPT_New_Tai_Lue, - UNICODE_SCRIPT_Newa, - UNICODE_SCRIPT_Nko, - UNICODE_SCRIPT_Nushu, - UNICODE_SCRIPT_Nyiakeng_Puachue_Hmong, - UNICODE_SCRIPT_Ogham, - UNICODE_SCRIPT_Ol_Chiki, - UNICODE_SCRIPT_Ol_Onal, - UNICODE_SCRIPT_Old_Hungarian, - UNICODE_SCRIPT_Old_Italic, - UNICODE_SCRIPT_Old_North_Arabian, - UNICODE_SCRIPT_Old_Permic, - UNICODE_SCRIPT_Old_Persian, - UNICODE_SCRIPT_Old_Sogdian, - UNICODE_SCRIPT_Old_South_Arabian, - UNICODE_SCRIPT_Old_Turkic, - UNICODE_SCRIPT_Old_Uyghur, - UNICODE_SCRIPT_Oriya, - UNICODE_SCRIPT_Osage, - UNICODE_SCRIPT_Osmanya, - UNICODE_SCRIPT_Pahawh_Hmong, - UNICODE_SCRIPT_Palmyrene, - UNICODE_SCRIPT_Pau_Cin_Hau, - UNICODE_SCRIPT_Phags_Pa, - UNICODE_SCRIPT_Phoenician, - UNICODE_SCRIPT_Psalter_Pahlavi, - UNICODE_SCRIPT_Rejang, - UNICODE_SCRIPT_Runic, - UNICODE_SCRIPT_Samaritan, - UNICODE_SCRIPT_Saurashtra, - UNICODE_SCRIPT_Sharada, - UNICODE_SCRIPT_Shavian, - UNICODE_SCRIPT_Siddham, - UNICODE_SCRIPT_SignWriting, - UNICODE_SCRIPT_Sinhala, - UNICODE_SCRIPT_Sogdian, - UNICODE_SCRIPT_Sora_Sompeng, - UNICODE_SCRIPT_Soyombo, - UNICODE_SCRIPT_Sundanese, - UNICODE_SCRIPT_Sunuwar, - UNICODE_SCRIPT_Syloti_Nagri, - UNICODE_SCRIPT_Syriac, - UNICODE_SCRIPT_Tagalog, - UNICODE_SCRIPT_Tagbanwa, - UNICODE_SCRIPT_Tai_Le, - UNICODE_SCRIPT_Tai_Tham, - UNICODE_SCRIPT_Tai_Viet, - UNICODE_SCRIPT_Takri, - UNICODE_SCRIPT_Tamil, - UNICODE_SCRIPT_Tangut, - UNICODE_SCRIPT_Telugu, - UNICODE_SCRIPT_Thaana, - UNICODE_SCRIPT_Thai, - UNICODE_SCRIPT_Tibetan, - UNICODE_SCRIPT_Tifinagh, - UNICODE_SCRIPT_Tirhuta, - UNICODE_SCRIPT_Tangsa, - UNICODE_SCRIPT_Todhri, - UNICODE_SCRIPT_Toto, - UNICODE_SCRIPT_Tulu_Tigalari, - UNICODE_SCRIPT_Ugaritic, - UNICODE_SCRIPT_Vai, - UNICODE_SCRIPT_Vithkuqi, - UNICODE_SCRIPT_Wancho, - UNICODE_SCRIPT_Warang_Citi, - UNICODE_SCRIPT_Yezidi, - UNICODE_SCRIPT_Yi, - UNICODE_SCRIPT_Zanabazar_Square, - UNICODE_SCRIPT_COUNT, -} UnicodeScriptEnum; - -static const char unicode_script_name_table[] = - "Unknown,Zzzz" "\0" - "Adlam,Adlm" "\0" - "Ahom,Ahom" "\0" - "Anatolian_Hieroglyphs,Hluw" "\0" - "Arabic,Arab" "\0" - "Armenian,Armn" "\0" - "Avestan,Avst" "\0" - "Balinese,Bali" "\0" - "Bamum,Bamu" "\0" - "Bassa_Vah,Bass" "\0" - "Batak,Batk" "\0" - "Bengali,Beng" "\0" - "Bhaiksuki,Bhks" "\0" - "Bopomofo,Bopo" "\0" - "Brahmi,Brah" "\0" - "Braille,Brai" "\0" - "Buginese,Bugi" "\0" - "Buhid,Buhd" "\0" - "Canadian_Aboriginal,Cans" "\0" - "Carian,Cari" "\0" - "Caucasian_Albanian,Aghb" "\0" - "Chakma,Cakm" "\0" - "Cham,Cham" "\0" - "Cherokee,Cher" "\0" - "Chorasmian,Chrs" "\0" - "Common,Zyyy" "\0" - "Coptic,Copt,Qaac" "\0" - "Cuneiform,Xsux" "\0" - "Cypriot,Cprt" "\0" - "Cyrillic,Cyrl" "\0" - "Cypro_Minoan,Cpmn" "\0" - "Deseret,Dsrt" "\0" - "Devanagari,Deva" "\0" - "Dives_Akuru,Diak" "\0" - "Dogra,Dogr" "\0" - "Duployan,Dupl" "\0" - "Egyptian_Hieroglyphs,Egyp" "\0" - "Elbasan,Elba" "\0" - "Elymaic,Elym" "\0" - "Ethiopic,Ethi" "\0" - "Garay,Gara" "\0" - "Georgian,Geor" "\0" - "Glagolitic,Glag" "\0" - "Gothic,Goth" "\0" - "Grantha,Gran" "\0" - "Greek,Grek" "\0" - "Gujarati,Gujr" "\0" - "Gunjala_Gondi,Gong" "\0" - "Gurmukhi,Guru" "\0" - "Gurung_Khema,Gukh" "\0" - "Han,Hani" "\0" - "Hangul,Hang" "\0" - "Hanifi_Rohingya,Rohg" "\0" - "Hanunoo,Hano" "\0" - "Hatran,Hatr" "\0" - "Hebrew,Hebr" "\0" - "Hiragana,Hira" "\0" - "Imperial_Aramaic,Armi" "\0" - "Inherited,Zinh,Qaai" "\0" - "Inscriptional_Pahlavi,Phli" "\0" - "Inscriptional_Parthian,Prti" "\0" - "Javanese,Java" "\0" - "Kaithi,Kthi" "\0" - "Kannada,Knda" "\0" - "Katakana,Kana" "\0" - "Kawi,Kawi" "\0" - "Kayah_Li,Kali" "\0" - "Kharoshthi,Khar" "\0" - "Khmer,Khmr" "\0" - "Khojki,Khoj" "\0" - "Khitan_Small_Script,Kits" "\0" - "Khudawadi,Sind" "\0" - "Kirat_Rai,Krai" "\0" - "Lao,Laoo" "\0" - "Latin,Latn" "\0" - "Lepcha,Lepc" "\0" - "Limbu,Limb" "\0" - "Linear_A,Lina" "\0" - "Linear_B,Linb" "\0" - "Lisu,Lisu" "\0" - "Lycian,Lyci" "\0" - "Lydian,Lydi" "\0" - "Makasar,Maka" "\0" - "Mahajani,Mahj" "\0" - "Malayalam,Mlym" "\0" - "Mandaic,Mand" "\0" - "Manichaean,Mani" "\0" - "Marchen,Marc" "\0" - "Masaram_Gondi,Gonm" "\0" - "Medefaidrin,Medf" "\0" - "Meetei_Mayek,Mtei" "\0" - "Mende_Kikakui,Mend" "\0" - "Meroitic_Cursive,Merc" "\0" - "Meroitic_Hieroglyphs,Mero" "\0" - "Miao,Plrd" "\0" - "Modi,Modi" "\0" - "Mongolian,Mong" "\0" - "Mro,Mroo" "\0" - "Multani,Mult" "\0" - "Myanmar,Mymr" "\0" - "Nabataean,Nbat" "\0" - "Nag_Mundari,Nagm" "\0" - "Nandinagari,Nand" "\0" - "New_Tai_Lue,Talu" "\0" - "Newa,Newa" "\0" - "Nko,Nkoo" "\0" - "Nushu,Nshu" "\0" - "Nyiakeng_Puachue_Hmong,Hmnp" "\0" - "Ogham,Ogam" "\0" - "Ol_Chiki,Olck" "\0" - "Ol_Onal,Onao" "\0" - "Old_Hungarian,Hung" "\0" - "Old_Italic,Ital" "\0" - "Old_North_Arabian,Narb" "\0" - "Old_Permic,Perm" "\0" - "Old_Persian,Xpeo" "\0" - "Old_Sogdian,Sogo" "\0" - "Old_South_Arabian,Sarb" "\0" - "Old_Turkic,Orkh" "\0" - "Old_Uyghur,Ougr" "\0" - "Oriya,Orya" "\0" - "Osage,Osge" "\0" - "Osmanya,Osma" "\0" - "Pahawh_Hmong,Hmng" "\0" - "Palmyrene,Palm" "\0" - "Pau_Cin_Hau,Pauc" "\0" - "Phags_Pa,Phag" "\0" - "Phoenician,Phnx" "\0" - "Psalter_Pahlavi,Phlp" "\0" - "Rejang,Rjng" "\0" - "Runic,Runr" "\0" - "Samaritan,Samr" "\0" - "Saurashtra,Saur" "\0" - "Sharada,Shrd" "\0" - "Shavian,Shaw" "\0" - "Siddham,Sidd" "\0" - "SignWriting,Sgnw" "\0" - "Sinhala,Sinh" "\0" - "Sogdian,Sogd" "\0" - "Sora_Sompeng,Sora" "\0" - "Soyombo,Soyo" "\0" - "Sundanese,Sund" "\0" - "Sunuwar,Sunu" "\0" - "Syloti_Nagri,Sylo" "\0" - "Syriac,Syrc" "\0" - "Tagalog,Tglg" "\0" - "Tagbanwa,Tagb" "\0" - "Tai_Le,Tale" "\0" - "Tai_Tham,Lana" "\0" - "Tai_Viet,Tavt" "\0" - "Takri,Takr" "\0" - "Tamil,Taml" "\0" - "Tangut,Tang" "\0" - "Telugu,Telu" "\0" - "Thaana,Thaa" "\0" - "Thai,Thai" "\0" - "Tibetan,Tibt" "\0" - "Tifinagh,Tfng" "\0" - "Tirhuta,Tirh" "\0" - "Tangsa,Tnsa" "\0" - "Todhri,Todr" "\0" - "Toto,Toto" "\0" - "Tulu_Tigalari,Tutg" "\0" - "Ugaritic,Ugar" "\0" - "Vai,Vaii" "\0" - "Vithkuqi,Vith" "\0" - "Wancho,Wcho" "\0" - "Warang_Citi,Wara" "\0" - "Yezidi,Yezi" "\0" - "Yi,Yiii" "\0" - "Zanabazar_Square,Zanb" "\0" -; - -static const uint8_t unicode_script_table[2803] = { - 0xc0, 0x19, 0x99, 0x4a, 0x85, 0x19, 0x99, 0x4a, - 0xae, 0x19, 0x80, 0x4a, 0x8e, 0x19, 0x80, 0x4a, - 0x84, 0x19, 0x96, 0x4a, 0x80, 0x19, 0x9e, 0x4a, - 0x80, 0x19, 0xe1, 0x60, 0x4a, 0xa6, 0x19, 0x84, - 0x4a, 0x84, 0x19, 0x81, 0x0d, 0x93, 0x19, 0xe0, - 0x0f, 0x3a, 0x83, 0x2d, 0x80, 0x19, 0x82, 0x2d, - 0x01, 0x83, 0x2d, 0x80, 0x19, 0x80, 0x2d, 0x03, - 0x80, 0x2d, 0x80, 0x19, 0x80, 0x2d, 0x80, 0x19, - 0x82, 0x2d, 0x00, 0x80, 0x2d, 0x00, 0x93, 0x2d, - 0x00, 0xbe, 0x2d, 0x8d, 0x1a, 0x8f, 0x2d, 0xe0, - 0x24, 0x1d, 0x81, 0x3a, 0xe0, 0x48, 0x1d, 0x00, - 0xa5, 0x05, 0x01, 0xb1, 0x05, 0x01, 0x82, 0x05, - 0x00, 0xb6, 0x37, 0x07, 0x9a, 0x37, 0x03, 0x85, - 0x37, 0x0a, 0x84, 0x04, 0x80, 0x19, 0x85, 0x04, - 0x80, 0x19, 0x8d, 0x04, 0x80, 0x19, 0x82, 0x04, - 0x80, 0x19, 0x9f, 0x04, 0x80, 0x19, 0x89, 0x04, - 0x8a, 0x3a, 0x99, 0x04, 0x80, 0x3a, 0xe0, 0x0b, - 0x04, 0x80, 0x19, 0xa1, 0x04, 0x8d, 0x90, 0x00, - 0xbb, 0x90, 0x01, 0x82, 0x90, 0xaf, 0x04, 0xb1, - 0x9a, 0x0d, 0xba, 0x69, 0x01, 0x82, 0x69, 0xad, - 0x83, 0x01, 0x8e, 0x83, 0x00, 0x9b, 0x55, 0x01, - 0x80, 0x55, 0x00, 0x8a, 0x90, 0x04, 0x9e, 0x04, - 0x00, 0x81, 0x04, 0x04, 0xca, 0x04, 0x80, 0x19, - 0x9c, 0x04, 0xd0, 0x20, 0x83, 0x3a, 0x8e, 0x20, - 0x81, 0x19, 0x99, 0x20, 0x83, 0x0b, 0x00, 0x87, - 0x0b, 0x01, 0x81, 0x0b, 0x01, 0x95, 0x0b, 0x00, - 0x86, 0x0b, 0x00, 0x80, 0x0b, 0x02, 0x83, 0x0b, - 0x01, 0x88, 0x0b, 0x01, 0x81, 0x0b, 0x01, 0x83, - 0x0b, 0x07, 0x80, 0x0b, 0x03, 0x81, 0x0b, 0x00, - 0x84, 0x0b, 0x01, 0x98, 0x0b, 0x01, 0x82, 0x30, - 0x00, 0x85, 0x30, 0x03, 0x81, 0x30, 0x01, 0x95, - 0x30, 0x00, 0x86, 0x30, 0x00, 0x81, 0x30, 0x00, - 0x81, 0x30, 0x00, 0x81, 0x30, 0x01, 0x80, 0x30, - 0x00, 0x84, 0x30, 0x03, 0x81, 0x30, 0x01, 0x82, - 0x30, 0x02, 0x80, 0x30, 0x06, 0x83, 0x30, 0x00, - 0x80, 0x30, 0x06, 0x90, 0x30, 0x09, 0x82, 0x2e, - 0x00, 0x88, 0x2e, 0x00, 0x82, 0x2e, 0x00, 0x95, - 0x2e, 0x00, 0x86, 0x2e, 0x00, 0x81, 0x2e, 0x00, - 0x84, 0x2e, 0x01, 0x89, 0x2e, 0x00, 0x82, 0x2e, - 0x00, 0x82, 0x2e, 0x01, 0x80, 0x2e, 0x0e, 0x83, - 0x2e, 0x01, 0x8b, 0x2e, 0x06, 0x86, 0x2e, 0x00, - 0x82, 0x78, 0x00, 0x87, 0x78, 0x01, 0x81, 0x78, - 0x01, 0x95, 0x78, 0x00, 0x86, 0x78, 0x00, 0x81, - 0x78, 0x00, 0x84, 0x78, 0x01, 0x88, 0x78, 0x01, - 0x81, 0x78, 0x01, 0x82, 0x78, 0x06, 0x82, 0x78, - 0x03, 0x81, 0x78, 0x00, 0x84, 0x78, 0x01, 0x91, - 0x78, 0x09, 0x81, 0x97, 0x00, 0x85, 0x97, 0x02, - 0x82, 0x97, 0x00, 0x83, 0x97, 0x02, 0x81, 0x97, - 0x00, 0x80, 0x97, 0x00, 0x81, 0x97, 0x02, 0x81, - 0x97, 0x02, 0x82, 0x97, 0x02, 0x8b, 0x97, 0x03, - 0x84, 0x97, 0x02, 0x82, 0x97, 0x00, 0x83, 0x97, - 0x01, 0x80, 0x97, 0x05, 0x80, 0x97, 0x0d, 0x94, - 0x97, 0x04, 0x8c, 0x99, 0x00, 0x82, 0x99, 0x00, - 0x96, 0x99, 0x00, 0x8f, 0x99, 0x01, 0x88, 0x99, - 0x00, 0x82, 0x99, 0x00, 0x83, 0x99, 0x06, 0x81, - 0x99, 0x00, 0x82, 0x99, 0x01, 0x80, 0x99, 0x01, - 0x83, 0x99, 0x01, 0x89, 0x99, 0x06, 0x88, 0x99, - 0x8c, 0x3f, 0x00, 0x82, 0x3f, 0x00, 0x96, 0x3f, - 0x00, 0x89, 0x3f, 0x00, 0x84, 0x3f, 0x01, 0x88, - 0x3f, 0x00, 0x82, 0x3f, 0x00, 0x83, 0x3f, 0x06, - 0x81, 0x3f, 0x05, 0x81, 0x3f, 0x00, 0x83, 0x3f, - 0x01, 0x89, 0x3f, 0x00, 0x82, 0x3f, 0x0b, 0x8c, - 0x54, 0x00, 0x82, 0x54, 0x00, 0xb2, 0x54, 0x00, - 0x82, 0x54, 0x00, 0x85, 0x54, 0x03, 0x8f, 0x54, - 0x01, 0x99, 0x54, 0x00, 0x82, 0x89, 0x00, 0x91, - 0x89, 0x02, 0x97, 0x89, 0x00, 0x88, 0x89, 0x00, - 0x80, 0x89, 0x01, 0x86, 0x89, 0x02, 0x80, 0x89, - 0x03, 0x85, 0x89, 0x00, 0x80, 0x89, 0x00, 0x87, - 0x89, 0x05, 0x89, 0x89, 0x01, 0x82, 0x89, 0x0b, - 0xb9, 0x9b, 0x03, 0x80, 0x19, 0x9b, 0x9b, 0x24, - 0x81, 0x49, 0x00, 0x80, 0x49, 0x00, 0x84, 0x49, - 0x00, 0x97, 0x49, 0x00, 0x80, 0x49, 0x00, 0x96, - 0x49, 0x01, 0x84, 0x49, 0x00, 0x80, 0x49, 0x00, - 0x86, 0x49, 0x00, 0x89, 0x49, 0x01, 0x83, 0x49, - 0x1f, 0xc7, 0x9c, 0x00, 0xa3, 0x9c, 0x03, 0xa6, - 0x9c, 0x00, 0xa3, 0x9c, 0x00, 0x8e, 0x9c, 0x00, - 0x86, 0x9c, 0x83, 0x19, 0x81, 0x9c, 0x24, 0xe0, - 0x3f, 0x63, 0xa5, 0x29, 0x00, 0x80, 0x29, 0x04, - 0x80, 0x29, 0x01, 0xaa, 0x29, 0x80, 0x19, 0x83, - 0x29, 0xe0, 0x9f, 0x33, 0xc8, 0x27, 0x00, 0x83, - 0x27, 0x01, 0x86, 0x27, 0x00, 0x80, 0x27, 0x00, - 0x83, 0x27, 0x01, 0xa8, 0x27, 0x00, 0x83, 0x27, - 0x01, 0xa0, 0x27, 0x00, 0x83, 0x27, 0x01, 0x86, - 0x27, 0x00, 0x80, 0x27, 0x00, 0x83, 0x27, 0x01, - 0x8e, 0x27, 0x00, 0xb8, 0x27, 0x00, 0x83, 0x27, - 0x01, 0xc2, 0x27, 0x01, 0x9f, 0x27, 0x02, 0x99, - 0x27, 0x05, 0xd5, 0x17, 0x01, 0x85, 0x17, 0x01, - 0xe2, 0x1f, 0x12, 0x9c, 0x6c, 0x02, 0xca, 0x82, - 0x82, 0x19, 0x8a, 0x82, 0x06, 0x95, 0x91, 0x08, - 0x80, 0x91, 0x94, 0x35, 0x81, 0x19, 0x08, 0x93, - 0x11, 0x0b, 0x8c, 0x92, 0x00, 0x82, 0x92, 0x00, - 0x81, 0x92, 0x0b, 0xdd, 0x44, 0x01, 0x89, 0x44, - 0x05, 0x89, 0x44, 0x05, 0x81, 0x60, 0x81, 0x19, - 0x80, 0x60, 0x80, 0x19, 0x93, 0x60, 0x05, 0xd8, - 0x60, 0x06, 0xaa, 0x60, 0x04, 0xc5, 0x12, 0x09, - 0x9e, 0x4c, 0x00, 0x8b, 0x4c, 0x03, 0x8b, 0x4c, - 0x03, 0x80, 0x4c, 0x02, 0x8b, 0x4c, 0x9d, 0x93, - 0x01, 0x84, 0x93, 0x0a, 0xab, 0x67, 0x03, 0x99, - 0x67, 0x05, 0x8a, 0x67, 0x02, 0x81, 0x67, 0x9f, - 0x44, 0x9b, 0x10, 0x01, 0x81, 0x10, 0xbe, 0x94, - 0x00, 0x9c, 0x94, 0x01, 0x8a, 0x94, 0x05, 0x89, - 0x94, 0x05, 0x8d, 0x94, 0x01, 0x9e, 0x3a, 0x30, - 0xcc, 0x07, 0x00, 0xb1, 0x07, 0xbf, 0x8d, 0xb3, - 0x0a, 0x07, 0x83, 0x0a, 0xb7, 0x4b, 0x02, 0x8e, - 0x4b, 0x02, 0x82, 0x4b, 0xaf, 0x6d, 0x8a, 0x1d, - 0x04, 0xaa, 0x29, 0x01, 0x82, 0x29, 0x87, 0x8d, - 0x07, 0x82, 0x3a, 0x80, 0x19, 0x8c, 0x3a, 0x80, - 0x19, 0x86, 0x3a, 0x83, 0x19, 0x80, 0x3a, 0x85, - 0x19, 0x80, 0x3a, 0x82, 0x19, 0x81, 0x3a, 0x80, - 0x19, 0x04, 0xa5, 0x4a, 0x84, 0x2d, 0x80, 0x1d, - 0xb0, 0x4a, 0x84, 0x2d, 0x83, 0x4a, 0x84, 0x2d, - 0x8c, 0x4a, 0x80, 0x1d, 0xc5, 0x4a, 0x80, 0x2d, - 0xbf, 0x3a, 0xe0, 0x9f, 0x4a, 0x95, 0x2d, 0x01, - 0x85, 0x2d, 0x01, 0xa5, 0x2d, 0x01, 0x85, 0x2d, - 0x01, 0x87, 0x2d, 0x00, 0x80, 0x2d, 0x00, 0x80, - 0x2d, 0x00, 0x80, 0x2d, 0x00, 0x9e, 0x2d, 0x01, - 0xb4, 0x2d, 0x00, 0x8e, 0x2d, 0x00, 0x8d, 0x2d, - 0x01, 0x85, 0x2d, 0x00, 0x92, 0x2d, 0x01, 0x82, - 0x2d, 0x00, 0x88, 0x2d, 0x00, 0x8b, 0x19, 0x81, - 0x3a, 0xd6, 0x19, 0x00, 0x8a, 0x19, 0x80, 0x4a, - 0x01, 0x8a, 0x19, 0x80, 0x4a, 0x8e, 0x19, 0x00, - 0x8c, 0x4a, 0x02, 0xa0, 0x19, 0x0e, 0xa0, 0x3a, - 0x0e, 0xa5, 0x19, 0x80, 0x2d, 0x82, 0x19, 0x81, - 0x4a, 0x85, 0x19, 0x80, 0x4a, 0x9a, 0x19, 0x80, - 0x4a, 0x90, 0x19, 0xa8, 0x4a, 0x82, 0x19, 0x03, - 0xe2, 0x39, 0x19, 0x15, 0x8a, 0x19, 0x14, 0xe3, - 0x3f, 0x19, 0xe0, 0x9f, 0x0f, 0xe2, 0x13, 0x19, - 0x01, 0x9f, 0x19, 0x00, 0xe0, 0x08, 0x19, 0xdf, - 0x2a, 0x9f, 0x4a, 0xe0, 0x13, 0x1a, 0x04, 0x86, - 0x1a, 0xa5, 0x29, 0x00, 0x80, 0x29, 0x04, 0x80, - 0x29, 0x01, 0xb7, 0x9d, 0x06, 0x81, 0x9d, 0x0d, - 0x80, 0x9d, 0x96, 0x27, 0x08, 0x86, 0x27, 0x00, - 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86, 0x27, - 0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86, - 0x27, 0x00, 0x86, 0x27, 0x00, 0x9f, 0x1d, 0xdd, - 0x19, 0x21, 0x99, 0x32, 0x00, 0xd8, 0x32, 0x0b, - 0xe0, 0x75, 0x32, 0x19, 0x94, 0x19, 0x80, 0x32, - 0x80, 0x19, 0x80, 0x32, 0x98, 0x19, 0x88, 0x32, - 0x83, 0x3a, 0x81, 0x33, 0x87, 0x19, 0x83, 0x32, - 0x83, 0x19, 0x00, 0xd5, 0x38, 0x01, 0x81, 0x3a, - 0x81, 0x19, 0x82, 0x38, 0x80, 0x19, 0xd9, 0x40, - 0x81, 0x19, 0x82, 0x40, 0x04, 0xaa, 0x0d, 0x00, - 0xdd, 0x33, 0x00, 0x8f, 0x19, 0x9f, 0x0d, 0xa5, - 0x19, 0x08, 0x80, 0x19, 0x8f, 0x40, 0x9e, 0x33, - 0x00, 0xbf, 0x19, 0x9e, 0x33, 0xd0, 0x19, 0xae, - 0x40, 0x80, 0x19, 0xd7, 0x40, 0xe0, 0x47, 0x19, - 0xf0, 0x09, 0x5f, 0x32, 0xbf, 0x19, 0xf0, 0x41, - 0x9f, 0x32, 0xe4, 0x2c, 0xa9, 0x02, 0xb6, 0xa9, - 0x08, 0xaf, 0x4f, 0xe0, 0xcb, 0xa4, 0x13, 0xdf, - 0x1d, 0xd7, 0x08, 0x07, 0xa1, 0x19, 0xe0, 0x05, - 0x4a, 0x82, 0x19, 0xc2, 0x4a, 0x01, 0x81, 0x4a, - 0x00, 0x80, 0x4a, 0x00, 0x87, 0x4a, 0x14, 0x8d, - 0x4a, 0xac, 0x8f, 0x02, 0x89, 0x19, 0x05, 0xb7, - 0x7e, 0x07, 0xc5, 0x84, 0x07, 0x8b, 0x84, 0x05, - 0x9f, 0x20, 0xad, 0x42, 0x80, 0x19, 0x80, 0x42, - 0xa3, 0x81, 0x0a, 0x80, 0x81, 0x9c, 0x33, 0x02, - 0xcd, 0x3d, 0x00, 0x80, 0x19, 0x89, 0x3d, 0x03, - 0x81, 0x3d, 0x9e, 0x63, 0x00, 0xb6, 0x16, 0x08, - 0x8d, 0x16, 0x01, 0x89, 0x16, 0x01, 0x83, 0x16, - 0x9f, 0x63, 0xc2, 0x95, 0x17, 0x84, 0x95, 0x96, - 0x5a, 0x09, 0x85, 0x27, 0x01, 0x85, 0x27, 0x01, - 0x85, 0x27, 0x08, 0x86, 0x27, 0x00, 0x86, 0x27, - 0x00, 0xaa, 0x4a, 0x80, 0x19, 0x88, 0x4a, 0x80, - 0x2d, 0x83, 0x4a, 0x81, 0x19, 0x03, 0xcf, 0x17, - 0xad, 0x5a, 0x01, 0x89, 0x5a, 0x05, 0xf0, 0x1b, - 0x43, 0x33, 0x0b, 0x96, 0x33, 0x03, 0xb0, 0x33, - 0x70, 0x10, 0xa3, 0xe1, 0x0d, 0x32, 0x01, 0xe0, - 0x09, 0x32, 0x25, 0x86, 0x4a, 0x0b, 0x84, 0x05, - 0x04, 0x99, 0x37, 0x00, 0x84, 0x37, 0x00, 0x80, - 0x37, 0x00, 0x81, 0x37, 0x00, 0x81, 0x37, 0x00, - 0x89, 0x37, 0xe0, 0x12, 0x04, 0x0f, 0xe1, 0x0a, - 0x04, 0x81, 0x19, 0xcf, 0x04, 0x01, 0xb5, 0x04, - 0x06, 0x80, 0x04, 0x1f, 0x8f, 0x04, 0x8f, 0x3a, - 0x89, 0x19, 0x05, 0x8d, 0x3a, 0x81, 0x1d, 0xa2, - 0x19, 0x00, 0x92, 0x19, 0x00, 0x83, 0x19, 0x03, - 0x84, 0x04, 0x00, 0xe0, 0x26, 0x04, 0x01, 0x80, - 0x19, 0x00, 0x9f, 0x19, 0x99, 0x4a, 0x85, 0x19, - 0x99, 0x4a, 0x8a, 0x19, 0x89, 0x40, 0x80, 0x19, - 0xac, 0x40, 0x81, 0x19, 0x9e, 0x33, 0x02, 0x85, - 0x33, 0x01, 0x85, 0x33, 0x01, 0x85, 0x33, 0x01, - 0x82, 0x33, 0x02, 0x86, 0x19, 0x00, 0x86, 0x19, - 0x09, 0x84, 0x19, 0x01, 0x8b, 0x4e, 0x00, 0x99, - 0x4e, 0x00, 0x92, 0x4e, 0x00, 0x81, 0x4e, 0x00, - 0x8e, 0x4e, 0x01, 0x8d, 0x4e, 0x21, 0xe0, 0x1a, - 0x4e, 0x04, 0x82, 0x19, 0x03, 0xac, 0x19, 0x02, - 0x88, 0x19, 0xce, 0x2d, 0x00, 0x8c, 0x19, 0x02, - 0x80, 0x2d, 0x2e, 0xac, 0x19, 0x80, 0x3a, 0x60, - 0x21, 0x9c, 0x50, 0x02, 0xb0, 0x13, 0x0e, 0x80, - 0x3a, 0x9a, 0x19, 0x03, 0xa3, 0x70, 0x08, 0x82, - 0x70, 0x9a, 0x2b, 0x04, 0xaa, 0x72, 0x04, 0x9d, - 0xa3, 0x00, 0x80, 0xa3, 0xa3, 0x73, 0x03, 0x8d, - 0x73, 0x29, 0xcf, 0x1f, 0xaf, 0x86, 0x9d, 0x7a, - 0x01, 0x89, 0x7a, 0x05, 0xa3, 0x79, 0x03, 0xa3, - 0x79, 0x03, 0xa7, 0x25, 0x07, 0xb3, 0x14, 0x0a, - 0x80, 0x14, 0x8a, 0xa5, 0x00, 0x8e, 0xa5, 0x00, - 0x86, 0xa5, 0x00, 0x81, 0xa5, 0x00, 0x8a, 0xa5, - 0x00, 0x8e, 0xa5, 0x00, 0x86, 0xa5, 0x00, 0x81, - 0xa5, 0x02, 0xb3, 0xa0, 0x0b, 0xe0, 0xd6, 0x4d, - 0x08, 0x95, 0x4d, 0x09, 0x87, 0x4d, 0x17, 0x85, - 0x4a, 0x00, 0xa9, 0x4a, 0x00, 0x88, 0x4a, 0x44, - 0x85, 0x1c, 0x01, 0x80, 0x1c, 0x00, 0xab, 0x1c, - 0x00, 0x81, 0x1c, 0x02, 0x80, 0x1c, 0x01, 0x80, - 0x1c, 0x95, 0x39, 0x00, 0x88, 0x39, 0x9f, 0x7c, - 0x9e, 0x64, 0x07, 0x88, 0x64, 0x2f, 0x92, 0x36, - 0x00, 0x81, 0x36, 0x04, 0x84, 0x36, 0x9b, 0x7f, - 0x02, 0x80, 0x7f, 0x99, 0x51, 0x04, 0x80, 0x51, - 0x3f, 0x9f, 0x5d, 0x97, 0x5c, 0x03, 0x93, 0x5c, - 0x01, 0xad, 0x5c, 0x83, 0x43, 0x00, 0x81, 0x43, - 0x04, 0x87, 0x43, 0x00, 0x82, 0x43, 0x00, 0x9c, - 0x43, 0x01, 0x82, 0x43, 0x03, 0x89, 0x43, 0x06, - 0x88, 0x43, 0x06, 0x9f, 0x75, 0x9f, 0x71, 0x1f, - 0xa6, 0x56, 0x03, 0x8b, 0x56, 0x08, 0xb5, 0x06, - 0x02, 0x86, 0x06, 0x95, 0x3c, 0x01, 0x87, 0x3c, - 0x92, 0x3b, 0x04, 0x87, 0x3b, 0x91, 0x80, 0x06, - 0x83, 0x80, 0x0b, 0x86, 0x80, 0x4f, 0xc8, 0x76, - 0x36, 0xb2, 0x6f, 0x0c, 0xb2, 0x6f, 0x06, 0x85, - 0x6f, 0xa7, 0x34, 0x07, 0x89, 0x34, 0x05, 0xa5, - 0x28, 0x02, 0x9c, 0x28, 0x07, 0x81, 0x28, 0x60, - 0x6f, 0x9e, 0x04, 0x00, 0xa9, 0xa8, 0x00, 0x82, - 0xa8, 0x01, 0x81, 0xa8, 0x0f, 0x82, 0x04, 0x36, - 0x83, 0x04, 0xa7, 0x74, 0x07, 0xa9, 0x8a, 0x15, - 0x99, 0x77, 0x25, 0x9b, 0x18, 0x13, 0x96, 0x26, - 0x08, 0xcd, 0x0e, 0x03, 0xa3, 0x0e, 0x08, 0x80, - 0x0e, 0xc2, 0x3e, 0x09, 0x80, 0x3e, 0x01, 0x98, - 0x8b, 0x06, 0x89, 0x8b, 0x05, 0xb4, 0x15, 0x00, - 0x91, 0x15, 0x07, 0xa6, 0x53, 0x08, 0xdf, 0x85, - 0x00, 0x93, 0x89, 0x0a, 0x91, 0x45, 0x00, 0xae, - 0x45, 0x3d, 0x86, 0x62, 0x00, 0x80, 0x62, 0x00, - 0x83, 0x62, 0x00, 0x8e, 0x62, 0x00, 0x8a, 0x62, - 0x05, 0xba, 0x47, 0x04, 0x89, 0x47, 0x05, 0x83, - 0x2c, 0x00, 0x87, 0x2c, 0x01, 0x81, 0x2c, 0x01, - 0x95, 0x2c, 0x00, 0x86, 0x2c, 0x00, 0x81, 0x2c, - 0x00, 0x84, 0x2c, 0x00, 0x80, 0x3a, 0x88, 0x2c, - 0x01, 0x81, 0x2c, 0x01, 0x82, 0x2c, 0x01, 0x80, - 0x2c, 0x05, 0x80, 0x2c, 0x04, 0x86, 0x2c, 0x01, - 0x86, 0x2c, 0x02, 0x84, 0x2c, 0x0a, 0x89, 0xa2, - 0x00, 0x80, 0xa2, 0x01, 0x80, 0xa2, 0x00, 0xa5, - 0xa2, 0x00, 0x89, 0xa2, 0x00, 0x80, 0xa2, 0x01, - 0x80, 0xa2, 0x00, 0x83, 0xa2, 0x00, 0x89, 0xa2, - 0x00, 0x81, 0xa2, 0x07, 0x81, 0xa2, 0x1c, 0xdb, - 0x68, 0x00, 0x84, 0x68, 0x1d, 0xc7, 0x9e, 0x07, - 0x89, 0x9e, 0x60, 0x45, 0xb5, 0x87, 0x01, 0xa5, - 0x87, 0x21, 0xc4, 0x5f, 0x0a, 0x89, 0x5f, 0x05, - 0x8c, 0x60, 0x12, 0xb9, 0x96, 0x05, 0x89, 0x96, - 0x05, 0x93, 0x63, 0x1b, 0x9a, 0x02, 0x01, 0x8e, - 0x02, 0x03, 0x96, 0x02, 0x60, 0x58, 0xbb, 0x22, - 0x60, 0x03, 0xd2, 0xa7, 0x0b, 0x80, 0xa7, 0x86, - 0x21, 0x01, 0x80, 0x21, 0x01, 0x87, 0x21, 0x00, - 0x81, 0x21, 0x00, 0x9d, 0x21, 0x00, 0x81, 0x21, - 0x01, 0x8b, 0x21, 0x08, 0x89, 0x21, 0x45, 0x87, - 0x66, 0x01, 0xad, 0x66, 0x01, 0x8a, 0x66, 0x1a, - 0xc7, 0xaa, 0x07, 0xd2, 0x8c, 0x0c, 0x8f, 0x12, - 0xb8, 0x7d, 0x06, 0x89, 0x20, 0x60, 0x55, 0xa1, - 0x8e, 0x0d, 0x89, 0x8e, 0x05, 0x88, 0x0c, 0x00, - 0xac, 0x0c, 0x00, 0x8d, 0x0c, 0x09, 0x9c, 0x0c, - 0x02, 0x9f, 0x57, 0x01, 0x95, 0x57, 0x00, 0x8d, - 0x57, 0x48, 0x86, 0x58, 0x00, 0x81, 0x58, 0x00, - 0xab, 0x58, 0x02, 0x80, 0x58, 0x00, 0x81, 0x58, - 0x00, 0x88, 0x58, 0x07, 0x89, 0x58, 0x05, 0x85, - 0x2f, 0x00, 0x81, 0x2f, 0x00, 0xa4, 0x2f, 0x00, - 0x81, 0x2f, 0x00, 0x85, 0x2f, 0x06, 0x89, 0x2f, - 0x60, 0xd5, 0x98, 0x52, 0x06, 0x90, 0x41, 0x00, - 0xa8, 0x41, 0x02, 0x9c, 0x41, 0x54, 0x80, 0x4f, - 0x0e, 0xb1, 0x97, 0x0c, 0x80, 0x97, 0xe3, 0x39, - 0x1b, 0x60, 0x05, 0xe0, 0x0e, 0x1b, 0x00, 0x84, - 0x1b, 0x0a, 0xe0, 0x63, 0x1b, 0x69, 0xeb, 0xe0, - 0x02, 0x1e, 0x0c, 0xe3, 0xf5, 0x24, 0x09, 0xef, - 0x3a, 0x24, 0x04, 0xe1, 0xe6, 0x03, 0x70, 0x0a, - 0x58, 0xb9, 0x31, 0x66, 0x65, 0xe1, 0xd8, 0x08, - 0x06, 0x9e, 0x61, 0x00, 0x89, 0x61, 0x03, 0x81, - 0x61, 0xce, 0x9f, 0x00, 0x89, 0x9f, 0x05, 0x9d, - 0x09, 0x01, 0x85, 0x09, 0x09, 0xc5, 0x7b, 0x09, - 0x89, 0x7b, 0x00, 0x86, 0x7b, 0x00, 0x94, 0x7b, - 0x04, 0x92, 0x7b, 0x61, 0x4f, 0xb9, 0x48, 0x60, - 0x65, 0xda, 0x59, 0x60, 0x04, 0xca, 0x5e, 0x03, - 0xb8, 0x5e, 0x06, 0x90, 0x5e, 0x3f, 0x80, 0x98, - 0x80, 0x6a, 0x81, 0x32, 0x80, 0x46, 0x0a, 0x81, - 0x32, 0x0d, 0xf0, 0x07, 0x97, 0x98, 0x07, 0xe2, - 0x9f, 0x98, 0xe1, 0x75, 0x46, 0x28, 0x80, 0x46, - 0x88, 0x98, 0x70, 0x12, 0x86, 0x83, 0x40, 0x00, - 0x86, 0x40, 0x00, 0x81, 0x40, 0x00, 0x80, 0x40, - 0xe0, 0xbe, 0x38, 0x82, 0x40, 0x0e, 0x80, 0x38, - 0x1c, 0x82, 0x38, 0x01, 0x80, 0x40, 0x0d, 0x83, - 0x40, 0x07, 0xe1, 0x2b, 0x6a, 0x68, 0xa3, 0xe0, - 0x0a, 0x23, 0x04, 0x8c, 0x23, 0x02, 0x88, 0x23, - 0x06, 0x89, 0x23, 0x01, 0x83, 0x23, 0x83, 0x19, - 0x6e, 0xfb, 0xe0, 0x99, 0x19, 0x05, 0xe1, 0x53, - 0x19, 0x4b, 0xad, 0x3a, 0x01, 0x96, 0x3a, 0x08, - 0xe0, 0x13, 0x19, 0x3b, 0xe0, 0x95, 0x19, 0x09, - 0xa6, 0x19, 0x01, 0xbd, 0x19, 0x82, 0x3a, 0x90, - 0x19, 0x87, 0x3a, 0x81, 0x19, 0x86, 0x3a, 0x9d, - 0x19, 0x83, 0x3a, 0xbc, 0x19, 0x14, 0xc5, 0x2d, - 0x60, 0x19, 0x93, 0x19, 0x0b, 0x93, 0x19, 0x0b, - 0xd6, 0x19, 0x08, 0x98, 0x19, 0x60, 0x26, 0xd4, - 0x19, 0x00, 0xc6, 0x19, 0x00, 0x81, 0x19, 0x01, - 0x80, 0x19, 0x01, 0x81, 0x19, 0x01, 0x83, 0x19, - 0x00, 0x8b, 0x19, 0x00, 0x80, 0x19, 0x00, 0x86, - 0x19, 0x00, 0xc0, 0x19, 0x00, 0x83, 0x19, 0x01, - 0x87, 0x19, 0x00, 0x86, 0x19, 0x00, 0x9b, 0x19, - 0x00, 0x83, 0x19, 0x00, 0x84, 0x19, 0x00, 0x80, - 0x19, 0x02, 0x86, 0x19, 0x00, 0xe0, 0xf3, 0x19, - 0x01, 0xe0, 0xc3, 0x19, 0x01, 0xb1, 0x19, 0xe2, - 0x2b, 0x88, 0x0e, 0x84, 0x88, 0x00, 0x8e, 0x88, - 0x63, 0xef, 0x9e, 0x4a, 0x05, 0x85, 0x4a, 0x60, - 0x74, 0x86, 0x2a, 0x00, 0x90, 0x2a, 0x01, 0x86, - 0x2a, 0x00, 0x81, 0x2a, 0x00, 0x84, 0x2a, 0x04, - 0xbd, 0x1d, 0x20, 0x80, 0x1d, 0x60, 0x0f, 0xac, - 0x6b, 0x02, 0x8d, 0x6b, 0x01, 0x89, 0x6b, 0x03, - 0x81, 0x6b, 0x60, 0xdf, 0x9e, 0xa1, 0x10, 0xb9, - 0xa6, 0x04, 0x80, 0xa6, 0x61, 0x6f, 0xa9, 0x65, - 0x60, 0x75, 0xaa, 0x6e, 0x03, 0x80, 0x6e, 0x61, - 0x7f, 0x86, 0x27, 0x00, 0x83, 0x27, 0x00, 0x81, - 0x27, 0x00, 0x8e, 0x27, 0x00, 0xe0, 0x64, 0x5b, - 0x01, 0x8f, 0x5b, 0x28, 0xcb, 0x01, 0x03, 0x89, - 0x01, 0x03, 0x81, 0x01, 0x62, 0xb0, 0xc3, 0x19, - 0x4b, 0xbc, 0x19, 0x60, 0x61, 0x83, 0x04, 0x00, - 0x9a, 0x04, 0x00, 0x81, 0x04, 0x00, 0x80, 0x04, - 0x01, 0x80, 0x04, 0x00, 0x89, 0x04, 0x00, 0x83, - 0x04, 0x00, 0x80, 0x04, 0x00, 0x80, 0x04, 0x05, - 0x80, 0x04, 0x03, 0x80, 0x04, 0x00, 0x80, 0x04, - 0x00, 0x80, 0x04, 0x00, 0x82, 0x04, 0x00, 0x81, - 0x04, 0x00, 0x80, 0x04, 0x01, 0x80, 0x04, 0x00, - 0x80, 0x04, 0x00, 0x80, 0x04, 0x00, 0x80, 0x04, - 0x00, 0x80, 0x04, 0x00, 0x81, 0x04, 0x00, 0x80, - 0x04, 0x01, 0x83, 0x04, 0x00, 0x86, 0x04, 0x00, - 0x83, 0x04, 0x00, 0x83, 0x04, 0x00, 0x80, 0x04, - 0x00, 0x89, 0x04, 0x00, 0x90, 0x04, 0x04, 0x82, - 0x04, 0x00, 0x84, 0x04, 0x00, 0x90, 0x04, 0x33, - 0x81, 0x04, 0x60, 0xad, 0xab, 0x19, 0x03, 0xe0, - 0x03, 0x19, 0x0b, 0x8e, 0x19, 0x01, 0x8e, 0x19, - 0x00, 0x8e, 0x19, 0x00, 0xa4, 0x19, 0x09, 0xe0, - 0x4d, 0x19, 0x37, 0x99, 0x19, 0x80, 0x38, 0x81, - 0x19, 0x0c, 0xab, 0x19, 0x03, 0x88, 0x19, 0x06, - 0x81, 0x19, 0x0d, 0x85, 0x19, 0x60, 0x39, 0xe3, - 0x77, 0x19, 0x03, 0x90, 0x19, 0x02, 0x8c, 0x19, - 0x02, 0xe0, 0x16, 0x19, 0x03, 0xde, 0x19, 0x05, - 0x8b, 0x19, 0x03, 0x80, 0x19, 0x0e, 0x8b, 0x19, - 0x03, 0xb7, 0x19, 0x07, 0x89, 0x19, 0x05, 0xa7, - 0x19, 0x07, 0x9d, 0x19, 0x01, 0x8b, 0x19, 0x03, - 0x81, 0x19, 0x3d, 0xe0, 0xf3, 0x19, 0x0b, 0x8d, - 0x19, 0x01, 0x8c, 0x19, 0x02, 0x89, 0x19, 0x04, - 0xb7, 0x19, 0x06, 0x8e, 0x19, 0x01, 0x8a, 0x19, - 0x05, 0x88, 0x19, 0x06, 0xe0, 0x32, 0x19, 0x00, - 0xe0, 0x05, 0x19, 0x63, 0xa5, 0xf0, 0x96, 0x7f, - 0x32, 0x1f, 0xef, 0xd9, 0x32, 0x05, 0xe0, 0x7d, - 0x32, 0x01, 0xf0, 0x06, 0x21, 0x32, 0x0d, 0xf0, - 0x0c, 0xd0, 0x32, 0x0e, 0xe2, 0x0d, 0x32, 0x69, - 0x41, 0xe1, 0xbd, 0x32, 0x65, 0x81, 0xf0, 0x02, - 0xea, 0x32, 0x04, 0xef, 0xff, 0x32, 0x7a, 0xcb, - 0xf0, 0x80, 0x19, 0x1d, 0xdf, 0x19, 0x60, 0x1f, - 0xe0, 0x8f, 0x3a, -}; - -static const uint8_t unicode_script_ext_table[1253] = { - 0x80, 0x36, 0x00, 0x00, 0x10, 0x06, 0x13, 0x1a, - 0x23, 0x25, 0x29, 0x2a, 0x2f, 0x2b, 0x2d, 0x32, - 0x4a, 0x51, 0x53, 0x72, 0x86, 0x81, 0x83, 0x00, - 0x00, 0x07, 0x0b, 0x1d, 0x20, 0x4a, 0x4f, 0x9b, - 0xa1, 0x09, 0x00, 0x00, 0x02, 0x0d, 0x4a, 0x00, - 0x00, 0x02, 0x02, 0x0d, 0x4a, 0x00, 0x00, 0x00, - 0x02, 0x4a, 0x4f, 0x08, 0x00, 0x00, 0x02, 0x4a, - 0x9b, 0x00, 0x00, 0x00, 0x02, 0x0d, 0x4a, 0x25, - 0x00, 0x00, 0x08, 0x17, 0x1a, 0x1d, 0x2d, 0x4a, - 0x72, 0x8e, 0x93, 0x00, 0x08, 0x17, 0x1d, 0x2d, - 0x4a, 0x79, 0x8e, 0x93, 0xa0, 0x00, 0x04, 0x17, - 0x1d, 0x4a, 0x9d, 0x00, 0x05, 0x2a, 0x4a, 0x8e, - 0x90, 0x9b, 0x00, 0x0b, 0x14, 0x17, 0x1a, 0x1d, - 0x2b, 0x2d, 0x4a, 0x79, 0x90, 0x9d, 0xa0, 0x00, - 0x06, 0x1a, 0x25, 0x2a, 0x2b, 0x40, 0x4a, 0x00, - 0x04, 0x1d, 0x2d, 0x4a, 0x72, 0x00, 0x09, 0x1a, - 0x23, 0x37, 0x4a, 0x72, 0x90, 0x93, 0x9d, 0xa0, - 0x00, 0x0a, 0x05, 0x1d, 0x23, 0x2b, 0x2d, 0x37, - 0x4a, 0x72, 0x90, 0x93, 0x00, 0x02, 0x4a, 0x9d, - 0x00, 0x03, 0x23, 0x4a, 0x90, 0x00, 0x04, 0x17, - 0x1d, 0x4a, 0x79, 0x00, 0x03, 0x17, 0x4a, 0x93, - 0x00, 0x02, 0x4a, 0x8e, 0x00, 0x02, 0x27, 0x4a, - 0x00, 0x00, 0x00, 0x02, 0x4a, 0x8e, 0x00, 0x03, - 0x1d, 0x4a, 0xa0, 0x00, 0x00, 0x00, 0x04, 0x2d, - 0x4a, 0x72, 0xa0, 0x0b, 0x00, 0x00, 0x02, 0x4a, - 0x90, 0x01, 0x00, 0x00, 0x05, 0x17, 0x23, 0x40, - 0x4a, 0x90, 0x00, 0x04, 0x17, 0x23, 0x4a, 0x90, - 0x00, 0x02, 0x4a, 0x90, 0x06, 0x00, 0x00, 0x03, - 0x4a, 0x8e, 0x90, 0x00, 0x02, 0x4a, 0x90, 0x00, - 0x00, 0x00, 0x03, 0x17, 0x4a, 0x90, 0x00, 0x06, - 0x14, 0x17, 0x2b, 0x4a, 0x8e, 0x9b, 0x0f, 0x00, - 0x00, 0x01, 0x2d, 0x01, 0x00, 0x00, 0x01, 0x2d, - 0x11, 0x00, 0x00, 0x02, 0x4a, 0x79, 0x04, 0x00, - 0x00, 0x03, 0x14, 0x4a, 0xa0, 0x03, 0x00, 0x0c, - 0x01, 0x4a, 0x03, 0x00, 0x01, 0x02, 0x1a, 0x2d, - 0x80, 0x8c, 0x00, 0x00, 0x02, 0x1d, 0x72, 0x00, - 0x02, 0x1d, 0x2a, 0x01, 0x02, 0x1d, 0x4a, 0x00, - 0x02, 0x1d, 0x2a, 0x80, 0x80, 0x00, 0x00, 0x03, - 0x05, 0x29, 0x2a, 0x80, 0x01, 0x00, 0x00, 0x07, - 0x04, 0x28, 0x69, 0x34, 0x90, 0x9a, 0xa8, 0x0d, - 0x00, 0x00, 0x07, 0x04, 0x28, 0x69, 0x34, 0x90, - 0x9a, 0xa8, 0x00, 0x03, 0x04, 0x90, 0x9a, 0x01, - 0x00, 0x00, 0x08, 0x01, 0x04, 0x28, 0x69, 0x34, - 0x90, 0x9a, 0xa8, 0x1f, 0x00, 0x00, 0x09, 0x01, - 0x04, 0x55, 0x56, 0x77, 0x80, 0x34, 0x8a, 0x90, - 0x09, 0x00, 0x0a, 0x02, 0x04, 0x90, 0x09, 0x00, - 0x09, 0x03, 0x04, 0x9a, 0xa8, 0x05, 0x00, 0x00, - 0x02, 0x04, 0x90, 0x62, 0x00, 0x00, 0x02, 0x04, - 0x34, 0x81, 0xfb, 0x00, 0x00, 0x0d, 0x0b, 0x20, - 0x2c, 0x2e, 0x30, 0x3f, 0x4a, 0x54, 0x78, 0x85, - 0x97, 0x99, 0x9e, 0x00, 0x0c, 0x0b, 0x20, 0x2c, - 0x2e, 0x30, 0x3f, 0x4a, 0x54, 0x78, 0x97, 0x99, - 0x9e, 0x10, 0x00, 0x00, 0x15, 0x0b, 0x20, 0x22, - 0x2f, 0x58, 0x2c, 0x2e, 0x30, 0x3f, 0x53, 0x54, - 0x66, 0x6e, 0x78, 0x47, 0x89, 0x8f, 0x96, 0x97, - 0x99, 0x9e, 0x00, 0x17, 0x0b, 0x20, 0x22, 0x2f, - 0x58, 0x2c, 0x2e, 0x31, 0x30, 0x3f, 0x4c, 0x53, - 0x54, 0x66, 0x6e, 0x78, 0x47, 0x89, 0x8f, 0x96, - 0x97, 0x99, 0x9e, 0x09, 0x04, 0x20, 0x22, 0x3e, - 0x53, 0x75, 0x00, 0x09, 0x03, 0x0b, 0x15, 0x8f, - 0x75, 0x00, 0x09, 0x02, 0x30, 0x62, 0x75, 0x00, - 0x09, 0x02, 0x2e, 0x45, 0x80, 0x75, 0x00, 0x0d, - 0x02, 0x2c, 0x97, 0x80, 0x71, 0x00, 0x09, 0x03, - 0x3f, 0x66, 0xa2, 0x82, 0xcf, 0x00, 0x09, 0x03, - 0x15, 0x63, 0x93, 0x80, 0x30, 0x00, 0x00, 0x03, - 0x29, 0x2a, 0x4a, 0x85, 0x6e, 0x00, 0x02, 0x01, - 0x82, 0x46, 0x00, 0x01, 0x04, 0x11, 0x35, 0x92, - 0x91, 0x80, 0x4a, 0x00, 0x01, 0x02, 0x60, 0x7e, - 0x00, 0x00, 0x00, 0x02, 0x60, 0x7e, 0x84, 0x49, - 0x00, 0x00, 0x04, 0x0b, 0x20, 0x2c, 0x3f, 0x00, - 0x01, 0x20, 0x00, 0x04, 0x0b, 0x20, 0x2c, 0x3f, - 0x00, 0x03, 0x20, 0x2c, 0x3f, 0x00, 0x01, 0x20, - 0x01, 0x02, 0x0b, 0x20, 0x00, 0x02, 0x20, 0x85, - 0x00, 0x02, 0x0b, 0x20, 0x00, 0x02, 0x20, 0x85, - 0x00, 0x06, 0x20, 0x3f, 0x54, 0x78, 0x97, 0x99, - 0x00, 0x01, 0x20, 0x01, 0x02, 0x20, 0x85, 0x01, - 0x01, 0x20, 0x00, 0x02, 0x20, 0x85, 0x00, 0x02, - 0x0b, 0x20, 0x06, 0x01, 0x20, 0x00, 0x02, 0x20, - 0x66, 0x00, 0x02, 0x0b, 0x20, 0x01, 0x01, 0x20, - 0x00, 0x02, 0x0b, 0x20, 0x03, 0x01, 0x20, 0x00, - 0x0b, 0x0b, 0x20, 0x2c, 0x3f, 0x54, 0x66, 0x78, - 0x89, 0x99, 0x9e, 0xa2, 0x00, 0x02, 0x20, 0x2c, - 0x00, 0x04, 0x20, 0x2c, 0x3f, 0xa2, 0x01, 0x02, - 0x0b, 0x20, 0x00, 0x01, 0x0b, 0x01, 0x02, 0x20, - 0x2c, 0x00, 0x01, 0x66, 0x80, 0x44, 0x00, 0x01, - 0x01, 0x2d, 0x35, 0x00, 0x00, 0x03, 0x1d, 0x4a, - 0x90, 0x00, 0x00, 0x00, 0x01, 0x90, 0x81, 0xb3, - 0x00, 0x00, 0x03, 0x4a, 0x60, 0x7e, 0x1e, 0x00, - 0x00, 0x02, 0x01, 0x04, 0x09, 0x00, 0x00, 0x06, - 0x13, 0x29, 0x2a, 0x6f, 0x50, 0x76, 0x01, 0x00, - 0x00, 0x04, 0x13, 0x2d, 0x6f, 0x5d, 0x80, 0x11, - 0x00, 0x00, 0x03, 0x20, 0x2c, 0x4a, 0x8c, 0xa5, - 0x00, 0x00, 0x02, 0x1a, 0x4a, 0x17, 0x00, 0x00, - 0x02, 0x06, 0x76, 0x00, 0x07, 0x06, 0x13, 0x29, - 0x6f, 0x3e, 0x51, 0x83, 0x09, 0x00, 0x00, 0x01, - 0x23, 0x03, 0x00, 0x00, 0x03, 0x01, 0x04, 0x6f, - 0x00, 0x00, 0x00, 0x02, 0x1d, 0x2a, 0x81, 0x2b, - 0x00, 0x0f, 0x02, 0x32, 0x98, 0x00, 0x00, 0x00, - 0x07, 0x0d, 0x33, 0x32, 0x38, 0x40, 0x60, 0xa9, - 0x00, 0x08, 0x0d, 0x33, 0x32, 0x38, 0x40, 0x60, - 0x7e, 0xa9, 0x00, 0x05, 0x0d, 0x33, 0x32, 0x38, - 0x40, 0x01, 0x00, 0x00, 0x01, 0x32, 0x00, 0x00, - 0x01, 0x08, 0x0d, 0x33, 0x32, 0x38, 0x40, 0x60, - 0x9c, 0xa9, 0x01, 0x09, 0x0d, 0x33, 0x32, 0x38, - 0x40, 0x4f, 0x60, 0x9c, 0xa9, 0x05, 0x06, 0x0d, - 0x33, 0x32, 0x38, 0x40, 0xa9, 0x00, 0x00, 0x00, - 0x05, 0x0d, 0x33, 0x32, 0x38, 0x40, 0x07, 0x06, - 0x0d, 0x33, 0x32, 0x38, 0x40, 0xa9, 0x03, 0x05, - 0x0d, 0x33, 0x32, 0x38, 0x40, 0x09, 0x00, 0x03, - 0x02, 0x0d, 0x32, 0x01, 0x00, 0x00, 0x05, 0x0d, - 0x33, 0x32, 0x38, 0x40, 0x04, 0x02, 0x38, 0x40, - 0x00, 0x00, 0x00, 0x05, 0x0d, 0x33, 0x32, 0x38, - 0x40, 0x03, 0x00, 0x01, 0x03, 0x32, 0x38, 0x40, - 0x01, 0x01, 0x32, 0x58, 0x00, 0x03, 0x02, 0x38, - 0x40, 0x02, 0x00, 0x00, 0x02, 0x38, 0x40, 0x59, - 0x00, 0x00, 0x06, 0x0d, 0x33, 0x32, 0x38, 0x40, - 0xa9, 0x00, 0x02, 0x38, 0x40, 0x80, 0x12, 0x00, - 0x0f, 0x01, 0x32, 0x1f, 0x00, 0x25, 0x01, 0x32, - 0x08, 0x00, 0x00, 0x02, 0x32, 0x98, 0x2f, 0x00, - 0x27, 0x01, 0x32, 0x37, 0x00, 0x30, 0x01, 0x32, - 0x0e, 0x00, 0x0b, 0x01, 0x32, 0x32, 0x00, 0x00, - 0x01, 0x32, 0x57, 0x00, 0x18, 0x01, 0x32, 0x09, - 0x00, 0x04, 0x01, 0x32, 0x5f, 0x00, 0x1e, 0x01, - 0x32, 0xc0, 0x31, 0xef, 0x00, 0x00, 0x02, 0x1d, - 0x2a, 0x80, 0x0f, 0x00, 0x07, 0x02, 0x32, 0x4a, - 0x80, 0xa7, 0x00, 0x02, 0x10, 0x20, 0x22, 0x2e, - 0x30, 0x45, 0x3f, 0x3e, 0x53, 0x54, 0x5f, 0x66, - 0x85, 0x47, 0x96, 0x9e, 0xa2, 0x02, 0x0f, 0x20, - 0x22, 0x2e, 0x30, 0x45, 0x3f, 0x3e, 0x53, 0x5f, - 0x66, 0x85, 0x47, 0x96, 0x9e, 0xa2, 0x01, 0x0b, - 0x20, 0x22, 0x2e, 0x30, 0x45, 0x3e, 0x53, 0x5f, - 0x47, 0x96, 0x9e, 0x00, 0x0c, 0x20, 0x22, 0x2e, - 0x30, 0x45, 0x3e, 0x53, 0x5f, 0x85, 0x47, 0x96, - 0x9e, 0x00, 0x0b, 0x20, 0x22, 0x2e, 0x30, 0x45, - 0x3e, 0x53, 0x5f, 0x47, 0x96, 0x9e, 0x80, 0x36, - 0x00, 0x00, 0x03, 0x0b, 0x20, 0xa2, 0x00, 0x00, - 0x00, 0x02, 0x20, 0x97, 0x39, 0x00, 0x00, 0x03, - 0x42, 0x4a, 0x63, 0x80, 0x1f, 0x00, 0x00, 0x02, - 0x10, 0x3d, 0xc0, 0x12, 0xed, 0x00, 0x01, 0x02, - 0x04, 0x69, 0x80, 0x31, 0x00, 0x00, 0x02, 0x04, - 0x9a, 0x09, 0x00, 0x00, 0x02, 0x04, 0x9a, 0x46, - 0x00, 0x01, 0x05, 0x0d, 0x33, 0x32, 0x38, 0x40, - 0x80, 0x99, 0x00, 0x04, 0x06, 0x0d, 0x33, 0x32, - 0x38, 0x40, 0xa9, 0x09, 0x00, 0x00, 0x02, 0x38, - 0x40, 0x2c, 0x00, 0x01, 0x02, 0x38, 0x40, 0x80, - 0xdf, 0x00, 0x01, 0x03, 0x1e, 0x1c, 0x4e, 0x00, - 0x02, 0x1c, 0x4e, 0x03, 0x00, 0x2c, 0x03, 0x1c, - 0x4d, 0x4e, 0x02, 0x00, 0x08, 0x02, 0x1c, 0x4e, - 0x81, 0x1f, 0x00, 0x1b, 0x02, 0x04, 0x1a, 0x87, - 0x75, 0x00, 0x00, 0x02, 0x56, 0x77, 0x87, 0x8d, - 0x00, 0x00, 0x02, 0x2c, 0x97, 0x00, 0x00, 0x00, - 0x02, 0x2c, 0x97, 0x36, 0x00, 0x01, 0x02, 0x2c, - 0x97, 0x8c, 0x12, 0x00, 0x01, 0x02, 0x2c, 0x97, - 0x00, 0x00, 0x00, 0x02, 0x2c, 0x97, 0xc0, 0x5c, - 0x4b, 0x00, 0x03, 0x01, 0x23, 0x96, 0x3b, 0x00, - 0x11, 0x01, 0x32, 0x9e, 0x5d, 0x00, 0x01, 0x01, - 0x32, 0xce, 0xcd, 0x2d, 0x00, -}; - -static const uint8_t unicode_prop_Hyphen_table[28] = { - 0xac, 0x80, 0xfe, 0x80, 0x44, 0xdb, 0x80, 0x52, - 0x7a, 0x80, 0x48, 0x08, 0x81, 0x4e, 0x04, 0x80, - 0x42, 0xe2, 0x80, 0x60, 0xcd, 0x66, 0x80, 0x40, - 0xa8, 0x80, 0xd6, 0x80, -}; - -static const uint8_t unicode_prop_Other_Math_table[200] = { - 0xdd, 0x80, 0x43, 0x70, 0x11, 0x80, 0x99, 0x09, - 0x81, 0x5c, 0x1f, 0x80, 0x9a, 0x82, 0x8a, 0x80, - 0x9f, 0x83, 0x97, 0x81, 0x8d, 0x81, 0xc0, 0x8c, - 0x18, 0x11, 0x1c, 0x91, 0x03, 0x01, 0x89, 0x00, - 0x14, 0x28, 0x11, 0x09, 0x02, 0x05, 0x13, 0x24, - 0xca, 0x21, 0x18, 0x08, 0x08, 0x00, 0x21, 0x0b, - 0x0b, 0x91, 0x09, 0x00, 0x06, 0x00, 0x29, 0x41, - 0x21, 0x83, 0x40, 0xa7, 0x08, 0x80, 0x97, 0x80, - 0x90, 0x80, 0x41, 0xbc, 0x81, 0x8b, 0x88, 0x24, - 0x21, 0x09, 0x14, 0x8d, 0x00, 0x01, 0x85, 0x97, - 0x81, 0xb8, 0x00, 0x80, 0x9c, 0x83, 0x88, 0x81, - 0x41, 0x55, 0x81, 0x9e, 0x89, 0x41, 0x92, 0x95, - 0xbe, 0x83, 0x9f, 0x81, 0x60, 0xd4, 0x62, 0x00, - 0x03, 0x80, 0x40, 0xd2, 0x00, 0x80, 0x60, 0xd4, - 0xc0, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b, - 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f, - 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80, - 0x41, 0x53, 0x81, 0x98, 0x80, 0x98, 0x80, 0x9e, - 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, - 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07, 0x81, - 0xb1, 0x55, 0xff, 0x18, 0x9a, 0x01, 0x00, 0x08, - 0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18, 0x00, - 0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00, - 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90, -}; - -static const uint8_t unicode_prop_Other_Alphabetic_table[443] = { - 0x43, 0x44, 0x80, 0x9c, 0x8c, 0x42, 0x3f, 0x8d, - 0x00, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xaf, 0x8c, - 0x06, 0x8f, 0x80, 0xe4, 0x33, 0x19, 0x0b, 0x80, - 0xa2, 0x80, 0x9d, 0x8f, 0xe5, 0x8a, 0xe4, 0x0a, - 0x88, 0x02, 0x03, 0xe9, 0x80, 0xbb, 0x8b, 0x16, - 0x85, 0x93, 0xb5, 0x09, 0x8e, 0x01, 0x22, 0x89, - 0x81, 0x9c, 0x82, 0xb9, 0x31, 0x09, 0x81, 0x89, - 0x80, 0x89, 0x81, 0x9c, 0x82, 0xb9, 0x23, 0x09, - 0x0b, 0x80, 0x9d, 0x0a, 0x80, 0x8a, 0x82, 0xb9, - 0x38, 0x10, 0x81, 0x94, 0x81, 0x95, 0x13, 0x82, - 0xb9, 0x31, 0x09, 0x81, 0x88, 0x81, 0x89, 0x81, - 0x9d, 0x80, 0xba, 0x22, 0x10, 0x82, 0x89, 0x80, - 0xa7, 0x84, 0xb8, 0x30, 0x10, 0x17, 0x81, 0x8a, - 0x81, 0x9c, 0x82, 0xb9, 0x30, 0x10, 0x17, 0x81, - 0x8a, 0x81, 0x8e, 0x80, 0x8b, 0x83, 0xb9, 0x30, - 0x10, 0x82, 0x89, 0x80, 0x89, 0x81, 0x9c, 0x82, - 0xca, 0x28, 0x00, 0x87, 0x91, 0x81, 0xbc, 0x01, - 0x86, 0x91, 0x80, 0xe2, 0x01, 0x28, 0x81, 0x8f, - 0x80, 0x40, 0xa2, 0x92, 0x88, 0x8a, 0x80, 0xa3, - 0xed, 0x8b, 0x00, 0x0b, 0x96, 0x1b, 0x10, 0x11, - 0x32, 0x83, 0x8c, 0x8b, 0x00, 0x89, 0x83, 0x46, - 0x73, 0x81, 0x9d, 0x81, 0x9d, 0x81, 0x9d, 0x81, - 0xc1, 0x92, 0x40, 0xbb, 0x81, 0xa1, 0x80, 0xf5, - 0x8b, 0x83, 0x88, 0x40, 0xdd, 0x84, 0xb8, 0x89, - 0x81, 0x93, 0xc9, 0x81, 0x8a, 0x82, 0xb0, 0x84, - 0xaf, 0x8e, 0xbb, 0x82, 0x9d, 0x88, 0x09, 0xb8, - 0x8a, 0xb1, 0x92, 0x41, 0x9b, 0xa1, 0x46, 0xc0, - 0xb3, 0x48, 0xf5, 0x9f, 0x60, 0x78, 0x73, 0x87, - 0xa1, 0x81, 0x41, 0x61, 0x07, 0x80, 0x96, 0x84, - 0xd7, 0x81, 0xb1, 0x8f, 0x00, 0xb8, 0x80, 0xa5, - 0x84, 0x9b, 0x8b, 0xac, 0x83, 0xaf, 0x8b, 0xa4, - 0x80, 0xc2, 0x8d, 0x8b, 0x07, 0x81, 0xac, 0x82, - 0xb1, 0x00, 0x11, 0x0c, 0x80, 0xab, 0x24, 0x80, - 0x40, 0xec, 0x87, 0x60, 0x4f, 0x32, 0x80, 0x48, - 0x56, 0x84, 0x46, 0x85, 0x10, 0x0c, 0x83, 0x43, - 0x13, 0x83, 0xc0, 0x80, 0x41, 0x40, 0x81, 0xce, - 0x80, 0x41, 0x02, 0x82, 0xb4, 0x8d, 0xac, 0x81, - 0x8a, 0x82, 0xac, 0x88, 0x88, 0x80, 0xbc, 0x82, - 0xa3, 0x8b, 0x91, 0x81, 0xb8, 0x82, 0xaf, 0x8c, - 0x8d, 0x81, 0xdb, 0x88, 0x08, 0x28, 0x08, 0x40, - 0x9c, 0x89, 0x96, 0x83, 0xb9, 0x31, 0x09, 0x81, - 0x89, 0x80, 0x89, 0x81, 0xd3, 0x88, 0x00, 0x08, - 0x03, 0x01, 0xe6, 0x8c, 0x02, 0xe9, 0x91, 0x40, - 0xec, 0x31, 0x86, 0x9c, 0x81, 0xd1, 0x8e, 0x00, - 0xe9, 0x8a, 0xe6, 0x8d, 0x41, 0x00, 0x8c, 0x40, - 0xf6, 0x28, 0x09, 0x0a, 0x00, 0x80, 0x40, 0x8d, - 0x31, 0x2b, 0x80, 0x9b, 0x89, 0xa9, 0x20, 0x83, - 0x91, 0x8a, 0xad, 0x8d, 0x41, 0x96, 0x38, 0x86, - 0xd2, 0x95, 0x80, 0x8d, 0xf9, 0x2a, 0x00, 0x08, - 0x10, 0x02, 0x80, 0xc1, 0x20, 0x08, 0x83, 0x41, - 0x5b, 0x83, 0x88, 0x08, 0x80, 0xaf, 0x32, 0x82, - 0x60, 0x41, 0xdc, 0x90, 0x4e, 0x1f, 0x00, 0xb6, - 0x33, 0xdc, 0x81, 0x60, 0x4c, 0xab, 0x80, 0x60, - 0x23, 0x60, 0x30, 0x90, 0x0e, 0x01, 0x04, 0xe3, - 0x80, 0x48, 0xb6, 0x80, 0x47, 0xe7, 0x99, 0x85, - 0x99, 0x85, 0x99, -}; - -static const uint8_t unicode_prop_Other_Lowercase_table[69] = { - 0x40, 0xa9, 0x80, 0x8e, 0x80, 0x41, 0xf4, 0x88, - 0x31, 0x9d, 0x84, 0xdf, 0x80, 0xb3, 0x80, 0x4d, - 0x80, 0x80, 0x4c, 0x2e, 0xbe, 0x8c, 0x80, 0xa1, - 0xa4, 0x42, 0xb0, 0x80, 0x8c, 0x80, 0x8f, 0x8c, - 0x40, 0xd2, 0x8f, 0x43, 0x4f, 0x99, 0x47, 0x91, - 0x81, 0x60, 0x7a, 0x1d, 0x81, 0x40, 0xd1, 0x80, - 0x40, 0x80, 0x12, 0x81, 0x43, 0x61, 0x83, 0x88, - 0x80, 0x60, 0x5c, 0x15, 0x01, 0x10, 0xa9, 0x80, - 0x88, 0x60, 0xd8, 0x74, 0xbd, -}; - -static const uint8_t unicode_prop_Other_Uppercase_table[15] = { - 0x60, 0x21, 0x5f, 0x8f, 0x43, 0x45, 0x99, 0x61, - 0xcc, 0x5f, 0x99, 0x85, 0x99, 0x85, 0x99, -}; - -static const uint8_t unicode_prop_Other_Grapheme_Extend_table[112] = { - 0x49, 0xbd, 0x80, 0x97, 0x80, 0x41, 0x65, 0x80, - 0x97, 0x80, 0xe5, 0x80, 0x97, 0x80, 0x40, 0xe7, - 0x00, 0x03, 0x08, 0x81, 0x88, 0x81, 0xe6, 0x80, - 0x97, 0x80, 0xf6, 0x80, 0x8e, 0x80, 0x49, 0x34, - 0x80, 0x9d, 0x80, 0x43, 0xff, 0x04, 0x00, 0x04, - 0x81, 0xe4, 0x80, 0xc6, 0x81, 0x44, 0x17, 0x80, - 0x50, 0x20, 0x81, 0x60, 0x79, 0x22, 0x80, 0xeb, - 0x80, 0x60, 0x55, 0xdc, 0x81, 0x52, 0x1f, 0x80, - 0xf3, 0x80, 0x41, 0x07, 0x80, 0x8d, 0x80, 0x88, - 0x80, 0xdf, 0x80, 0x88, 0x01, 0x00, 0x14, 0x80, - 0x40, 0xdf, 0x80, 0x8b, 0x80, 0x40, 0xf0, 0x80, - 0x41, 0x05, 0x80, 0x42, 0x78, 0x80, 0x8b, 0x80, - 0x46, 0x02, 0x80, 0x60, 0x50, 0xad, 0x81, 0x60, - 0x61, 0x72, 0x0d, 0x85, 0x6c, 0x2e, 0xac, 0xdf, -}; - -static const uint8_t unicode_prop_Other_Default_Ignorable_Code_Point_table[32] = { - 0x43, 0x4e, 0x80, 0x4e, 0x0e, 0x81, 0x46, 0x52, - 0x81, 0x48, 0xae, 0x80, 0x50, 0xfd, 0x80, 0x60, - 0xce, 0x3a, 0x80, 0xce, 0x88, 0x6d, 0x00, 0x06, - 0x00, 0x9d, 0xdf, 0xff, 0x40, 0xef, 0x4e, 0x0f, -}; - -static const uint8_t unicode_prop_Other_ID_Start_table[11] = { - 0x58, 0x84, 0x81, 0x48, 0x90, 0x80, 0x94, 0x80, - 0x4f, 0x6b, 0x81, -}; - -static const uint8_t unicode_prop_Other_ID_Continue_table[22] = { - 0x40, 0xb6, 0x80, 0x42, 0xce, 0x80, 0x4f, 0xe0, - 0x88, 0x46, 0x67, 0x80, 0x46, 0x30, 0x81, 0x50, - 0xec, 0x80, 0x60, 0xce, 0x68, 0x80, -}; - -static const uint8_t unicode_prop_Prepended_Concatenation_Mark_table[19] = { - 0x45, 0xff, 0x85, 0x40, 0xd6, 0x80, 0xb0, 0x80, - 0x41, 0x7f, 0x81, 0xcf, 0x80, 0x61, 0x07, 0xd9, - 0x80, 0x8e, 0x80, -}; - -static const uint8_t unicode_prop_XID_Start1_table[31] = { - 0x43, 0x79, 0x80, 0x4a, 0xb7, 0x80, 0xfe, 0x80, - 0x60, 0x21, 0xe6, 0x81, 0x60, 0xcb, 0xc0, 0x85, - 0x41, 0x95, 0x81, 0xf3, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x80, 0x41, 0x1e, 0x81, -}; - -static const uint8_t unicode_prop_XID_Continue1_table[23] = { - 0x43, 0x79, 0x80, 0x60, 0x2d, 0x1f, 0x81, 0x60, - 0xcb, 0xc0, 0x85, 0x41, 0x95, 0x81, 0xf3, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -}; - -static const uint8_t unicode_prop_Changes_When_Titlecased1_table[22] = { - 0x41, 0xc3, 0x08, 0x08, 0x81, 0xa4, 0x81, 0x4e, - 0xdc, 0xaa, 0x0a, 0x4e, 0x87, 0x3f, 0x3f, 0x87, - 0x8b, 0x80, 0x8e, 0x80, 0xae, 0x80, -}; - -static const uint8_t unicode_prop_Changes_When_Casefolded1_table[29] = { - 0x41, 0xef, 0x80, 0x41, 0x9e, 0x80, 0x9e, 0x80, - 0x5a, 0xe4, 0x83, 0x40, 0xb5, 0x00, 0x00, 0x00, - 0x80, 0xde, 0x06, 0x06, 0x80, 0x8a, 0x09, 0x81, - 0x89, 0x10, 0x81, 0x8d, 0x80, -}; - -static const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[450] = { - 0x40, 0x9f, 0x06, 0x00, 0x01, 0x00, 0x01, 0x12, - 0x10, 0x82, 0xf3, 0x80, 0x8b, 0x80, 0x40, 0x84, - 0x01, 0x01, 0x80, 0xa2, 0x01, 0x80, 0x40, 0xbb, - 0x88, 0x9e, 0x29, 0x84, 0xda, 0x08, 0x81, 0x89, - 0x80, 0xa3, 0x04, 0x02, 0x04, 0x08, 0x07, 0x80, - 0x9e, 0x80, 0xa0, 0x82, 0x9c, 0x80, 0x42, 0x28, - 0x80, 0xd7, 0x83, 0x42, 0xde, 0x87, 0xfb, 0x08, - 0x80, 0xd2, 0x01, 0x80, 0xa1, 0x11, 0x80, 0x40, - 0xfc, 0x81, 0x42, 0xd4, 0x80, 0xfe, 0x80, 0xa7, - 0x81, 0xad, 0x80, 0xb5, 0x80, 0x88, 0x03, 0x03, - 0x03, 0x80, 0x8b, 0x80, 0x88, 0x00, 0x26, 0x80, - 0x90, 0x80, 0x88, 0x03, 0x03, 0x03, 0x80, 0x8b, - 0x80, 0x41, 0x41, 0x80, 0xe1, 0x81, 0x46, 0x52, - 0x81, 0xd4, 0x84, 0x45, 0x1b, 0x10, 0x8a, 0x80, - 0x91, 0x80, 0x9b, 0x8c, 0x80, 0xa1, 0xa4, 0x40, - 0xd5, 0x83, 0x40, 0xb5, 0x00, 0x00, 0x00, 0x80, - 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0xb7, 0x05, 0x00, 0x13, 0x05, 0x11, 0x02, 0x0c, - 0x11, 0x00, 0x00, 0x0c, 0x15, 0x05, 0x08, 0x8f, - 0x00, 0x20, 0x8b, 0x12, 0x2a, 0x08, 0x0b, 0x00, - 0x07, 0x82, 0x8c, 0x06, 0x92, 0x81, 0x9a, 0x80, - 0x8c, 0x8a, 0x80, 0xd6, 0x18, 0x10, 0x8a, 0x01, - 0x0c, 0x0a, 0x00, 0x10, 0x11, 0x02, 0x06, 0x05, - 0x1c, 0x85, 0x8f, 0x8f, 0x8f, 0x88, 0x80, 0x40, - 0xa1, 0x08, 0x81, 0x40, 0xf7, 0x81, 0x41, 0x34, - 0xd5, 0x99, 0x9a, 0x45, 0x20, 0x80, 0xe6, 0x82, - 0xe4, 0x80, 0x41, 0x9e, 0x81, 0x40, 0xf0, 0x80, - 0x41, 0x2e, 0x80, 0xd2, 0x80, 0x8b, 0x40, 0xd5, - 0xa9, 0x80, 0xb4, 0x00, 0x82, 0xdf, 0x09, 0x80, - 0xde, 0x80, 0xb0, 0xdd, 0x82, 0x8d, 0xdf, 0x9e, - 0x80, 0xa7, 0x87, 0xae, 0x80, 0x41, 0x7f, 0x60, - 0x72, 0x9b, 0x81, 0x40, 0xd1, 0x80, 0x40, 0x80, - 0x12, 0x81, 0x43, 0x61, 0x83, 0x88, 0x80, 0x60, - 0x4d, 0x95, 0x41, 0x0d, 0x08, 0x00, 0x81, 0x89, - 0x00, 0x00, 0x09, 0x82, 0xc3, 0x81, 0xe9, 0xc2, - 0x00, 0x97, 0x04, 0x00, 0x01, 0x01, 0x80, 0xeb, - 0xa0, 0x41, 0x6a, 0x91, 0xbf, 0x81, 0xb5, 0xa7, - 0x8c, 0x82, 0x99, 0x95, 0x94, 0x81, 0x8b, 0x80, - 0x92, 0x03, 0x1a, 0x00, 0x80, 0x40, 0x86, 0x08, - 0x80, 0x9f, 0x99, 0x40, 0x83, 0x15, 0x0d, 0x0d, - 0x0a, 0x16, 0x06, 0x80, 0x88, 0x47, 0x87, 0x20, - 0xa9, 0x80, 0x88, 0x60, 0xb4, 0xe4, 0x83, 0x50, - 0x31, 0xa3, 0x44, 0x63, 0x86, 0x8d, 0x87, 0xbf, - 0x85, 0x42, 0x3e, 0xd4, 0x80, 0xc6, 0x01, 0x08, - 0x09, 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, - 0x03, 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, - 0x16, 0x80, 0x41, 0x53, 0x81, 0x41, 0x23, 0x81, - 0xb1, 0x48, 0x2f, 0xbd, 0x4d, 0x91, 0x18, 0x9a, - 0x01, 0x00, 0x08, 0x80, 0x89, 0x03, 0x00, 0x00, - 0x28, 0x18, 0x00, 0x00, 0x02, 0x01, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x06, - 0x03, 0x03, 0x00, 0x80, 0x89, 0x80, 0x90, 0x22, - 0x04, 0x80, 0x90, 0x42, 0x43, 0x8a, 0x84, 0x9e, - 0x80, 0x9f, 0x99, 0x82, 0xa2, 0x80, 0xee, 0x82, - 0x8c, 0xab, 0x83, 0x88, 0x31, 0x49, 0x9d, 0x89, - 0x60, 0xfc, 0x05, 0x42, 0x1d, 0x6b, 0x05, 0xe1, - 0x4f, 0xff, -}; - -static const uint8_t unicode_prop_Basic_Emoji1_table[143] = { - 0x60, 0x23, 0x19, 0x81, 0x40, 0xcc, 0x1a, 0x01, - 0x80, 0x42, 0x08, 0x81, 0x94, 0x81, 0xb1, 0x8b, - 0xaa, 0x80, 0x92, 0x80, 0x8c, 0x07, 0x81, 0x90, - 0x0c, 0x0f, 0x04, 0x80, 0x94, 0x06, 0x08, 0x03, - 0x01, 0x06, 0x03, 0x81, 0x9b, 0x80, 0xa2, 0x00, - 0x03, 0x10, 0x80, 0xbc, 0x82, 0x97, 0x80, 0x8d, - 0x80, 0x43, 0x5a, 0x81, 0xb2, 0x03, 0x80, 0x61, - 0xc4, 0xad, 0x80, 0x40, 0xc9, 0x80, 0x40, 0xbd, - 0x01, 0x89, 0xe5, 0x80, 0x97, 0x80, 0x93, 0x01, - 0x20, 0x82, 0x94, 0x81, 0x40, 0xad, 0xa0, 0x8b, - 0x88, 0x80, 0xc5, 0x80, 0x95, 0x8b, 0xaa, 0x1c, - 0x8b, 0x90, 0x10, 0x82, 0xc6, 0x00, 0x80, 0x40, - 0xba, 0x81, 0xbe, 0x8c, 0x18, 0x97, 0x91, 0x80, - 0x99, 0x81, 0x8c, 0x80, 0xd5, 0xd4, 0xaf, 0xc5, - 0x28, 0x12, 0x0a, 0x1b, 0x8a, 0x0e, 0x88, 0x40, - 0xe2, 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, 0x89, - 0x80, 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x89, 0x84, - 0xb7, 0x86, 0x8e, 0x81, 0x8a, 0x85, 0x88, -}; - -static const uint8_t unicode_prop_Basic_Emoji2_table[183] = { - 0x40, 0xa8, 0x03, 0x80, 0x5f, 0x8c, 0x80, 0x8b, - 0x80, 0x40, 0xd7, 0x80, 0x95, 0x80, 0xd9, 0x85, - 0x8e, 0x81, 0x41, 0x7c, 0x80, 0x40, 0xa5, 0x80, - 0x9c, 0x10, 0x0c, 0x82, 0x40, 0xc6, 0x80, 0x40, - 0xe6, 0x81, 0x89, 0x80, 0x88, 0x80, 0xb9, 0x0a, - 0x84, 0x88, 0x01, 0x05, 0x03, 0x01, 0x00, 0x09, - 0x02, 0x02, 0x0f, 0x14, 0x00, 0x80, 0x9b, 0x09, - 0x00, 0x08, 0x80, 0x91, 0x01, 0x80, 0x92, 0x00, - 0x18, 0x00, 0x0a, 0x05, 0x07, 0x81, 0x95, 0x05, - 0x00, 0x00, 0x80, 0x94, 0x05, 0x09, 0x01, 0x17, - 0x04, 0x09, 0x08, 0x01, 0x00, 0x00, 0x05, 0x02, - 0x80, 0x90, 0x81, 0x8e, 0x01, 0x80, 0x9a, 0x81, - 0xbb, 0x80, 0x41, 0x91, 0x81, 0x41, 0xce, 0x82, - 0x45, 0x27, 0x80, 0x8b, 0x80, 0x42, 0x58, 0x00, - 0x80, 0x61, 0xbe, 0xd5, 0x81, 0x8b, 0x81, 0x40, - 0x81, 0x80, 0xb3, 0x80, 0x40, 0xe8, 0x01, 0x88, - 0x88, 0x80, 0xc5, 0x80, 0x97, 0x08, 0x11, 0x81, - 0xaa, 0x1c, 0x8b, 0x92, 0x00, 0x00, 0x80, 0xc6, - 0x00, 0x80, 0x40, 0xba, 0x80, 0xca, 0x81, 0xa3, - 0x09, 0x86, 0x8c, 0x01, 0x19, 0x80, 0x93, 0x01, - 0x07, 0x81, 0x88, 0x04, 0x82, 0x8b, 0x17, 0x11, - 0x00, 0x03, 0x05, 0x02, 0x05, 0x80, 0x40, 0xcf, - 0x00, 0x82, 0x8f, 0x2a, 0x05, 0x01, 0x80, -}; - -static const uint8_t unicode_prop_RGI_Emoji_Modifier_Sequence_table[73] = { - 0x60, 0x26, 0x1c, 0x80, 0x40, 0xda, 0x80, 0x8f, - 0x83, 0x61, 0xcc, 0x76, 0x80, 0xbb, 0x11, 0x01, - 0x82, 0xf4, 0x09, 0x8a, 0x94, 0x18, 0x18, 0x88, - 0x10, 0x1a, 0x02, 0x30, 0x00, 0x97, 0x80, 0x40, - 0xc8, 0x0b, 0x80, 0x94, 0x03, 0x81, 0x40, 0xad, - 0x12, 0x84, 0xd2, 0x80, 0x8f, 0x82, 0x88, 0x80, - 0x8a, 0x80, 0x42, 0x3e, 0x01, 0x07, 0x3d, 0x80, - 0x88, 0x89, 0x11, 0xb7, 0x80, 0xbc, 0x08, 0x08, - 0x80, 0x90, 0x10, 0x8c, 0x40, 0xe4, 0x82, 0xa9, - 0x88, -}; - -static const uint8_t unicode_prop_RGI_Emoji_Flag_Sequence_table[128] = { - 0x0c, 0x00, 0x09, 0x00, 0x04, 0x01, 0x02, 0x06, - 0x03, 0x03, 0x01, 0x02, 0x01, 0x03, 0x07, 0x0d, - 0x18, 0x00, 0x09, 0x00, 0x00, 0x89, 0x08, 0x00, - 0x00, 0x81, 0x88, 0x83, 0x8c, 0x10, 0x00, 0x01, - 0x07, 0x08, 0x29, 0x10, 0x28, 0x00, 0x80, 0x8a, - 0x00, 0x0a, 0x00, 0x0e, 0x15, 0x18, 0x83, 0x89, - 0x06, 0x00, 0x81, 0x8d, 0x00, 0x12, 0x08, 0x00, - 0x03, 0x00, 0x24, 0x00, 0x05, 0x21, 0x00, 0x00, - 0x29, 0x90, 0x00, 0x02, 0x00, 0x08, 0x09, 0x00, - 0x08, 0x18, 0x8b, 0x80, 0x8c, 0x02, 0x19, 0x1a, - 0x11, 0x00, 0x00, 0x80, 0x9c, 0x80, 0x88, 0x02, - 0x00, 0x00, 0x02, 0x20, 0x88, 0x0a, 0x00, 0x03, - 0x01, 0x02, 0x05, 0x08, 0x00, 0x01, 0x09, 0x20, - 0x21, 0x18, 0x22, 0x00, 0x00, 0x00, 0x00, 0x18, - 0x28, 0x89, 0x80, 0x8b, 0x80, 0x90, 0x80, 0x92, - 0x80, 0x8d, 0x05, 0x80, 0x8a, 0x80, 0x88, 0x80, -}; - -static const uint8_t unicode_prop_Emoji_Keycap_Sequence_table[4] = { - 0xa2, 0x05, 0x04, 0x89, -}; - -static const uint8_t unicode_prop_ASCII_Hex_Digit_table[5] = { - 0xaf, 0x89, 0x35, 0x99, 0x85, -}; - -static const uint8_t unicode_prop_Bidi_Control_table[10] = { - 0x46, 0x1b, 0x80, 0x59, 0xf0, 0x81, 0x99, 0x84, - 0xb6, 0x83, -}; - -static const uint8_t unicode_prop_Dash_table[58] = { - 0xac, 0x80, 0x45, 0x5b, 0x80, 0xb2, 0x80, 0x4e, - 0x40, 0x80, 0x44, 0x04, 0x80, 0x48, 0x08, 0x85, - 0xbc, 0x80, 0xa6, 0x80, 0x8e, 0x80, 0x41, 0x85, - 0x80, 0x4c, 0x03, 0x01, 0x80, 0x9e, 0x0b, 0x80, - 0x9b, 0x80, 0x41, 0xbd, 0x80, 0x92, 0x80, 0xee, - 0x80, 0x60, 0xcd, 0x8f, 0x81, 0xa4, 0x80, 0x89, - 0x80, 0x40, 0xa8, 0x80, 0x4e, 0x5f, 0x80, 0x41, - 0x3d, 0x80, -}; - -static const uint8_t unicode_prop_Deprecated_table[23] = { - 0x41, 0x48, 0x80, 0x45, 0x28, 0x80, 0x49, 0x02, - 0x00, 0x80, 0x48, 0x28, 0x81, 0x48, 0xc4, 0x85, - 0x42, 0xb8, 0x81, 0x6d, 0xdc, 0xd5, 0x80, -}; - -static const uint8_t unicode_prop_Diacritic_table[438] = { - 0xdd, 0x00, 0x80, 0xc6, 0x05, 0x03, 0x01, 0x81, - 0x41, 0xf6, 0x40, 0x9e, 0x07, 0x25, 0x90, 0x0b, - 0x80, 0x88, 0x81, 0x40, 0xfc, 0x84, 0x40, 0xd0, - 0x80, 0xb6, 0x90, 0x80, 0x9a, 0x00, 0x01, 0x00, - 0x40, 0x85, 0x3b, 0x81, 0x40, 0x85, 0x0b, 0x0a, - 0x82, 0xc2, 0x9a, 0xda, 0x8a, 0xb9, 0x8a, 0xa1, - 0x81, 0xfd, 0x87, 0xa8, 0x89, 0x8f, 0x9b, 0xbc, - 0x80, 0x8f, 0x02, 0x83, 0x9b, 0x80, 0xc9, 0x80, - 0x8f, 0x80, 0xed, 0x80, 0x8f, 0x80, 0xed, 0x80, - 0x8f, 0x80, 0xae, 0x82, 0xbb, 0x80, 0x8f, 0x06, - 0x80, 0xf6, 0x80, 0xed, 0x80, 0x8f, 0x80, 0xed, - 0x80, 0x8f, 0x80, 0xec, 0x81, 0x8f, 0x80, 0xfb, - 0x80, 0xee, 0x80, 0x8b, 0x28, 0x80, 0xea, 0x80, - 0x8c, 0x84, 0xca, 0x81, 0x9a, 0x00, 0x00, 0x03, - 0x81, 0xc1, 0x10, 0x81, 0xbd, 0x80, 0xef, 0x00, - 0x81, 0xa7, 0x0b, 0x84, 0x98, 0x30, 0x80, 0x89, - 0x81, 0x42, 0xc0, 0x82, 0x43, 0xb3, 0x81, 0x9d, - 0x80, 0x40, 0x93, 0x8a, 0x88, 0x80, 0x41, 0x5a, - 0x82, 0x41, 0x23, 0x80, 0x93, 0x39, 0x80, 0xaf, - 0x8e, 0x81, 0x8a, 0xe7, 0x80, 0x8e, 0x80, 0xa5, - 0x88, 0xb5, 0x81, 0xb9, 0x80, 0x8a, 0x81, 0xc1, - 0x81, 0xbf, 0x85, 0xd1, 0x98, 0x18, 0x28, 0x0a, - 0xb1, 0xbe, 0xd8, 0x8b, 0xa4, 0x8a, 0x41, 0xbc, - 0x00, 0x82, 0x8a, 0x82, 0x8c, 0x82, 0x8c, 0x82, - 0x8c, 0x81, 0x4c, 0xef, 0x82, 0x41, 0x3c, 0x80, - 0x41, 0xf9, 0x85, 0xe8, 0x83, 0xde, 0x80, 0x60, - 0x75, 0x71, 0x80, 0x8b, 0x08, 0x80, 0x9b, 0x81, - 0xd1, 0x81, 0x8d, 0xa1, 0xe5, 0x82, 0xec, 0x81, - 0x8b, 0x80, 0xa4, 0x80, 0x40, 0x96, 0x80, 0x9a, - 0x91, 0xb8, 0x83, 0xa3, 0x80, 0xde, 0x80, 0x8b, - 0x80, 0xa3, 0x80, 0x40, 0x94, 0x82, 0xc0, 0x83, - 0xb2, 0x80, 0xe3, 0x84, 0x88, 0x82, 0xff, 0x81, - 0x60, 0x4f, 0x2f, 0x80, 0x43, 0x00, 0x8f, 0x41, - 0x0d, 0x00, 0x80, 0xae, 0x80, 0xac, 0x81, 0xc2, - 0x80, 0x42, 0xfb, 0x80, 0x44, 0x9e, 0x28, 0xa9, - 0x80, 0x88, 0x42, 0x7c, 0x13, 0x80, 0x40, 0xa4, - 0x81, 0x42, 0x3a, 0x85, 0xa5, 0x80, 0x99, 0x84, - 0x41, 0x8e, 0x82, 0xc5, 0x8a, 0xb0, 0x83, 0x40, - 0xbf, 0x80, 0xa8, 0x80, 0xc7, 0x81, 0xf7, 0x81, - 0xbd, 0x80, 0xcb, 0x80, 0x88, 0x82, 0xe7, 0x81, - 0x40, 0xb1, 0x81, 0xcf, 0x81, 0x8f, 0x80, 0x97, - 0x32, 0x84, 0xd8, 0x10, 0x81, 0x8c, 0x81, 0xde, - 0x02, 0x80, 0xfa, 0x81, 0x40, 0xfa, 0x81, 0xfd, - 0x80, 0xf5, 0x81, 0xf2, 0x80, 0x41, 0x0c, 0x81, - 0x41, 0x01, 0x0b, 0x80, 0x40, 0x9b, 0x80, 0xd2, - 0x80, 0x91, 0x80, 0xd0, 0x80, 0x41, 0xa4, 0x80, - 0x41, 0x01, 0x00, 0x81, 0xd0, 0x80, 0x41, 0xa8, - 0x81, 0x96, 0x80, 0x54, 0xeb, 0x8e, 0x60, 0x2c, - 0xd8, 0x80, 0x49, 0xbf, 0x84, 0xba, 0x86, 0x42, - 0x33, 0x81, 0x42, 0x21, 0x90, 0xcf, 0x81, 0x60, - 0x3f, 0xfd, 0x18, 0x30, 0x81, 0x5f, 0x00, 0xad, - 0x81, 0x96, 0x42, 0x1f, 0x12, 0x2f, 0x39, 0x86, - 0x9d, 0x83, 0x4e, 0x81, 0xbd, 0x40, 0xc1, 0x86, - 0x41, 0x76, 0x80, 0xbc, 0x83, 0x42, 0xfd, 0x81, - 0x42, 0xdf, 0x86, 0xec, 0x10, 0x82, -}; - -static const uint8_t unicode_prop_Extender_table[111] = { - 0x40, 0xb6, 0x80, 0x42, 0x17, 0x81, 0x43, 0x6d, - 0x80, 0x41, 0xb8, 0x80, 0x42, 0x75, 0x80, 0x40, - 0x88, 0x80, 0xd8, 0x80, 0x42, 0xef, 0x80, 0xfe, - 0x80, 0x49, 0x42, 0x80, 0xb7, 0x80, 0x42, 0x62, - 0x80, 0x41, 0x8d, 0x80, 0xc3, 0x80, 0x53, 0x88, - 0x80, 0xaa, 0x84, 0xe6, 0x81, 0xdc, 0x82, 0x60, - 0x6f, 0x15, 0x80, 0x45, 0xf5, 0x80, 0x43, 0xc1, - 0x80, 0x95, 0x80, 0x40, 0x88, 0x80, 0xeb, 0x80, - 0x94, 0x81, 0x60, 0x54, 0x7a, 0x80, 0x48, 0x0f, - 0x81, 0x45, 0xca, 0x80, 0x9a, 0x03, 0x80, 0x44, - 0xc6, 0x80, 0x41, 0x24, 0x80, 0xf3, 0x81, 0x41, - 0xf1, 0x82, 0x44, 0xce, 0x80, 0x60, 0x50, 0xa8, - 0x81, 0x44, 0x9b, 0x08, 0x80, 0x60, 0x71, 0x57, - 0x81, 0x44, 0xb0, 0x80, 0x43, 0x53, 0x82, -}; - -static const uint8_t unicode_prop_Hex_Digit_table[12] = { - 0xaf, 0x89, 0x35, 0x99, 0x85, 0x60, 0xfe, 0xa8, - 0x89, 0x35, 0x99, 0x85, -}; - -static const uint8_t unicode_prop_IDS_Unary_Operator_table[4] = { - 0x60, 0x2f, 0xfd, 0x81, -}; - -static const uint8_t unicode_prop_IDS_Binary_Operator_table[8] = { - 0x60, 0x2f, 0xef, 0x09, 0x89, 0x41, 0xf0, 0x80, -}; - -static const uint8_t unicode_prop_IDS_Trinary_Operator_table[4] = { - 0x60, 0x2f, 0xf1, 0x81, -}; - -static const uint8_t unicode_prop_Ideographic_table[72] = { - 0x60, 0x30, 0x05, 0x81, 0x98, 0x88, 0x8d, 0x82, - 0x43, 0xc4, 0x59, 0xbf, 0xbf, 0x60, 0x51, 0xff, - 0x60, 0x58, 0xff, 0x41, 0x6d, 0x81, 0xe9, 0x60, - 0x75, 0x09, 0x80, 0x9a, 0x57, 0xf7, 0x87, 0x44, - 0xd5, 0xa8, 0x89, 0x60, 0x24, 0x66, 0x41, 0x8b, - 0x60, 0x4d, 0x03, 0x60, 0xa6, 0xdf, 0x9f, 0x50, - 0x39, 0x85, 0x40, 0xdd, 0x81, 0x56, 0x81, 0x8d, - 0x5d, 0x30, 0x8e, 0x42, 0x6d, 0x49, 0xa1, 0x42, - 0x1d, 0x45, 0xe1, 0x53, 0x4a, 0x84, 0x50, 0x5f, -}; - -static const uint8_t unicode_prop_Join_Control_table[4] = { - 0x60, 0x20, 0x0b, 0x81, -}; - -static const uint8_t unicode_prop_Logical_Order_Exception_table[15] = { - 0x4e, 0x3f, 0x84, 0xfa, 0x84, 0x4a, 0xef, 0x11, - 0x80, 0x60, 0x90, 0xf9, 0x09, 0x00, 0x81, -}; - -static const uint8_t unicode_prop_Modifier_Combining_Mark_table[16] = { - 0x46, 0x53, 0x09, 0x80, 0x40, 0x82, 0x05, 0x02, - 0x81, 0x41, 0xe0, 0x08, 0x12, 0x80, 0x9e, 0x80, -}; - -static const uint8_t unicode_prop_Noncharacter_Code_Point_table[71] = { - 0x60, 0xfd, 0xcf, 0x9f, 0x42, 0x0d, 0x81, 0x60, - 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, - 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, - 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, - 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, - 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, - 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, - 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, - 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, -}; - -static const uint8_t unicode_prop_Pattern_Syntax_table[58] = { - 0xa0, 0x8e, 0x89, 0x86, 0x99, 0x18, 0x80, 0x99, - 0x83, 0xa1, 0x30, 0x00, 0x08, 0x00, 0x0b, 0x03, - 0x02, 0x80, 0x96, 0x80, 0x9e, 0x80, 0x5f, 0x17, - 0x97, 0x87, 0x8e, 0x81, 0x92, 0x80, 0x89, 0x41, - 0x30, 0x42, 0xcf, 0x40, 0x9f, 0x42, 0x75, 0x9d, - 0x44, 0x6b, 0x41, 0xff, 0xff, 0x41, 0x80, 0x13, - 0x98, 0x8e, 0x80, 0x60, 0xcd, 0x0c, 0x81, 0x41, - 0x04, 0x81, -}; - -static const uint8_t unicode_prop_Pattern_White_Space_table[11] = { - 0x88, 0x84, 0x91, 0x80, 0xe3, 0x80, 0x5f, 0x87, - 0x81, 0x97, 0x81, -}; - -static const uint8_t unicode_prop_Quotation_Mark_table[31] = { - 0xa1, 0x03, 0x80, 0x40, 0x82, 0x80, 0x8e, 0x80, - 0x5f, 0x5b, 0x87, 0x98, 0x81, 0x4e, 0x06, 0x80, - 0x41, 0xc8, 0x83, 0x8c, 0x82, 0x60, 0xce, 0x20, - 0x83, 0x40, 0xbc, 0x03, 0x80, 0xd9, 0x81, -}; - -static const uint8_t unicode_prop_Radical_table[9] = { - 0x60, 0x2e, 0x7f, 0x99, 0x80, 0xd8, 0x8b, 0x40, - 0xd5, -}; - -static const uint8_t unicode_prop_Regional_Indicator_table[4] = { - 0x61, 0xf1, 0xe5, 0x99, -}; - -static const uint8_t unicode_prop_Sentence_Terminal_table[213] = { - 0xa0, 0x80, 0x8b, 0x80, 0x8f, 0x80, 0x45, 0x48, - 0x80, 0x40, 0x92, 0x82, 0x40, 0xb3, 0x80, 0xaa, - 0x82, 0x40, 0xf5, 0x80, 0xbc, 0x00, 0x02, 0x81, - 0x41, 0x24, 0x81, 0x46, 0xe3, 0x81, 0x43, 0x15, - 0x03, 0x81, 0x43, 0x04, 0x80, 0x40, 0xc5, 0x81, - 0x40, 0x9c, 0x81, 0xac, 0x04, 0x80, 0x41, 0x39, - 0x81, 0x41, 0x61, 0x83, 0x40, 0xa1, 0x81, 0x89, - 0x09, 0x81, 0x9c, 0x82, 0x40, 0xba, 0x81, 0xc0, - 0x81, 0x43, 0xa3, 0x80, 0x96, 0x81, 0x88, 0x82, - 0x4c, 0xae, 0x82, 0x41, 0x31, 0x80, 0x8c, 0x80, - 0x95, 0x81, 0x41, 0xac, 0x80, 0x60, 0x74, 0xfb, - 0x80, 0x41, 0x0d, 0x81, 0x40, 0xe2, 0x02, 0x80, - 0x41, 0x7d, 0x81, 0xd5, 0x81, 0xde, 0x80, 0x40, - 0x97, 0x81, 0x40, 0x92, 0x82, 0x40, 0x8f, 0x81, - 0x40, 0xf8, 0x80, 0x60, 0x52, 0x25, 0x01, 0x81, - 0xba, 0x02, 0x81, 0x40, 0xa8, 0x80, 0x8b, 0x80, - 0x8f, 0x80, 0xc0, 0x80, 0x4a, 0xf3, 0x81, 0x44, - 0xfc, 0x84, 0xab, 0x83, 0x40, 0xbc, 0x81, 0xf4, - 0x83, 0xfe, 0x82, 0x40, 0x80, 0x0d, 0x80, 0x8f, - 0x81, 0xd7, 0x08, 0x81, 0xeb, 0x80, 0x41, 0x29, - 0x81, 0xf4, 0x81, 0x41, 0x74, 0x0c, 0x8e, 0xe8, - 0x81, 0x40, 0xf8, 0x82, 0x42, 0x04, 0x00, 0x80, - 0x40, 0xfa, 0x81, 0xd6, 0x81, 0x41, 0xa3, 0x81, - 0x42, 0xb3, 0x81, 0xc9, 0x81, 0x60, 0x4b, 0x28, - 0x81, 0x40, 0x84, 0x80, 0xc0, 0x81, 0x8a, 0x80, - 0x42, 0x28, 0x81, 0x41, 0x27, 0x80, 0x60, 0x4e, - 0x05, 0x80, 0x5d, 0xe7, 0x80, -}; - -static const uint8_t unicode_prop_Soft_Dotted_table[79] = { - 0xe8, 0x81, 0x40, 0xc3, 0x80, 0x41, 0x18, 0x80, - 0x9d, 0x80, 0xb3, 0x80, 0x93, 0x80, 0x41, 0x3f, - 0x80, 0xe1, 0x00, 0x80, 0x59, 0x08, 0x80, 0xb2, - 0x80, 0x8c, 0x02, 0x80, 0x40, 0x83, 0x80, 0x40, - 0x9c, 0x80, 0x41, 0xa4, 0x80, 0x40, 0xd5, 0x81, - 0x4b, 0x31, 0x80, 0x61, 0xa7, 0xa4, 0x81, 0xb1, - 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, - 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, - 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0x48, - 0x85, 0x80, 0x41, 0x30, 0x81, 0x99, 0x80, -}; - -static const uint8_t unicode_prop_Terminal_Punctuation_table[264] = { - 0xa0, 0x80, 0x89, 0x00, 0x80, 0x8a, 0x0a, 0x80, - 0x43, 0x3d, 0x07, 0x80, 0x42, 0x00, 0x80, 0xb8, - 0x80, 0xc7, 0x80, 0x8d, 0x00, 0x82, 0x40, 0xb3, - 0x80, 0xaa, 0x8a, 0x00, 0x40, 0xea, 0x81, 0xb5, - 0x28, 0x87, 0x9e, 0x80, 0x41, 0x04, 0x81, 0x44, - 0xf3, 0x81, 0x40, 0xab, 0x03, 0x85, 0x41, 0x36, - 0x81, 0x43, 0x14, 0x87, 0x43, 0x04, 0x80, 0xfb, - 0x82, 0xc6, 0x81, 0x40, 0x9c, 0x12, 0x80, 0xa6, - 0x19, 0x81, 0x41, 0x39, 0x81, 0x41, 0x61, 0x83, - 0x40, 0xa1, 0x81, 0x89, 0x08, 0x82, 0x9c, 0x82, - 0x40, 0xba, 0x84, 0xbd, 0x81, 0x43, 0xa3, 0x80, - 0x96, 0x81, 0x88, 0x82, 0x4c, 0xae, 0x82, 0x41, - 0x31, 0x80, 0x8c, 0x03, 0x80, 0x89, 0x00, 0x0a, - 0x81, 0x41, 0xab, 0x81, 0x60, 0x74, 0xfa, 0x81, - 0x41, 0x0c, 0x82, 0x40, 0xe2, 0x84, 0x41, 0x7d, - 0x81, 0xd5, 0x81, 0xde, 0x80, 0x40, 0x96, 0x82, - 0x40, 0x92, 0x82, 0xfe, 0x80, 0x8f, 0x81, 0x40, - 0xf8, 0x80, 0x60, 0x52, 0x25, 0x01, 0x81, 0xb8, - 0x10, 0x83, 0x40, 0xa8, 0x80, 0x89, 0x00, 0x80, - 0x8a, 0x0a, 0x80, 0xc0, 0x01, 0x80, 0x44, 0x39, - 0x80, 0xaf, 0x80, 0x44, 0x85, 0x80, 0x40, 0xc6, - 0x80, 0x41, 0x35, 0x81, 0x40, 0x97, 0x85, 0xc3, - 0x85, 0xd8, 0x83, 0x43, 0xb7, 0x84, 0xab, 0x83, - 0x40, 0xbc, 0x86, 0xef, 0x83, 0xfe, 0x82, 0x40, - 0x80, 0x0d, 0x80, 0x8f, 0x81, 0xd7, 0x84, 0xeb, - 0x80, 0x41, 0x29, 0x81, 0xf4, 0x82, 0x8b, 0x81, - 0x41, 0x65, 0x1a, 0x8e, 0xe8, 0x81, 0x40, 0xf8, - 0x82, 0x42, 0x04, 0x00, 0x80, 0x40, 0xfa, 0x81, - 0xd6, 0x0b, 0x81, 0x41, 0x9d, 0x82, 0xac, 0x80, - 0x42, 0x84, 0x81, 0xc9, 0x81, 0x45, 0x2a, 0x84, - 0x60, 0x45, 0xf8, 0x81, 0x40, 0x84, 0x80, 0xc0, - 0x82, 0x89, 0x80, 0x42, 0x28, 0x81, 0x41, 0x26, - 0x81, 0x60, 0x4e, 0x05, 0x80, 0x5d, 0xe6, 0x83, -}; - -static const uint8_t unicode_prop_Unified_Ideograph_table[48] = { - 0x60, 0x33, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x51, - 0xff, 0x60, 0x5a, 0x0d, 0x08, 0x00, 0x81, 0x89, - 0x00, 0x00, 0x09, 0x82, 0x61, 0x05, 0xd5, 0x60, - 0xa6, 0xdf, 0x9f, 0x50, 0x39, 0x85, 0x40, 0xdd, - 0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x8e, 0x42, - 0x6d, 0x51, 0xa1, 0x53, 0x4a, 0x84, 0x50, 0x5f, -}; - -static const uint8_t unicode_prop_Variation_Selector_table[13] = { - 0x58, 0x0a, 0x10, 0x80, 0x60, 0xe5, 0xef, 0x8f, - 0x6d, 0x02, 0xef, 0x40, 0xef, -}; - -static const uint8_t unicode_prop_White_Space_table[22] = { - 0x88, 0x84, 0x91, 0x80, 0xe3, 0x80, 0x99, 0x80, - 0x55, 0xde, 0x80, 0x49, 0x7e, 0x8a, 0x9c, 0x0c, - 0x80, 0xae, 0x80, 0x4f, 0x9f, 0x80, -}; - -static const uint8_t unicode_prop_Bidi_Mirrored_table[173] = { - 0xa7, 0x81, 0x91, 0x00, 0x80, 0x9b, 0x00, 0x80, - 0x9c, 0x00, 0x80, 0xac, 0x80, 0x8e, 0x80, 0x4e, - 0x7d, 0x83, 0x47, 0x5c, 0x81, 0x49, 0x9b, 0x81, - 0x89, 0x81, 0xb5, 0x81, 0x8d, 0x81, 0x40, 0xb0, - 0x80, 0x40, 0xbf, 0x1a, 0x2a, 0x02, 0x0a, 0x18, - 0x18, 0x00, 0x03, 0x88, 0x20, 0x80, 0x91, 0x23, - 0x88, 0x08, 0x00, 0x38, 0x9f, 0x0b, 0x20, 0x88, - 0x09, 0x92, 0x21, 0x88, 0x21, 0x0b, 0x97, 0x81, - 0x8f, 0x3b, 0x93, 0x0e, 0x81, 0x44, 0x3c, 0x8d, - 0xc9, 0x01, 0x18, 0x08, 0x14, 0x1c, 0x12, 0x8d, - 0x41, 0x92, 0x95, 0x0d, 0x80, 0x8d, 0x38, 0x35, - 0x10, 0x1c, 0x01, 0x0c, 0x18, 0x02, 0x09, 0x89, - 0x29, 0x81, 0x8b, 0x92, 0x03, 0x08, 0x00, 0x08, - 0x03, 0x21, 0x2a, 0x97, 0x81, 0x8a, 0x0b, 0x18, - 0x09, 0x0b, 0xaa, 0x0f, 0x80, 0xa7, 0x20, 0x00, - 0x14, 0x22, 0x18, 0x14, 0x00, 0x40, 0xff, 0x80, - 0x42, 0x02, 0x1a, 0x08, 0x81, 0x8d, 0x09, 0x89, - 0xaa, 0x87, 0x41, 0xaa, 0x89, 0x0f, 0x60, 0xce, - 0x3c, 0x2c, 0x81, 0x40, 0xa1, 0x81, 0x91, 0x00, - 0x80, 0x9b, 0x00, 0x80, 0x9c, 0x00, 0x00, 0x08, - 0x81, 0x60, 0xd7, 0x76, 0x80, 0xb8, 0x80, 0xb8, - 0x80, 0xb8, 0x80, 0xb8, 0x80, -}; - -static const uint8_t unicode_prop_Emoji_table[238] = { - 0xa2, 0x05, 0x04, 0x89, 0xee, 0x03, 0x80, 0x5f, - 0x8c, 0x80, 0x8b, 0x80, 0x40, 0xd7, 0x80, 0x95, - 0x80, 0xd9, 0x85, 0x8e, 0x81, 0x41, 0x6e, 0x81, - 0x8b, 0x80, 0x40, 0xa5, 0x80, 0x98, 0x8a, 0x1a, - 0x40, 0xc6, 0x80, 0x40, 0xe6, 0x81, 0x89, 0x80, - 0x88, 0x80, 0xb9, 0x18, 0x84, 0x88, 0x01, 0x01, - 0x09, 0x03, 0x01, 0x00, 0x09, 0x02, 0x02, 0x0f, - 0x14, 0x00, 0x04, 0x8b, 0x8a, 0x09, 0x00, 0x08, - 0x80, 0x91, 0x01, 0x81, 0x91, 0x28, 0x00, 0x0a, - 0x0c, 0x01, 0x0b, 0x81, 0x8a, 0x0c, 0x09, 0x04, - 0x08, 0x00, 0x81, 0x93, 0x0c, 0x28, 0x19, 0x03, - 0x01, 0x01, 0x28, 0x01, 0x00, 0x00, 0x05, 0x02, - 0x05, 0x80, 0x89, 0x81, 0x8e, 0x01, 0x03, 0x00, - 0x03, 0x10, 0x80, 0x8a, 0x81, 0xaf, 0x82, 0x88, - 0x80, 0x8d, 0x80, 0x8d, 0x80, 0x41, 0x73, 0x81, - 0x41, 0xce, 0x82, 0x92, 0x81, 0xb2, 0x03, 0x80, - 0x44, 0xd9, 0x80, 0x8b, 0x80, 0x42, 0x58, 0x00, - 0x80, 0x61, 0xbd, 0x69, 0x80, 0x40, 0xc9, 0x80, - 0x40, 0x9f, 0x81, 0x8b, 0x81, 0x8d, 0x01, 0x89, - 0xca, 0x99, 0x01, 0x96, 0x80, 0x93, 0x01, 0x88, - 0x94, 0x81, 0x40, 0xad, 0xa1, 0x81, 0xef, 0x09, - 0x02, 0x81, 0xd2, 0x0a, 0x80, 0x41, 0x06, 0x80, - 0xbe, 0x8a, 0x28, 0x97, 0x31, 0x0f, 0x8b, 0x01, - 0x19, 0x03, 0x81, 0x8c, 0x09, 0x07, 0x81, 0x88, - 0x04, 0x82, 0x8b, 0x17, 0x11, 0x00, 0x03, 0x05, - 0x02, 0x05, 0xd5, 0xaf, 0xc5, 0x27, 0x0a, 0x83, - 0x89, 0x10, 0x01, 0x10, 0x81, 0x89, 0x40, 0xe2, - 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, 0x89, 0x80, - 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x89, 0x84, 0xb7, - 0x86, 0x8e, 0x81, 0x8a, 0x85, 0x88, -}; - -static const uint8_t unicode_prop_Emoji_Component_table[28] = { - 0xa2, 0x05, 0x04, 0x89, 0x5f, 0xd2, 0x80, 0x40, - 0xd4, 0x80, 0x60, 0xdd, 0x2a, 0x80, 0x60, 0xf3, - 0xd5, 0x99, 0x41, 0xfa, 0x84, 0x45, 0xaf, 0x83, - 0x6c, 0x06, 0x6b, 0xdf, -}; - -static const uint8_t unicode_prop_Emoji_Modifier_table[4] = { - 0x61, 0xf3, 0xfa, 0x84, -}; - -static const uint8_t unicode_prop_Emoji_Modifier_Base_table[71] = { - 0x60, 0x26, 0x1c, 0x80, 0x40, 0xda, 0x80, 0x8f, - 0x83, 0x61, 0xcc, 0x76, 0x80, 0xbb, 0x11, 0x01, - 0x82, 0xf4, 0x09, 0x8a, 0x94, 0x92, 0x10, 0x1a, - 0x02, 0x30, 0x00, 0x97, 0x80, 0x40, 0xc8, 0x0b, - 0x80, 0x94, 0x03, 0x81, 0x40, 0xad, 0x12, 0x84, - 0xd2, 0x80, 0x8f, 0x82, 0x88, 0x80, 0x8a, 0x80, - 0x42, 0x3e, 0x01, 0x07, 0x3d, 0x80, 0x88, 0x89, - 0x0a, 0xb7, 0x80, 0xbc, 0x08, 0x08, 0x80, 0x90, - 0x10, 0x8c, 0x40, 0xe4, 0x82, 0xa9, 0x88, -}; - -static const uint8_t unicode_prop_Emoji_Presentation_table[144] = { - 0x60, 0x23, 0x19, 0x81, 0x40, 0xcc, 0x1a, 0x01, - 0x80, 0x42, 0x08, 0x81, 0x94, 0x81, 0xb1, 0x8b, - 0xaa, 0x80, 0x92, 0x80, 0x8c, 0x07, 0x81, 0x90, - 0x0c, 0x0f, 0x04, 0x80, 0x94, 0x06, 0x08, 0x03, - 0x01, 0x06, 0x03, 0x81, 0x9b, 0x80, 0xa2, 0x00, - 0x03, 0x10, 0x80, 0xbc, 0x82, 0x97, 0x80, 0x8d, - 0x80, 0x43, 0x5a, 0x81, 0xb2, 0x03, 0x80, 0x61, - 0xc4, 0xad, 0x80, 0x40, 0xc9, 0x80, 0x40, 0xbd, - 0x01, 0x89, 0xca, 0x99, 0x00, 0x97, 0x80, 0x93, - 0x01, 0x20, 0x82, 0x94, 0x81, 0x40, 0xad, 0xa0, - 0x8b, 0x88, 0x80, 0xc5, 0x80, 0x95, 0x8b, 0xaa, - 0x1c, 0x8b, 0x90, 0x10, 0x82, 0xc6, 0x00, 0x80, - 0x40, 0xba, 0x81, 0xbe, 0x8c, 0x18, 0x97, 0x91, - 0x80, 0x99, 0x81, 0x8c, 0x80, 0xd5, 0xd4, 0xaf, - 0xc5, 0x28, 0x12, 0x0a, 0x1b, 0x8a, 0x0e, 0x88, - 0x40, 0xe2, 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, - 0x89, 0x80, 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x89, - 0x84, 0xb7, 0x86, 0x8e, 0x81, 0x8a, 0x85, 0x88, -}; - -static const uint8_t unicode_prop_Extended_Pictographic_table[156] = { - 0x40, 0xa8, 0x03, 0x80, 0x5f, 0x8c, 0x80, 0x8b, - 0x80, 0x40, 0xd7, 0x80, 0x95, 0x80, 0xd9, 0x85, - 0x8e, 0x81, 0x41, 0x6e, 0x81, 0x8b, 0x80, 0xde, - 0x80, 0xc5, 0x80, 0x98, 0x8a, 0x1a, 0x40, 0xc6, - 0x80, 0x40, 0xe6, 0x81, 0x89, 0x80, 0x88, 0x80, - 0xb9, 0x18, 0x28, 0x8b, 0x80, 0xf1, 0x89, 0xf5, - 0x81, 0x8a, 0x00, 0x00, 0x28, 0x10, 0x28, 0x89, - 0x81, 0x8e, 0x01, 0x03, 0x00, 0x03, 0x10, 0x80, - 0x8a, 0x84, 0xac, 0x82, 0x88, 0x80, 0x8d, 0x80, - 0x8d, 0x80, 0x41, 0x73, 0x81, 0x41, 0xce, 0x82, - 0x92, 0x81, 0xb2, 0x03, 0x80, 0x44, 0xd9, 0x80, - 0x8b, 0x80, 0x42, 0x58, 0x00, 0x80, 0x61, 0xbd, - 0x65, 0x40, 0xff, 0x8c, 0x82, 0x9e, 0x80, 0xbb, - 0x85, 0x8b, 0x81, 0x8d, 0x01, 0x89, 0x91, 0xb8, - 0x9a, 0x8e, 0x89, 0x80, 0x93, 0x01, 0x88, 0x03, - 0x88, 0x41, 0xb1, 0x84, 0x41, 0x3d, 0x87, 0x41, - 0x09, 0xaf, 0xff, 0xf3, 0x8b, 0xd4, 0xaa, 0x8b, - 0x83, 0xb7, 0x87, 0x89, 0x85, 0xa7, 0x87, 0x9d, - 0xd1, 0x8b, 0xae, 0x80, 0x89, 0x80, 0x41, 0xb8, - 0x40, 0xff, 0x43, 0xfd, -}; - -static const uint8_t unicode_prop_Default_Ignorable_Code_Point_table[51] = { - 0x40, 0xac, 0x80, 0x42, 0xa0, 0x80, 0x42, 0xcb, - 0x80, 0x4b, 0x41, 0x81, 0x46, 0x52, 0x81, 0xd4, - 0x84, 0x47, 0xfa, 0x84, 0x99, 0x84, 0xb0, 0x8f, - 0x50, 0xf3, 0x80, 0x60, 0xcc, 0x9a, 0x8f, 0x40, - 0xee, 0x80, 0x40, 0x9f, 0x80, 0xce, 0x88, 0x60, - 0xbc, 0xa6, 0x83, 0x54, 0xce, 0x87, 0x6c, 0x2e, - 0x84, 0x4f, 0xff, -}; - -typedef enum { - UNICODE_PROP_Hyphen, - UNICODE_PROP_Other_Math, - UNICODE_PROP_Other_Alphabetic, - UNICODE_PROP_Other_Lowercase, - UNICODE_PROP_Other_Uppercase, - UNICODE_PROP_Other_Grapheme_Extend, - UNICODE_PROP_Other_Default_Ignorable_Code_Point, - UNICODE_PROP_Other_ID_Start, - UNICODE_PROP_Other_ID_Continue, - UNICODE_PROP_Prepended_Concatenation_Mark, - UNICODE_PROP_ID_Continue1, - UNICODE_PROP_XID_Start1, - UNICODE_PROP_XID_Continue1, - UNICODE_PROP_Changes_When_Titlecased1, - UNICODE_PROP_Changes_When_Casefolded1, - UNICODE_PROP_Changes_When_NFKC_Casefolded1, - UNICODE_PROP_Basic_Emoji1, - UNICODE_PROP_Basic_Emoji2, - UNICODE_PROP_RGI_Emoji_Modifier_Sequence, - UNICODE_PROP_RGI_Emoji_Flag_Sequence, - UNICODE_PROP_Emoji_Keycap_Sequence, - UNICODE_PROP_ASCII_Hex_Digit, - UNICODE_PROP_Bidi_Control, - UNICODE_PROP_Dash, - UNICODE_PROP_Deprecated, - UNICODE_PROP_Diacritic, - UNICODE_PROP_Extender, - UNICODE_PROP_Hex_Digit, - UNICODE_PROP_IDS_Unary_Operator, - UNICODE_PROP_IDS_Binary_Operator, - UNICODE_PROP_IDS_Trinary_Operator, - UNICODE_PROP_Ideographic, - UNICODE_PROP_Join_Control, - UNICODE_PROP_Logical_Order_Exception, - UNICODE_PROP_Modifier_Combining_Mark, - UNICODE_PROP_Noncharacter_Code_Point, - UNICODE_PROP_Pattern_Syntax, - UNICODE_PROP_Pattern_White_Space, - UNICODE_PROP_Quotation_Mark, - UNICODE_PROP_Radical, - UNICODE_PROP_Regional_Indicator, - UNICODE_PROP_Sentence_Terminal, - UNICODE_PROP_Soft_Dotted, - UNICODE_PROP_Terminal_Punctuation, - UNICODE_PROP_Unified_Ideograph, - UNICODE_PROP_Variation_Selector, - UNICODE_PROP_White_Space, - UNICODE_PROP_Bidi_Mirrored, - UNICODE_PROP_Emoji, - UNICODE_PROP_Emoji_Component, - UNICODE_PROP_Emoji_Modifier, - UNICODE_PROP_Emoji_Modifier_Base, - UNICODE_PROP_Emoji_Presentation, - UNICODE_PROP_Extended_Pictographic, - UNICODE_PROP_Default_Ignorable_Code_Point, - UNICODE_PROP_ID_Start, - UNICODE_PROP_Case_Ignorable, - UNICODE_PROP_ASCII, - UNICODE_PROP_Alphabetic, - UNICODE_PROP_Any, - UNICODE_PROP_Assigned, - UNICODE_PROP_Cased, - UNICODE_PROP_Changes_When_Casefolded, - UNICODE_PROP_Changes_When_Casemapped, - UNICODE_PROP_Changes_When_Lowercased, - UNICODE_PROP_Changes_When_NFKC_Casefolded, - UNICODE_PROP_Changes_When_Titlecased, - UNICODE_PROP_Changes_When_Uppercased, - UNICODE_PROP_Grapheme_Base, - UNICODE_PROP_Grapheme_Extend, - UNICODE_PROP_ID_Continue, - UNICODE_PROP_ID_Compat_Math_Start, - UNICODE_PROP_ID_Compat_Math_Continue, - UNICODE_PROP_InCB, - UNICODE_PROP_Lowercase, - UNICODE_PROP_Math, - UNICODE_PROP_Uppercase, - UNICODE_PROP_XID_Continue, - UNICODE_PROP_XID_Start, - UNICODE_PROP_Cased1, - UNICODE_PROP_COUNT, -} UnicodePropertyEnum; - -static const char unicode_prop_name_table[] = - "ASCII_Hex_Digit,AHex" "\0" - "Bidi_Control,Bidi_C" "\0" - "Dash" "\0" - "Deprecated,Dep" "\0" - "Diacritic,Dia" "\0" - "Extender,Ext" "\0" - "Hex_Digit,Hex" "\0" - "IDS_Unary_Operator,IDSU" "\0" - "IDS_Binary_Operator,IDSB" "\0" - "IDS_Trinary_Operator,IDST" "\0" - "Ideographic,Ideo" "\0" - "Join_Control,Join_C" "\0" - "Logical_Order_Exception,LOE" "\0" - "Modifier_Combining_Mark,MCM" "\0" - "Noncharacter_Code_Point,NChar" "\0" - "Pattern_Syntax,Pat_Syn" "\0" - "Pattern_White_Space,Pat_WS" "\0" - "Quotation_Mark,QMark" "\0" - "Radical" "\0" - "Regional_Indicator,RI" "\0" - "Sentence_Terminal,STerm" "\0" - "Soft_Dotted,SD" "\0" - "Terminal_Punctuation,Term" "\0" - "Unified_Ideograph,UIdeo" "\0" - "Variation_Selector,VS" "\0" - "White_Space,space" "\0" - "Bidi_Mirrored,Bidi_M" "\0" - "Emoji" "\0" - "Emoji_Component,EComp" "\0" - "Emoji_Modifier,EMod" "\0" - "Emoji_Modifier_Base,EBase" "\0" - "Emoji_Presentation,EPres" "\0" - "Extended_Pictographic,ExtPict" "\0" - "Default_Ignorable_Code_Point,DI" "\0" - "ID_Start,IDS" "\0" - "Case_Ignorable,CI" "\0" - "ASCII" "\0" - "Alphabetic,Alpha" "\0" - "Any" "\0" - "Assigned" "\0" - "Cased" "\0" - "Changes_When_Casefolded,CWCF" "\0" - "Changes_When_Casemapped,CWCM" "\0" - "Changes_When_Lowercased,CWL" "\0" - "Changes_When_NFKC_Casefolded,CWKCF" "\0" - "Changes_When_Titlecased,CWT" "\0" - "Changes_When_Uppercased,CWU" "\0" - "Grapheme_Base,Gr_Base" "\0" - "Grapheme_Extend,Gr_Ext" "\0" - "ID_Continue,IDC" "\0" - "ID_Compat_Math_Start" "\0" - "ID_Compat_Math_Continue" "\0" - "InCB" "\0" - "Lowercase,Lower" "\0" - "Math" "\0" - "Uppercase,Upper" "\0" - "XID_Continue,XIDC" "\0" - "XID_Start,XIDS" "\0" -; - -static const uint8_t * const unicode_prop_table[] = { - unicode_prop_Hyphen_table, - unicode_prop_Other_Math_table, - unicode_prop_Other_Alphabetic_table, - unicode_prop_Other_Lowercase_table, - unicode_prop_Other_Uppercase_table, - unicode_prop_Other_Grapheme_Extend_table, - unicode_prop_Other_Default_Ignorable_Code_Point_table, - unicode_prop_Other_ID_Start_table, - unicode_prop_Other_ID_Continue_table, - unicode_prop_Prepended_Concatenation_Mark_table, - unicode_prop_ID_Continue1_table, - unicode_prop_XID_Start1_table, - unicode_prop_XID_Continue1_table, - unicode_prop_Changes_When_Titlecased1_table, - unicode_prop_Changes_When_Casefolded1_table, - unicode_prop_Changes_When_NFKC_Casefolded1_table, - unicode_prop_Basic_Emoji1_table, - unicode_prop_Basic_Emoji2_table, - unicode_prop_RGI_Emoji_Modifier_Sequence_table, - unicode_prop_RGI_Emoji_Flag_Sequence_table, - unicode_prop_Emoji_Keycap_Sequence_table, - unicode_prop_ASCII_Hex_Digit_table, - unicode_prop_Bidi_Control_table, - unicode_prop_Dash_table, - unicode_prop_Deprecated_table, - unicode_prop_Diacritic_table, - unicode_prop_Extender_table, - unicode_prop_Hex_Digit_table, - unicode_prop_IDS_Unary_Operator_table, - unicode_prop_IDS_Binary_Operator_table, - unicode_prop_IDS_Trinary_Operator_table, - unicode_prop_Ideographic_table, - unicode_prop_Join_Control_table, - unicode_prop_Logical_Order_Exception_table, - unicode_prop_Modifier_Combining_Mark_table, - unicode_prop_Noncharacter_Code_Point_table, - unicode_prop_Pattern_Syntax_table, - unicode_prop_Pattern_White_Space_table, - unicode_prop_Quotation_Mark_table, - unicode_prop_Radical_table, - unicode_prop_Regional_Indicator_table, - unicode_prop_Sentence_Terminal_table, - unicode_prop_Soft_Dotted_table, - unicode_prop_Terminal_Punctuation_table, - unicode_prop_Unified_Ideograph_table, - unicode_prop_Variation_Selector_table, - unicode_prop_White_Space_table, - unicode_prop_Bidi_Mirrored_table, - unicode_prop_Emoji_table, - unicode_prop_Emoji_Component_table, - unicode_prop_Emoji_Modifier_table, - unicode_prop_Emoji_Modifier_Base_table, - unicode_prop_Emoji_Presentation_table, - unicode_prop_Extended_Pictographic_table, - unicode_prop_Default_Ignorable_Code_Point_table, - unicode_prop_ID_Start_table, - unicode_prop_Case_Ignorable_table, -}; - -static const uint16_t unicode_prop_len_table[] = { - countof(unicode_prop_Hyphen_table), - countof(unicode_prop_Other_Math_table), - countof(unicode_prop_Other_Alphabetic_table), - countof(unicode_prop_Other_Lowercase_table), - countof(unicode_prop_Other_Uppercase_table), - countof(unicode_prop_Other_Grapheme_Extend_table), - countof(unicode_prop_Other_Default_Ignorable_Code_Point_table), - countof(unicode_prop_Other_ID_Start_table), - countof(unicode_prop_Other_ID_Continue_table), - countof(unicode_prop_Prepended_Concatenation_Mark_table), - countof(unicode_prop_ID_Continue1_table), - countof(unicode_prop_XID_Start1_table), - countof(unicode_prop_XID_Continue1_table), - countof(unicode_prop_Changes_When_Titlecased1_table), - countof(unicode_prop_Changes_When_Casefolded1_table), - countof(unicode_prop_Changes_When_NFKC_Casefolded1_table), - countof(unicode_prop_Basic_Emoji1_table), - countof(unicode_prop_Basic_Emoji2_table), - countof(unicode_prop_RGI_Emoji_Modifier_Sequence_table), - countof(unicode_prop_RGI_Emoji_Flag_Sequence_table), - countof(unicode_prop_Emoji_Keycap_Sequence_table), - countof(unicode_prop_ASCII_Hex_Digit_table), - countof(unicode_prop_Bidi_Control_table), - countof(unicode_prop_Dash_table), - countof(unicode_prop_Deprecated_table), - countof(unicode_prop_Diacritic_table), - countof(unicode_prop_Extender_table), - countof(unicode_prop_Hex_Digit_table), - countof(unicode_prop_IDS_Unary_Operator_table), - countof(unicode_prop_IDS_Binary_Operator_table), - countof(unicode_prop_IDS_Trinary_Operator_table), - countof(unicode_prop_Ideographic_table), - countof(unicode_prop_Join_Control_table), - countof(unicode_prop_Logical_Order_Exception_table), - countof(unicode_prop_Modifier_Combining_Mark_table), - countof(unicode_prop_Noncharacter_Code_Point_table), - countof(unicode_prop_Pattern_Syntax_table), - countof(unicode_prop_Pattern_White_Space_table), - countof(unicode_prop_Quotation_Mark_table), - countof(unicode_prop_Radical_table), - countof(unicode_prop_Regional_Indicator_table), - countof(unicode_prop_Sentence_Terminal_table), - countof(unicode_prop_Soft_Dotted_table), - countof(unicode_prop_Terminal_Punctuation_table), - countof(unicode_prop_Unified_Ideograph_table), - countof(unicode_prop_Variation_Selector_table), - countof(unicode_prop_White_Space_table), - countof(unicode_prop_Bidi_Mirrored_table), - countof(unicode_prop_Emoji_table), - countof(unicode_prop_Emoji_Component_table), - countof(unicode_prop_Emoji_Modifier_table), - countof(unicode_prop_Emoji_Modifier_Base_table), - countof(unicode_prop_Emoji_Presentation_table), - countof(unicode_prop_Extended_Pictographic_table), - countof(unicode_prop_Default_Ignorable_Code_Point_table), - countof(unicode_prop_ID_Start_table), - countof(unicode_prop_Case_Ignorable_table), -}; - -typedef enum { - UNICODE_SEQUENCE_PROP_Basic_Emoji, - UNICODE_SEQUENCE_PROP_Emoji_Keycap_Sequence, - UNICODE_SEQUENCE_PROP_RGI_Emoji_Modifier_Sequence, - UNICODE_SEQUENCE_PROP_RGI_Emoji_Flag_Sequence, - UNICODE_SEQUENCE_PROP_RGI_Emoji_Tag_Sequence, - UNICODE_SEQUENCE_PROP_RGI_Emoji_ZWJ_Sequence, - UNICODE_SEQUENCE_PROP_RGI_Emoji, - UNICODE_SEQUENCE_PROP_COUNT, -} UnicodeSequencePropertyEnum; - -static const char unicode_sequence_prop_name_table[] = - "Basic_Emoji" "\0" - "Emoji_Keycap_Sequence" "\0" - "RGI_Emoji_Modifier_Sequence" "\0" - "RGI_Emoji_Flag_Sequence" "\0" - "RGI_Emoji_Tag_Sequence" "\0" - "RGI_Emoji_ZWJ_Sequence" "\0" - "RGI_Emoji" "\0" -; - -static const uint8_t unicode_rgi_emoji_tag_sequence[18] = { - 0x67, 0x62, 0x65, 0x6e, 0x67, 0x00, 0x67, 0x62, - 0x73, 0x63, 0x74, 0x00, 0x67, 0x62, 0x77, 0x6c, - 0x73, 0x00, -}; - -static const uint8_t unicode_rgi_emoji_zwj_sequence[2320] = { - 0x02, 0xb8, 0x19, 0x40, 0x86, 0x02, 0xd1, 0x39, - 0xb0, 0x19, 0x02, 0x26, 0x39, 0x42, 0x86, 0x02, - 0xb4, 0x36, 0x42, 0x86, 0x03, 0x68, 0x54, 0x64, - 0x87, 0x68, 0x54, 0x02, 0xdc, 0x39, 0x42, 0x86, - 0x02, 0xd1, 0x39, 0x73, 0x13, 0x02, 0x39, 0x39, - 0x40, 0x86, 0x02, 0x69, 0x34, 0xbd, 0x19, 0x03, - 0xb6, 0x36, 0x40, 0x86, 0xa1, 0x87, 0x03, 0x68, - 0x74, 0x1d, 0x19, 0x68, 0x74, 0x03, 0x68, 0x34, - 0xbd, 0x19, 0xa1, 0x87, 0x02, 0xf1, 0x7a, 0xf2, - 0x7a, 0x02, 0xca, 0x33, 0x42, 0x86, 0x02, 0x69, - 0x34, 0xb0, 0x19, 0x04, 0x68, 0x14, 0x68, 0x14, - 0x67, 0x14, 0x66, 0x14, 0x02, 0xf9, 0x26, 0x42, - 0x86, 0x03, 0x69, 0x74, 0x1d, 0x19, 0x69, 0x74, - 0x03, 0xd1, 0x19, 0xbc, 0x19, 0xa1, 0x87, 0x02, - 0x3c, 0x19, 0x40, 0x86, 0x02, 0x68, 0x34, 0xeb, - 0x13, 0x02, 0xc3, 0x33, 0xa1, 0x87, 0x02, 0x70, - 0x34, 0x40, 0x86, 0x02, 0xd4, 0x39, 0x42, 0x86, - 0x02, 0xcf, 0x39, 0x42, 0x86, 0x02, 0x47, 0x36, - 0x40, 0x86, 0x02, 0x39, 0x39, 0x42, 0x86, 0x04, - 0xd1, 0x79, 0x64, 0x87, 0x8b, 0x14, 0xd1, 0x79, - 0x02, 0xd1, 0x39, 0x95, 0x86, 0x02, 0x68, 0x34, - 0x93, 0x13, 0x02, 0x69, 0x34, 0xed, 0x13, 0x02, - 0xda, 0x39, 0x40, 0x86, 0x03, 0x69, 0x34, 0xaf, - 0x19, 0xa1, 0x87, 0x02, 0xd1, 0x39, 0x93, 0x13, - 0x03, 0xce, 0x39, 0x42, 0x86, 0xa1, 0x87, 0x03, - 0xd1, 0x79, 0x64, 0x87, 0xd1, 0x79, 0x03, 0xc3, - 0x33, 0x42, 0x86, 0xa1, 0x87, 0x03, 0x69, 0x74, - 0x1d, 0x19, 0x68, 0x74, 0x02, 0x69, 0x34, 0x92, - 0x16, 0x02, 0xd1, 0x39, 0x96, 0x86, 0x04, 0x69, - 0x14, 0x64, 0x87, 0x8b, 0x14, 0x68, 0x14, 0x02, - 0x68, 0x34, 0x7c, 0x13, 0x02, 0x47, 0x36, 0x42, - 0x86, 0x02, 0x86, 0x34, 0x42, 0x86, 0x02, 0xd1, - 0x39, 0x7c, 0x13, 0x02, 0x69, 0x14, 0xa4, 0x13, - 0x02, 0xda, 0x39, 0x42, 0x86, 0x02, 0x37, 0x39, - 0x40, 0x86, 0x02, 0xd1, 0x39, 0x08, 0x87, 0x04, - 0x68, 0x54, 0x64, 0x87, 0x8b, 0x14, 0x68, 0x54, - 0x02, 0x4d, 0x36, 0x40, 0x86, 0x02, 0x68, 0x34, - 0x2c, 0x15, 0x02, 0x69, 0x34, 0xaf, 0x19, 0x02, - 0x6e, 0x34, 0x40, 0x86, 0x02, 0xcd, 0x39, 0x42, - 0x86, 0x02, 0xd1, 0x39, 0x2c, 0x15, 0x02, 0x6f, - 0x14, 0x40, 0x86, 0x03, 0xd1, 0x39, 0xbc, 0x19, - 0xa1, 0x87, 0x02, 0x68, 0x34, 0xa8, 0x13, 0x02, - 0x69, 0x34, 0x73, 0x13, 0x04, 0x69, 0x54, 0x64, - 0x87, 0x8b, 0x14, 0x68, 0x54, 0x02, 0x71, 0x34, - 0x42, 0x86, 0x02, 0xd1, 0x39, 0xa8, 0x13, 0x02, - 0x45, 0x36, 0x40, 0x86, 0x03, 0x69, 0x54, 0x64, - 0x87, 0x68, 0x54, 0x03, 0x69, 0x54, 0x64, 0x87, - 0x69, 0x54, 0x03, 0xce, 0x39, 0x40, 0x86, 0xa1, - 0x87, 0x02, 0xd8, 0x39, 0x40, 0x86, 0x03, 0xc3, - 0x33, 0x40, 0x86, 0xa1, 0x87, 0x02, 0x4d, 0x36, - 0x42, 0x86, 0x02, 0xd1, 0x19, 0x92, 0x16, 0x02, - 0xd1, 0x39, 0xeb, 0x13, 0x02, 0x68, 0x34, 0xbc, - 0x14, 0x02, 0xd1, 0x39, 0xbc, 0x14, 0x02, 0x3d, - 0x39, 0x40, 0x86, 0x02, 0xb8, 0x39, 0x42, 0x86, - 0x02, 0xa3, 0x36, 0x40, 0x86, 0x02, 0x75, 0x35, - 0x40, 0x86, 0x02, 0xd8, 0x39, 0x42, 0x86, 0x02, - 0x69, 0x34, 0x93, 0x13, 0x02, 0x35, 0x39, 0x40, - 0x86, 0x02, 0x4b, 0x36, 0x40, 0x86, 0x02, 0x3d, - 0x39, 0x42, 0x86, 0x02, 0x38, 0x39, 0x42, 0x86, - 0x02, 0xa3, 0x36, 0x42, 0x86, 0x03, 0x69, 0x14, - 0x67, 0x14, 0x67, 0x14, 0x02, 0xb6, 0x36, 0x40, - 0x86, 0x02, 0x69, 0x34, 0x7c, 0x13, 0x02, 0x75, - 0x35, 0x42, 0x86, 0x02, 0xcc, 0x93, 0x40, 0x86, - 0x02, 0xcc, 0x33, 0x40, 0x86, 0x03, 0xd1, 0x39, - 0xbd, 0x19, 0xa1, 0x87, 0x02, 0x82, 0x34, 0x40, - 0x86, 0x02, 0x87, 0x34, 0x40, 0x86, 0x02, 0x69, - 0x14, 0x3e, 0x13, 0x02, 0xd6, 0x39, 0x40, 0x86, - 0x02, 0x68, 0x14, 0xbd, 0x19, 0x02, 0x46, 0x36, - 0x42, 0x86, 0x02, 0x4b, 0x36, 0x42, 0x86, 0x02, - 0x69, 0x34, 0x2c, 0x15, 0x03, 0xb6, 0x36, 0x42, - 0x86, 0xa1, 0x87, 0x02, 0xc4, 0x33, 0x40, 0x86, - 0x02, 0x26, 0x19, 0x40, 0x86, 0x02, 0x69, 0x14, - 0xb0, 0x19, 0x02, 0xde, 0x19, 0x42, 0x86, 0x02, - 0x69, 0x34, 0xa8, 0x13, 0x02, 0xcc, 0x33, 0x42, - 0x86, 0x02, 0x82, 0x34, 0x42, 0x86, 0x02, 0xd1, - 0x19, 0x93, 0x13, 0x02, 0x81, 0x14, 0x42, 0x86, - 0x02, 0x69, 0x34, 0x95, 0x86, 0x02, 0x68, 0x34, - 0xbb, 0x14, 0x02, 0xd1, 0x39, 0xbb, 0x14, 0x02, - 0x69, 0x34, 0xeb, 0x13, 0x02, 0xd1, 0x39, 0x84, - 0x13, 0x02, 0x69, 0x34, 0xbc, 0x14, 0x04, 0x69, - 0x54, 0x64, 0x87, 0x8b, 0x14, 0x69, 0x54, 0x02, - 0x26, 0x39, 0x40, 0x86, 0x02, 0xb4, 0x36, 0x40, - 0x86, 0x02, 0x47, 0x16, 0x42, 0x86, 0x02, 0xdc, - 0x39, 0x40, 0x86, 0x02, 0xca, 0x33, 0x40, 0x86, - 0x02, 0xf9, 0x26, 0x40, 0x86, 0x02, 0x69, 0x34, - 0x08, 0x87, 0x03, 0x69, 0x14, 0x69, 0x14, 0x66, - 0x14, 0x03, 0xd1, 0x59, 0x1d, 0x19, 0xd1, 0x59, - 0x02, 0xd4, 0x39, 0x40, 0x86, 0x02, 0xcf, 0x39, - 0x40, 0x86, 0x02, 0x68, 0x34, 0xa4, 0x13, 0x02, - 0xd1, 0x39, 0xa4, 0x13, 0x02, 0xd1, 0x19, 0xa8, - 0x13, 0x02, 0xd7, 0x39, 0x42, 0x86, 0x03, 0x69, - 0x34, 0xbc, 0x19, 0xa1, 0x87, 0x02, 0x68, 0x14, - 0xb0, 0x19, 0x02, 0x68, 0x14, 0x73, 0x13, 0x04, - 0x69, 0x14, 0x69, 0x14, 0x66, 0x14, 0x66, 0x14, - 0x03, 0x68, 0x34, 0xaf, 0x19, 0xa1, 0x87, 0x02, - 0x68, 0x34, 0x80, 0x16, 0x02, 0x73, 0x34, 0x42, - 0x86, 0x02, 0xd1, 0x39, 0x80, 0x16, 0x02, 0x68, - 0x34, 0xb0, 0x19, 0x02, 0x86, 0x34, 0x40, 0x86, - 0x02, 0x38, 0x19, 0x42, 0x86, 0x02, 0x69, 0x34, - 0xbb, 0x14, 0x02, 0xb5, 0x36, 0x42, 0x86, 0x02, - 0xcd, 0x39, 0x40, 0x86, 0x02, 0x68, 0x34, 0x95, - 0x86, 0x02, 0x68, 0x34, 0x27, 0x15, 0x03, 0x68, - 0x14, 0x68, 0x14, 0x66, 0x14, 0x02, 0x71, 0x34, - 0x40, 0x86, 0x02, 0xd1, 0x39, 0x27, 0x15, 0x02, - 0x2e, 0x16, 0xa8, 0x14, 0x02, 0xc3, 0x33, 0x42, - 0x86, 0x02, 0x69, 0x14, 0x66, 0x14, 0x02, 0x68, - 0x34, 0x96, 0x86, 0x02, 0x69, 0x34, 0xa4, 0x13, - 0x03, 0x69, 0x14, 0x64, 0x87, 0x68, 0x14, 0x02, - 0xb8, 0x39, 0x40, 0x86, 0x02, 0x68, 0x34, 0x3e, - 0x13, 0x03, 0xd1, 0x19, 0xaf, 0x19, 0xa1, 0x87, - 0x02, 0xd1, 0x39, 0x3e, 0x13, 0x02, 0x68, 0x34, - 0xbd, 0x19, 0x02, 0xd1, 0x19, 0xbb, 0x14, 0x02, - 0xd1, 0x19, 0x95, 0x86, 0x02, 0xdb, 0x39, 0x42, - 0x86, 0x02, 0x38, 0x39, 0x40, 0x86, 0x02, 0x69, - 0x34, 0x80, 0x16, 0x02, 0x69, 0x14, 0xeb, 0x13, - 0x04, 0x68, 0x14, 0x69, 0x14, 0x67, 0x14, 0x67, - 0x14, 0x02, 0x77, 0x34, 0x42, 0x86, 0x02, 0x46, - 0x36, 0x40, 0x86, 0x02, 0x68, 0x34, 0x92, 0x16, - 0x02, 0x4e, 0x36, 0x42, 0x86, 0x03, 0x69, 0x14, - 0xbd, 0x19, 0xa1, 0x87, 0x02, 0xde, 0x19, 0x40, - 0x86, 0x02, 0x69, 0x34, 0x27, 0x15, 0x03, 0xc3, - 0x13, 0x40, 0x86, 0xa1, 0x87, 0x02, 0x81, 0x14, - 0x40, 0x86, 0x03, 0xd1, 0x39, 0xaf, 0x19, 0xa1, - 0x87, 0x02, 0x68, 0x34, 0xbc, 0x19, 0x02, 0xd1, - 0x19, 0x80, 0x16, 0x02, 0xd9, 0x39, 0x42, 0x86, - 0x02, 0xd1, 0x39, 0xbc, 0x19, 0x02, 0xdc, 0x19, - 0x42, 0x86, 0x02, 0x68, 0x34, 0x73, 0x13, 0x02, - 0x69, 0x34, 0x3e, 0x13, 0x02, 0x47, 0x16, 0x40, - 0x86, 0x02, 0xd1, 0x39, 0xbd, 0x19, 0x02, 0x3e, - 0x39, 0x42, 0x86, 0x02, 0x69, 0x14, 0x95, 0x86, - 0x02, 0x68, 0x14, 0x96, 0x86, 0x03, 0x69, 0x34, - 0xbd, 0x19, 0xa1, 0x87, 0x02, 0xd7, 0x39, 0x40, - 0x86, 0x02, 0x45, 0x16, 0x42, 0x86, 0x02, 0x68, - 0x34, 0xed, 0x13, 0x03, 0x68, 0x34, 0xbc, 0x19, - 0xa1, 0x87, 0x02, 0xd1, 0x39, 0xed, 0x13, 0x02, - 0xd1, 0x39, 0x92, 0x16, 0x02, 0x73, 0x34, 0x40, - 0x86, 0x02, 0x38, 0x19, 0x40, 0x86, 0x02, 0xb5, - 0x36, 0x40, 0x86, 0x02, 0x68, 0x34, 0xaf, 0x19, - 0x02, 0xd1, 0x39, 0xaf, 0x19, 0x02, 0x69, 0x34, - 0xbc, 0x19, 0x02, 0xb6, 0x16, 0x42, 0x86, 0x02, - 0x26, 0x14, 0x25, 0x15, 0x02, 0xc3, 0x33, 0x40, - 0x86, 0x02, 0xdd, 0x39, 0x42, 0x86, 0x02, 0xcb, - 0x93, 0x42, 0x86, 0x02, 0xcb, 0x33, 0x42, 0x86, - 0x02, 0x81, 0x34, 0x42, 0x86, 0x02, 0xce, 0x39, - 0xa1, 0x87, 0x02, 0xdb, 0x39, 0x40, 0x86, 0x02, - 0x68, 0x34, 0x08, 0x87, 0x02, 0xd1, 0x19, 0xb0, - 0x19, 0x02, 0x77, 0x34, 0x40, 0x86, 0x02, 0x4e, - 0x36, 0x40, 0x86, 0x02, 0xce, 0x39, 0x42, 0x86, - 0x02, 0x4e, 0x16, 0x42, 0x86, 0x02, 0xd9, 0x39, - 0x40, 0x86, 0x02, 0xdc, 0x19, 0x40, 0x86, 0x02, - 0x3e, 0x39, 0x40, 0x86, 0x02, 0xb9, 0x39, 0x42, - 0x86, 0x02, 0xda, 0x19, 0x42, 0x86, 0x02, 0x42, - 0x16, 0x94, 0x81, 0x02, 0x45, 0x16, 0x40, 0x86, - 0x02, 0x69, 0x14, 0xbd, 0x19, 0x02, 0x70, 0x34, - 0x42, 0x86, 0x02, 0xce, 0x19, 0xa1, 0x87, 0x02, - 0xc3, 0x13, 0x42, 0x86, 0x02, 0x68, 0x14, 0x08, - 0x87, 0x02, 0xd1, 0x19, 0x7c, 0x13, 0x02, 0x68, - 0x14, 0x92, 0x16, 0x02, 0xb6, 0x16, 0x40, 0x86, - 0x02, 0x37, 0x39, 0x42, 0x86, 0x03, 0xce, 0x19, - 0x42, 0x86, 0xa1, 0x87, 0x03, 0x68, 0x14, 0x67, - 0x14, 0x67, 0x14, 0x02, 0xdd, 0x39, 0x40, 0x86, - 0x02, 0xcf, 0x19, 0x42, 0x86, 0x02, 0xd1, 0x19, - 0x2c, 0x15, 0x02, 0x4b, 0x13, 0xe9, 0x17, 0x02, - 0x68, 0x14, 0x67, 0x14, 0x02, 0xcb, 0x93, 0x40, - 0x86, 0x02, 0x6e, 0x34, 0x42, 0x86, 0x02, 0xcb, - 0x33, 0x40, 0x86, 0x02, 0x81, 0x34, 0x40, 0x86, - 0x02, 0xb6, 0x36, 0xa1, 0x87, 0x02, 0x45, 0x36, - 0x42, 0x86, 0x02, 0xb4, 0x16, 0x42, 0x86, 0x02, - 0x69, 0x14, 0x73, 0x13, 0x04, 0x69, 0x14, 0x69, - 0x14, 0x67, 0x14, 0x66, 0x14, 0x02, 0x35, 0x39, - 0x42, 0x86, 0x02, 0x68, 0x14, 0x93, 0x13, 0x02, - 0xb6, 0x36, 0x42, 0x86, 0x03, 0x68, 0x14, 0x69, - 0x14, 0x66, 0x14, 0x02, 0xce, 0x39, 0x40, 0x86, - 0x02, 0x4e, 0x16, 0x40, 0x86, 0x02, 0x87, 0x34, - 0x42, 0x86, 0x02, 0x86, 0x14, 0x42, 0x86, 0x02, - 0xd6, 0x39, 0x42, 0x86, 0x02, 0xc4, 0x33, 0x42, - 0x86, 0x02, 0x69, 0x34, 0x96, 0x86, 0x02, 0xb9, - 0x39, 0x40, 0x86, 0x02, 0x68, 0x14, 0xa8, 0x13, - 0x02, 0xd1, 0x19, 0x84, 0x13, 0x02, 0xda, 0x19, - 0x40, 0x86, 0x02, 0xd8, 0x19, 0x42, 0x86, 0x02, - 0xc3, 0x13, 0x40, 0x86, 0x02, 0xb9, 0x19, 0x42, - 0x86, 0x02, 0x3d, 0x19, 0x42, 0x86, 0x02, 0xcf, - 0x19, 0x40, 0x86, 0x04, 0x68, 0x14, 0x68, 0x14, - 0x67, 0x14, 0x67, 0x14, 0x03, 0xd1, 0x19, 0xd1, - 0x19, 0xd2, 0x19, 0x02, 0x68, 0x14, 0xbb, 0x14, - 0x02, 0x3b, 0x14, 0x44, 0x87, 0x02, 0xd1, 0x19, - 0x27, 0x15, 0x02, 0xb4, 0x16, 0x40, 0x86, 0x02, - 0xcd, 0x19, 0x42, 0x86, 0x02, 0xd3, 0x86, 0xa5, - 0x14, 0x02, 0x70, 0x14, 0x42, 0x86, 0x03, 0xb6, - 0x16, 0x42, 0x86, 0xa1, 0x87, 0x04, 0x69, 0x14, - 0x64, 0x87, 0x8b, 0x14, 0x69, 0x14, 0x02, 0x36, - 0x16, 0x2b, 0x93, 0x02, 0x68, 0x14, 0x80, 0x16, - 0x02, 0x86, 0x14, 0x40, 0x86, 0x02, 0x08, 0x14, - 0x1b, 0x0b, 0x02, 0xd1, 0x19, 0xbc, 0x19, 0x02, - 0xca, 0x13, 0x42, 0x86, 0x02, 0x41, 0x94, 0xe8, - 0x95, 0x02, 0xd8, 0x19, 0x40, 0x86, 0x02, 0xb9, - 0x19, 0x40, 0x86, 0x02, 0xd1, 0x19, 0xed, 0x13, - 0x02, 0xf9, 0x86, 0x42, 0x86, 0x03, 0xd1, 0x19, - 0xbd, 0x19, 0xa1, 0x87, 0x02, 0x3d, 0x19, 0x40, - 0x86, 0x02, 0xd6, 0x19, 0x42, 0x86, 0x03, 0x69, - 0x14, 0x66, 0x14, 0x66, 0x14, 0x02, 0xd1, 0x19, - 0xaf, 0x19, 0x03, 0x69, 0x14, 0x69, 0x14, 0x67, - 0x14, 0x02, 0xcd, 0x19, 0x40, 0x86, 0x02, 0x70, - 0x14, 0x40, 0x86, 0x03, 0x68, 0x14, 0xbc, 0x19, - 0xa1, 0x87, 0x02, 0x6e, 0x14, 0x42, 0x86, 0x02, - 0x69, 0x14, 0x92, 0x16, 0x03, 0x68, 0x14, 0x68, - 0x14, 0x67, 0x14, 0x02, 0x69, 0x14, 0x67, 0x14, - 0x02, 0x75, 0x95, 0x42, 0x86, 0x03, 0x69, 0x14, - 0x64, 0x87, 0x69, 0x14, 0x02, 0xd1, 0x19, 0xbc, - 0x14, 0x02, 0xdf, 0x19, 0x42, 0x86, 0x02, 0xca, - 0x13, 0x40, 0x86, 0x02, 0x82, 0x14, 0x42, 0x86, - 0x02, 0x69, 0x14, 0x93, 0x13, 0x02, 0x68, 0x14, - 0x7c, 0x13, 0x02, 0xf9, 0x86, 0x40, 0x86, 0x02, - 0xd6, 0x19, 0x40, 0x86, 0x02, 0x68, 0x14, 0x2c, - 0x15, 0x02, 0x69, 0x14, 0xa8, 0x13, 0x02, 0xd4, - 0x19, 0x42, 0x86, 0x04, 0x68, 0x14, 0x69, 0x14, - 0x66, 0x14, 0x66, 0x14, 0x02, 0x77, 0x14, 0x42, - 0x86, 0x02, 0x39, 0x19, 0x42, 0x86, 0x02, 0xd1, - 0x19, 0xa4, 0x13, 0x02, 0x6e, 0x14, 0x40, 0x86, - 0x03, 0xd1, 0x19, 0xd2, 0x19, 0xd2, 0x19, 0x02, - 0x69, 0x14, 0xbb, 0x14, 0x02, 0xd1, 0x19, 0x96, - 0x86, 0x02, 0x75, 0x95, 0x40, 0x86, 0x04, 0x68, - 0x14, 0x64, 0x87, 0x8b, 0x14, 0x68, 0x14, 0x02, - 0xd1, 0x19, 0x3e, 0x13, 0x02, 0xdf, 0x19, 0x40, - 0x86, 0x02, 0x82, 0x14, 0x40, 0x86, 0x02, 0x44, - 0x13, 0xeb, 0x17, 0x02, 0xdd, 0x19, 0x42, 0x86, - 0x02, 0x69, 0x14, 0x80, 0x16, 0x03, 0x68, 0x14, - 0xaf, 0x19, 0xa1, 0x87, 0x02, 0xa3, 0x16, 0x42, - 0x86, 0x02, 0x69, 0x14, 0x96, 0x86, 0x02, 0x46, - 0x16, 0x42, 0x86, 0x02, 0xb6, 0x16, 0xa1, 0x87, - 0x02, 0x68, 0x14, 0x27, 0x15, 0x02, 0x26, 0x14, - 0x1b, 0x0b, 0x02, 0xd4, 0x19, 0x40, 0x86, 0x02, - 0x77, 0x14, 0x40, 0x86, 0x02, 0x39, 0x19, 0x40, - 0x86, 0x02, 0x37, 0x19, 0x42, 0x86, 0x03, 0x69, - 0x14, 0x67, 0x14, 0x66, 0x14, 0x03, 0xc3, 0x13, - 0x42, 0x86, 0xa1, 0x87, 0x02, 0x68, 0x14, 0xbc, - 0x19, 0x02, 0xd1, 0x19, 0xeb, 0x13, 0x04, 0x69, - 0x14, 0x69, 0x14, 0x67, 0x14, 0x67, 0x14, 0x02, - 0xd1, 0x19, 0x08, 0x87, 0x02, 0x68, 0x14, 0xed, - 0x13, 0x03, 0x69, 0x14, 0xbc, 0x19, 0xa1, 0x87, - 0x02, 0xdd, 0x19, 0x40, 0x86, 0x02, 0xc3, 0x13, - 0xa1, 0x87, 0x03, 0x68, 0x14, 0x66, 0x14, 0x66, - 0x14, 0x03, 0x68, 0x14, 0x69, 0x14, 0x67, 0x14, - 0x02, 0xa3, 0x16, 0x40, 0x86, 0x02, 0xdb, 0x19, - 0x42, 0x86, 0x02, 0x68, 0x14, 0xaf, 0x19, 0x02, - 0x46, 0x16, 0x40, 0x86, 0x02, 0x35, 0x16, 0xab, - 0x14, 0x02, 0x68, 0x14, 0x95, 0x86, 0x02, 0x42, - 0x16, 0x95, 0x81, 0x02, 0xc4, 0x13, 0x42, 0x86, - 0x02, 0x15, 0x14, 0xba, 0x19, 0x02, 0x69, 0x14, - 0x08, 0x87, 0x03, 0xd1, 0x19, 0x1d, 0x19, 0xd1, - 0x19, 0x02, 0x69, 0x14, 0x7c, 0x13, 0x02, 0x37, - 0x19, 0x40, 0x86, 0x02, 0x73, 0x14, 0x42, 0x86, - 0x02, 0x69, 0x14, 0x2c, 0x15, 0x02, 0xb5, 0x16, - 0x42, 0x86, 0x02, 0x35, 0x19, 0x42, 0x86, 0x04, - 0x68, 0x14, 0x69, 0x14, 0x67, 0x14, 0x66, 0x14, - 0x02, 0x64, 0x87, 0x25, 0x15, 0x02, 0x64, 0x87, - 0x79, 0x1a, 0x02, 0x68, 0x14, 0xbc, 0x14, 0x03, - 0xce, 0x19, 0x40, 0x86, 0xa1, 0x87, 0x02, 0x87, - 0x14, 0x42, 0x86, 0x02, 0x4d, 0x16, 0x42, 0x86, - 0x04, 0x68, 0x14, 0x68, 0x14, 0x66, 0x14, 0x66, - 0x14, 0x02, 0xdb, 0x19, 0x40, 0x86, 0x02, 0xd9, - 0x19, 0x42, 0x86, 0x02, 0xc4, 0x13, 0x40, 0x86, - 0x02, 0xd1, 0x19, 0xbd, 0x19, 0x02, 0x68, 0x14, - 0xa4, 0x13, 0x02, 0x3e, 0x19, 0x42, 0x86, 0x02, - 0xf3, 0x93, 0xa7, 0x86, 0x03, 0x69, 0x14, 0xaf, - 0x19, 0xa1, 0x87, 0x02, 0xf3, 0x93, 0x08, 0x13, - 0x02, 0xd1, 0x19, 0xd2, 0x19, 0x02, 0x73, 0x14, - 0x40, 0x86, 0x02, 0xb5, 0x16, 0x40, 0x86, 0x02, - 0x35, 0x19, 0x40, 0x86, 0x02, 0x69, 0x14, 0x27, - 0x15, 0x02, 0xce, 0x19, 0x42, 0x86, 0x02, 0x71, - 0x14, 0x42, 0x86, 0x02, 0xd1, 0x19, 0x73, 0x13, - 0x02, 0x68, 0x14, 0x3e, 0x13, 0x02, 0xf4, 0x13, - 0x20, 0x86, 0x02, 0x87, 0x14, 0x40, 0x86, 0x03, - 0xb6, 0x16, 0x40, 0x86, 0xa1, 0x87, 0x02, 0x4d, - 0x16, 0x40, 0x86, 0x02, 0x69, 0x14, 0xbc, 0x19, - 0x02, 0x4b, 0x16, 0x42, 0x86, 0x02, 0xd9, 0x19, - 0x40, 0x86, 0x02, 0x3e, 0x19, 0x40, 0x86, 0x02, - 0x69, 0x14, 0xed, 0x13, 0x02, 0xd7, 0x19, 0x42, - 0x86, 0x02, 0xb8, 0x19, 0x42, 0x86, 0x03, 0x68, - 0x14, 0x67, 0x14, 0x66, 0x14, 0x02, 0x3c, 0x19, - 0x42, 0x86, 0x02, 0x68, 0x14, 0x66, 0x14, 0x03, - 0x68, 0x14, 0x64, 0x87, 0x68, 0x14, 0x02, 0x69, - 0x14, 0xaf, 0x19, 0x02, 0xce, 0x19, 0x40, 0x86, - 0x02, 0x71, 0x14, 0x40, 0x86, 0x02, 0x68, 0x14, - 0xeb, 0x13, 0x03, 0x68, 0x14, 0xbd, 0x19, 0xa1, - 0x87, 0x02, 0x6f, 0x14, 0x42, 0x86, 0x04, 0xd1, - 0x19, 0xd1, 0x19, 0xd2, 0x19, 0xd2, 0x19, 0x02, - 0x69, 0x14, 0xbc, 0x14, 0x02, 0xcc, 0x93, 0x42, - 0x86, 0x02, 0x4b, 0x16, 0x40, 0x86, 0x02, 0x26, - 0x19, 0x42, 0x86, 0x02, 0xd7, 0x19, 0x40, 0x86, -}; - -#endif /* CONFIG_ALL_UNICODE */ -/* 71 tables / 36311 bytes, 5 index / 351 bytes */ diff --git a/packages/javascript/javascript_android/cxx/quickjs/libunicode.c b/packages/javascript/javascript_android/cxx/quickjs/libunicode.c deleted file mode 100644 index 3791523..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/libunicode.c +++ /dev/null @@ -1,2123 +0,0 @@ -/* - * Unicode utilities - * - * Copyright (c) 2017-2018 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include -#include -#include -#include -#include - -#include "cutils.h" -#include "libunicode.h" -#include "libunicode-table.h" - -enum { - RUN_TYPE_U, - RUN_TYPE_L, - RUN_TYPE_UF, - RUN_TYPE_LF, - RUN_TYPE_UL, - RUN_TYPE_LSU, - RUN_TYPE_U2L_399_EXT2, - RUN_TYPE_UF_D20, - RUN_TYPE_UF_D1_EXT, - RUN_TYPE_U_EXT, - RUN_TYPE_LF_EXT, - RUN_TYPE_UF_EXT2, - RUN_TYPE_LF_EXT2, - RUN_TYPE_UF_EXT3, -}; - -static int lre_case_conv1(uint32_t c, int conv_type) -{ - uint32_t res[LRE_CC_RES_LEN_MAX]; - lre_case_conv(res, c, conv_type); - return res[0]; -} - -/* case conversion using the table entry 'idx' with value 'v' */ -static int lre_case_conv_entry(uint32_t *res, uint32_t c, int conv_type, uint32_t idx, uint32_t v) -{ - uint32_t code, data, type, a, is_lower; - is_lower = (conv_type != 0); - type = (v >> (32 - 17 - 7 - 4)) & 0xf; - data = ((v & 0xf) << 8) | case_conv_table2[idx]; - code = v >> (32 - 17); - switch(type) { - case RUN_TYPE_U: - case RUN_TYPE_L: - case RUN_TYPE_UF: - case RUN_TYPE_LF: - if (conv_type == (type & 1) || - (type >= RUN_TYPE_UF && conv_type == 2)) { - c = c - code + (case_conv_table1[data] >> (32 - 17)); - } - break; - case RUN_TYPE_UL: - a = c - code; - if ((a & 1) != (1 - is_lower)) - break; - c = (a ^ 1) + code; - break; - case RUN_TYPE_LSU: - a = c - code; - if (a == 1) { - c += 2 * is_lower - 1; - } else if (a == (1 - is_lower) * 2) { - c += (2 * is_lower - 1) * 2; - } - break; - case RUN_TYPE_U2L_399_EXT2: - if (!is_lower) { - res[0] = c - code + case_conv_ext[data >> 6]; - res[1] = 0x399; - return 2; - } else { - c = c - code + case_conv_ext[data & 0x3f]; - } - break; - case RUN_TYPE_UF_D20: - if (conv_type == 1) - break; - c = data + (conv_type == 2) * 0x20; - break; - case RUN_TYPE_UF_D1_EXT: - if (conv_type == 1) - break; - c = case_conv_ext[data] + (conv_type == 2); - break; - case RUN_TYPE_U_EXT: - case RUN_TYPE_LF_EXT: - if (is_lower != (type - RUN_TYPE_U_EXT)) - break; - c = case_conv_ext[data]; - break; - case RUN_TYPE_LF_EXT2: - if (!is_lower) - break; - res[0] = c - code + case_conv_ext[data >> 6]; - res[1] = case_conv_ext[data & 0x3f]; - return 2; - case RUN_TYPE_UF_EXT2: - if (conv_type == 1) - break; - res[0] = c - code + case_conv_ext[data >> 6]; - res[1] = case_conv_ext[data & 0x3f]; - if (conv_type == 2) { - /* convert to lower */ - res[0] = lre_case_conv1(res[0], 1); - res[1] = lre_case_conv1(res[1], 1); - } - return 2; - default: - case RUN_TYPE_UF_EXT3: - if (conv_type == 1) - break; - res[0] = case_conv_ext[data >> 8]; - res[1] = case_conv_ext[(data >> 4) & 0xf]; - res[2] = case_conv_ext[data & 0xf]; - if (conv_type == 2) { - /* convert to lower */ - res[0] = lre_case_conv1(res[0], 1); - res[1] = lre_case_conv1(res[1], 1); - res[2] = lre_case_conv1(res[2], 1); - } - return 3; - } - res[0] = c; - return 1; -} - -/* conv_type: - 0 = to upper - 1 = to lower - 2 = case folding (= to lower with modifications) -*/ -int lre_case_conv(uint32_t *res, uint32_t c, int conv_type) -{ - if (c < 128) { - if (conv_type) { - if (c >= 'A' && c <= 'Z') { - c = c - 'A' + 'a'; - } - } else { - if (c >= 'a' && c <= 'z') { - c = c - 'a' + 'A'; - } - } - } else { - uint32_t v, code, len; - int idx, idx_min, idx_max; - - idx_min = 0; - idx_max = countof(case_conv_table1) - 1; - while (idx_min <= idx_max) { - idx = (unsigned)(idx_max + idx_min) / 2; - v = case_conv_table1[idx]; - code = v >> (32 - 17); - len = (v >> (32 - 17 - 7)) & 0x7f; - if (c < code) { - idx_max = idx - 1; - } else if (c >= code + len) { - idx_min = idx + 1; - } else { - return lre_case_conv_entry(res, c, conv_type, idx, v); - } - } - } - res[0] = c; - return 1; -} - -static int lre_case_folding_entry(uint32_t c, uint32_t idx, uint32_t v, BOOL is_unicode) -{ - uint32_t res[LRE_CC_RES_LEN_MAX]; - int len; - - if (is_unicode) { - len = lre_case_conv_entry(res, c, 2, idx, v); - if (len == 1) { - c = res[0]; - } else { - /* handle the few specific multi-character cases (see - unicode_gen.c:dump_case_folding_special_cases()) */ - if (c == 0xfb06) { - c = 0xfb05; - } else if (c == 0x01fd3) { - c = 0x390; - } else if (c == 0x01fe3) { - c = 0x3b0; - } - } - } else { - if (likely(c < 128)) { - if (c >= 'a' && c <= 'z') - c = c - 'a' + 'A'; - } else { - /* legacy regexp: to upper case if single char >= 128 */ - len = lre_case_conv_entry(res, c, FALSE, idx, v); - if (len == 1 && res[0] >= 128) - c = res[0]; - } - } - return c; -} - -/* JS regexp specific rules for case folding */ -int lre_canonicalize(uint32_t c, BOOL is_unicode) -{ - if (c < 128) { - /* fast case */ - if (is_unicode) { - if (c >= 'A' && c <= 'Z') { - c = c - 'A' + 'a'; - } - } else { - if (c >= 'a' && c <= 'z') { - c = c - 'a' + 'A'; - } - } - } else { - uint32_t v, code, len; - int idx, idx_min, idx_max; - - idx_min = 0; - idx_max = countof(case_conv_table1) - 1; - while (idx_min <= idx_max) { - idx = (unsigned)(idx_max + idx_min) / 2; - v = case_conv_table1[idx]; - code = v >> (32 - 17); - len = (v >> (32 - 17 - 7)) & 0x7f; - if (c < code) { - idx_max = idx - 1; - } else if (c >= code + len) { - idx_min = idx + 1; - } else { - return lre_case_folding_entry(c, idx, v, is_unicode); - } - } - } - return c; -} - -static uint32_t get_le24(const uint8_t *ptr) -{ - return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16); -} - -#define UNICODE_INDEX_BLOCK_LEN 32 - -/* return -1 if not in table, otherwise the offset in the block */ -static int get_index_pos(uint32_t *pcode, uint32_t c, - const uint8_t *index_table, int index_table_len) -{ - uint32_t code, v; - int idx_min, idx_max, idx; - - idx_min = 0; - v = get_le24(index_table); - code = v & ((1 << 21) - 1); - if (c < code) { - *pcode = 0; - return 0; - } - idx_max = index_table_len - 1; - code = get_le24(index_table + idx_max * 3); - if (c >= code) - return -1; - /* invariant: tab[idx_min] <= c < tab2[idx_max] */ - while ((idx_max - idx_min) > 1) { - idx = (idx_max + idx_min) / 2; - v = get_le24(index_table + idx * 3); - code = v & ((1 << 21) - 1); - if (c < code) { - idx_max = idx; - } else { - idx_min = idx; - } - } - v = get_le24(index_table + idx_min * 3); - *pcode = v & ((1 << 21) - 1); - return (idx_min + 1) * UNICODE_INDEX_BLOCK_LEN + (v >> 21); -} - -static BOOL lre_is_in_table(uint32_t c, const uint8_t *table, - const uint8_t *index_table, int index_table_len) -{ - uint32_t code, b, bit; - int pos; - const uint8_t *p; - - pos = get_index_pos(&code, c, index_table, index_table_len); - if (pos < 0) - return FALSE; /* outside the table */ - p = table + pos; - bit = 0; - /* Compressed run length encoding: - 00..3F: 2 packed lengths: 3-bit + 3-bit - 40..5F: 5-bits plus extra byte for length - 60..7F: 5-bits plus 2 extra bytes for length - 80..FF: 7-bit length - lengths must be incremented to get character count - Ranges alternate between false and true return value. - */ - for(;;) { - b = *p++; - if (b < 64) { - code += (b >> 3) + 1; - if (c < code) - return bit; - bit ^= 1; - code += (b & 7) + 1; - } else if (b >= 0x80) { - code += b - 0x80 + 1; - } else if (b < 0x60) { - code += (((b - 0x40) << 8) | p[0]) + 1; - p++; - } else { - code += (((b - 0x60) << 16) | (p[0] << 8) | p[1]) + 1; - p += 2; - } - if (c < code) - return bit; - bit ^= 1; - } -} - -BOOL lre_is_cased(uint32_t c) -{ - uint32_t v, code, len; - int idx, idx_min, idx_max; - - idx_min = 0; - idx_max = countof(case_conv_table1) - 1; - while (idx_min <= idx_max) { - idx = (unsigned)(idx_max + idx_min) / 2; - v = case_conv_table1[idx]; - code = v >> (32 - 17); - len = (v >> (32 - 17 - 7)) & 0x7f; - if (c < code) { - idx_max = idx - 1; - } else if (c >= code + len) { - idx_min = idx + 1; - } else { - return TRUE; - } - } - return lre_is_in_table(c, unicode_prop_Cased1_table, - unicode_prop_Cased1_index, - sizeof(unicode_prop_Cased1_index) / 3); -} - -BOOL lre_is_case_ignorable(uint32_t c) -{ - return lre_is_in_table(c, unicode_prop_Case_Ignorable_table, - unicode_prop_Case_Ignorable_index, - sizeof(unicode_prop_Case_Ignorable_index) / 3); -} - -/* character range */ - -static __maybe_unused void cr_dump(CharRange *cr) -{ - int i; - for(i = 0; i < cr->len; i++) - printf("%d: 0x%04x\n", i, cr->points[i]); -} - -static void *cr_default_realloc(void *opaque, void *ptr, size_t size) -{ - return realloc(ptr, size); -} - -void cr_init(CharRange *cr, void *mem_opaque, DynBufReallocFunc *realloc_func) -{ - cr->len = cr->size = 0; - cr->points = NULL; - cr->mem_opaque = mem_opaque; - cr->realloc_func = realloc_func ? realloc_func : cr_default_realloc; -} - -void cr_free(CharRange *cr) -{ - cr->realloc_func(cr->mem_opaque, cr->points, 0); -} - -int cr_realloc(CharRange *cr, int size) -{ - int new_size; - uint32_t *new_buf; - - if (size > cr->size) { - new_size = max_int(size, cr->size * 3 / 2); - new_buf = cr->realloc_func(cr->mem_opaque, cr->points, - new_size * sizeof(cr->points[0])); - if (!new_buf) - return -1; - cr->points = new_buf; - cr->size = new_size; - } - return 0; -} - -int cr_copy(CharRange *cr, const CharRange *cr1) -{ - if (cr_realloc(cr, cr1->len)) - return -1; - memcpy(cr->points, cr1->points, sizeof(cr->points[0]) * cr1->len); - cr->len = cr1->len; - return 0; -} - -/* merge consecutive intervals and remove empty intervals */ -static void cr_compress(CharRange *cr) -{ - int i, j, k, len; - uint32_t *pt; - - pt = cr->points; - len = cr->len; - i = 0; - j = 0; - k = 0; - while ((i + 1) < len) { - if (pt[i] == pt[i + 1]) { - /* empty interval */ - i += 2; - } else { - j = i; - while ((j + 3) < len && pt[j + 1] == pt[j + 2]) - j += 2; - /* just copy */ - pt[k] = pt[i]; - pt[k + 1] = pt[j + 1]; - k += 2; - i = j + 2; - } - } - cr->len = k; -} - -/* union or intersection */ -int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len, - const uint32_t *b_pt, int b_len, int op) -{ - int a_idx, b_idx, is_in; - uint32_t v; - - a_idx = 0; - b_idx = 0; - for(;;) { - /* get one more point from a or b in increasing order */ - if (a_idx < a_len && b_idx < b_len) { - if (a_pt[a_idx] < b_pt[b_idx]) { - goto a_add; - } else if (a_pt[a_idx] == b_pt[b_idx]) { - v = a_pt[a_idx]; - a_idx++; - b_idx++; - } else { - goto b_add; - } - } else if (a_idx < a_len) { - a_add: - v = a_pt[a_idx++]; - } else if (b_idx < b_len) { - b_add: - v = b_pt[b_idx++]; - } else { - break; - } - /* add the point if the in/out status changes */ - switch(op) { - case CR_OP_UNION: - is_in = (a_idx & 1) | (b_idx & 1); - break; - case CR_OP_INTER: - is_in = (a_idx & 1) & (b_idx & 1); - break; - case CR_OP_XOR: - is_in = (a_idx & 1) ^ (b_idx & 1); - break; - case CR_OP_SUB: - is_in = (a_idx & 1) & ((b_idx & 1) ^ 1); - break; - default: - abort(); - } - if (is_in != (cr->len & 1)) { - if (cr_add_point(cr, v)) - return -1; - } - } - cr_compress(cr); - return 0; -} - -int cr_op1(CharRange *cr, const uint32_t *b_pt, int b_len, int op) -{ - CharRange a = *cr; - int ret; - cr->len = 0; - cr->size = 0; - cr->points = NULL; - ret = cr_op(cr, a.points, a.len, b_pt, b_len, op); - cr_free(&a); - return ret; -} - -int cr_invert(CharRange *cr) -{ - int len; - len = cr->len; - if (cr_realloc(cr, len + 2)) - return -1; - memmove(cr->points + 1, cr->points, len * sizeof(cr->points[0])); - cr->points[0] = 0; - cr->points[len + 1] = UINT32_MAX; - cr->len = len + 2; - cr_compress(cr); - return 0; -} - -#define CASE_U (1 << 0) -#define CASE_L (1 << 1) -#define CASE_F (1 << 2) - -/* use the case conversion table to generate range of characters. - CASE_U: set char if modified by uppercasing, - CASE_L: set char if modified by lowercasing, - CASE_F: set char if modified by case folding, - */ -static int unicode_case1(CharRange *cr, int case_mask) -{ -#define MR(x) (1 << RUN_TYPE_ ## x) - const uint32_t tab_run_mask[3] = { - MR(U) | MR(UF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(UF_D20) | - MR(UF_D1_EXT) | MR(U_EXT) | MR(UF_EXT2) | MR(UF_EXT3), - - MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2), - - MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT) | MR(UF_EXT2) | MR(UF_EXT3), - }; -#undef MR - uint32_t mask, v, code, type, len, i, idx; - - if (case_mask == 0) - return 0; - mask = 0; - for(i = 0; i < 3; i++) { - if ((case_mask >> i) & 1) - mask |= tab_run_mask[i]; - } - for(idx = 0; idx < countof(case_conv_table1); idx++) { - v = case_conv_table1[idx]; - type = (v >> (32 - 17 - 7 - 4)) & 0xf; - code = v >> (32 - 17); - len = (v >> (32 - 17 - 7)) & 0x7f; - if ((mask >> type) & 1) { - // printf("%d: type=%d %04x %04x\n", idx, type, code, code + len - 1); - switch(type) { - case RUN_TYPE_UL: - if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F))) - goto def_case; - code += ((case_mask & CASE_U) != 0); - for(i = 0; i < len; i += 2) { - if (cr_add_interval(cr, code + i, code + i + 1)) - return -1; - } - break; - case RUN_TYPE_LSU: - if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F))) - goto def_case; - if (!(case_mask & CASE_U)) { - if (cr_add_interval(cr, code, code + 1)) - return -1; - } - if (cr_add_interval(cr, code + 1, code + 2)) - return -1; - if (case_mask & CASE_U) { - if (cr_add_interval(cr, code + 2, code + 3)) - return -1; - } - break; - default: - def_case: - if (cr_add_interval(cr, code, code + len)) - return -1; - break; - } - } - } - return 0; -} - -static int point_cmp(const void *p1, const void *p2, void *arg) -{ - uint32_t v1 = *(uint32_t *)p1; - uint32_t v2 = *(uint32_t *)p2; - return (v1 > v2) - (v1 < v2); -} - -static void cr_sort_and_remove_overlap(CharRange *cr) -{ - uint32_t start, end, start1, end1, i, j; - - /* the resulting ranges are not necessarily sorted and may overlap */ - rqsort(cr->points, cr->len / 2, sizeof(cr->points[0]) * 2, point_cmp, NULL); - j = 0; - for(i = 0; i < cr->len; ) { - start = cr->points[i]; - end = cr->points[i + 1]; - i += 2; - while (i < cr->len) { - start1 = cr->points[i]; - end1 = cr->points[i + 1]; - if (start1 > end) { - /* |------| - * |-------| */ - break; - } else if (end1 <= end) { - /* |------| - * |--| */ - i += 2; - } else { - /* |------| - * |-------| */ - end = end1; - i += 2; - } - } - cr->points[j] = start; - cr->points[j + 1] = end; - j += 2; - } - cr->len = j; -} - -/* canonicalize a character set using the JS regex case folding rules - (see lre_canonicalize()) */ -int cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode) -{ - CharRange cr_inter, cr_mask, cr_result, cr_sub; - uint32_t v, code, len, i, idx, start, end, c, d_start, d_end, d; - - cr_init(&cr_mask, cr->mem_opaque, cr->realloc_func); - cr_init(&cr_inter, cr->mem_opaque, cr->realloc_func); - cr_init(&cr_result, cr->mem_opaque, cr->realloc_func); - cr_init(&cr_sub, cr->mem_opaque, cr->realloc_func); - - if (unicode_case1(&cr_mask, is_unicode ? CASE_F : CASE_U)) - goto fail; - if (cr_op(&cr_inter, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER)) - goto fail; - - if (cr_invert(&cr_mask)) - goto fail; - if (cr_op(&cr_sub, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER)) - goto fail; - - /* cr_inter = cr & cr_mask */ - /* cr_sub = cr & ~cr_mask */ - - /* use the case conversion table to compute the result */ - d_start = -1; - d_end = -1; - idx = 0; - v = case_conv_table1[idx]; - code = v >> (32 - 17); - len = (v >> (32 - 17 - 7)) & 0x7f; - for(i = 0; i < cr_inter.len; i += 2) { - start = cr_inter.points[i]; - end = cr_inter.points[i + 1]; - - for(c = start; c < end; c++) { - for(;;) { - if (c >= code && c < code + len) - break; - idx++; - assert(idx < countof(case_conv_table1)); - v = case_conv_table1[idx]; - code = v >> (32 - 17); - len = (v >> (32 - 17 - 7)) & 0x7f; - } - d = lre_case_folding_entry(c, idx, v, is_unicode); - /* try to merge with the current interval */ - if (d_start == -1) { - d_start = d; - d_end = d + 1; - } else if (d_end == d) { - d_end++; - } else { - cr_add_interval(&cr_result, d_start, d_end); - d_start = d; - d_end = d + 1; - } - } - } - if (d_start != -1) { - if (cr_add_interval(&cr_result, d_start, d_end)) - goto fail; - } - - /* the resulting ranges are not necessarily sorted and may overlap */ - cr_sort_and_remove_overlap(&cr_result); - - /* or with the character not affected by the case folding */ - cr->len = 0; - if (cr_op(cr, cr_result.points, cr_result.len, cr_sub.points, cr_sub.len, CR_OP_UNION)) - goto fail; - - cr_free(&cr_inter); - cr_free(&cr_mask); - cr_free(&cr_result); - cr_free(&cr_sub); - return 0; - fail: - cr_free(&cr_inter); - cr_free(&cr_mask); - cr_free(&cr_result); - cr_free(&cr_sub); - return -1; -} - -#ifdef CONFIG_ALL_UNICODE - -BOOL lre_is_id_start(uint32_t c) -{ - return lre_is_in_table(c, unicode_prop_ID_Start_table, - unicode_prop_ID_Start_index, - sizeof(unicode_prop_ID_Start_index) / 3); -} - -BOOL lre_is_id_continue(uint32_t c) -{ - return lre_is_id_start(c) || - lre_is_in_table(c, unicode_prop_ID_Continue1_table, - unicode_prop_ID_Continue1_index, - sizeof(unicode_prop_ID_Continue1_index) / 3); -} - -#define UNICODE_DECOMP_LEN_MAX 18 - -typedef enum { - DECOMP_TYPE_C1, /* 16 bit char */ - DECOMP_TYPE_L1, /* 16 bit char table */ - DECOMP_TYPE_L2, - DECOMP_TYPE_L3, - DECOMP_TYPE_L4, - DECOMP_TYPE_L5, /* XXX: not used */ - DECOMP_TYPE_L6, /* XXX: could remove */ - DECOMP_TYPE_L7, /* XXX: could remove */ - DECOMP_TYPE_LL1, /* 18 bit char table */ - DECOMP_TYPE_LL2, - DECOMP_TYPE_S1, /* 8 bit char table */ - DECOMP_TYPE_S2, - DECOMP_TYPE_S3, - DECOMP_TYPE_S4, - DECOMP_TYPE_S5, - DECOMP_TYPE_I1, /* increment 16 bit char value */ - DECOMP_TYPE_I2_0, - DECOMP_TYPE_I2_1, - DECOMP_TYPE_I3_1, - DECOMP_TYPE_I3_2, - DECOMP_TYPE_I4_1, - DECOMP_TYPE_I4_2, - DECOMP_TYPE_B1, /* 16 bit base + 8 bit offset */ - DECOMP_TYPE_B2, - DECOMP_TYPE_B3, - DECOMP_TYPE_B4, - DECOMP_TYPE_B5, - DECOMP_TYPE_B6, - DECOMP_TYPE_B7, - DECOMP_TYPE_B8, - DECOMP_TYPE_B18, - DECOMP_TYPE_LS2, - DECOMP_TYPE_PAT3, - DECOMP_TYPE_S2_UL, - DECOMP_TYPE_LS2_UL, -} DecompTypeEnum; - -static uint32_t unicode_get_short_code(uint32_t c) -{ - static const uint16_t unicode_short_table[2] = { 0x2044, 0x2215 }; - - if (c < 0x80) - return c; - else if (c < 0x80 + 0x50) - return c - 0x80 + 0x300; - else - return unicode_short_table[c - 0x80 - 0x50]; -} - -static uint32_t unicode_get_lower_simple(uint32_t c) -{ - if (c < 0x100 || (c >= 0x410 && c <= 0x42f)) - c += 0x20; - else - c++; - return c; -} - -static uint16_t unicode_get16(const uint8_t *p) -{ - return p[0] | (p[1] << 8); -} - -static int unicode_decomp_entry(uint32_t *res, uint32_t c, - int idx, uint32_t code, uint32_t len, - uint32_t type) -{ - uint32_t c1; - int l, i, p; - const uint8_t *d; - - if (type == DECOMP_TYPE_C1) { - res[0] = unicode_decomp_table2[idx]; - return 1; - } else { - d = unicode_decomp_data + unicode_decomp_table2[idx]; - switch(type) { - case DECOMP_TYPE_L1: - case DECOMP_TYPE_L2: - case DECOMP_TYPE_L3: - case DECOMP_TYPE_L4: - case DECOMP_TYPE_L5: - case DECOMP_TYPE_L6: - case DECOMP_TYPE_L7: - l = type - DECOMP_TYPE_L1 + 1; - d += (c - code) * l * 2; - for(i = 0; i < l; i++) { - if ((res[i] = unicode_get16(d + 2 * i)) == 0) - return 0; - } - return l; - case DECOMP_TYPE_LL1: - case DECOMP_TYPE_LL2: - { - uint32_t k, p; - l = type - DECOMP_TYPE_LL1 + 1; - k = (c - code) * l; - p = len * l * 2; - for(i = 0; i < l; i++) { - c1 = unicode_get16(d + 2 * k) | - (((d[p + (k / 4)] >> ((k % 4) * 2)) & 3) << 16); - if (!c1) - return 0; - res[i] = c1; - k++; - } - } - return l; - case DECOMP_TYPE_S1: - case DECOMP_TYPE_S2: - case DECOMP_TYPE_S3: - case DECOMP_TYPE_S4: - case DECOMP_TYPE_S5: - l = type - DECOMP_TYPE_S1 + 1; - d += (c - code) * l; - for(i = 0; i < l; i++) { - if ((res[i] = unicode_get_short_code(d[i])) == 0) - return 0; - } - return l; - case DECOMP_TYPE_I1: - l = 1; - p = 0; - goto decomp_type_i; - case DECOMP_TYPE_I2_0: - case DECOMP_TYPE_I2_1: - case DECOMP_TYPE_I3_1: - case DECOMP_TYPE_I3_2: - case DECOMP_TYPE_I4_1: - case DECOMP_TYPE_I4_2: - l = 2 + ((type - DECOMP_TYPE_I2_0) >> 1); - p = ((type - DECOMP_TYPE_I2_0) & 1) + (l > 2); - decomp_type_i: - for(i = 0; i < l; i++) { - c1 = unicode_get16(d + 2 * i); - if (i == p) - c1 += c - code; - res[i] = c1; - } - return l; - case DECOMP_TYPE_B18: - l = 18; - goto decomp_type_b; - case DECOMP_TYPE_B1: - case DECOMP_TYPE_B2: - case DECOMP_TYPE_B3: - case DECOMP_TYPE_B4: - case DECOMP_TYPE_B5: - case DECOMP_TYPE_B6: - case DECOMP_TYPE_B7: - case DECOMP_TYPE_B8: - l = type - DECOMP_TYPE_B1 + 1; - decomp_type_b: - { - uint32_t c_min; - c_min = unicode_get16(d); - d += 2 + (c - code) * l; - for(i = 0; i < l; i++) { - c1 = d[i]; - if (c1 == 0xff) - c1 = 0x20; - else - c1 += c_min; - res[i] = c1; - } - } - return l; - case DECOMP_TYPE_LS2: - d += (c - code) * 3; - if (!(res[0] = unicode_get16(d))) - return 0; - res[1] = unicode_get_short_code(d[2]); - return 2; - case DECOMP_TYPE_PAT3: - res[0] = unicode_get16(d); - res[2] = unicode_get16(d + 2); - d += 4 + (c - code) * 2; - res[1] = unicode_get16(d); - return 3; - case DECOMP_TYPE_S2_UL: - case DECOMP_TYPE_LS2_UL: - c1 = c - code; - if (type == DECOMP_TYPE_S2_UL) { - d += c1 & ~1; - c = unicode_get_short_code(*d); - d++; - } else { - d += (c1 >> 1) * 3; - c = unicode_get16(d); - d += 2; - } - if (c1 & 1) - c = unicode_get_lower_simple(c); - res[0] = c; - res[1] = unicode_get_short_code(*d); - return 2; - } - } - return 0; -} - - -/* return the length of the decomposition (length <= - UNICODE_DECOMP_LEN_MAX) or 0 if no decomposition */ -static int unicode_decomp_char(uint32_t *res, uint32_t c, BOOL is_compat1) -{ - uint32_t v, type, is_compat, code, len; - int idx_min, idx_max, idx; - - idx_min = 0; - idx_max = countof(unicode_decomp_table1) - 1; - while (idx_min <= idx_max) { - idx = (idx_max + idx_min) / 2; - v = unicode_decomp_table1[idx]; - code = v >> (32 - 18); - len = (v >> (32 - 18 - 7)) & 0x7f; - // printf("idx=%d code=%05x len=%d\n", idx, code, len); - if (c < code) { - idx_max = idx - 1; - } else if (c >= code + len) { - idx_min = idx + 1; - } else { - is_compat = v & 1; - if (is_compat1 < is_compat) - break; - type = (v >> (32 - 18 - 7 - 6)) & 0x3f; - return unicode_decomp_entry(res, c, idx, code, len, type); - } - } - return 0; -} - -/* return 0 if no pair found */ -static int unicode_compose_pair(uint32_t c0, uint32_t c1) -{ - uint32_t code, len, type, v, idx1, d_idx, d_offset, ch; - int idx_min, idx_max, idx, d; - uint32_t pair[2]; - - idx_min = 0; - idx_max = countof(unicode_comp_table) - 1; - while (idx_min <= idx_max) { - idx = (idx_max + idx_min) / 2; - idx1 = unicode_comp_table[idx]; - - /* idx1 represent an entry of the decomposition table */ - d_idx = idx1 >> 6; - d_offset = idx1 & 0x3f; - v = unicode_decomp_table1[d_idx]; - code = v >> (32 - 18); - len = (v >> (32 - 18 - 7)) & 0x7f; - type = (v >> (32 - 18 - 7 - 6)) & 0x3f; - ch = code + d_offset; - unicode_decomp_entry(pair, ch, d_idx, code, len, type); - d = c0 - pair[0]; - if (d == 0) - d = c1 - pair[1]; - if (d < 0) { - idx_max = idx - 1; - } else if (d > 0) { - idx_min = idx + 1; - } else { - return ch; - } - } - return 0; -} - -/* return the combining class of character c (between 0 and 255) */ -static int unicode_get_cc(uint32_t c) -{ - uint32_t code, n, type, cc, c1, b; - int pos; - const uint8_t *p; - - pos = get_index_pos(&code, c, - unicode_cc_index, sizeof(unicode_cc_index) / 3); - if (pos < 0) - return 0; - p = unicode_cc_table + pos; - /* Compressed run length encoding: - - 2 high order bits are combining class type - - 0:0, 1:230, 2:extra byte linear progression, 3:extra byte - - 00..2F: range length (add 1) - - 30..37: 3-bit range-length + 1 extra byte - - 38..3F: 3-bit range-length + 2 extra byte - */ - for(;;) { - b = *p++; - type = b >> 6; - n = b & 0x3f; - if (n < 48) { - } else if (n < 56) { - n = (n - 48) << 8; - n |= *p++; - n += 48; - } else { - n = (n - 56) << 8; - n |= *p++ << 8; - n |= *p++; - n += 48 + (1 << 11); - } - if (type <= 1) - p++; - c1 = code + n + 1; - if (c < c1) { - switch(type) { - case 0: - cc = p[-1]; - break; - case 1: - cc = p[-1] + c - code; - break; - case 2: - cc = 0; - break; - default: - case 3: - cc = 230; - break; - } - return cc; - } - code = c1; - } -} - -static void sort_cc(int *buf, int len) -{ - int i, j, k, cc, cc1, start, ch1; - - for(i = 0; i < len; i++) { - cc = unicode_get_cc(buf[i]); - if (cc != 0) { - start = i; - j = i + 1; - while (j < len) { - ch1 = buf[j]; - cc1 = unicode_get_cc(ch1); - if (cc1 == 0) - break; - k = j - 1; - while (k >= start) { - if (unicode_get_cc(buf[k]) <= cc1) - break; - buf[k + 1] = buf[k]; - k--; - } - buf[k + 1] = ch1; - j++; - } -#if 0 - printf("cc:"); - for(k = start; k < j; k++) { - printf(" %3d", unicode_get_cc(buf[k])); - } - printf("\n"); -#endif - i = j; - } - } -} - -static void to_nfd_rec(DynBuf *dbuf, - const int *src, int src_len, int is_compat) -{ - uint32_t c, v; - int i, l; - uint32_t res[UNICODE_DECOMP_LEN_MAX]; - - for(i = 0; i < src_len; i++) { - c = src[i]; - if (c >= 0xac00 && c < 0xd7a4) { - /* Hangul decomposition */ - c -= 0xac00; - dbuf_put_u32(dbuf, 0x1100 + c / 588); - dbuf_put_u32(dbuf, 0x1161 + (c % 588) / 28); - v = c % 28; - if (v != 0) - dbuf_put_u32(dbuf, 0x11a7 + v); - } else { - l = unicode_decomp_char(res, c, is_compat); - if (l) { - to_nfd_rec(dbuf, (int *)res, l, is_compat); - } else { - dbuf_put_u32(dbuf, c); - } - } - } -} - -/* return 0 if not found */ -static int compose_pair(uint32_t c0, uint32_t c1) -{ - /* Hangul composition */ - if (c0 >= 0x1100 && c0 < 0x1100 + 19 && - c1 >= 0x1161 && c1 < 0x1161 + 21) { - return 0xac00 + (c0 - 0x1100) * 588 + (c1 - 0x1161) * 28; - } else if (c0 >= 0xac00 && c0 < 0xac00 + 11172 && - (c0 - 0xac00) % 28 == 0 && - c1 >= 0x11a7 && c1 < 0x11a7 + 28) { - return c0 + c1 - 0x11a7; - } else { - return unicode_compose_pair(c0, c1); - } -} - -int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len, - UnicodeNormalizationEnum n_type, - void *opaque, DynBufReallocFunc *realloc_func) -{ - int *buf, buf_len, i, p, starter_pos, cc, last_cc, out_len; - BOOL is_compat; - DynBuf dbuf_s, *dbuf = &dbuf_s; - - is_compat = n_type >> 1; - - dbuf_init2(dbuf, opaque, realloc_func); - if (dbuf_realloc(dbuf, sizeof(int) * src_len)) - goto fail; - - /* common case: latin1 is unaffected by NFC */ - if (n_type == UNICODE_NFC) { - for(i = 0; i < src_len; i++) { - if (src[i] >= 0x100) - goto not_latin1; - } - buf = (int *)dbuf->buf; - memcpy(buf, src, src_len * sizeof(int)); - *pdst = (uint32_t *)buf; - return src_len; - not_latin1: ; - } - - to_nfd_rec(dbuf, (const int *)src, src_len, is_compat); - if (dbuf_error(dbuf)) { - fail: - *pdst = NULL; - return -1; - } - buf = (int *)dbuf->buf; - buf_len = dbuf->size / sizeof(int); - - sort_cc(buf, buf_len); - - if (buf_len <= 1 || (n_type & 1) != 0) { - /* NFD / NFKD */ - *pdst = (uint32_t *)buf; - return buf_len; - } - - i = 1; - out_len = 1; - while (i < buf_len) { - /* find the starter character and test if it is blocked from - the character at 'i' */ - last_cc = unicode_get_cc(buf[i]); - starter_pos = out_len - 1; - while (starter_pos >= 0) { - cc = unicode_get_cc(buf[starter_pos]); - if (cc == 0) - break; - if (cc >= last_cc) - goto next; - last_cc = 256; - starter_pos--; - } - if (starter_pos >= 0 && - (p = compose_pair(buf[starter_pos], buf[i])) != 0) { - buf[starter_pos] = p; - i++; - } else { - next: - buf[out_len++] = buf[i++]; - } - } - *pdst = (uint32_t *)buf; - return out_len; -} - -/* char ranges for various unicode properties */ - -static int unicode_find_name(const char *name_table, const char *name) -{ - const char *p, *r; - int pos; - size_t name_len, len; - - p = name_table; - pos = 0; - name_len = strlen(name); - while (*p) { - for(;;) { - r = strchr(p, ','); - if (!r) - len = strlen(p); - else - len = r - p; - if (len == name_len && !memcmp(p, name, name_len)) - return pos; - p += len + 1; - if (!r) - break; - } - pos++; - } - return -1; -} - -/* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2 - if not found */ -int unicode_script(CharRange *cr, - const char *script_name, BOOL is_ext) -{ - int script_idx; - const uint8_t *p, *p_end; - uint32_t c, c1, b, n, v, v_len, i, type; - CharRange cr1_s, *cr1; - CharRange cr2_s, *cr2 = &cr2_s; - BOOL is_common; - - script_idx = unicode_find_name(unicode_script_name_table, script_name); - if (script_idx < 0) - return -2; - - is_common = (script_idx == UNICODE_SCRIPT_Common || - script_idx == UNICODE_SCRIPT_Inherited); - if (is_ext) { - cr1 = &cr1_s; - cr_init(cr1, cr->mem_opaque, cr->realloc_func); - cr_init(cr2, cr->mem_opaque, cr->realloc_func); - } else { - cr1 = cr; - } - - p = unicode_script_table; - p_end = unicode_script_table + countof(unicode_script_table); - c = 0; - while (p < p_end) { - b = *p++; - type = b >> 7; - n = b & 0x7f; - if (n < 96) { - } else if (n < 112) { - n = (n - 96) << 8; - n |= *p++; - n += 96; - } else { - n = (n - 112) << 16; - n |= *p++ << 8; - n |= *p++; - n += 96 + (1 << 12); - } - c1 = c + n + 1; - if (type != 0) { - v = *p++; - if (v == script_idx || script_idx == UNICODE_SCRIPT_Unknown) { - if (cr_add_interval(cr1, c, c1)) - goto fail; - } - } - c = c1; - } - if (script_idx == UNICODE_SCRIPT_Unknown) { - /* Unknown is all the characters outside scripts */ - if (cr_invert(cr1)) - goto fail; - } - - if (is_ext) { - /* add the script extensions */ - p = unicode_script_ext_table; - p_end = unicode_script_ext_table + countof(unicode_script_ext_table); - c = 0; - while (p < p_end) { - b = *p++; - if (b < 128) { - n = b; - } else if (b < 128 + 64) { - n = (b - 128) << 8; - n |= *p++; - n += 128; - } else { - n = (b - 128 - 64) << 16; - n |= *p++ << 8; - n |= *p++; - n += 128 + (1 << 14); - } - c1 = c + n + 1; - v_len = *p++; - if (is_common) { - if (v_len != 0) { - if (cr_add_interval(cr2, c, c1)) - goto fail; - } - } else { - for(i = 0; i < v_len; i++) { - if (p[i] == script_idx) { - if (cr_add_interval(cr2, c, c1)) - goto fail; - break; - } - } - } - p += v_len; - c = c1; - } - if (is_common) { - /* remove all the characters with script extensions */ - if (cr_invert(cr2)) - goto fail; - if (cr_op(cr, cr1->points, cr1->len, cr2->points, cr2->len, - CR_OP_INTER)) - goto fail; - } else { - if (cr_op(cr, cr1->points, cr1->len, cr2->points, cr2->len, - CR_OP_UNION)) - goto fail; - } - cr_free(cr1); - cr_free(cr2); - } - return 0; - fail: - if (is_ext) { - cr_free(cr1); - cr_free(cr2); - } - goto fail; -} - -#define M(id) (1U << UNICODE_GC_ ## id) - -static int unicode_general_category1(CharRange *cr, uint32_t gc_mask) -{ - const uint8_t *p, *p_end; - uint32_t c, c0, b, n, v; - - p = unicode_gc_table; - p_end = unicode_gc_table + countof(unicode_gc_table); - c = 0; - /* Compressed range encoding: - initial byte: - bits 0..4: category number (special case 31) - bits 5..7: range length (add 1) - special case bits 5..7 == 7: read an extra byte - - 00..7F: range length (add 7 + 1) - - 80..BF: 6-bits plus extra byte for range length (add 7 + 128) - - C0..FF: 6-bits plus 2 extra bytes for range length (add 7 + 128 + 16384) - */ - while (p < p_end) { - b = *p++; - n = b >> 5; - v = b & 0x1f; - if (n == 7) { - n = *p++; - if (n < 128) { - n += 7; - } else if (n < 128 + 64) { - n = (n - 128) << 8; - n |= *p++; - n += 7 + 128; - } else { - n = (n - 128 - 64) << 16; - n |= *p++ << 8; - n |= *p++; - n += 7 + 128 + (1 << 14); - } - } - c0 = c; - c += n + 1; - if (v == 31) { - /* run of Lu / Ll */ - b = gc_mask & (M(Lu) | M(Ll)); - if (b != 0) { - if (b == (M(Lu) | M(Ll))) { - goto add_range; - } else { - c0 += ((gc_mask & M(Ll)) != 0); - for(; c0 < c; c0 += 2) { - if (cr_add_interval(cr, c0, c0 + 1)) - return -1; - } - } - } - } else if ((gc_mask >> v) & 1) { - add_range: - if (cr_add_interval(cr, c0, c)) - return -1; - } - } - return 0; -} - -static int unicode_prop1(CharRange *cr, int prop_idx) -{ - const uint8_t *p, *p_end; - uint32_t c, c0, b, bit; - - p = unicode_prop_table[prop_idx]; - p_end = p + unicode_prop_len_table[prop_idx]; - c = 0; - bit = 0; - /* Compressed range encoding: - 00..3F: 2 packed lengths: 3-bit + 3-bit - 40..5F: 5-bits plus extra byte for length - 60..7F: 5-bits plus 2 extra bytes for length - 80..FF: 7-bit length - lengths must be incremented to get character count - Ranges alternate between false and true return value. - */ - while (p < p_end) { - c0 = c; - b = *p++; - if (b < 64) { - c += (b >> 3) + 1; - if (bit) { - if (cr_add_interval(cr, c0, c)) - return -1; - } - bit ^= 1; - c0 = c; - c += (b & 7) + 1; - } else if (b >= 0x80) { - c += b - 0x80 + 1; - } else if (b < 0x60) { - c += (((b - 0x40) << 8) | p[0]) + 1; - p++; - } else { - c += (((b - 0x60) << 16) | (p[0] << 8) | p[1]) + 1; - p += 2; - } - if (bit) { - if (cr_add_interval(cr, c0, c)) - return -1; - } - bit ^= 1; - } - return 0; -} - -typedef enum { - POP_GC, - POP_PROP, - POP_CASE, - POP_UNION, - POP_INTER, - POP_XOR, - POP_INVERT, - POP_END, -} PropOPEnum; - -#define POP_STACK_LEN_MAX 4 - -static int unicode_prop_ops(CharRange *cr, ...) -{ - va_list ap; - CharRange stack[POP_STACK_LEN_MAX]; - int stack_len, op, ret, i; - uint32_t a; - - va_start(ap, cr); - stack_len = 0; - for(;;) { - op = va_arg(ap, int); - switch(op) { - case POP_GC: - assert(stack_len < POP_STACK_LEN_MAX); - a = va_arg(ap, int); - cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func); - if (unicode_general_category1(&stack[stack_len - 1], a)) - goto fail; - break; - case POP_PROP: - assert(stack_len < POP_STACK_LEN_MAX); - a = va_arg(ap, int); - cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func); - if (unicode_prop1(&stack[stack_len - 1], a)) - goto fail; - break; - case POP_CASE: - assert(stack_len < POP_STACK_LEN_MAX); - a = va_arg(ap, int); - cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func); - if (unicode_case1(&stack[stack_len - 1], a)) - goto fail; - break; - case POP_UNION: - case POP_INTER: - case POP_XOR: - { - CharRange *cr1, *cr2, *cr3; - assert(stack_len >= 2); - assert(stack_len < POP_STACK_LEN_MAX); - cr1 = &stack[stack_len - 2]; - cr2 = &stack[stack_len - 1]; - cr3 = &stack[stack_len++]; - cr_init(cr3, cr->mem_opaque, cr->realloc_func); - /* CR_OP_XOR may be used here */ - if (cr_op(cr3, cr1->points, cr1->len, - cr2->points, cr2->len, op - POP_UNION + CR_OP_UNION)) - goto fail; - cr_free(cr1); - cr_free(cr2); - *cr1 = *cr3; - stack_len -= 2; - } - break; - case POP_INVERT: - assert(stack_len >= 1); - if (cr_invert(&stack[stack_len - 1])) - goto fail; - break; - case POP_END: - goto done; - default: - abort(); - } - } - done: - assert(stack_len == 1); - ret = cr_copy(cr, &stack[0]); - cr_free(&stack[0]); - return ret; - fail: - for(i = 0; i < stack_len; i++) - cr_free(&stack[i]); - return -1; -} - -static const uint32_t unicode_gc_mask_table[] = { - M(Lu) | M(Ll) | M(Lt), /* LC */ - M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo), /* L */ - M(Mn) | M(Mc) | M(Me), /* M */ - M(Nd) | M(Nl) | M(No), /* N */ - M(Sm) | M(Sc) | M(Sk) | M(So), /* S */ - M(Pc) | M(Pd) | M(Ps) | M(Pe) | M(Pi) | M(Pf) | M(Po), /* P */ - M(Zs) | M(Zl) | M(Zp), /* Z */ - M(Cc) | M(Cf) | M(Cs) | M(Co) | M(Cn), /* C */ -}; - -/* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2 - if not found */ -int unicode_general_category(CharRange *cr, const char *gc_name) -{ - int gc_idx; - uint32_t gc_mask; - - gc_idx = unicode_find_name(unicode_gc_name_table, gc_name); - if (gc_idx < 0) - return -2; - if (gc_idx <= UNICODE_GC_Co) { - gc_mask = (uint64_t)1 << gc_idx; - } else { - gc_mask = unicode_gc_mask_table[gc_idx - UNICODE_GC_LC]; - } - return unicode_general_category1(cr, gc_mask); -} - - -/* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2 - if not found */ -int unicode_prop(CharRange *cr, const char *prop_name) -{ - int prop_idx, ret; - - prop_idx = unicode_find_name(unicode_prop_name_table, prop_name); - if (prop_idx < 0) - return -2; - prop_idx += UNICODE_PROP_ASCII_Hex_Digit; - - ret = 0; - switch(prop_idx) { - case UNICODE_PROP_ASCII: - if (cr_add_interval(cr, 0x00, 0x7f + 1)) - return -1; - break; - case UNICODE_PROP_Any: - if (cr_add_interval(cr, 0x00000, 0x10ffff + 1)) - return -1; - break; - case UNICODE_PROP_Assigned: - ret = unicode_prop_ops(cr, - POP_GC, M(Cn), - POP_INVERT, - POP_END); - break; - case UNICODE_PROP_Math: - ret = unicode_prop_ops(cr, - POP_GC, M(Sm), - POP_PROP, UNICODE_PROP_Other_Math, - POP_UNION, - POP_END); - break; - case UNICODE_PROP_Lowercase: - ret = unicode_prop_ops(cr, - POP_GC, M(Ll), - POP_PROP, UNICODE_PROP_Other_Lowercase, - POP_UNION, - POP_END); - break; - case UNICODE_PROP_Uppercase: - ret = unicode_prop_ops(cr, - POP_GC, M(Lu), - POP_PROP, UNICODE_PROP_Other_Uppercase, - POP_UNION, - POP_END); - break; - case UNICODE_PROP_Cased: - ret = unicode_prop_ops(cr, - POP_GC, M(Lu) | M(Ll) | M(Lt), - POP_PROP, UNICODE_PROP_Other_Uppercase, - POP_UNION, - POP_PROP, UNICODE_PROP_Other_Lowercase, - POP_UNION, - POP_END); - break; - case UNICODE_PROP_Alphabetic: - ret = unicode_prop_ops(cr, - POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl), - POP_PROP, UNICODE_PROP_Other_Uppercase, - POP_UNION, - POP_PROP, UNICODE_PROP_Other_Lowercase, - POP_UNION, - POP_PROP, UNICODE_PROP_Other_Alphabetic, - POP_UNION, - POP_END); - break; - case UNICODE_PROP_Grapheme_Base: - ret = unicode_prop_ops(cr, - POP_GC, M(Cc) | M(Cf) | M(Cs) | M(Co) | M(Cn) | M(Zl) | M(Zp) | M(Me) | M(Mn), - POP_PROP, UNICODE_PROP_Other_Grapheme_Extend, - POP_UNION, - POP_INVERT, - POP_END); - break; - case UNICODE_PROP_Grapheme_Extend: - ret = unicode_prop_ops(cr, - POP_GC, M(Me) | M(Mn), - POP_PROP, UNICODE_PROP_Other_Grapheme_Extend, - POP_UNION, - POP_END); - break; - case UNICODE_PROP_XID_Start: - ret = unicode_prop_ops(cr, - POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl), - POP_PROP, UNICODE_PROP_Other_ID_Start, - POP_UNION, - POP_PROP, UNICODE_PROP_Pattern_Syntax, - POP_PROP, UNICODE_PROP_Pattern_White_Space, - POP_UNION, - POP_PROP, UNICODE_PROP_XID_Start1, - POP_UNION, - POP_INVERT, - POP_INTER, - POP_END); - break; - case UNICODE_PROP_XID_Continue: - ret = unicode_prop_ops(cr, - POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl) | - M(Mn) | M(Mc) | M(Nd) | M(Pc), - POP_PROP, UNICODE_PROP_Other_ID_Start, - POP_UNION, - POP_PROP, UNICODE_PROP_Other_ID_Continue, - POP_UNION, - POP_PROP, UNICODE_PROP_Pattern_Syntax, - POP_PROP, UNICODE_PROP_Pattern_White_Space, - POP_UNION, - POP_PROP, UNICODE_PROP_XID_Continue1, - POP_UNION, - POP_INVERT, - POP_INTER, - POP_END); - break; - case UNICODE_PROP_Changes_When_Uppercased: - ret = unicode_case1(cr, CASE_U); - break; - case UNICODE_PROP_Changes_When_Lowercased: - ret = unicode_case1(cr, CASE_L); - break; - case UNICODE_PROP_Changes_When_Casemapped: - ret = unicode_case1(cr, CASE_U | CASE_L | CASE_F); - break; - case UNICODE_PROP_Changes_When_Titlecased: - ret = unicode_prop_ops(cr, - POP_CASE, CASE_U, - POP_PROP, UNICODE_PROP_Changes_When_Titlecased1, - POP_XOR, - POP_END); - break; - case UNICODE_PROP_Changes_When_Casefolded: - ret = unicode_prop_ops(cr, - POP_CASE, CASE_F, - POP_PROP, UNICODE_PROP_Changes_When_Casefolded1, - POP_XOR, - POP_END); - break; - case UNICODE_PROP_Changes_When_NFKC_Casefolded: - ret = unicode_prop_ops(cr, - POP_CASE, CASE_F, - POP_PROP, UNICODE_PROP_Changes_When_NFKC_Casefolded1, - POP_XOR, - POP_END); - break; -#if 0 - case UNICODE_PROP_ID_Start: - ret = unicode_prop_ops(cr, - POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl), - POP_PROP, UNICODE_PROP_Other_ID_Start, - POP_UNION, - POP_PROP, UNICODE_PROP_Pattern_Syntax, - POP_PROP, UNICODE_PROP_Pattern_White_Space, - POP_UNION, - POP_INVERT, - POP_INTER, - POP_END); - break; - case UNICODE_PROP_ID_Continue: - ret = unicode_prop_ops(cr, - POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl) | - M(Mn) | M(Mc) | M(Nd) | M(Pc), - POP_PROP, UNICODE_PROP_Other_ID_Start, - POP_UNION, - POP_PROP, UNICODE_PROP_Other_ID_Continue, - POP_UNION, - POP_PROP, UNICODE_PROP_Pattern_Syntax, - POP_PROP, UNICODE_PROP_Pattern_White_Space, - POP_UNION, - POP_INVERT, - POP_INTER, - POP_END); - break; - case UNICODE_PROP_Case_Ignorable: - ret = unicode_prop_ops(cr, - POP_GC, M(Mn) | M(Cf) | M(Lm) | M(Sk), - POP_PROP, UNICODE_PROP_Case_Ignorable1, - POP_XOR, - POP_END); - break; -#else - /* we use the existing tables */ - case UNICODE_PROP_ID_Continue: - ret = unicode_prop_ops(cr, - POP_PROP, UNICODE_PROP_ID_Start, - POP_PROP, UNICODE_PROP_ID_Continue1, - POP_XOR, - POP_END); - break; -#endif - default: - if (prop_idx >= countof(unicode_prop_table)) - return -2; - ret = unicode_prop1(cr, prop_idx); - break; - } - return ret; -} - -#endif /* CONFIG_ALL_UNICODE */ - -/*---- lre codepoint categorizing functions ----*/ - -#define S UNICODE_C_SPACE -#define D UNICODE_C_DIGIT -#define X UNICODE_C_XDIGIT -#define U UNICODE_C_UPPER -#define L UNICODE_C_LOWER -#define _ UNICODE_C_UNDER -#define d UNICODE_C_DOLLAR - -uint8_t const lre_ctype_bits[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, S, S, S, S, S, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - - S, 0, 0, 0, d, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - X|D, X|D, X|D, X|D, X|D, X|D, X|D, X|D, - X|D, X|D, 0, 0, 0, 0, 0, 0, - - 0, X|U, X|U, X|U, X|U, X|U, X|U, U, - U, U, U, U, U, U, U, U, - U, U, U, U, U, U, U, U, - U, U, U, 0, 0, 0, 0, _, - - 0, X|L, X|L, X|L, X|L, X|L, X|L, L, - L, L, L, L, L, L, L, L, - L, L, L, L, L, L, L, L, - L, L, L, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - - S, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, -}; - -#undef S -#undef D -#undef X -#undef U -#undef L -#undef _ -#undef d - -/* code point ranges for Zs,Zl or Zp property */ -static const uint16_t char_range_s[] = { - 10, - 0x0009, 0x000D + 1, - 0x0020, 0x0020 + 1, - 0x00A0, 0x00A0 + 1, - 0x1680, 0x1680 + 1, - 0x2000, 0x200A + 1, - /* 2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; */ - /* 2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; */ - 0x2028, 0x2029 + 1, - 0x202F, 0x202F + 1, - 0x205F, 0x205F + 1, - 0x3000, 0x3000 + 1, - /* FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; */ - 0xFEFF, 0xFEFF + 1, -}; - -BOOL lre_is_space_non_ascii(uint32_t c) -{ - size_t i, n; - - n = countof(char_range_s); - for(i = 5; i < n; i += 2) { - uint32_t low = char_range_s[i]; - uint32_t high = char_range_s[i + 1]; - if (c < low) - return FALSE; - if (c < high) - return TRUE; - } - return FALSE; -} - -#define SEQ_MAX_LEN 16 - -static int unicode_sequence_prop1(int seq_prop_idx, UnicodeSequencePropCB *cb, void *opaque, - CharRange *cr) -{ - int i, c, j; - uint32_t seq[SEQ_MAX_LEN]; - - switch(seq_prop_idx) { - case UNICODE_SEQUENCE_PROP_Basic_Emoji: - if (unicode_prop1(cr, UNICODE_PROP_Basic_Emoji1) < 0) - return -1; - for(i = 0; i < cr->len; i += 2) { - for(c = cr->points[i]; c < cr->points[i + 1]; c++) { - seq[0] = c; - cb(opaque, seq, 1); - } - } - - cr->len = 0; - - if (unicode_prop1(cr, UNICODE_PROP_Basic_Emoji2) < 0) - return -1; - for(i = 0; i < cr->len; i += 2) { - for(c = cr->points[i]; c < cr->points[i + 1]; c++) { - seq[0] = c; - seq[1] = 0xfe0f; - cb(opaque, seq, 2); - } - } - - break; - case UNICODE_SEQUENCE_PROP_RGI_Emoji_Modifier_Sequence: - if (unicode_prop1(cr, UNICODE_PROP_Emoji_Modifier_Base) < 0) - return -1; - for(i = 0; i < cr->len; i += 2) { - for(c = cr->points[i]; c < cr->points[i + 1]; c++) { - for(j = 0; j < 5; j++) { - seq[0] = c; - seq[1] = 0x1f3fb + j; - cb(opaque, seq, 2); - } - } - } - break; - case UNICODE_SEQUENCE_PROP_RGI_Emoji_Flag_Sequence: - if (unicode_prop1(cr, UNICODE_PROP_RGI_Emoji_Flag_Sequence) < 0) - return -1; - for(i = 0; i < cr->len; i += 2) { - for(c = cr->points[i]; c < cr->points[i + 1]; c++) { - int c0, c1; - c0 = c / 26; - c1 = c % 26; - seq[0] = 0x1F1E6 + c0; - seq[1] = 0x1F1E6 + c1; - cb(opaque, seq, 2); - } - } - break; - case UNICODE_SEQUENCE_PROP_RGI_Emoji_ZWJ_Sequence: - { - int len, code, pres, k, mod, mod_count, mod_pos[2], hc_pos, n_mod, n_hc, mod1; - int mod_idx, hc_idx, i0, i1; - const uint8_t *tab = unicode_rgi_emoji_zwj_sequence; - - for(i = 0; i < countof(unicode_rgi_emoji_zwj_sequence);) { - len = tab[i++]; - k = 0; - mod = 0; - mod_count = 0; - hc_pos = -1; - for(j = 0; j < len; j++) { - code = tab[i++]; - code |= tab[i++] << 8; - pres = code >> 15; - mod1 = (code >> 13) & 3; - code &= 0x1fff; - if (code < 0x1000) { - c = code + 0x2000; - } else { - c = 0x1f000 + (code - 0x1000); - } - if (c == 0x1f9b0) - hc_pos = k; - seq[k++] = c; - if (mod1 != 0) { - assert(mod_count < 2); - mod = mod1; - mod_pos[mod_count++] = k; - seq[k++] = 0; /* will be filled later */ - } - if (pres) { - seq[k++] = 0xfe0f; - } - if (j < len - 1) { - seq[k++] = 0x200d; - } - } - - /* genrate all the variants */ - switch(mod) { - case 1: - n_mod = 5; - break; - case 2: - n_mod = 25; - break; - case 3: - n_mod = 20; - break; - default: - n_mod = 1; - break; - } - if (hc_pos >= 0) - n_hc = 4; - else - n_hc = 1; - for(hc_idx = 0; hc_idx < n_hc; hc_idx++) { - for(mod_idx = 0; mod_idx < n_mod; mod_idx++) { - if (hc_pos >= 0) - seq[hc_pos] = 0x1f9b0 + hc_idx; - - switch(mod) { - case 1: - seq[mod_pos[0]] = 0x1f3fb + mod_idx; - break; - case 2: - case 3: - i0 = mod_idx / 5; - i1 = mod_idx % 5; - /* avoid identical values */ - if (mod == 3 && i0 >= i1) - i0++; - seq[mod_pos[0]] = 0x1f3fb + i0; - seq[mod_pos[1]] = 0x1f3fb + i1; - break; - default: - break; - } -#if 0 - for(j = 0; j < k; j++) - printf(" %04x", seq[j]); - printf("\n"); -#endif - cb(opaque, seq, k); - } - } - } - } - break; - case UNICODE_SEQUENCE_PROP_RGI_Emoji_Tag_Sequence: - { - for(i = 0; i < countof(unicode_rgi_emoji_tag_sequence);) { - j = 0; - seq[j++] = 0x1F3F4; - for(;;) { - c = unicode_rgi_emoji_tag_sequence[i++]; - if (c == 0x00) - break; - seq[j++] = 0xe0000 + c; - } - seq[j++] = 0xe007f; - cb(opaque, seq, j); - } - } - break; - case UNICODE_SEQUENCE_PROP_Emoji_Keycap_Sequence: - if (unicode_prop1(cr, UNICODE_PROP_Emoji_Keycap_Sequence) < 0) - return -1; - for(i = 0; i < cr->len; i += 2) { - for(c = cr->points[i]; c < cr->points[i + 1]; c++) { - seq[0] = c; - seq[1] = 0xfe0f; - seq[2] = 0x20e3; - cb(opaque, seq, 3); - } - } - break; - case UNICODE_SEQUENCE_PROP_RGI_Emoji: - /* all prevous sequences */ - for(i = UNICODE_SEQUENCE_PROP_Basic_Emoji; i <= UNICODE_SEQUENCE_PROP_RGI_Emoji_ZWJ_Sequence; i++) { - int ret; - ret = unicode_sequence_prop1(i, cb, opaque, cr); - if (ret < 0) - return ret; - cr->len = 0; - } - break; - default: - return -2; - } - return 0; -} - -/* build a unicode sequence property */ -/* return -2 if not found, -1 if other error. 'cr' is used as temporary memory. */ -int unicode_sequence_prop(const char *prop_name, UnicodeSequencePropCB *cb, void *opaque, - CharRange *cr) -{ - int seq_prop_idx; - seq_prop_idx = unicode_find_name(unicode_sequence_prop_name_table, prop_name); - if (seq_prop_idx < 0) - return -2; - return unicode_sequence_prop1(seq_prop_idx, cb, opaque, cr); -} diff --git a/packages/javascript/javascript_android/cxx/quickjs/libunicode.h b/packages/javascript/javascript_android/cxx/quickjs/libunicode.h deleted file mode 100644 index 5d964e4..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/libunicode.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Unicode utilities - * - * Copyright (c) 2017-2018 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef LIBUNICODE_H -#define LIBUNICODE_H - -#include - -/* define it to include all the unicode tables (40KB larger) */ -#define CONFIG_ALL_UNICODE - -#define LRE_CC_RES_LEN_MAX 3 - -/* char ranges */ - -typedef struct { - int len; /* in points, always even */ - int size; - uint32_t *points; /* points sorted by increasing value */ - void *mem_opaque; - void *(*realloc_func)(void *opaque, void *ptr, size_t size); -} CharRange; - -typedef enum { - CR_OP_UNION, - CR_OP_INTER, - CR_OP_XOR, - CR_OP_SUB, -} CharRangeOpEnum; - -void cr_init(CharRange *cr, void *mem_opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size)); -void cr_free(CharRange *cr); -int cr_realloc(CharRange *cr, int size); -int cr_copy(CharRange *cr, const CharRange *cr1); - -static inline int cr_add_point(CharRange *cr, uint32_t v) -{ - if (cr->len >= cr->size) { - if (cr_realloc(cr, cr->len + 1)) - return -1; - } - cr->points[cr->len++] = v; - return 0; -} - -static inline int cr_add_interval(CharRange *cr, uint32_t c1, uint32_t c2) -{ - if ((cr->len + 2) > cr->size) { - if (cr_realloc(cr, cr->len + 2)) - return -1; - } - cr->points[cr->len++] = c1; - cr->points[cr->len++] = c2; - return 0; -} - -int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len, - const uint32_t *b_pt, int b_len, int op); -int cr_op1(CharRange *cr, const uint32_t *b_pt, int b_len, int op); - -static inline int cr_union_interval(CharRange *cr, uint32_t c1, uint32_t c2) -{ - uint32_t b_pt[2]; - b_pt[0] = c1; - b_pt[1] = c2 + 1; - return cr_op1(cr, b_pt, 2, CR_OP_UNION); -} - -int cr_invert(CharRange *cr); - -int cr_regexp_canonicalize(CharRange *cr, int is_unicode); - -typedef enum { - UNICODE_NFC, - UNICODE_NFD, - UNICODE_NFKC, - UNICODE_NFKD, -} UnicodeNormalizationEnum; - -int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len, - UnicodeNormalizationEnum n_type, - void *opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size)); - -/* Unicode character range functions */ - -int unicode_script(CharRange *cr, const char *script_name, int is_ext); -int unicode_general_category(CharRange *cr, const char *gc_name); -int unicode_prop(CharRange *cr, const char *prop_name); - -typedef void UnicodeSequencePropCB(void *opaque, const uint32_t *buf, int len); -int unicode_sequence_prop(const char *prop_name, UnicodeSequencePropCB *cb, void *opaque, - CharRange *cr); - -int lre_case_conv(uint32_t *res, uint32_t c, int conv_type); -int lre_canonicalize(uint32_t c, int is_unicode); - -/* Code point type categories */ -enum { - UNICODE_C_SPACE = (1 << 0), - UNICODE_C_DIGIT = (1 << 1), - UNICODE_C_UPPER = (1 << 2), - UNICODE_C_LOWER = (1 << 3), - UNICODE_C_UNDER = (1 << 4), - UNICODE_C_DOLLAR = (1 << 5), - UNICODE_C_XDIGIT = (1 << 6), -}; -extern uint8_t const lre_ctype_bits[256]; - -/* zero or non-zero return value */ -int lre_is_cased(uint32_t c); -int lre_is_case_ignorable(uint32_t c); -int lre_is_id_start(uint32_t c); -int lre_is_id_continue(uint32_t c); - -static inline int lre_is_space_byte(uint8_t c) { - return lre_ctype_bits[c] & UNICODE_C_SPACE; -} - -static inline int lre_is_id_start_byte(uint8_t c) { - return lre_ctype_bits[c] & (UNICODE_C_UPPER | UNICODE_C_LOWER | - UNICODE_C_UNDER | UNICODE_C_DOLLAR); -} - -static inline int lre_is_id_continue_byte(uint8_t c) { - return lre_ctype_bits[c] & (UNICODE_C_UPPER | UNICODE_C_LOWER | - UNICODE_C_UNDER | UNICODE_C_DOLLAR | - UNICODE_C_DIGIT); -} - -int lre_is_space_non_ascii(uint32_t c); - -static inline int lre_is_space(uint32_t c) { - if (c < 256) - return lre_is_space_byte(c); - else - return lre_is_space_non_ascii(c); -} - -static inline int lre_js_is_ident_first(uint32_t c) { - if (c < 128) { - return lre_is_id_start_byte(c); - } else { -#ifdef CONFIG_ALL_UNICODE - return lre_is_id_start(c); -#else - return !lre_is_space_non_ascii(c); -#endif - } -} - -static inline int lre_js_is_ident_next(uint32_t c) { - if (c < 128) { - return lre_is_id_continue_byte(c); - } else { - /* ZWNJ and ZWJ are accepted in identifiers */ - if (c >= 0x200C && c <= 0x200D) - return TRUE; -#ifdef CONFIG_ALL_UNICODE - return lre_is_id_continue(c); -#else - return !lre_is_space_non_ascii(c); -#endif - } -} - -#endif /* LIBUNICODE_H */ diff --git a/packages/javascript/javascript_android/cxx/quickjs/list.h b/packages/javascript/javascript_android/cxx/quickjs/list.h deleted file mode 100644 index 8098311..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/list.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Linux klist like system - * - * Copyright (c) 2016-2017 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef LIST_H -#define LIST_H - -#ifndef NULL -#include -#endif - -struct list_head { - struct list_head *prev; - struct list_head *next; -}; - -#define LIST_HEAD_INIT(el) { &(el), &(el) } - -/* return the pointer of type 'type *' containing 'el' as field 'member' */ -#define list_entry(el, type, member) container_of(el, type, member) - -static inline void init_list_head(struct list_head *head) -{ - head->prev = head; - head->next = head; -} - -/* insert 'el' between 'prev' and 'next' */ -static inline void __list_add(struct list_head *el, - struct list_head *prev, struct list_head *next) -{ - prev->next = el; - el->prev = prev; - el->next = next; - next->prev = el; -} - -/* add 'el' at the head of the list 'head' (= after element head) */ -static inline void list_add(struct list_head *el, struct list_head *head) -{ - __list_add(el, head, head->next); -} - -/* add 'el' at the end of the list 'head' (= before element head) */ -static inline void list_add_tail(struct list_head *el, struct list_head *head) -{ - __list_add(el, head->prev, head); -} - -static inline void list_del(struct list_head *el) -{ - struct list_head *prev, *next; - prev = el->prev; - next = el->next; - prev->next = next; - next->prev = prev; - el->prev = NULL; /* fail safe */ - el->next = NULL; /* fail safe */ -} - -static inline int list_empty(struct list_head *el) -{ - return el->next == el; -} - -#define list_for_each(el, head) \ - for(el = (head)->next; el != (head); el = el->next) - -#define list_for_each_safe(el, el1, head) \ - for(el = (head)->next, el1 = el->next; el != (head); \ - el = el1, el1 = el->next) - -#define list_for_each_prev(el, head) \ - for(el = (head)->prev; el != (head); el = el->prev) - -#define list_for_each_prev_safe(el, el1, head) \ - for(el = (head)->prev, el1 = el->prev; el != (head); \ - el = el1, el1 = el->prev) - -#endif /* LIST_H */ diff --git a/packages/javascript/javascript_android/cxx/quickjs/qjs.c b/packages/javascript/javascript_android/cxx/quickjs/qjs.c deleted file mode 100644 index a88e39a..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/qjs.c +++ /dev/null @@ -1,551 +0,0 @@ -/* - * QuickJS stand alone interpreter - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__APPLE__) -#include -#elif defined(__linux__) || defined(__GLIBC__) -#include -#elif defined(__FreeBSD__) -#include -#endif - -#include "cutils.h" -#include "quickjs-libc.h" - -extern const uint8_t qjsc_repl[]; -extern const uint32_t qjsc_repl_size; - -static int eval_buf(JSContext *ctx, const void *buf, int buf_len, - const char *filename, int eval_flags) -{ - JSValue val; - int ret; - - if ((eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_MODULE) { - /* for the modules, we compile then run to be able to set - import.meta */ - val = JS_Eval(ctx, buf, buf_len, filename, - eval_flags | JS_EVAL_FLAG_COMPILE_ONLY); - if (!JS_IsException(val)) { - js_module_set_import_meta(ctx, val, TRUE, TRUE); - val = JS_EvalFunction(ctx, val); - } - val = js_std_await(ctx, val); - } else { - val = JS_Eval(ctx, buf, buf_len, filename, eval_flags); - } - if (JS_IsException(val)) { - js_std_dump_error(ctx); - ret = -1; - } else { - ret = 0; - } - JS_FreeValue(ctx, val); - return ret; -} - -static int eval_file(JSContext *ctx, const char *filename, int module) -{ - uint8_t *buf; - int ret, eval_flags; - size_t buf_len; - - buf = js_load_file(ctx, &buf_len, filename); - if (!buf) { - perror(filename); - exit(1); - } - - if (module < 0) { - module = (has_suffix(filename, ".mjs") || - JS_DetectModule((const char *)buf, buf_len)); - } - if (module) - eval_flags = JS_EVAL_TYPE_MODULE; - else - eval_flags = JS_EVAL_TYPE_GLOBAL; - ret = eval_buf(ctx, buf, buf_len, filename, eval_flags); - js_free(ctx, buf); - return ret; -} - -/* also used to initialize the worker context */ -static JSContext *JS_NewCustomContext(JSRuntime *rt) -{ - JSContext *ctx; - ctx = JS_NewContext(rt); - if (!ctx) - return NULL; - /* system modules */ - js_init_module_std(ctx, "std"); - js_init_module_os(ctx, "os"); - return ctx; -} - -#if defined(__APPLE__) -#define MALLOC_OVERHEAD 0 -#else -#define MALLOC_OVERHEAD 8 -#endif - -struct trace_malloc_data { - uint8_t *base; -}; - -static inline unsigned long long js_trace_malloc_ptr_offset(uint8_t *ptr, - struct trace_malloc_data *dp) -{ - return ptr - dp->base; -} - -/* default memory allocation functions with memory limitation */ -static size_t js_trace_malloc_usable_size(const void *ptr) -{ -#if defined(__APPLE__) - return malloc_size(ptr); -#elif defined(_WIN32) - return _msize((void *)ptr); -#elif defined(EMSCRIPTEN) - return 0; -#elif defined(__linux__) || defined(__GLIBC__) - return malloc_usable_size((void *)ptr); -#else - /* change this to `return 0;` if compilation fails */ - return malloc_usable_size((void *)ptr); -#endif -} - -static void -#ifdef _WIN32 -/* mingw printf is used */ -__attribute__((format(gnu_printf, 2, 3))) -#else -__attribute__((format(printf, 2, 3))) -#endif - js_trace_malloc_printf(JSMallocState *s, const char *fmt, ...) -{ - va_list ap; - int c; - - va_start(ap, fmt); - while ((c = *fmt++) != '\0') { - if (c == '%') { - /* only handle %p and %zd */ - if (*fmt == 'p') { - uint8_t *ptr = va_arg(ap, void *); - if (ptr == NULL) { - printf("NULL"); - } else { - printf("H%+06lld.%zd", - js_trace_malloc_ptr_offset(ptr, s->opaque), - js_trace_malloc_usable_size(ptr)); - } - fmt++; - continue; - } - if (fmt[0] == 'z' && fmt[1] == 'd') { - size_t sz = va_arg(ap, size_t); - printf("%zd", sz); - fmt += 2; - continue; - } - } - putc(c, stdout); - } - va_end(ap); -} - -static void js_trace_malloc_init(struct trace_malloc_data *s) -{ - free(s->base = malloc(8)); -} - -static void *js_trace_malloc(JSMallocState *s, size_t size) -{ - void *ptr; - - /* Do not allocate zero bytes: behavior is platform dependent */ - assert(size != 0); - - if (unlikely(s->malloc_size + size > s->malloc_limit)) - return NULL; - ptr = malloc(size); - js_trace_malloc_printf(s, "A %zd -> %p\n", size, ptr); - if (ptr) { - s->malloc_count++; - s->malloc_size += js_trace_malloc_usable_size(ptr) + MALLOC_OVERHEAD; - } - return ptr; -} - -static void js_trace_free(JSMallocState *s, void *ptr) -{ - if (!ptr) - return; - - js_trace_malloc_printf(s, "F %p\n", ptr); - s->malloc_count--; - s->malloc_size -= js_trace_malloc_usable_size(ptr) + MALLOC_OVERHEAD; - free(ptr); -} - -static void *js_trace_realloc(JSMallocState *s, void *ptr, size_t size) -{ - size_t old_size; - - if (!ptr) { - if (size == 0) - return NULL; - return js_trace_malloc(s, size); - } - old_size = js_trace_malloc_usable_size(ptr); - if (size == 0) { - js_trace_malloc_printf(s, "R %zd %p\n", size, ptr); - s->malloc_count--; - s->malloc_size -= old_size + MALLOC_OVERHEAD; - free(ptr); - return NULL; - } - if (s->malloc_size + size - old_size > s->malloc_limit) - return NULL; - - js_trace_malloc_printf(s, "R %zd %p", size, ptr); - - ptr = realloc(ptr, size); - js_trace_malloc_printf(s, " -> %p\n", ptr); - if (ptr) { - s->malloc_size += js_trace_malloc_usable_size(ptr) - old_size; - } - return ptr; -} - -static const JSMallocFunctions trace_mf = { - js_trace_malloc, - js_trace_free, - js_trace_realloc, - js_trace_malloc_usable_size, -}; - -static size_t get_suffixed_size(const char *str) -{ - char *p; - size_t v; - v = (size_t)strtod(str, &p); - switch(*p) { - case 'G': - v <<= 30; - break; - case 'M': - v <<= 20; - break; - case 'k': - case 'K': - v <<= 10; - break; - default: - if (*p != '\0') { - fprintf(stderr, "qjs: invalid suffix: %s\n", p); - exit(1); - } - break; - } - return v; -} - -#define PROG_NAME "qjs" - -void help(void) -{ - printf("QuickJS version " CONFIG_VERSION "\n" - "usage: " PROG_NAME " [options] [file [args]]\n" - "-h --help list options\n" - "-e --eval EXPR evaluate EXPR\n" - "-i --interactive go to interactive mode\n" - "-m --module load as ES6 module (default=autodetect)\n" - " --script load as ES6 script (default=autodetect)\n" - "-I --include file include an additional file\n" - " --std make 'std' and 'os' available to the loaded script\n" - "-T --trace trace memory allocation\n" - "-d --dump dump the memory usage stats\n" - " --memory-limit n limit the memory usage to 'n' bytes (SI suffixes allowed)\n" - " --stack-size n limit the stack size to 'n' bytes (SI suffixes allowed)\n" - " --no-unhandled-rejection ignore unhandled promise rejections\n" - "-s strip all the debug info\n" - " --strip-source strip the source code\n" - "-q --quit just instantiate the interpreter and quit\n"); - exit(1); -} - -int main(int argc, char **argv) -{ - JSRuntime *rt; - JSContext *ctx; - struct trace_malloc_data trace_data = { NULL }; - int optind; - char *expr = NULL; - int interactive = 0; - int dump_memory = 0; - int trace_memory = 0; - int empty_run = 0; - int module = -1; - int load_std = 0; - int dump_unhandled_promise_rejection = 1; - size_t memory_limit = 0; - char *include_list[32]; - int i, include_count = 0; - int strip_flags = 0; - size_t stack_size = 0; - - /* cannot use getopt because we want to pass the command line to - the script */ - optind = 1; - while (optind < argc && *argv[optind] == '-') { - char *arg = argv[optind] + 1; - const char *longopt = ""; - /* a single - is not an option, it also stops argument scanning */ - if (!*arg) - break; - optind++; - if (*arg == '-') { - longopt = arg + 1; - arg += strlen(arg); - /* -- stops argument scanning */ - if (!*longopt) - break; - } - for (; *arg || *longopt; longopt = "") { - char opt = *arg; - if (opt) - arg++; - if (opt == 'h' || opt == '?' || !strcmp(longopt, "help")) { - help(); - continue; - } - if (opt == 'e' || !strcmp(longopt, "eval")) { - if (*arg) { - expr = arg; - break; - } - if (optind < argc) { - expr = argv[optind++]; - break; - } - fprintf(stderr, "qjs: missing expression for -e\n"); - exit(2); - } - if (opt == 'I' || !strcmp(longopt, "include")) { - if (optind >= argc) { - fprintf(stderr, "expecting filename"); - exit(1); - } - if (include_count >= countof(include_list)) { - fprintf(stderr, "too many included files"); - exit(1); - } - include_list[include_count++] = argv[optind++]; - continue; - } - if (opt == 'i' || !strcmp(longopt, "interactive")) { - interactive++; - continue; - } - if (opt == 'm' || !strcmp(longopt, "module")) { - module = 1; - continue; - } - if (!strcmp(longopt, "script")) { - module = 0; - continue; - } - if (opt == 'd' || !strcmp(longopt, "dump")) { - dump_memory++; - continue; - } - if (opt == 'T' || !strcmp(longopt, "trace")) { - trace_memory++; - continue; - } - if (!strcmp(longopt, "std")) { - load_std = 1; - continue; - } - if (!strcmp(longopt, "no-unhandled-rejection")) { - dump_unhandled_promise_rejection = 0; - continue; - } - if (opt == 'q' || !strcmp(longopt, "quit")) { - empty_run++; - continue; - } - if (!strcmp(longopt, "memory-limit")) { - if (optind >= argc) { - fprintf(stderr, "expecting memory limit"); - exit(1); - } - memory_limit = get_suffixed_size(argv[optind++]); - continue; - } - if (!strcmp(longopt, "stack-size")) { - if (optind >= argc) { - fprintf(stderr, "expecting stack size"); - exit(1); - } - stack_size = get_suffixed_size(argv[optind++]); - continue; - } - if (opt == 's') { - strip_flags = JS_STRIP_DEBUG; - continue; - } - if (!strcmp(longopt, "strip-source")) { - strip_flags = JS_STRIP_SOURCE; - continue; - } - if (opt) { - fprintf(stderr, "qjs: unknown option '-%c'\n", opt); - } else { - fprintf(stderr, "qjs: unknown option '--%s'\n", longopt); - } - help(); - } - } - - if (trace_memory) { - js_trace_malloc_init(&trace_data); - rt = JS_NewRuntime2(&trace_mf, &trace_data); - } else { - rt = JS_NewRuntime(); - } - if (!rt) { - fprintf(stderr, "qjs: cannot allocate JS runtime\n"); - exit(2); - } - if (memory_limit != 0) - JS_SetMemoryLimit(rt, memory_limit); - if (stack_size != 0) - JS_SetMaxStackSize(rt, stack_size); - JS_SetStripInfo(rt, strip_flags); - js_std_set_worker_new_context_func(JS_NewCustomContext); - js_std_init_handlers(rt); - ctx = JS_NewCustomContext(rt); - if (!ctx) { - fprintf(stderr, "qjs: cannot allocate JS context\n"); - exit(2); - } - - /* loader for ES6 modules */ - JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL); - - if (dump_unhandled_promise_rejection) { - JS_SetHostPromiseRejectionTracker(rt, js_std_promise_rejection_tracker, - NULL); - } - - if (!empty_run) { - js_std_add_helpers(ctx, argc - optind, argv + optind); - - /* make 'std' and 'os' visible to non module code */ - if (load_std) { - const char *str = "import * as std from 'std';\n" - "import * as os from 'os';\n" - "globalThis.std = std;\n" - "globalThis.os = os;\n"; - eval_buf(ctx, str, strlen(str), "", JS_EVAL_TYPE_MODULE); - } - - for(i = 0; i < include_count; i++) { - if (eval_file(ctx, include_list[i], module)) - goto fail; - } - - if (expr) { - if (eval_buf(ctx, expr, strlen(expr), "", 0)) - goto fail; - } else - if (optind >= argc) { - /* interactive mode */ - interactive = 1; - } else { - const char *filename; - filename = argv[optind]; - if (eval_file(ctx, filename, module)) - goto fail; - } - if (interactive) { - JS_SetHostPromiseRejectionTracker(rt, NULL, NULL); - js_std_eval_binary(ctx, qjsc_repl, qjsc_repl_size, 0); - } - js_std_loop(ctx); - } - - if (dump_memory) { - JSMemoryUsage stats; - JS_ComputeMemoryUsage(rt, &stats); - JS_DumpMemoryUsage(stdout, &stats, rt); - } - js_std_free_handlers(rt); - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - - if (empty_run && dump_memory) { - clock_t t[5]; - double best[5]; - int i, j; - for (i = 0; i < 100; i++) { - t[0] = clock(); - rt = JS_NewRuntime(); - t[1] = clock(); - ctx = JS_NewContext(rt); - t[2] = clock(); - JS_FreeContext(ctx); - t[3] = clock(); - JS_FreeRuntime(rt); - t[4] = clock(); - for (j = 4; j > 0; j--) { - double ms = 1000.0 * (t[j] - t[j - 1]) / CLOCKS_PER_SEC; - if (i == 0 || best[j] > ms) - best[j] = ms; - } - } - printf("\nInstantiation times (ms): %.3f = %.3f+%.3f+%.3f+%.3f\n", - best[1] + best[2] + best[3] + best[4], - best[1], best[2], best[3], best[4]); - } - return 0; - fail: - js_std_free_handlers(rt); - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - return 1; -} diff --git a/packages/javascript/javascript_android/cxx/quickjs/qjsc.c b/packages/javascript/javascript_android/cxx/quickjs/qjsc.c deleted file mode 100644 index 49aa449..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/qjsc.c +++ /dev/null @@ -1,873 +0,0 @@ -/* - * QuickJS command line compiler - * - * Copyright (c) 2018-2021 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#if !defined(_WIN32) -#include -#endif - -#include "cutils.h" -#include "quickjs-libc.h" - -typedef struct { - char *name; - char *short_name; - int flags; -} namelist_entry_t; - -typedef struct namelist_t { - namelist_entry_t *array; - int count; - int size; -} namelist_t; - -typedef struct { - const char *option_name; - const char *init_name; -} FeatureEntry; - -static namelist_t cname_list; -static namelist_t cmodule_list; -static namelist_t init_module_list; -static uint64_t feature_bitmap; -static FILE *outfile; -static BOOL byte_swap; -static BOOL dynamic_export; -static const char *c_ident_prefix = "qjsc_"; - -#define FE_ALL (-1) - -static const FeatureEntry feature_list[] = { - { "date", "Date" }, - { "eval", "Eval" }, - { "string-normalize", "StringNormalize" }, - { "regexp", "RegExp" }, - { "json", "JSON" }, - { "proxy", "Proxy" }, - { "map", "MapSet" }, - { "typedarray", "TypedArrays" }, - { "promise", "Promise" }, -#define FE_MODULE_LOADER 9 - { "module-loader", NULL }, - { "weakref", "WeakRef" }, -}; - -void namelist_add(namelist_t *lp, const char *name, const char *short_name, - int flags) -{ - namelist_entry_t *e; - if (lp->count == lp->size) { - size_t newsize = lp->size + (lp->size >> 1) + 4; - namelist_entry_t *a = - realloc(lp->array, sizeof(lp->array[0]) * newsize); - /* XXX: check for realloc failure */ - lp->array = a; - lp->size = newsize; - } - e = &lp->array[lp->count++]; - e->name = strdup(name); - if (short_name) - e->short_name = strdup(short_name); - else - e->short_name = NULL; - e->flags = flags; -} - -void namelist_free(namelist_t *lp) -{ - while (lp->count > 0) { - namelist_entry_t *e = &lp->array[--lp->count]; - free(e->name); - free(e->short_name); - } - free(lp->array); - lp->array = NULL; - lp->size = 0; -} - -namelist_entry_t *namelist_find(namelist_t *lp, const char *name) -{ - int i; - for(i = 0; i < lp->count; i++) { - namelist_entry_t *e = &lp->array[i]; - if (!strcmp(e->name, name)) - return e; - } - return NULL; -} - -static void get_c_name(char *buf, size_t buf_size, const char *file) -{ - const char *p, *r; - size_t len, i; - int c; - char *q; - - p = strrchr(file, '/'); - if (!p) - p = file; - else - p++; - r = strrchr(p, '.'); - if (!r) - len = strlen(p); - else - len = r - p; - pstrcpy(buf, buf_size, c_ident_prefix); - q = buf + strlen(buf); - for(i = 0; i < len; i++) { - c = p[i]; - if (!((c >= '0' && c <= '9') || - (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z'))) { - c = '_'; - } - if ((q - buf) < buf_size - 1) - *q++ = c; - } - *q = '\0'; -} - -static void dump_hex(FILE *f, const uint8_t *buf, size_t len) -{ - size_t i, col; - col = 0; - for(i = 0; i < len; i++) { - fprintf(f, " 0x%02x,", buf[i]); - if (++col == 8) { - fprintf(f, "\n"); - col = 0; - } - } - if (col != 0) - fprintf(f, "\n"); -} - -typedef enum { - CNAME_TYPE_SCRIPT, - CNAME_TYPE_MODULE, - CNAME_TYPE_JSON_MODULE, -} CNameTypeEnum; - -static void output_object_code(JSContext *ctx, - FILE *fo, JSValueConst obj, const char *c_name, - CNameTypeEnum c_name_type) -{ - uint8_t *out_buf; - size_t out_buf_len; - int flags; - - if (c_name_type == CNAME_TYPE_JSON_MODULE) - flags = 0; - else - flags = JS_WRITE_OBJ_BYTECODE; - if (byte_swap) - flags |= JS_WRITE_OBJ_BSWAP; - out_buf = JS_WriteObject(ctx, &out_buf_len, obj, flags); - if (!out_buf) { - js_std_dump_error(ctx); - exit(1); - } - - namelist_add(&cname_list, c_name, NULL, c_name_type); - - fprintf(fo, "const uint32_t %s_size = %u;\n\n", - c_name, (unsigned int)out_buf_len); - fprintf(fo, "const uint8_t %s[%u] = {\n", - c_name, (unsigned int)out_buf_len); - dump_hex(fo, out_buf, out_buf_len); - fprintf(fo, "};\n\n"); - - js_free(ctx, out_buf); -} - -static int js_module_dummy_init(JSContext *ctx, JSModuleDef *m) -{ - /* should never be called when compiling JS code */ - abort(); -} - -static void find_unique_cname(char *cname, size_t cname_size) -{ - char cname1[1024]; - int suffix_num; - size_t len, max_len; - assert(cname_size >= 32); - /* find a C name not matching an existing module C name by - adding a numeric suffix */ - len = strlen(cname); - max_len = cname_size - 16; - if (len > max_len) - cname[max_len] = '\0'; - suffix_num = 1; - for(;;) { - snprintf(cname1, sizeof(cname1), "%s_%d", cname, suffix_num); - if (!namelist_find(&cname_list, cname1)) - break; - suffix_num++; - } - pstrcpy(cname, cname_size, cname1); -} - -JSModuleDef *jsc_module_loader(JSContext *ctx, - const char *module_name, void *opaque, - JSValueConst attributes) -{ - JSModuleDef *m; - namelist_entry_t *e; - - /* check if it is a declared C or system module */ - e = namelist_find(&cmodule_list, module_name); - if (e) { - /* add in the static init module list */ - namelist_add(&init_module_list, e->name, e->short_name, 0); - /* create a dummy module */ - m = JS_NewCModule(ctx, module_name, js_module_dummy_init); - } else if (has_suffix(module_name, ".so")) { - fprintf(stderr, "Warning: binary module '%s' will be dynamically loaded\n", module_name); - /* create a dummy module */ - m = JS_NewCModule(ctx, module_name, js_module_dummy_init); - /* the resulting executable will export its symbols for the - dynamic library */ - dynamic_export = TRUE; - } else { - size_t buf_len; - uint8_t *buf; - char cname[1024]; - int res; - - buf = js_load_file(ctx, &buf_len, module_name); - if (!buf) { - JS_ThrowReferenceError(ctx, "could not load module filename '%s'", - module_name); - return NULL; - } - - res = js_module_test_json(ctx, attributes); - if (has_suffix(module_name, ".json") || res > 0) { - /* compile as JSON or JSON5 depending on "type" */ - JSValue val; - int flags; - - if (res == 2) - flags = JS_PARSE_JSON_EXT; - else - flags = 0; - val = JS_ParseJSON2(ctx, (char *)buf, buf_len, module_name, flags); - js_free(ctx, buf); - if (JS_IsException(val)) - return NULL; - /* create a dummy module */ - m = JS_NewCModule(ctx, module_name, js_module_dummy_init); - if (!m) { - JS_FreeValue(ctx, val); - return NULL; - } - - get_c_name(cname, sizeof(cname), module_name); - if (namelist_find(&cname_list, cname)) { - find_unique_cname(cname, sizeof(cname)); - } - - /* output the module name */ - fprintf(outfile, "static const uint8_t %s_module_name[] = {\n", - cname); - dump_hex(outfile, (const uint8_t *)module_name, strlen(module_name) + 1); - fprintf(outfile, "};\n\n"); - - output_object_code(ctx, outfile, val, cname, CNAME_TYPE_JSON_MODULE); - JS_FreeValue(ctx, val); - } else { - JSValue func_val; - - /* compile the module */ - func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, - JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); - js_free(ctx, buf); - if (JS_IsException(func_val)) - return NULL; - get_c_name(cname, sizeof(cname), module_name); - if (namelist_find(&cname_list, cname)) { - find_unique_cname(cname, sizeof(cname)); - } - output_object_code(ctx, outfile, func_val, cname, CNAME_TYPE_MODULE); - - /* the module is already referenced, so we must free it */ - m = JS_VALUE_GET_PTR(func_val); - JS_FreeValue(ctx, func_val); - } - } - return m; -} - -static void compile_file(JSContext *ctx, FILE *fo, - const char *filename, - const char *c_name1, - int module) -{ - uint8_t *buf; - char c_name[1024]; - int eval_flags; - JSValue obj; - size_t buf_len; - - buf = js_load_file(ctx, &buf_len, filename); - if (!buf) { - fprintf(stderr, "Could not load '%s'\n", filename); - exit(1); - } - eval_flags = JS_EVAL_FLAG_COMPILE_ONLY; - if (module < 0) { - module = (has_suffix(filename, ".mjs") || - JS_DetectModule((const char *)buf, buf_len)); - } - if (module) - eval_flags |= JS_EVAL_TYPE_MODULE; - else - eval_flags |= JS_EVAL_TYPE_GLOBAL; - obj = JS_Eval(ctx, (const char *)buf, buf_len, filename, eval_flags); - if (JS_IsException(obj)) { - js_std_dump_error(ctx); - exit(1); - } - js_free(ctx, buf); - if (c_name1) { - pstrcpy(c_name, sizeof(c_name), c_name1); - } else { - get_c_name(c_name, sizeof(c_name), filename); - } - output_object_code(ctx, fo, obj, c_name, CNAME_TYPE_SCRIPT); - JS_FreeValue(ctx, obj); -} - -static const char main_c_template1[] = - "int main(int argc, char **argv)\n" - "{\n" - " JSRuntime *rt;\n" - " JSContext *ctx;\n" - " rt = JS_NewRuntime();\n" - " js_std_set_worker_new_context_func(JS_NewCustomContext);\n" - " js_std_init_handlers(rt);\n" - ; - -static const char main_c_template2[] = - " js_std_loop(ctx);\n" - " js_std_free_handlers(rt);\n" - " JS_FreeContext(ctx);\n" - " JS_FreeRuntime(rt);\n" - " return 0;\n" - "}\n"; - -#define PROG_NAME "qjsc" - -void help(void) -{ - printf("QuickJS Compiler version " CONFIG_VERSION "\n" - "usage: " PROG_NAME " [options] [files]\n" - "\n" - "options are:\n" - "-c only output bytecode to a C file\n" - "-e output main() and bytecode to a C file (default = executable output)\n" - "-o output set the output filename\n" - "-N cname set the C name of the generated data\n" - "-m compile as Javascript module (default=autodetect)\n" - "-D module_name compile a dynamically loaded module or worker\n" - "-M module_name[,cname] add initialization code for an external C module\n" - "-x byte swapped output\n" - "-p prefix set the prefix of the generated C names\n" - "-S n set the maximum stack size to 'n' bytes (default=%d)\n" - "-s strip all the debug info\n" - "--keep-source keep the source code\n", - JS_DEFAULT_STACK_SIZE); -#ifdef CONFIG_LTO - { - int i; - printf("-flto use link time optimization\n"); - printf("-fno-["); - for(i = 0; i < countof(feature_list); i++) { - if (i != 0) - printf("|"); - printf("%s", feature_list[i].option_name); - } - printf("]\n" - " disable selected language features (smaller code size)\n"); - } -#endif - exit(1); -} - -#if defined(CONFIG_CC) && !defined(_WIN32) - -int exec_cmd(char **argv) -{ - int pid, status, ret; - - pid = fork(); - if (pid == 0) { - execvp(argv[0], argv); - exit(1); - } - - for(;;) { - ret = waitpid(pid, &status, 0); - if (ret == pid && WIFEXITED(status)) - break; - } - return WEXITSTATUS(status); -} - -static int output_executable(const char *out_filename, const char *cfilename, - BOOL use_lto, BOOL verbose, const char *exename) -{ - const char *argv[64]; - const char **arg, *bn_suffix, *lto_suffix; - char libjsname[1024]; - char exe_dir[1024], inc_dir[1024], lib_dir[1024], buf[1024], *p; - int ret; - - /* get the directory of the executable */ - pstrcpy(exe_dir, sizeof(exe_dir), exename); - p = strrchr(exe_dir, '/'); - if (p) { - *p = '\0'; - } else { - pstrcpy(exe_dir, sizeof(exe_dir), "."); - } - - /* if 'quickjs.h' is present at the same path as the executable, we - use it as include and lib directory */ - snprintf(buf, sizeof(buf), "%s/quickjs.h", exe_dir); - if (access(buf, R_OK) == 0) { - pstrcpy(inc_dir, sizeof(inc_dir), exe_dir); - pstrcpy(lib_dir, sizeof(lib_dir), exe_dir); - } else { - snprintf(inc_dir, sizeof(inc_dir), "%s/include/quickjs", CONFIG_PREFIX); - snprintf(lib_dir, sizeof(lib_dir), "%s/lib/quickjs", CONFIG_PREFIX); - } - - lto_suffix = ""; - bn_suffix = ""; - - arg = argv; - *arg++ = CONFIG_CC; - *arg++ = "-O2"; -#ifdef CONFIG_LTO - if (use_lto) { - *arg++ = "-flto"; - lto_suffix = ".lto"; - } -#endif - /* XXX: use the executable path to find the includes files and - libraries */ - *arg++ = "-D"; - *arg++ = "_GNU_SOURCE"; - *arg++ = "-I"; - *arg++ = inc_dir; - *arg++ = "-o"; - *arg++ = out_filename; - if (dynamic_export) - *arg++ = "-rdynamic"; - *arg++ = cfilename; - snprintf(libjsname, sizeof(libjsname), "%s/libquickjs%s%s.a", - lib_dir, bn_suffix, lto_suffix); - *arg++ = libjsname; - *arg++ = "-lm"; - *arg++ = "-ldl"; - *arg++ = "-lpthread"; - *arg = NULL; - - if (verbose) { - for(arg = argv; *arg != NULL; arg++) - printf("%s ", *arg); - printf("\n"); - } - - ret = exec_cmd((char **)argv); - unlink(cfilename); - return ret; -} -#else -static int output_executable(const char *out_filename, const char *cfilename, - BOOL use_lto, BOOL verbose, const char *exename) -{ - fprintf(stderr, "Executable output is not supported for this target\n"); - exit(1); - return 0; -} -#endif - -static size_t get_suffixed_size(const char *str) -{ - char *p; - size_t v; - v = (size_t)strtod(str, &p); - switch(*p) { - case 'G': - v <<= 30; - break; - case 'M': - v <<= 20; - break; - case 'k': - case 'K': - v <<= 10; - break; - default: - if (*p != '\0') { - fprintf(stderr, "qjs: invalid suffix: %s\n", p); - exit(1); - } - break; - } - return v; -} - -typedef enum { - OUTPUT_C, - OUTPUT_C_MAIN, - OUTPUT_EXECUTABLE, -} OutputTypeEnum; - -static const char *get_short_optarg(int *poptind, int opt, - const char *arg, int argc, char **argv) -{ - const char *optarg; - if (*arg) { - optarg = arg; - } else if (*poptind < argc) { - optarg = argv[(*poptind)++]; - } else { - fprintf(stderr, "qjsc: expecting parameter for -%c\n", opt); - exit(1); - } - return optarg; -} - -int main(int argc, char **argv) -{ - int i, verbose, strip_flags; - const char *out_filename, *cname; - char cfilename[1024]; - FILE *fo; - JSRuntime *rt; - JSContext *ctx; - BOOL use_lto; - int module; - OutputTypeEnum output_type; - size_t stack_size; - namelist_t dynamic_module_list; - - out_filename = NULL; - output_type = OUTPUT_EXECUTABLE; - cname = NULL; - feature_bitmap = FE_ALL; - module = -1; - byte_swap = FALSE; - verbose = 0; - strip_flags = JS_STRIP_SOURCE; - use_lto = FALSE; - stack_size = 0; - memset(&dynamic_module_list, 0, sizeof(dynamic_module_list)); - - /* add system modules */ - namelist_add(&cmodule_list, "std", "std", 0); - namelist_add(&cmodule_list, "os", "os", 0); - - optind = 1; - while (optind < argc && *argv[optind] == '-') { - char *arg = argv[optind] + 1; - const char *longopt = ""; - const char *optarg; - /* a single - is not an option, it also stops argument scanning */ - if (!*arg) - break; - optind++; - if (*arg == '-') { - longopt = arg + 1; - arg += strlen(arg); - /* -- stops argument scanning */ - if (!*longopt) - break; - } - for (; *arg || *longopt; longopt = "") { - char opt = *arg; - if (opt) - arg++; - if (opt == 'h' || opt == '?' || !strcmp(longopt, "help")) { - help(); - continue; - } - if (opt == 'o') { - out_filename = get_short_optarg(&optind, opt, arg, argc, argv); - break; - } - if (opt == 'c') { - output_type = OUTPUT_C; - continue; - } - if (opt == 'e') { - output_type = OUTPUT_C_MAIN; - continue; - } - if (opt == 'N') { - cname = get_short_optarg(&optind, opt, arg, argc, argv); - break; - } - if (opt == 'f') { - const char *p; - optarg = get_short_optarg(&optind, opt, arg, argc, argv); - p = optarg; - if (!strcmp(p, "lto")) { - use_lto = TRUE; - } else if (strstart(p, "no-", &p)) { - use_lto = TRUE; - for(i = 0; i < countof(feature_list); i++) { - if (!strcmp(p, feature_list[i].option_name)) { - feature_bitmap &= ~((uint64_t)1 << i); - break; - } - } - if (i == countof(feature_list)) - goto bad_feature; - } else { - bad_feature: - fprintf(stderr, "unsupported feature: %s\n", optarg); - exit(1); - } - break; - } - if (opt == 'm') { - module = 1; - continue; - } - if (opt == 'M') { - char *p; - char path[1024]; - char cname[1024]; - - optarg = get_short_optarg(&optind, opt, arg, argc, argv); - pstrcpy(path, sizeof(path), optarg); - p = strchr(path, ','); - if (p) { - *p = '\0'; - pstrcpy(cname, sizeof(cname), p + 1); - } else { - get_c_name(cname, sizeof(cname), path); - } - namelist_add(&cmodule_list, path, cname, 0); - break; - } - if (opt == 'D') { - optarg = get_short_optarg(&optind, opt, arg, argc, argv); - namelist_add(&dynamic_module_list, optarg, NULL, 0); - break; - } - if (opt == 'x') { - byte_swap = 1; - continue; - } - if (opt == 'v') { - verbose++; - continue; - } - if (opt == 'p') { - c_ident_prefix = get_short_optarg(&optind, opt, arg, argc, argv); - break; - } - if (opt == 'S') { - optarg = get_short_optarg(&optind, opt, arg, argc, argv); - stack_size = get_suffixed_size(optarg); - break; - } - if (opt == 's') { - strip_flags = JS_STRIP_DEBUG; - continue; - } - if (!strcmp(longopt, "keep-source")) { - strip_flags = 0; - continue; - } - if (opt) { - fprintf(stderr, "qjsc: unknown option '-%c'\n", opt); - } else { - fprintf(stderr, "qjsc: unknown option '--%s'\n", longopt); - } - help(); - } - } - - if (optind >= argc) - help(); - - if (!out_filename) { - if (output_type == OUTPUT_EXECUTABLE) { - out_filename = "a.out"; - } else { - out_filename = "out.c"; - } - } - - if (output_type == OUTPUT_EXECUTABLE) { -#if defined(_WIN32) || defined(__ANDROID__) - /* XXX: find a /tmp directory ? */ - snprintf(cfilename, sizeof(cfilename), "out%d.c", getpid()); -#else - snprintf(cfilename, sizeof(cfilename), "/tmp/out%d.c", getpid()); -#endif - } else { - pstrcpy(cfilename, sizeof(cfilename), out_filename); - } - - fo = fopen(cfilename, "w"); - if (!fo) { - perror(cfilename); - exit(1); - } - outfile = fo; - - rt = JS_NewRuntime(); - ctx = JS_NewContext(rt); - - JS_SetStripInfo(rt, strip_flags); - - /* loader for ES6 modules */ - JS_SetModuleLoaderFunc2(rt, NULL, jsc_module_loader, NULL, NULL); - - fprintf(fo, "/* File generated automatically by the QuickJS compiler. */\n" - "\n" - ); - - if (output_type != OUTPUT_C) { - fprintf(fo, "#include \"quickjs-libc.h\"\n" - "\n" - ); - } else { - fprintf(fo, "#include \n" - "\n" - ); - } - - for(i = optind; i < argc; i++) { - const char *filename = argv[i]; - compile_file(ctx, fo, filename, cname, module); - cname = NULL; - } - - for(i = 0; i < dynamic_module_list.count; i++) { - if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL, JS_UNDEFINED)) { - fprintf(stderr, "Could not load dynamic module '%s'\n", - dynamic_module_list.array[i].name); - exit(1); - } - } - - if (output_type != OUTPUT_C) { - fprintf(fo, - "static JSContext *JS_NewCustomContext(JSRuntime *rt)\n" - "{\n" - " JSContext *ctx = JS_NewContextRaw(rt);\n" - " if (!ctx)\n" - " return NULL;\n"); - /* add the basic objects */ - fprintf(fo, " JS_AddIntrinsicBaseObjects(ctx);\n"); - for(i = 0; i < countof(feature_list); i++) { - if ((feature_bitmap & ((uint64_t)1 << i)) && - feature_list[i].init_name) { - fprintf(fo, " JS_AddIntrinsic%s(ctx);\n", - feature_list[i].init_name); - } - } - /* add the precompiled modules (XXX: could modify the module - loader instead) */ - for(i = 0; i < init_module_list.count; i++) { - namelist_entry_t *e = &init_module_list.array[i]; - /* initialize the static C modules */ - - fprintf(fo, - " {\n" - " extern JSModuleDef *js_init_module_%s(JSContext *ctx, const char *name);\n" - " js_init_module_%s(ctx, \"%s\");\n" - " }\n", - e->short_name, e->short_name, e->name); - } - for(i = 0; i < cname_list.count; i++) { - namelist_entry_t *e = &cname_list.array[i]; - if (e->flags == CNAME_TYPE_MODULE) { - fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 1);\n", - e->name, e->name); - } else if (e->flags == CNAME_TYPE_JSON_MODULE) { - fprintf(fo, " js_std_eval_binary_json_module(ctx, %s, %s_size, (const char *)%s_module_name);\n", - e->name, e->name, e->name); - } - } - fprintf(fo, - " return ctx;\n" - "}\n\n"); - - fputs(main_c_template1, fo); - - if (stack_size != 0) { - fprintf(fo, " JS_SetMaxStackSize(rt, %u);\n", - (unsigned int)stack_size); - } - - /* add the module loader if necessary */ - if (feature_bitmap & (1 << FE_MODULE_LOADER)) { - fprintf(fo, " JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL);\n"); - } - - fprintf(fo, - " ctx = JS_NewCustomContext(rt);\n" - " js_std_add_helpers(ctx, argc, argv);\n"); - - for(i = 0; i < cname_list.count; i++) { - namelist_entry_t *e = &cname_list.array[i]; - if (e->flags == CNAME_TYPE_SCRIPT) { - fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 0);\n", - e->name, e->name); - } - } - fputs(main_c_template2, fo); - } - - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - - fclose(fo); - - if (output_type == OUTPUT_EXECUTABLE) { - return output_executable(out_filename, cfilename, use_lto, verbose, - argv[0]); - } - namelist_free(&cname_list); - namelist_free(&cmodule_list); - namelist_free(&init_module_list); - return 0; -} diff --git a/packages/javascript/javascript_android/cxx/quickjs/quickjs-atom.h b/packages/javascript/javascript_android/cxx/quickjs/quickjs-atom.h deleted file mode 100644 index 425c2e9..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/quickjs-atom.h +++ /dev/null @@ -1,270 +0,0 @@ -/* - * QuickJS atom definitions - * - * Copyright (c) 2017-2018 Fabrice Bellard - * Copyright (c) 2017-2018 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifdef DEF - -/* Note: first atoms are considered as keywords in the parser */ -DEF(null, "null") /* must be first */ -DEF(false, "false") -DEF(true, "true") -DEF(if, "if") -DEF(else, "else") -DEF(return, "return") -DEF(var, "var") -DEF(this, "this") -DEF(delete, "delete") -DEF(void, "void") -DEF(typeof, "typeof") -DEF(new, "new") -DEF(in, "in") -DEF(instanceof, "instanceof") -DEF(do, "do") -DEF(while, "while") -DEF(for, "for") -DEF(break, "break") -DEF(continue, "continue") -DEF(switch, "switch") -DEF(case, "case") -DEF(default, "default") -DEF(throw, "throw") -DEF(try, "try") -DEF(catch, "catch") -DEF(finally, "finally") -DEF(function, "function") -DEF(debugger, "debugger") -DEF(with, "with") -/* FutureReservedWord */ -DEF(class, "class") -DEF(const, "const") -DEF(enum, "enum") -DEF(export, "export") -DEF(extends, "extends") -DEF(import, "import") -DEF(super, "super") -/* FutureReservedWords when parsing strict mode code */ -DEF(implements, "implements") -DEF(interface, "interface") -DEF(let, "let") -DEF(package, "package") -DEF(private, "private") -DEF(protected, "protected") -DEF(public, "public") -DEF(static, "static") -DEF(yield, "yield") -DEF(await, "await") - -/* empty string */ -DEF(empty_string, "") -/* identifiers */ -DEF(length, "length") -DEF(fileName, "fileName") -DEF(lineNumber, "lineNumber") -DEF(columnNumber, "columnNumber") -DEF(message, "message") -DEF(cause, "cause") -DEF(errors, "errors") -DEF(stack, "stack") -DEF(name, "name") -DEF(toString, "toString") -DEF(toLocaleString, "toLocaleString") -DEF(valueOf, "valueOf") -DEF(eval, "eval") -DEF(prototype, "prototype") -DEF(constructor, "constructor") -DEF(configurable, "configurable") -DEF(writable, "writable") -DEF(enumerable, "enumerable") -DEF(value, "value") -DEF(get, "get") -DEF(set, "set") -DEF(of, "of") -DEF(__proto__, "__proto__") -DEF(undefined, "undefined") -DEF(number, "number") -DEF(boolean, "boolean") -DEF(string, "string") -DEF(object, "object") -DEF(symbol, "symbol") -DEF(integer, "integer") -DEF(unknown, "unknown") -DEF(arguments, "arguments") -DEF(callee, "callee") -DEF(caller, "caller") -DEF(_eval_, "") -DEF(_ret_, "") -DEF(_var_, "") -DEF(_arg_var_, "") -DEF(_with_, "") -DEF(lastIndex, "lastIndex") -DEF(target, "target") -DEF(index, "index") -DEF(input, "input") -DEF(defineProperties, "defineProperties") -DEF(apply, "apply") -DEF(join, "join") -DEF(concat, "concat") -DEF(split, "split") -DEF(construct, "construct") -DEF(getPrototypeOf, "getPrototypeOf") -DEF(setPrototypeOf, "setPrototypeOf") -DEF(isExtensible, "isExtensible") -DEF(preventExtensions, "preventExtensions") -DEF(has, "has") -DEF(deleteProperty, "deleteProperty") -DEF(defineProperty, "defineProperty") -DEF(getOwnPropertyDescriptor, "getOwnPropertyDescriptor") -DEF(ownKeys, "ownKeys") -DEF(add, "add") -DEF(done, "done") -DEF(next, "next") -DEF(values, "values") -DEF(source, "source") -DEF(flags, "flags") -DEF(global, "global") -DEF(unicode, "unicode") -DEF(raw, "raw") -DEF(new_target, "new.target") -DEF(this_active_func, "this.active_func") -DEF(home_object, "") -DEF(computed_field, "") -DEF(static_computed_field, "") /* must come after computed_fields */ -DEF(class_fields_init, "") -DEF(brand, "") -DEF(hash_constructor, "#constructor") -DEF(as, "as") -DEF(from, "from") -DEF(meta, "meta") -DEF(_default_, "*default*") -DEF(_star_, "*") -DEF(Module, "Module") -DEF(then, "then") -DEF(resolve, "resolve") -DEF(reject, "reject") -DEF(promise, "promise") -DEF(proxy, "proxy") -DEF(revoke, "revoke") -DEF(async, "async") -DEF(exec, "exec") -DEF(groups, "groups") -DEF(indices, "indices") -DEF(status, "status") -DEF(reason, "reason") -DEF(globalThis, "globalThis") -DEF(bigint, "bigint") -DEF(minus_zero, "-0") -DEF(Infinity, "Infinity") -DEF(minus_Infinity, "-Infinity") -DEF(NaN, "NaN") -DEF(hasIndices, "hasIndices") -DEF(ignoreCase, "ignoreCase") -DEF(multiline, "multiline") -DEF(dotAll, "dotAll") -DEF(sticky, "sticky") -DEF(unicodeSets, "unicodeSets") -/* the following 3 atoms are only used with CONFIG_ATOMICS */ -DEF(not_equal, "not-equal") -DEF(timed_out, "timed-out") -DEF(ok, "ok") -/* */ -DEF(toJSON, "toJSON") -/* class names */ -DEF(Object, "Object") -DEF(Array, "Array") -DEF(Error, "Error") -DEF(Number, "Number") -DEF(String, "String") -DEF(Boolean, "Boolean") -DEF(Symbol, "Symbol") -DEF(Arguments, "Arguments") -DEF(Math, "Math") -DEF(JSON, "JSON") -DEF(Date, "Date") -DEF(Function, "Function") -DEF(GeneratorFunction, "GeneratorFunction") -DEF(ForInIterator, "ForInIterator") -DEF(RegExp, "RegExp") -DEF(ArrayBuffer, "ArrayBuffer") -DEF(SharedArrayBuffer, "SharedArrayBuffer") -/* must keep same order as class IDs for typed arrays */ -DEF(Uint8ClampedArray, "Uint8ClampedArray") -DEF(Int8Array, "Int8Array") -DEF(Uint8Array, "Uint8Array") -DEF(Int16Array, "Int16Array") -DEF(Uint16Array, "Uint16Array") -DEF(Int32Array, "Int32Array") -DEF(Uint32Array, "Uint32Array") -DEF(BigInt64Array, "BigInt64Array") -DEF(BigUint64Array, "BigUint64Array") -DEF(Float16Array, "Float16Array") -DEF(Float32Array, "Float32Array") -DEF(Float64Array, "Float64Array") -DEF(DataView, "DataView") -DEF(BigInt, "BigInt") -DEF(WeakRef, "WeakRef") -DEF(FinalizationRegistry, "FinalizationRegistry") -DEF(Map, "Map") -DEF(Set, "Set") /* Map + 1 */ -DEF(WeakMap, "WeakMap") /* Map + 2 */ -DEF(WeakSet, "WeakSet") /* Map + 3 */ -DEF(Map_Iterator, "Map Iterator") -DEF(Set_Iterator, "Set Iterator") -DEF(Array_Iterator, "Array Iterator") -DEF(String_Iterator, "String Iterator") -DEF(RegExp_String_Iterator, "RegExp String Iterator") -DEF(Generator, "Generator") -DEF(Proxy, "Proxy") -DEF(Promise, "Promise") -DEF(PromiseResolveFunction, "PromiseResolveFunction") -DEF(PromiseRejectFunction, "PromiseRejectFunction") -DEF(AsyncFunction, "AsyncFunction") -DEF(AsyncFunctionResolve, "AsyncFunctionResolve") -DEF(AsyncFunctionReject, "AsyncFunctionReject") -DEF(AsyncGeneratorFunction, "AsyncGeneratorFunction") -DEF(AsyncGenerator, "AsyncGenerator") -DEF(EvalError, "EvalError") -DEF(RangeError, "RangeError") -DEF(ReferenceError, "ReferenceError") -DEF(SyntaxError, "SyntaxError") -DEF(TypeError, "TypeError") -DEF(URIError, "URIError") -DEF(InternalError, "InternalError") -/* private symbols */ -DEF(Private_brand, "") -/* symbols */ -DEF(Symbol_toPrimitive, "Symbol.toPrimitive") -DEF(Symbol_iterator, "Symbol.iterator") -DEF(Symbol_match, "Symbol.match") -DEF(Symbol_matchAll, "Symbol.matchAll") -DEF(Symbol_replace, "Symbol.replace") -DEF(Symbol_search, "Symbol.search") -DEF(Symbol_split, "Symbol.split") -DEF(Symbol_toStringTag, "Symbol.toStringTag") -DEF(Symbol_isConcatSpreadable, "Symbol.isConcatSpreadable") -DEF(Symbol_hasInstance, "Symbol.hasInstance") -DEF(Symbol_species, "Symbol.species") -DEF(Symbol_unscopables, "Symbol.unscopables") -DEF(Symbol_asyncIterator, "Symbol.asyncIterator") - -#endif /* DEF */ diff --git a/packages/javascript/javascript_android/cxx/quickjs/quickjs-libc.c b/packages/javascript/javascript_android/cxx/quickjs/quickjs-libc.c deleted file mode 100644 index 54a7a15..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/quickjs-libc.c +++ /dev/null @@ -1,4342 +0,0 @@ -/* - * QuickJS C library - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(_WIN32) -#include -#include -#include -#else -#include -#include -#include -#include - -#if defined(__FreeBSD__) -extern char **environ; -#endif - -#if defined(__APPLE__) || defined(__FreeBSD__) -typedef sig_t sighandler_t; -#endif - -#if defined(__APPLE__) -#if !defined(environ) -#include -#define environ (*_NSGetEnviron()) -#endif -#endif /* __APPLE__ */ - -#endif - -/* enable the os.Worker API. It relies on POSIX threads */ -#define USE_WORKER - -#ifdef USE_WORKER -#include -#include -#endif - -#include "cutils.h" -#include "list.h" -#include "quickjs-libc.h" - -#if !defined(PATH_MAX) -#define PATH_MAX 4096 -#endif - -/* TODO: - - add socket calls -*/ - -typedef struct { - struct list_head link; - int fd; - JSValue rw_func[2]; -} JSOSRWHandler; - -typedef struct { - struct list_head link; - int sig_num; - JSValue func; -} JSOSSignalHandler; - -typedef struct { - struct list_head link; - int timer_id; - int64_t timeout; - JSValue func; -} JSOSTimer; - -typedef struct { - struct list_head link; - uint8_t *data; - size_t data_len; - /* list of SharedArrayBuffers, necessary to free the message */ - uint8_t **sab_tab; - size_t sab_tab_len; -} JSWorkerMessage; - -typedef struct JSWaker { -#ifdef _WIN32 - HANDLE handle; -#else - int read_fd; - int write_fd; -#endif -} JSWaker; - -typedef struct { - int ref_count; -#ifdef USE_WORKER - pthread_mutex_t mutex; -#endif - struct list_head msg_queue; /* list of JSWorkerMessage.link */ - JSWaker waker; -} JSWorkerMessagePipe; - -typedef struct { - struct list_head link; - JSWorkerMessagePipe *recv_pipe; - JSValue on_message_func; -} JSWorkerMessageHandler; - -typedef struct { - struct list_head link; - JSValue promise; - JSValue reason; -} JSRejectedPromiseEntry; - -typedef struct JSThreadState { - struct list_head os_rw_handlers; /* list of JSOSRWHandler.link */ - struct list_head os_signal_handlers; /* list JSOSSignalHandler.link */ - struct list_head os_timers; /* list of JSOSTimer.link */ - struct list_head port_list; /* list of JSWorkerMessageHandler.link */ - struct list_head rejected_promise_list; /* list of JSRejectedPromiseEntry.link */ - int eval_script_recurse; /* only used in the main thread */ - int next_timer_id; /* for setTimeout() */ - /* not used in the main thread */ - JSWorkerMessagePipe *recv_pipe, *send_pipe; -} JSThreadState; - -static uint64_t os_pending_signals; -static int (*os_poll_func)(JSContext *ctx); - -static void js_std_dbuf_init(JSContext *ctx, DynBuf *s) -{ - dbuf_init2(s, JS_GetRuntime(ctx), (DynBufReallocFunc *)js_realloc_rt); -} - -static BOOL my_isdigit(int c) -{ - return (c >= '0' && c <= '9'); -} - -/* XXX: use 'o' and 'O' for object using JS_PrintValue() ? */ -static JSValue js_printf_internal(JSContext *ctx, - int argc, JSValueConst *argv, FILE *fp) -{ - char fmtbuf[32]; - uint8_t cbuf[UTF8_CHAR_LEN_MAX+1]; - JSValue res; - DynBuf dbuf; - const char *fmt_str = NULL; - const uint8_t *fmt, *fmt_end; - const uint8_t *p; - char *q; - int i, c, len, mod; - size_t fmt_len; - int32_t int32_arg; - int64_t int64_arg; - double double_arg; - const char *string_arg; - /* Use indirect call to dbuf_printf to prevent gcc warning */ - int (*dbuf_printf_fun)(DynBuf *s, const char *fmt, ...) = (void*)dbuf_printf; - - js_std_dbuf_init(ctx, &dbuf); - - if (argc > 0) { - fmt_str = JS_ToCStringLen(ctx, &fmt_len, argv[0]); - if (!fmt_str) - goto fail; - - i = 1; - fmt = (const uint8_t *)fmt_str; - fmt_end = fmt + fmt_len; - while (fmt < fmt_end) { - for (p = fmt; fmt < fmt_end && *fmt != '%'; fmt++) - continue; - dbuf_put(&dbuf, p, fmt - p); - if (fmt >= fmt_end) - break; - q = fmtbuf; - *q++ = *fmt++; /* copy '%' */ - - /* flags */ - for(;;) { - c = *fmt; - if (c == '0' || c == '#' || c == '+' || c == '-' || c == ' ' || - c == '\'') { - if (q >= fmtbuf + sizeof(fmtbuf) - 1) - goto invalid; - *q++ = c; - fmt++; - } else { - break; - } - } - /* width */ - if (*fmt == '*') { - if (i >= argc) - goto missing; - if (JS_ToInt32(ctx, &int32_arg, argv[i++])) - goto fail; - q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg); - fmt++; - } else { - while (my_isdigit(*fmt)) { - if (q >= fmtbuf + sizeof(fmtbuf) - 1) - goto invalid; - *q++ = *fmt++; - } - } - if (*fmt == '.') { - if (q >= fmtbuf + sizeof(fmtbuf) - 1) - goto invalid; - *q++ = *fmt++; - if (*fmt == '*') { - if (i >= argc) - goto missing; - if (JS_ToInt32(ctx, &int32_arg, argv[i++])) - goto fail; - q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg); - fmt++; - } else { - while (my_isdigit(*fmt)) { - if (q >= fmtbuf + sizeof(fmtbuf) - 1) - goto invalid; - *q++ = *fmt++; - } - } - } - - /* we only support the "l" modifier for 64 bit numbers */ - mod = ' '; - if (*fmt == 'l') { - mod = *fmt++; - } - - /* type */ - c = *fmt++; - if (q >= fmtbuf + sizeof(fmtbuf) - 1) - goto invalid; - *q++ = c; - *q = '\0'; - - switch (c) { - case 'c': - if (i >= argc) - goto missing; - if (JS_IsString(argv[i])) { - string_arg = JS_ToCString(ctx, argv[i++]); - if (!string_arg) - goto fail; - int32_arg = unicode_from_utf8((const uint8_t *)string_arg, UTF8_CHAR_LEN_MAX, &p); - JS_FreeCString(ctx, string_arg); - } else { - if (JS_ToInt32(ctx, &int32_arg, argv[i++])) - goto fail; - } - /* handle utf-8 encoding explicitly */ - if ((unsigned)int32_arg > 0x10FFFF) - int32_arg = 0xFFFD; - /* ignore conversion flags, width and precision */ - len = unicode_to_utf8(cbuf, int32_arg); - dbuf_put(&dbuf, cbuf, len); - break; - - case 'd': - case 'i': - case 'o': - case 'u': - case 'x': - case 'X': - if (i >= argc) - goto missing; - if (JS_ToInt64Ext(ctx, &int64_arg, argv[i++])) - goto fail; - if (mod == 'l') { - /* 64 bit number */ -#if defined(_WIN32) - if (q >= fmtbuf + sizeof(fmtbuf) - 3) - goto invalid; - q[2] = q[-1]; - q[-1] = 'I'; - q[0] = '6'; - q[1] = '4'; - q[3] = '\0'; - dbuf_printf_fun(&dbuf, fmtbuf, (int64_t)int64_arg); -#else - if (q >= fmtbuf + sizeof(fmtbuf) - 2) - goto invalid; - q[1] = q[-1]; - q[-1] = q[0] = 'l'; - q[2] = '\0'; - dbuf_printf_fun(&dbuf, fmtbuf, (long long)int64_arg); -#endif - } else { - dbuf_printf_fun(&dbuf, fmtbuf, (int)int64_arg); - } - break; - - case 's': - if (i >= argc) - goto missing; - /* XXX: handle strings containing null characters */ - string_arg = JS_ToCString(ctx, argv[i++]); - if (!string_arg) - goto fail; - dbuf_printf_fun(&dbuf, fmtbuf, string_arg); - JS_FreeCString(ctx, string_arg); - break; - - case 'e': - case 'f': - case 'g': - case 'a': - case 'E': - case 'F': - case 'G': - case 'A': - if (i >= argc) - goto missing; - if (JS_ToFloat64(ctx, &double_arg, argv[i++])) - goto fail; - dbuf_printf_fun(&dbuf, fmtbuf, double_arg); - break; - - case '%': - dbuf_putc(&dbuf, '%'); - break; - - default: - /* XXX: should support an extension mechanism */ - invalid: - JS_ThrowTypeError(ctx, "invalid conversion specifier in format string"); - goto fail; - missing: - JS_ThrowReferenceError(ctx, "missing argument for conversion specifier"); - goto fail; - } - } - JS_FreeCString(ctx, fmt_str); - } - if (dbuf.error) { - res = JS_ThrowOutOfMemory(ctx); - } else { - if (fp) { - len = fwrite(dbuf.buf, 1, dbuf.size, fp); - res = JS_NewInt32(ctx, len); - } else { - res = JS_NewStringLen(ctx, (char *)dbuf.buf, dbuf.size); - } - } - dbuf_free(&dbuf); - return res; - -fail: - JS_FreeCString(ctx, fmt_str); - dbuf_free(&dbuf); - return JS_EXCEPTION; -} - -uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename) -{ - FILE *f; - uint8_t *buf; - size_t buf_len; - long lret; - - f = fopen(filename, "rb"); - if (!f) - return NULL; - if (fseek(f, 0, SEEK_END) < 0) - goto fail; - lret = ftell(f); - if (lret < 0) - goto fail; - /* XXX: on Linux, ftell() return LONG_MAX for directories */ - if (lret == LONG_MAX) { - errno = EISDIR; - goto fail; - } - buf_len = lret; - if (fseek(f, 0, SEEK_SET) < 0) - goto fail; - if (ctx) - buf = js_malloc(ctx, buf_len + 1); - else - buf = malloc(buf_len + 1); - if (!buf) - goto fail; - if (fread(buf, 1, buf_len, f) != buf_len) { - errno = EIO; - if (ctx) - js_free(ctx, buf); - else - free(buf); - fail: - fclose(f); - return NULL; - } - buf[buf_len] = '\0'; - fclose(f); - *pbuf_len = buf_len; - return buf; -} - -/* load and evaluate a file */ -static JSValue js_loadScript(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - uint8_t *buf; - const char *filename; - JSValue ret; - size_t buf_len; - - filename = JS_ToCString(ctx, argv[0]); - if (!filename) - return JS_EXCEPTION; - buf = js_load_file(ctx, &buf_len, filename); - if (!buf) { - JS_ThrowReferenceError(ctx, "could not load '%s'", filename); - JS_FreeCString(ctx, filename); - return JS_EXCEPTION; - } - ret = JS_Eval(ctx, (char *)buf, buf_len, filename, - JS_EVAL_TYPE_GLOBAL); - js_free(ctx, buf); - JS_FreeCString(ctx, filename); - return ret; -} - -/* load a file as a UTF-8 encoded string */ -static JSValue js_std_loadFile(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - uint8_t *buf; - const char *filename; - JSValue ret; - size_t buf_len; - - filename = JS_ToCString(ctx, argv[0]); - if (!filename) - return JS_EXCEPTION; - buf = js_load_file(ctx, &buf_len, filename); - JS_FreeCString(ctx, filename); - if (!buf) - return JS_NULL; - ret = JS_NewStringLen(ctx, (char *)buf, buf_len); - js_free(ctx, buf); - return ret; -} - -typedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx, - const char *module_name); - - -#if defined(_WIN32) -static JSModuleDef *js_module_loader_so(JSContext *ctx, - const char *module_name) -{ - JS_ThrowReferenceError(ctx, "shared library modules are not supported yet"); - return NULL; -} -#else -static JSModuleDef *js_module_loader_so(JSContext *ctx, - const char *module_name) -{ - JSModuleDef *m; - void *hd; - JSInitModuleFunc *init; - char *filename; - - if (!strchr(module_name, '/')) { - /* must add a '/' so that the DLL is not searched in the - system library paths */ - filename = js_malloc(ctx, strlen(module_name) + 2 + 1); - if (!filename) - return NULL; - strcpy(filename, "./"); - strcpy(filename + 2, module_name); - } else { - filename = (char *)module_name; - } - - /* C module */ - hd = dlopen(filename, RTLD_NOW | RTLD_LOCAL); - if (filename != module_name) - js_free(ctx, filename); - if (!hd) { - JS_ThrowReferenceError(ctx, "could not load module filename '%s' as shared library", - module_name); - goto fail; - } - - init = dlsym(hd, "js_init_module"); - if (!init) { - JS_ThrowReferenceError(ctx, "could not load module filename '%s': js_init_module not found", - module_name); - goto fail; - } - - m = init(ctx, module_name); - if (!m) { - JS_ThrowReferenceError(ctx, "could not load module filename '%s': initialization error", - module_name); - fail: - if (hd) - dlclose(hd); - return NULL; - } - return m; -} -#endif /* !_WIN32 */ - -int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, - JS_BOOL use_realpath, JS_BOOL is_main) -{ - JSModuleDef *m; - char buf[PATH_MAX + 16]; - JSValue meta_obj; - JSAtom module_name_atom; - const char *module_name; - - assert(JS_VALUE_GET_TAG(func_val) == JS_TAG_MODULE); - m = JS_VALUE_GET_PTR(func_val); - - module_name_atom = JS_GetModuleName(ctx, m); - module_name = JS_AtomToCString(ctx, module_name_atom); - JS_FreeAtom(ctx, module_name_atom); - if (!module_name) - return -1; - if (!strchr(module_name, ':')) { - strcpy(buf, "file://"); -#if !defined(_WIN32) - /* realpath() cannot be used with modules compiled with qjsc - because the corresponding module source code is not - necessarily present */ - if (use_realpath) { - char *res = realpath(module_name, buf + strlen(buf)); - if (!res) { - JS_ThrowTypeError(ctx, "realpath failure"); - JS_FreeCString(ctx, module_name); - return -1; - } - } else -#endif - { - pstrcat(buf, sizeof(buf), module_name); - } - } else { - pstrcpy(buf, sizeof(buf), module_name); - } - JS_FreeCString(ctx, module_name); - - meta_obj = JS_GetImportMeta(ctx, m); - if (JS_IsException(meta_obj)) - return -1; - JS_DefinePropertyValueStr(ctx, meta_obj, "url", - JS_NewString(ctx, buf), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, meta_obj, "main", - JS_NewBool(ctx, is_main), - JS_PROP_C_W_E); - JS_FreeValue(ctx, meta_obj); - return 0; -} - -static int json_module_init(JSContext *ctx, JSModuleDef *m) -{ - JSValue val; - val = JS_GetModulePrivateValue(ctx, m); - JS_SetModuleExport(ctx, m, "default", val); - return 0; -} - -static JSModuleDef *create_json_module(JSContext *ctx, const char *module_name, JSValue val) -{ - JSModuleDef *m; - m = JS_NewCModule(ctx, module_name, json_module_init); - if (!m) { - JS_FreeValue(ctx, val); - return NULL; - } - /* only export the "default" symbol which will contain the JSON object */ - JS_AddModuleExport(ctx, m, "default"); - JS_SetModulePrivateValue(ctx, m, val); - return m; -} - -/* in order to conform with the specification, only the keys should be - tested and not the associated values. */ -int js_module_check_attributes(JSContext *ctx, void *opaque, - JSValueConst attributes) -{ - JSPropertyEnum *tab; - uint32_t i, len; - int ret; - const char *cstr; - size_t cstr_len; - - if (JS_GetOwnPropertyNames(ctx, &tab, &len, attributes, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK)) - return -1; - ret = 0; - for(i = 0; i < len; i++) { - cstr = JS_AtomToCStringLen(ctx, &cstr_len, tab[i].atom); - if (!cstr) { - ret = -1; - break; - } - if (!(cstr_len == 4 && !memcmp(cstr, "type", cstr_len))) { - JS_ThrowTypeError(ctx, "import attribute '%s' is not supported", cstr); - ret = -1; - } - JS_FreeCString(ctx, cstr); - if (ret) - break; - } - JS_FreePropertyEnum(ctx, tab, len); - return ret; -} - -/* return > 0 if the attributes indicate a JSON module */ -int js_module_test_json(JSContext *ctx, JSValueConst attributes) -{ - JSValue str; - const char *cstr; - size_t len; - BOOL res; - - if (JS_IsUndefined(attributes)) - return FALSE; - str = JS_GetPropertyStr(ctx, attributes, "type"); - if (!JS_IsString(str)) - return FALSE; - cstr = JS_ToCStringLen(ctx, &len, str); - JS_FreeValue(ctx, str); - if (!cstr) - return FALSE; - /* XXX: raise an error if unknown type ? */ - if (len == 4 && !memcmp(cstr, "json", len)) { - res = 1; - } else if (len == 5 && !memcmp(cstr, "json5", len)) { - res = 2; - } else { - res = 0; - } - JS_FreeCString(ctx, cstr); - return res; -} - -JSModuleDef *js_module_loader(JSContext *ctx, - const char *module_name, void *opaque, - JSValueConst attributes) -{ - JSModuleDef *m; - int res; - - if (has_suffix(module_name, ".so")) { - m = js_module_loader_so(ctx, module_name); - } else { - size_t buf_len; - uint8_t *buf; - - buf = js_load_file(ctx, &buf_len, module_name); - if (!buf) { - JS_ThrowReferenceError(ctx, "could not load module filename '%s'", - module_name); - return NULL; - } - res = js_module_test_json(ctx, attributes); - if (has_suffix(module_name, ".json") || res > 0) { - /* compile as JSON or JSON5 depending on "type" */ - JSValue val; - int flags; - if (res == 2) - flags = JS_PARSE_JSON_EXT; - else - flags = 0; - val = JS_ParseJSON2(ctx, (char *)buf, buf_len, module_name, flags); - js_free(ctx, buf); - if (JS_IsException(val)) - return NULL; - m = create_json_module(ctx, module_name, val); - if (!m) - return NULL; - } else { - JSValue func_val; - /* compile the module */ - func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, - JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); - js_free(ctx, buf); - if (JS_IsException(func_val)) - return NULL; - /* XXX: could propagate the exception */ - js_module_set_import_meta(ctx, func_val, TRUE, FALSE); - /* the module is already referenced, so we must free it */ - m = JS_VALUE_GET_PTR(func_val); - JS_FreeValue(ctx, func_val); - } - } - return m; -} - -static JSValue js_std_exit(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int status; - if (JS_ToInt32(ctx, &status, argv[0])) - status = -1; - exit(status); - return JS_UNDEFINED; -} - -static JSValue js_std_getenv(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *name, *str; - name = JS_ToCString(ctx, argv[0]); - if (!name) - return JS_EXCEPTION; - str = getenv(name); - JS_FreeCString(ctx, name); - if (!str) - return JS_UNDEFINED; - else - return JS_NewString(ctx, str); -} - -#if defined(_WIN32) -static void setenv(const char *name, const char *value, int overwrite) -{ - char *str; - size_t name_len, value_len; - name_len = strlen(name); - value_len = strlen(value); - str = malloc(name_len + 1 + value_len + 1); - memcpy(str, name, name_len); - str[name_len] = '='; - memcpy(str + name_len + 1, value, value_len); - str[name_len + 1 + value_len] = '\0'; - _putenv(str); - free(str); -} - -static void unsetenv(const char *name) -{ - setenv(name, "", TRUE); -} -#endif /* _WIN32 */ - -static JSValue js_std_setenv(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *name, *value; - name = JS_ToCString(ctx, argv[0]); - if (!name) - return JS_EXCEPTION; - value = JS_ToCString(ctx, argv[1]); - if (!value) { - JS_FreeCString(ctx, name); - return JS_EXCEPTION; - } - setenv(name, value, TRUE); - JS_FreeCString(ctx, name); - JS_FreeCString(ctx, value); - return JS_UNDEFINED; -} - -static JSValue js_std_unsetenv(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *name; - name = JS_ToCString(ctx, argv[0]); - if (!name) - return JS_EXCEPTION; - unsetenv(name); - JS_FreeCString(ctx, name); - return JS_UNDEFINED; -} - -/* return an object containing the list of the available environment - variables. */ -static JSValue js_std_getenviron(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - char **envp; - const char *name, *p, *value; - JSValue obj; - uint32_t idx; - size_t name_len; - JSAtom atom; - int ret; - - obj = JS_NewObject(ctx); - if (JS_IsException(obj)) - return JS_EXCEPTION; - envp = environ; - for(idx = 0; envp[idx] != NULL; idx++) { - name = envp[idx]; - p = strchr(name, '='); - name_len = p - name; - if (!p) - continue; - value = p + 1; - atom = JS_NewAtomLen(ctx, name, name_len); - if (atom == JS_ATOM_NULL) - goto fail; - ret = JS_DefinePropertyValue(ctx, obj, atom, JS_NewString(ctx, value), - JS_PROP_C_W_E); - JS_FreeAtom(ctx, atom); - if (ret < 0) - goto fail; - } - return obj; - fail: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue js_std_gc(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JS_RunGC(JS_GetRuntime(ctx)); - return JS_UNDEFINED; -} - -static int interrupt_handler(JSRuntime *rt, void *opaque) -{ - return (os_pending_signals >> SIGINT) & 1; -} - -static int get_bool_option(JSContext *ctx, BOOL *pbool, - JSValueConst obj, - const char *option) -{ - JSValue val; - val = JS_GetPropertyStr(ctx, obj, option); - if (JS_IsException(val)) - return -1; - if (!JS_IsUndefined(val)) { - *pbool = JS_ToBool(ctx, val); - } - JS_FreeValue(ctx, val); - return 0; -} - -static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - const char *str; - size_t len; - JSValue ret; - JSValueConst options_obj; - BOOL backtrace_barrier = FALSE; - BOOL is_async = FALSE; - int flags; - - if (argc >= 2) { - options_obj = argv[1]; - if (get_bool_option(ctx, &backtrace_barrier, options_obj, - "backtrace_barrier")) - return JS_EXCEPTION; - if (get_bool_option(ctx, &is_async, options_obj, - "async")) - return JS_EXCEPTION; - } - - str = JS_ToCStringLen(ctx, &len, argv[0]); - if (!str) - return JS_EXCEPTION; - if (!ts->recv_pipe && ++ts->eval_script_recurse == 1) { - /* install the interrupt handler */ - JS_SetInterruptHandler(JS_GetRuntime(ctx), interrupt_handler, NULL); - } - flags = JS_EVAL_TYPE_GLOBAL; - if (backtrace_barrier) - flags |= JS_EVAL_FLAG_BACKTRACE_BARRIER; - if (is_async) - flags |= JS_EVAL_FLAG_ASYNC; - ret = JS_Eval(ctx, str, len, "", flags); - JS_FreeCString(ctx, str); - if (!ts->recv_pipe && --ts->eval_script_recurse == 0) { - /* remove the interrupt handler */ - JS_SetInterruptHandler(JS_GetRuntime(ctx), NULL, NULL); - os_pending_signals &= ~((uint64_t)1 << SIGINT); - /* convert the uncatchable "interrupted" error into a normal error - so that it can be caught by the REPL */ - if (JS_IsException(ret)) - JS_SetUncatchableException(ctx, FALSE); - } - return ret; -} - -static JSClassID js_std_file_class_id; - -typedef struct { - FILE *f; - BOOL close_in_finalizer; - BOOL is_popen; -} JSSTDFile; - -static void js_std_file_finalizer(JSRuntime *rt, JSValue val) -{ - JSSTDFile *s = JS_GetOpaque(val, js_std_file_class_id); - if (s) { - if (s->f && s->close_in_finalizer) { - if (s->is_popen) - pclose(s->f); - else - fclose(s->f); - } - js_free_rt(rt, s); - } -} - -static ssize_t js_get_errno(ssize_t ret) -{ - if (ret == -1) - ret = -errno; - return ret; -} - -static JSValue js_std_strerror(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int err; - if (JS_ToInt32(ctx, &err, argv[0])) - return JS_EXCEPTION; - return JS_NewString(ctx, strerror(err)); -} - -static JSValue js_std_parseExtJSON(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj; - const char *str; - size_t len; - - str = JS_ToCStringLen(ctx, &len, argv[0]); - if (!str) - return JS_EXCEPTION; - obj = JS_ParseJSON2(ctx, str, len, "", JS_PARSE_JSON_EXT); - JS_FreeCString(ctx, str); - return obj; -} - -static JSValue js_new_std_file(JSContext *ctx, FILE *f, - BOOL close_in_finalizer, - BOOL is_popen) -{ - JSSTDFile *s; - JSValue obj; - obj = JS_NewObjectClass(ctx, js_std_file_class_id); - if (JS_IsException(obj)) - return obj; - s = js_mallocz(ctx, sizeof(*s)); - if (!s) { - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - s->close_in_finalizer = close_in_finalizer; - s->is_popen = is_popen; - s->f = f; - JS_SetOpaque(obj, s); - return obj; -} - -static void js_set_error_object(JSContext *ctx, JSValue obj, int err) -{ - if (!JS_IsUndefined(obj)) { - JS_SetPropertyStr(ctx, obj, "errno", JS_NewInt32(ctx, err)); - } -} - -static JSValue js_std_open(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *filename, *mode = NULL; - FILE *f; - int err; - - filename = JS_ToCString(ctx, argv[0]); - if (!filename) - goto fail; - mode = JS_ToCString(ctx, argv[1]); - if (!mode) - goto fail; - if (mode[strspn(mode, "rwa+b")] != '\0') { - JS_ThrowTypeError(ctx, "invalid file mode"); - goto fail; - } - - f = fopen(filename, mode); - if (!f) - err = errno; - else - err = 0; - if (argc >= 3) - js_set_error_object(ctx, argv[2], err); - JS_FreeCString(ctx, filename); - JS_FreeCString(ctx, mode); - if (!f) - return JS_NULL; - return js_new_std_file(ctx, f, TRUE, FALSE); - fail: - JS_FreeCString(ctx, filename); - JS_FreeCString(ctx, mode); - return JS_EXCEPTION; -} - -static JSValue js_std_popen(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *filename, *mode = NULL; - FILE *f; - int err; - - filename = JS_ToCString(ctx, argv[0]); - if (!filename) - goto fail; - mode = JS_ToCString(ctx, argv[1]); - if (!mode) - goto fail; - if (mode[strspn(mode, "rw")] != '\0') { - JS_ThrowTypeError(ctx, "invalid file mode"); - goto fail; - } - - f = popen(filename, mode); - if (!f) - err = errno; - else - err = 0; - if (argc >= 3) - js_set_error_object(ctx, argv[2], err); - JS_FreeCString(ctx, filename); - JS_FreeCString(ctx, mode); - if (!f) - return JS_NULL; - return js_new_std_file(ctx, f, TRUE, TRUE); - fail: - JS_FreeCString(ctx, filename); - JS_FreeCString(ctx, mode); - return JS_EXCEPTION; -} - -static JSValue js_std_fdopen(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *mode; - FILE *f; - int fd, err; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - mode = JS_ToCString(ctx, argv[1]); - if (!mode) - goto fail; - if (mode[strspn(mode, "rwa+")] != '\0') { - JS_ThrowTypeError(ctx, "invalid file mode"); - goto fail; - } - - f = fdopen(fd, mode); - if (!f) - err = errno; - else - err = 0; - if (argc >= 3) - js_set_error_object(ctx, argv[2], err); - JS_FreeCString(ctx, mode); - if (!f) - return JS_NULL; - return js_new_std_file(ctx, f, TRUE, FALSE); - fail: - JS_FreeCString(ctx, mode); - return JS_EXCEPTION; -} - -static JSValue js_std_tmpfile(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f; - f = tmpfile(); - if (argc >= 1) - js_set_error_object(ctx, argv[0], f ? 0 : errno); - if (!f) - return JS_NULL; - return js_new_std_file(ctx, f, TRUE, FALSE); -} - -static JSValue js_std_sprintf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return js_printf_internal(ctx, argc, argv, NULL); -} - -static JSValue js_std_printf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return js_printf_internal(ctx, argc, argv, stdout); -} - -static FILE *js_std_file_get(JSContext *ctx, JSValueConst obj) -{ - JSSTDFile *s = JS_GetOpaque2(ctx, obj, js_std_file_class_id); - if (!s) - return NULL; - if (!s->f) { - JS_ThrowTypeError(ctx, "invalid file handle"); - return NULL; - } - return s->f; -} - -static JSValue js_std_file_puts(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - FILE *f; - int i; - const char *str; - size_t len; - - if (magic == 0) { - f = stdout; - } else { - f = js_std_file_get(ctx, this_val); - if (!f) - return JS_EXCEPTION; - } - - for(i = 0; i < argc; i++) { - str = JS_ToCStringLen(ctx, &len, argv[i]); - if (!str) - return JS_EXCEPTION; - fwrite(str, 1, len, f); - JS_FreeCString(ctx, str); - } - return JS_UNDEFINED; -} - -static JSValue js_std_file_close(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSSTDFile *s = JS_GetOpaque2(ctx, this_val, js_std_file_class_id); - int err; - if (!s) - return JS_EXCEPTION; - if (!s->f) - return JS_ThrowTypeError(ctx, "invalid file handle"); - if (s->is_popen) - err = js_get_errno(pclose(s->f)); - else - err = js_get_errno(fclose(s->f)); - s->f = NULL; - return JS_NewInt32(ctx, err); -} - -static JSValue js_std_file_printf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - if (!f) - return JS_EXCEPTION; - return js_printf_internal(ctx, argc, argv, f); -} - -static void js_print_value_write(void *opaque, const char *buf, size_t len) -{ - FILE *fo = opaque; - fwrite(buf, 1, len, fo); -} - -static JSValue js_std_file_printObject(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JS_PrintValue(ctx, js_print_value_write, stdout, argv[0], NULL); - return JS_UNDEFINED; -} - -static JSValue js_std_file_flush(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - if (!f) - return JS_EXCEPTION; - fflush(f); - return JS_UNDEFINED; -} - -static JSValue js_std_file_tell(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int is_bigint) -{ - FILE *f = js_std_file_get(ctx, this_val); - int64_t pos; - if (!f) - return JS_EXCEPTION; -#if defined(__linux__) || defined(__GLIBC__) - pos = ftello(f); -#else - pos = ftell(f); -#endif - if (is_bigint) - return JS_NewBigInt64(ctx, pos); - else - return JS_NewInt64(ctx, pos); -} - -static JSValue js_std_file_seek(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - int64_t pos; - int whence, ret; - if (!f) - return JS_EXCEPTION; - if (JS_ToInt64Ext(ctx, &pos, argv[0])) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &whence, argv[1])) - return JS_EXCEPTION; -#if defined(__linux__) || defined(__GLIBC__) - ret = fseeko(f, pos, whence); -#else - ret = fseek(f, pos, whence); -#endif - if (ret < 0) - ret = -errno; - return JS_NewInt32(ctx, ret); -} - -static JSValue js_std_file_eof(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - if (!f) - return JS_EXCEPTION; - return JS_NewBool(ctx, feof(f)); -} - -static JSValue js_std_file_error(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - if (!f) - return JS_EXCEPTION; - return JS_NewBool(ctx, ferror(f)); -} - -static JSValue js_std_file_clearerr(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - if (!f) - return JS_EXCEPTION; - clearerr(f); - return JS_UNDEFINED; -} - -static JSValue js_std_file_fileno(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - if (!f) - return JS_EXCEPTION; - return JS_NewInt32(ctx, fileno(f)); -} - -static JSValue js_std_file_read_write(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - FILE *f = js_std_file_get(ctx, this_val); - uint64_t pos, len; - size_t size, ret; - uint8_t *buf; - - if (!f) - return JS_EXCEPTION; - if (JS_ToIndex(ctx, &pos, argv[1])) - return JS_EXCEPTION; - if (JS_ToIndex(ctx, &len, argv[2])) - return JS_EXCEPTION; - buf = JS_GetArrayBuffer(ctx, &size, argv[0]); - if (!buf) - return JS_EXCEPTION; - if (pos + len > size) - return JS_ThrowRangeError(ctx, "read/write array buffer overflow"); - if (magic) - ret = fwrite(buf + pos, 1, len, f); - else - ret = fread(buf + pos, 1, len, f); - return JS_NewInt64(ctx, ret); -} - -/* XXX: could use less memory and go faster */ -static JSValue js_std_file_getline(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - int c; - DynBuf dbuf; - JSValue obj; - - if (!f) - return JS_EXCEPTION; - - js_std_dbuf_init(ctx, &dbuf); - for(;;) { - c = fgetc(f); - if (c == EOF) { - if (dbuf.size == 0) { - /* EOF */ - dbuf_free(&dbuf); - return JS_NULL; - } else { - break; - } - } - if (c == '\n') - break; - if (dbuf_putc(&dbuf, c)) { - dbuf_free(&dbuf); - return JS_ThrowOutOfMemory(ctx); - } - } - obj = JS_NewStringLen(ctx, (const char *)dbuf.buf, dbuf.size); - dbuf_free(&dbuf); - return obj; -} - -/* XXX: could use less memory and go faster */ -static JSValue js_std_file_readAsString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - int c; - DynBuf dbuf; - JSValue obj; - uint64_t max_size64; - size_t max_size; - JSValueConst max_size_val; - - if (!f) - return JS_EXCEPTION; - - if (argc >= 1) - max_size_val = argv[0]; - else - max_size_val = JS_UNDEFINED; - max_size = (size_t)-1; - if (!JS_IsUndefined(max_size_val)) { - if (JS_ToIndex(ctx, &max_size64, max_size_val)) - return JS_EXCEPTION; - if (max_size64 < max_size) - max_size = max_size64; - } - - js_std_dbuf_init(ctx, &dbuf); - while (max_size != 0) { - c = fgetc(f); - if (c == EOF) - break; - if (dbuf_putc(&dbuf, c)) { - dbuf_free(&dbuf); - return JS_EXCEPTION; - } - max_size--; - } - obj = JS_NewStringLen(ctx, (const char *)dbuf.buf, dbuf.size); - dbuf_free(&dbuf); - return obj; -} - -static JSValue js_std_file_getByte(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - if (!f) - return JS_EXCEPTION; - return JS_NewInt32(ctx, fgetc(f)); -} - -static JSValue js_std_file_putByte(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - int c; - if (!f) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &c, argv[0])) - return JS_EXCEPTION; - c = fputc(c, f); - return JS_NewInt32(ctx, c); -} - -/* urlGet */ - -#define URL_GET_PROGRAM "curl -s -i --" -#define URL_GET_BUF_SIZE 4096 - -static int http_get_header_line(FILE *f, char *buf, size_t buf_size, - DynBuf *dbuf) -{ - int c; - char *p; - - p = buf; - for(;;) { - c = fgetc(f); - if (c < 0) - return -1; - if ((p - buf) < buf_size - 1) - *p++ = c; - if (dbuf) - dbuf_putc(dbuf, c); - if (c == '\n') - break; - } - *p = '\0'; - return 0; -} - -static int http_get_status(const char *buf) -{ - const char *p = buf; - while (*p != ' ' && *p != '\0') - p++; - if (*p != ' ') - return 0; - while (*p == ' ') - p++; - return atoi(p); -} - -static JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *url; - DynBuf cmd_buf; - DynBuf data_buf_s, *data_buf = &data_buf_s; - DynBuf header_buf_s, *header_buf = &header_buf_s; - char *buf; - size_t i, len; - int status; - JSValue response = JS_UNDEFINED, ret_obj; - JSValueConst options_obj; - FILE *f; - BOOL binary_flag, full_flag; - - url = JS_ToCString(ctx, argv[0]); - if (!url) - return JS_EXCEPTION; - - binary_flag = FALSE; - full_flag = FALSE; - - if (argc >= 2) { - options_obj = argv[1]; - - if (get_bool_option(ctx, &binary_flag, options_obj, "binary")) - goto fail_obj; - - if (get_bool_option(ctx, &full_flag, options_obj, "full")) { - fail_obj: - JS_FreeCString(ctx, url); - return JS_EXCEPTION; - } - } - - js_std_dbuf_init(ctx, &cmd_buf); - dbuf_printf(&cmd_buf, "%s '", URL_GET_PROGRAM); - for(i = 0; url[i] != '\0'; i++) { - unsigned char c = url[i]; - switch (c) { - case '\'': - /* shell single quoted string does not support \' */ - dbuf_putstr(&cmd_buf, "'\\''"); - break; - case '[': case ']': case '{': case '}': case '\\': - /* prevent interpretation by curl as range or set specification */ - dbuf_putc(&cmd_buf, '\\'); - /* FALLTHROUGH */ - default: - dbuf_putc(&cmd_buf, c); - break; - } - } - JS_FreeCString(ctx, url); - dbuf_putstr(&cmd_buf, "'"); - dbuf_putc(&cmd_buf, '\0'); - if (dbuf_error(&cmd_buf)) { - dbuf_free(&cmd_buf); - return JS_EXCEPTION; - } - // printf("%s\n", (char *)cmd_buf.buf); - f = popen((char *)cmd_buf.buf, "r"); - dbuf_free(&cmd_buf); - if (!f) { - return JS_ThrowTypeError(ctx, "could not start curl"); - } - - js_std_dbuf_init(ctx, data_buf); - js_std_dbuf_init(ctx, header_buf); - - buf = js_malloc(ctx, URL_GET_BUF_SIZE); - if (!buf) - goto fail; - - /* get the HTTP status */ - if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, NULL) < 0) { - status = 0; - goto bad_header; - } - status = http_get_status(buf); - if (!full_flag && !(status >= 200 && status <= 299)) { - goto bad_header; - } - - /* wait until there is an empty line */ - for(;;) { - if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, header_buf) < 0) { - bad_header: - response = JS_NULL; - goto done; - } - if (!strcmp(buf, "\r\n")) - break; - } - if (dbuf_error(header_buf)) - goto fail; - header_buf->size -= 2; /* remove the trailing CRLF */ - - /* download the data */ - for(;;) { - len = fread(buf, 1, URL_GET_BUF_SIZE, f); - if (len == 0) - break; - dbuf_put(data_buf, (uint8_t *)buf, len); - } - if (dbuf_error(data_buf)) - goto fail; - if (binary_flag) { - response = JS_NewArrayBufferCopy(ctx, - data_buf->buf, data_buf->size); - } else { - response = JS_NewStringLen(ctx, (char *)data_buf->buf, data_buf->size); - } - if (JS_IsException(response)) - goto fail; - done: - js_free(ctx, buf); - buf = NULL; - pclose(f); - f = NULL; - dbuf_free(data_buf); - data_buf = NULL; - - if (full_flag) { - ret_obj = JS_NewObject(ctx); - if (JS_IsException(ret_obj)) - goto fail; - JS_DefinePropertyValueStr(ctx, ret_obj, "response", - response, - JS_PROP_C_W_E); - if (!JS_IsNull(response)) { - JS_DefinePropertyValueStr(ctx, ret_obj, "responseHeaders", - JS_NewStringLen(ctx, (char *)header_buf->buf, - header_buf->size), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, ret_obj, "status", - JS_NewInt32(ctx, status), - JS_PROP_C_W_E); - } - } else { - ret_obj = response; - } - dbuf_free(header_buf); - return ret_obj; - fail: - if (f) - pclose(f); - js_free(ctx, buf); - if (data_buf) - dbuf_free(data_buf); - if (header_buf) - dbuf_free(header_buf); - JS_FreeValue(ctx, response); - return JS_EXCEPTION; -} - -static JSClassDef js_std_file_class = { - "FILE", - .finalizer = js_std_file_finalizer, -}; - -static const JSCFunctionListEntry js_std_error_props[] = { - /* various errno values */ -#define DEF(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE ) - DEF(EINVAL), - DEF(EIO), - DEF(EACCES), - DEF(EEXIST), - DEF(ENOSPC), - DEF(ENOSYS), - DEF(EBUSY), - DEF(ENOENT), - DEF(EPERM), - DEF(EPIPE), - DEF(EBADF), -#undef DEF -}; - -static const JSCFunctionListEntry js_std_funcs[] = { - JS_CFUNC_DEF("exit", 1, js_std_exit ), - JS_CFUNC_DEF("gc", 0, js_std_gc ), - JS_CFUNC_DEF("evalScript", 1, js_evalScript ), - JS_CFUNC_DEF("loadScript", 1, js_loadScript ), - JS_CFUNC_DEF("getenv", 1, js_std_getenv ), - JS_CFUNC_DEF("setenv", 1, js_std_setenv ), - JS_CFUNC_DEF("unsetenv", 1, js_std_unsetenv ), - JS_CFUNC_DEF("getenviron", 1, js_std_getenviron ), - JS_CFUNC_DEF("urlGet", 1, js_std_urlGet ), - JS_CFUNC_DEF("loadFile", 1, js_std_loadFile ), - JS_CFUNC_DEF("strerror", 1, js_std_strerror ), - JS_CFUNC_DEF("parseExtJSON", 1, js_std_parseExtJSON ), - - /* FILE I/O */ - JS_CFUNC_DEF("open", 2, js_std_open ), - JS_CFUNC_DEF("popen", 2, js_std_popen ), - JS_CFUNC_DEF("fdopen", 2, js_std_fdopen ), - JS_CFUNC_DEF("tmpfile", 0, js_std_tmpfile ), - JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 0 ), - JS_CFUNC_DEF("printf", 1, js_std_printf ), - JS_CFUNC_DEF("sprintf", 1, js_std_sprintf ), - JS_PROP_INT32_DEF("SEEK_SET", SEEK_SET, JS_PROP_CONFIGURABLE ), - JS_PROP_INT32_DEF("SEEK_CUR", SEEK_CUR, JS_PROP_CONFIGURABLE ), - JS_PROP_INT32_DEF("SEEK_END", SEEK_END, JS_PROP_CONFIGURABLE ), - JS_OBJECT_DEF("Error", js_std_error_props, countof(js_std_error_props), JS_PROP_CONFIGURABLE), - JS_CFUNC_DEF("__printObject", 1, js_std_file_printObject ), -}; - -static const JSCFunctionListEntry js_std_file_proto_funcs[] = { - JS_CFUNC_DEF("close", 0, js_std_file_close ), - JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 1 ), - JS_CFUNC_DEF("printf", 1, js_std_file_printf ), - JS_CFUNC_DEF("flush", 0, js_std_file_flush ), - JS_CFUNC_MAGIC_DEF("tell", 0, js_std_file_tell, 0 ), - JS_CFUNC_MAGIC_DEF("tello", 0, js_std_file_tell, 1 ), - JS_CFUNC_DEF("seek", 2, js_std_file_seek ), - JS_CFUNC_DEF("eof", 0, js_std_file_eof ), - JS_CFUNC_DEF("fileno", 0, js_std_file_fileno ), - JS_CFUNC_DEF("error", 0, js_std_file_error ), - JS_CFUNC_DEF("clearerr", 0, js_std_file_clearerr ), - JS_CFUNC_MAGIC_DEF("read", 3, js_std_file_read_write, 0 ), - JS_CFUNC_MAGIC_DEF("write", 3, js_std_file_read_write, 1 ), - JS_CFUNC_DEF("getline", 0, js_std_file_getline ), - JS_CFUNC_DEF("readAsString", 0, js_std_file_readAsString ), - JS_CFUNC_DEF("getByte", 0, js_std_file_getByte ), - JS_CFUNC_DEF("putByte", 1, js_std_file_putByte ), - /* setvbuf, ... */ -}; - -static int js_std_init(JSContext *ctx, JSModuleDef *m) -{ - JSValue proto; - - /* FILE class */ - /* the class ID is created once */ - JS_NewClassID(&js_std_file_class_id); - /* the class is created once per runtime */ - JS_NewClass(JS_GetRuntime(ctx), js_std_file_class_id, &js_std_file_class); - proto = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, proto, js_std_file_proto_funcs, - countof(js_std_file_proto_funcs)); - JS_SetClassProto(ctx, js_std_file_class_id, proto); - - JS_SetModuleExportList(ctx, m, js_std_funcs, - countof(js_std_funcs)); - JS_SetModuleExport(ctx, m, "in", js_new_std_file(ctx, stdin, FALSE, FALSE)); - JS_SetModuleExport(ctx, m, "out", js_new_std_file(ctx, stdout, FALSE, FALSE)); - JS_SetModuleExport(ctx, m, "err", js_new_std_file(ctx, stderr, FALSE, FALSE)); - return 0; -} - -JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name) -{ - JSModuleDef *m; - m = JS_NewCModule(ctx, module_name, js_std_init); - if (!m) - return NULL; - JS_AddModuleExportList(ctx, m, js_std_funcs, countof(js_std_funcs)); - JS_AddModuleExport(ctx, m, "in"); - JS_AddModuleExport(ctx, m, "out"); - JS_AddModuleExport(ctx, m, "err"); - return m; -} - -/**********************************************************/ -/* 'os' object */ - -static JSValue js_os_open(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *filename; - int flags, mode, ret; - - filename = JS_ToCString(ctx, argv[0]); - if (!filename) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &flags, argv[1])) - goto fail; - if (argc >= 3 && !JS_IsUndefined(argv[2])) { - if (JS_ToInt32(ctx, &mode, argv[2])) { - fail: - JS_FreeCString(ctx, filename); - return JS_EXCEPTION; - } - } else { - mode = 0666; - } -#if defined(_WIN32) - /* force binary mode by default */ - if (!(flags & O_TEXT)) - flags |= O_BINARY; -#endif - ret = js_get_errno(open(filename, flags, mode)); - JS_FreeCString(ctx, filename); - return JS_NewInt32(ctx, ret); -} - -static JSValue js_os_close(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int fd, ret; - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - ret = js_get_errno(close(fd)); - return JS_NewInt32(ctx, ret); -} - -static JSValue js_os_seek(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int fd, whence; - int64_t pos, ret; - BOOL is_bigint; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - is_bigint = JS_IsBigInt(ctx, argv[1]); - if (JS_ToInt64Ext(ctx, &pos, argv[1])) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &whence, argv[2])) - return JS_EXCEPTION; - ret = lseek(fd, pos, whence); - if (ret == -1) - ret = -errno; - if (is_bigint) - return JS_NewBigInt64(ctx, ret); - else - return JS_NewInt64(ctx, ret); -} - -static JSValue js_os_read_write(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - int fd; - uint64_t pos, len; - size_t size; - ssize_t ret; - uint8_t *buf; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - if (JS_ToIndex(ctx, &pos, argv[2])) - return JS_EXCEPTION; - if (JS_ToIndex(ctx, &len, argv[3])) - return JS_EXCEPTION; - buf = JS_GetArrayBuffer(ctx, &size, argv[1]); - if (!buf) - return JS_EXCEPTION; - if (pos + len > size) - return JS_ThrowRangeError(ctx, "read/write array buffer overflow"); - if (magic) - ret = js_get_errno(write(fd, buf + pos, len)); - else - ret = js_get_errno(read(fd, buf + pos, len)); - return JS_NewInt64(ctx, ret); -} - -static JSValue js_os_isatty(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int fd; - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - return JS_NewBool(ctx, isatty(fd)); -} - -#if defined(_WIN32) -static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int fd; - HANDLE handle; - CONSOLE_SCREEN_BUFFER_INFO info; - JSValue obj; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - handle = (HANDLE)_get_osfhandle(fd); - - if (!GetConsoleScreenBufferInfo(handle, &info)) - return JS_NULL; - obj = JS_NewArray(ctx); - if (JS_IsException(obj)) - return obj; - JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, info.dwSize.X), JS_PROP_C_W_E); - JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, info.dwSize.Y), JS_PROP_C_W_E); - return obj; -} - -/* Windows 10 built-in VT100 emulation */ -#define __ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 -#define __ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200 - -static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int fd; - HANDLE handle; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - handle = (HANDLE)_get_osfhandle(fd); - SetConsoleMode(handle, ENABLE_WINDOW_INPUT | __ENABLE_VIRTUAL_TERMINAL_INPUT); - _setmode(fd, _O_BINARY); - if (fd == 0) { - handle = (HANDLE)_get_osfhandle(1); /* corresponding output */ - SetConsoleMode(handle, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | __ENABLE_VIRTUAL_TERMINAL_PROCESSING); - } - return JS_UNDEFINED; -} -#else -static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int fd; - struct winsize ws; - JSValue obj; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - if (ioctl(fd, TIOCGWINSZ, &ws) == 0 && - ws.ws_col >= 4 && ws.ws_row >= 4) { - obj = JS_NewArray(ctx); - if (JS_IsException(obj)) - return obj; - JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, ws.ws_col), JS_PROP_C_W_E); - JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, ws.ws_row), JS_PROP_C_W_E); - return obj; - } else { - return JS_NULL; - } -} - -static struct termios oldtty; - -static void term_exit(void) -{ - tcsetattr(0, TCSANOW, &oldtty); -} - -/* XXX: should add a way to go back to normal mode */ -static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - struct termios tty; - int fd; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - - memset(&tty, 0, sizeof(tty)); - tcgetattr(fd, &tty); - oldtty = tty; - - tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP - |INLCR|IGNCR|ICRNL|IXON); - tty.c_oflag |= OPOST; - tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); - tty.c_cflag &= ~(CSIZE|PARENB); - tty.c_cflag |= CS8; - tty.c_cc[VMIN] = 1; - tty.c_cc[VTIME] = 0; - - tcsetattr(fd, TCSANOW, &tty); - - atexit(term_exit); - return JS_UNDEFINED; -} - -#endif /* !_WIN32 */ - -static JSValue js_os_remove(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *filename; - int ret; - - filename = JS_ToCString(ctx, argv[0]); - if (!filename) - return JS_EXCEPTION; -#if defined(_WIN32) - { - struct stat st; - if (stat(filename, &st) == 0 && S_ISDIR(st.st_mode)) { - ret = rmdir(filename); - } else { - ret = unlink(filename); - } - } -#else - ret = remove(filename); -#endif - ret = js_get_errno(ret); - JS_FreeCString(ctx, filename); - return JS_NewInt32(ctx, ret); -} - -static JSValue js_os_rename(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *oldpath, *newpath; - int ret; - - oldpath = JS_ToCString(ctx, argv[0]); - if (!oldpath) - return JS_EXCEPTION; - newpath = JS_ToCString(ctx, argv[1]); - if (!newpath) { - JS_FreeCString(ctx, oldpath); - return JS_EXCEPTION; - } - ret = js_get_errno(rename(oldpath, newpath)); - JS_FreeCString(ctx, oldpath); - JS_FreeCString(ctx, newpath); - return JS_NewInt32(ctx, ret); -} - -static BOOL is_main_thread(JSRuntime *rt) -{ - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - return !ts->recv_pipe; -} - -static JSOSRWHandler *find_rh(JSThreadState *ts, int fd) -{ - JSOSRWHandler *rh; - struct list_head *el; - - list_for_each(el, &ts->os_rw_handlers) { - rh = list_entry(el, JSOSRWHandler, link); - if (rh->fd == fd) - return rh; - } - return NULL; -} - -static void free_rw_handler(JSRuntime *rt, JSOSRWHandler *rh) -{ - int i; - list_del(&rh->link); - for(i = 0; i < 2; i++) { - JS_FreeValueRT(rt, rh->rw_func[i]); - } - js_free_rt(rt, rh); -} - -static JSValue js_os_setReadHandler(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - JSOSRWHandler *rh; - int fd; - JSValueConst func; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - func = argv[1]; - if (JS_IsNull(func)) { - rh = find_rh(ts, fd); - if (rh) { - JS_FreeValue(ctx, rh->rw_func[magic]); - rh->rw_func[magic] = JS_NULL; - if (JS_IsNull(rh->rw_func[0]) && - JS_IsNull(rh->rw_func[1])) { - /* remove the entry */ - free_rw_handler(JS_GetRuntime(ctx), rh); - } - } - } else { - if (!JS_IsFunction(ctx, func)) - return JS_ThrowTypeError(ctx, "not a function"); - rh = find_rh(ts, fd); - if (!rh) { - rh = js_mallocz(ctx, sizeof(*rh)); - if (!rh) - return JS_EXCEPTION; - rh->fd = fd; - rh->rw_func[0] = JS_NULL; - rh->rw_func[1] = JS_NULL; - list_add_tail(&rh->link, &ts->os_rw_handlers); - } - JS_FreeValue(ctx, rh->rw_func[magic]); - rh->rw_func[magic] = JS_DupValue(ctx, func); - } - return JS_UNDEFINED; -} - -static JSOSSignalHandler *find_sh(JSThreadState *ts, int sig_num) -{ - JSOSSignalHandler *sh; - struct list_head *el; - list_for_each(el, &ts->os_signal_handlers) { - sh = list_entry(el, JSOSSignalHandler, link); - if (sh->sig_num == sig_num) - return sh; - } - return NULL; -} - -static void free_sh(JSRuntime *rt, JSOSSignalHandler *sh) -{ - list_del(&sh->link); - JS_FreeValueRT(rt, sh->func); - js_free_rt(rt, sh); -} - -static void os_signal_handler(int sig_num) -{ - os_pending_signals |= ((uint64_t)1 << sig_num); -} - -#if defined(_WIN32) -typedef void (*sighandler_t)(int sig_num); -#endif - -static JSValue js_os_signal(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - JSOSSignalHandler *sh; - uint32_t sig_num; - JSValueConst func; - sighandler_t handler; - - if (!is_main_thread(rt)) - return JS_ThrowTypeError(ctx, "signal handler can only be set in the main thread"); - - if (JS_ToUint32(ctx, &sig_num, argv[0])) - return JS_EXCEPTION; - if (sig_num >= 64) - return JS_ThrowRangeError(ctx, "invalid signal number"); - func = argv[1]; - /* func = null: SIG_DFL, func = undefined, SIG_IGN */ - if (JS_IsNull(func) || JS_IsUndefined(func)) { - sh = find_sh(ts, sig_num); - if (sh) { - free_sh(JS_GetRuntime(ctx), sh); - } - if (JS_IsNull(func)) - handler = SIG_DFL; - else - handler = SIG_IGN; - signal(sig_num, handler); - } else { - if (!JS_IsFunction(ctx, func)) - return JS_ThrowTypeError(ctx, "not a function"); - sh = find_sh(ts, sig_num); - if (!sh) { - sh = js_mallocz(ctx, sizeof(*sh)); - if (!sh) - return JS_EXCEPTION; - sh->sig_num = sig_num; - list_add_tail(&sh->link, &ts->os_signal_handlers); - } - JS_FreeValue(ctx, sh->func); - sh->func = JS_DupValue(ctx, func); - signal(sig_num, os_signal_handler); - } - return JS_UNDEFINED; -} - -#if defined(__linux__) || defined(__APPLE__) -static int64_t get_time_ms(void) -{ - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (uint64_t)ts.tv_sec * 1000 + (ts.tv_nsec / 1000000); -} - -static int64_t get_time_ns(void) -{ - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (uint64_t)ts.tv_sec * 1000000000 + ts.tv_nsec; -} -#else -/* more portable, but does not work if the date is updated */ -static int64_t get_time_ms(void) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000); -} - -static int64_t get_time_ns(void) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return (int64_t)tv.tv_sec * 1000000000 + (tv.tv_usec * 1000); -} -#endif - -static JSValue js_os_now(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv) -{ - return JS_NewFloat64(ctx, (double)get_time_ns() / 1e6); -} - -static void free_timer(JSRuntime *rt, JSOSTimer *th) -{ - list_del(&th->link); - JS_FreeValueRT(rt, th->func); - js_free_rt(rt, th); -} - -static JSValue js_os_setTimeout(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - int64_t delay; - JSValueConst func; - JSOSTimer *th; - - func = argv[0]; - if (!JS_IsFunction(ctx, func)) - return JS_ThrowTypeError(ctx, "not a function"); - if (JS_ToInt64(ctx, &delay, argv[1])) - return JS_EXCEPTION; - th = js_mallocz(ctx, sizeof(*th)); - if (!th) - return JS_EXCEPTION; - th->timer_id = ts->next_timer_id; - if (ts->next_timer_id == INT32_MAX) - ts->next_timer_id = 1; - else - ts->next_timer_id++; - th->timeout = get_time_ms() + delay; - th->func = JS_DupValue(ctx, func); - list_add_tail(&th->link, &ts->os_timers); - return JS_NewInt32(ctx, th->timer_id); -} - -static JSOSTimer *find_timer_by_id(JSThreadState *ts, int timer_id) -{ - struct list_head *el; - if (timer_id <= 0) - return NULL; - list_for_each(el, &ts->os_timers) { - JSOSTimer *th = list_entry(el, JSOSTimer, link); - if (th->timer_id == timer_id) - return th; - } - return NULL; -} - -static JSValue js_os_clearTimeout(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - JSOSTimer *th; - int timer_id; - - if (JS_ToInt32(ctx, &timer_id, argv[0])) - return JS_EXCEPTION; - th = find_timer_by_id(ts, timer_id); - if (!th) - return JS_UNDEFINED; - free_timer(rt, th); - return JS_UNDEFINED; -} - -/* return a promise */ -static JSValue js_os_sleepAsync(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - int64_t delay; - JSOSTimer *th; - JSValue promise, resolving_funcs[2]; - - if (JS_ToInt64(ctx, &delay, argv[0])) - return JS_EXCEPTION; - promise = JS_NewPromiseCapability(ctx, resolving_funcs); - if (JS_IsException(promise)) - return JS_EXCEPTION; - - th = js_mallocz(ctx, sizeof(*th)); - if (!th) { - JS_FreeValue(ctx, promise); - JS_FreeValue(ctx, resolving_funcs[0]); - JS_FreeValue(ctx, resolving_funcs[1]); - return JS_EXCEPTION; - } - th->timer_id = -1; - th->timeout = get_time_ms() + delay; - th->func = JS_DupValue(ctx, resolving_funcs[0]); - list_add_tail(&th->link, &ts->os_timers); - JS_FreeValue(ctx, resolving_funcs[0]); - JS_FreeValue(ctx, resolving_funcs[1]); - return promise; -} - -static void call_handler(JSContext *ctx, JSValueConst func) -{ - JSValue ret, func1; - /* 'func' might be destroyed when calling itself (if it frees the - handler), so must take extra care */ - func1 = JS_DupValue(ctx, func); - ret = JS_Call(ctx, func1, JS_UNDEFINED, 0, NULL); - JS_FreeValue(ctx, func1); - if (JS_IsException(ret)) - js_std_dump_error(ctx); - JS_FreeValue(ctx, ret); -} - -#ifdef USE_WORKER - -#ifdef _WIN32 - -static int js_waker_init(JSWaker *w) -{ - w->handle = CreateEvent(NULL, TRUE, FALSE, NULL); - return w->handle ? 0 : -1; -} - -static void js_waker_signal(JSWaker *w) -{ - SetEvent(w->handle); -} - -static void js_waker_clear(JSWaker *w) -{ - ResetEvent(w->handle); -} - -static void js_waker_close(JSWaker *w) -{ - CloseHandle(w->handle); - w->handle = INVALID_HANDLE_VALUE; -} - -#else // !_WIN32 - -static int js_waker_init(JSWaker *w) -{ - int fds[2]; - - if (pipe(fds) < 0) - return -1; - w->read_fd = fds[0]; - w->write_fd = fds[1]; - return 0; -} - -static void js_waker_signal(JSWaker *w) -{ - int ret; - - for(;;) { - ret = write(w->write_fd, "", 1); - if (ret == 1) - break; - if (ret < 0 && (errno != EAGAIN || errno != EINTR)) - break; - } -} - -static void js_waker_clear(JSWaker *w) -{ - uint8_t buf[16]; - int ret; - - for(;;) { - ret = read(w->read_fd, buf, sizeof(buf)); - if (ret >= 0) - break; - if (errno != EAGAIN && errno != EINTR) - break; - } -} - -static void js_waker_close(JSWaker *w) -{ - close(w->read_fd); - close(w->write_fd); - w->read_fd = -1; - w->write_fd = -1; -} - -#endif // _WIN32 - -static void js_free_message(JSWorkerMessage *msg); - -/* return 1 if a message was handled, 0 if no message */ -static int handle_posted_message(JSRuntime *rt, JSContext *ctx, - JSWorkerMessageHandler *port) -{ - JSWorkerMessagePipe *ps = port->recv_pipe; - int ret; - struct list_head *el; - JSWorkerMessage *msg; - JSValue obj, data_obj, func, retval; - - pthread_mutex_lock(&ps->mutex); - if (!list_empty(&ps->msg_queue)) { - el = ps->msg_queue.next; - msg = list_entry(el, JSWorkerMessage, link); - - /* remove the message from the queue */ - list_del(&msg->link); - - if (list_empty(&ps->msg_queue)) - js_waker_clear(&ps->waker); - - pthread_mutex_unlock(&ps->mutex); - - data_obj = JS_ReadObject(ctx, msg->data, msg->data_len, - JS_READ_OBJ_SAB | JS_READ_OBJ_REFERENCE); - - js_free_message(msg); - - if (JS_IsException(data_obj)) - goto fail; - obj = JS_NewObject(ctx); - if (JS_IsException(obj)) { - JS_FreeValue(ctx, data_obj); - goto fail; - } - JS_DefinePropertyValueStr(ctx, obj, "data", data_obj, JS_PROP_C_W_E); - - /* 'func' might be destroyed when calling itself (if it frees the - handler), so must take extra care */ - func = JS_DupValue(ctx, port->on_message_func); - retval = JS_Call(ctx, func, JS_UNDEFINED, 1, (JSValueConst *)&obj); - JS_FreeValue(ctx, obj); - JS_FreeValue(ctx, func); - if (JS_IsException(retval)) { - fail: - js_std_dump_error(ctx); - } else { - JS_FreeValue(ctx, retval); - } - ret = 1; - } else { - pthread_mutex_unlock(&ps->mutex); - ret = 0; - } - return ret; -} -#else -static int handle_posted_message(JSRuntime *rt, JSContext *ctx, - JSWorkerMessageHandler *port) -{ - return 0; -} -#endif /* !USE_WORKER */ - -#if defined(_WIN32) - -static int js_os_poll(JSContext *ctx) -{ - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - int min_delay, count; - int64_t cur_time, delay; - JSOSRWHandler *rh; - struct list_head *el; - HANDLE handles[MAXIMUM_WAIT_OBJECTS]; // 64 - - /* XXX: handle signals if useful */ - - if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers) && - list_empty(&ts->port_list)) { - return -1; /* no more events */ - } - - if (!list_empty(&ts->os_timers)) { - cur_time = get_time_ms(); - min_delay = 10000; - list_for_each(el, &ts->os_timers) { - JSOSTimer *th = list_entry(el, JSOSTimer, link); - delay = th->timeout - cur_time; - if (delay <= 0) { - JSValue func; - /* the timer expired */ - func = th->func; - th->func = JS_UNDEFINED; - free_timer(rt, th); - call_handler(ctx, func); - JS_FreeValue(ctx, func); - return 0; - } else if (delay < min_delay) { - min_delay = delay; - } - } - } else { - min_delay = -1; - } - - count = 0; - list_for_each(el, &ts->os_rw_handlers) { - rh = list_entry(el, JSOSRWHandler, link); - if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) { - handles[count++] = (HANDLE)_get_osfhandle(rh->fd); // stdin - if (count == (int)countof(handles)) - break; - } - } - - list_for_each(el, &ts->port_list) { - JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link); - if (JS_IsNull(port->on_message_func)) - continue; - handles[count++] = port->recv_pipe->waker.handle; - if (count == (int)countof(handles)) - break; - } - - if (count > 0) { - DWORD ret, timeout = INFINITE; - if (min_delay != -1) - timeout = min_delay; - ret = WaitForMultipleObjects(count, handles, FALSE, timeout); - - if (ret < count) { - list_for_each(el, &ts->os_rw_handlers) { - rh = list_entry(el, JSOSRWHandler, link); - if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) { - call_handler(ctx, rh->rw_func[0]); - /* must stop because the list may have been modified */ - goto done; - } - } - - list_for_each(el, &ts->port_list) { - JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link); - if (!JS_IsNull(port->on_message_func)) { - JSWorkerMessagePipe *ps = port->recv_pipe; - if (ps->waker.handle == handles[ret]) { - if (handle_posted_message(rt, ctx, port)) - goto done; - } - } - } - } - } else { - Sleep(min_delay); - } - done: - return 0; -} - -#else - -static int js_os_poll(JSContext *ctx) -{ - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - int ret, fd_max, min_delay; - int64_t cur_time, delay; - fd_set rfds, wfds; - JSOSRWHandler *rh; - struct list_head *el; - struct timeval tv, *tvp; - - /* only check signals in the main thread */ - if (!ts->recv_pipe && - unlikely(os_pending_signals != 0)) { - JSOSSignalHandler *sh; - uint64_t mask; - - list_for_each(el, &ts->os_signal_handlers) { - sh = list_entry(el, JSOSSignalHandler, link); - mask = (uint64_t)1 << sh->sig_num; - if (os_pending_signals & mask) { - os_pending_signals &= ~mask; - call_handler(ctx, sh->func); - return 0; - } - } - } - - if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers) && - list_empty(&ts->port_list)) - return -1; /* no more events */ - - if (!list_empty(&ts->os_timers)) { - cur_time = get_time_ms(); - min_delay = 10000; - list_for_each(el, &ts->os_timers) { - JSOSTimer *th = list_entry(el, JSOSTimer, link); - delay = th->timeout - cur_time; - if (delay <= 0) { - JSValue func; - /* the timer expired */ - func = th->func; - th->func = JS_UNDEFINED; - free_timer(rt, th); - call_handler(ctx, func); - JS_FreeValue(ctx, func); - return 0; - } else if (delay < min_delay) { - min_delay = delay; - } - } - tv.tv_sec = min_delay / 1000; - tv.tv_usec = (min_delay % 1000) * 1000; - tvp = &tv; - } else { - tvp = NULL; - } - - FD_ZERO(&rfds); - FD_ZERO(&wfds); - fd_max = -1; - list_for_each(el, &ts->os_rw_handlers) { - rh = list_entry(el, JSOSRWHandler, link); - fd_max = max_int(fd_max, rh->fd); - if (!JS_IsNull(rh->rw_func[0])) - FD_SET(rh->fd, &rfds); - if (!JS_IsNull(rh->rw_func[1])) - FD_SET(rh->fd, &wfds); - } - - list_for_each(el, &ts->port_list) { - JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link); - if (!JS_IsNull(port->on_message_func)) { - JSWorkerMessagePipe *ps = port->recv_pipe; - fd_max = max_int(fd_max, ps->waker.read_fd); - FD_SET(ps->waker.read_fd, &rfds); - } - } - - ret = select(fd_max + 1, &rfds, &wfds, NULL, tvp); - if (ret > 0) { - list_for_each(el, &ts->os_rw_handlers) { - rh = list_entry(el, JSOSRWHandler, link); - if (!JS_IsNull(rh->rw_func[0]) && - FD_ISSET(rh->fd, &rfds)) { - call_handler(ctx, rh->rw_func[0]); - /* must stop because the list may have been modified */ - goto done; - } - if (!JS_IsNull(rh->rw_func[1]) && - FD_ISSET(rh->fd, &wfds)) { - call_handler(ctx, rh->rw_func[1]); - /* must stop because the list may have been modified */ - goto done; - } - } - - list_for_each(el, &ts->port_list) { - JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link); - if (!JS_IsNull(port->on_message_func)) { - JSWorkerMessagePipe *ps = port->recv_pipe; - if (FD_ISSET(ps->waker.read_fd, &rfds)) { - if (handle_posted_message(rt, ctx, port)) - goto done; - } - } - } - } - done: - return 0; -} -#endif /* !_WIN32 */ - -static JSValue make_obj_error(JSContext *ctx, - JSValue obj, - int err) -{ - JSValue arr; - if (JS_IsException(obj)) - return obj; - arr = JS_NewArray(ctx); - if (JS_IsException(arr)) - return JS_EXCEPTION; - JS_DefinePropertyValueUint32(ctx, arr, 0, obj, - JS_PROP_C_W_E); - JS_DefinePropertyValueUint32(ctx, arr, 1, JS_NewInt32(ctx, err), - JS_PROP_C_W_E); - return arr; -} - -static JSValue make_string_error(JSContext *ctx, - const char *buf, - int err) -{ - return make_obj_error(ctx, JS_NewString(ctx, buf), err); -} - -/* return [cwd, errorcode] */ -static JSValue js_os_getcwd(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - char buf[PATH_MAX]; - int err; - - if (!getcwd(buf, sizeof(buf))) { - buf[0] = '\0'; - err = errno; - } else { - err = 0; - } - return make_string_error(ctx, buf, err); -} - -static JSValue js_os_chdir(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *target; - int err; - - target = JS_ToCString(ctx, argv[0]); - if (!target) - return JS_EXCEPTION; - err = js_get_errno(chdir(target)); - JS_FreeCString(ctx, target); - return JS_NewInt32(ctx, err); -} - -static JSValue js_os_mkdir(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int mode, ret; - const char *path; - - if (argc >= 2) { - if (JS_ToInt32(ctx, &mode, argv[1])) - return JS_EXCEPTION; - } else { - mode = 0777; - } - path = JS_ToCString(ctx, argv[0]); - if (!path) - return JS_EXCEPTION; -#if defined(_WIN32) - (void)mode; - ret = js_get_errno(mkdir(path)); -#else - ret = js_get_errno(mkdir(path, mode)); -#endif - JS_FreeCString(ctx, path); - return JS_NewInt32(ctx, ret); -} - -/* return [array, errorcode] */ -static JSValue js_os_readdir(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *path; - DIR *f; - struct dirent *d; - JSValue obj; - int err; - uint32_t len; - - path = JS_ToCString(ctx, argv[0]); - if (!path) - return JS_EXCEPTION; - obj = JS_NewArray(ctx); - if (JS_IsException(obj)) { - JS_FreeCString(ctx, path); - return JS_EXCEPTION; - } - f = opendir(path); - if (!f) - err = errno; - else - err = 0; - JS_FreeCString(ctx, path); - if (!f) - goto done; - len = 0; - for(;;) { - errno = 0; - d = readdir(f); - if (!d) { - err = errno; - break; - } - JS_DefinePropertyValueUint32(ctx, obj, len++, - JS_NewString(ctx, d->d_name), - JS_PROP_C_W_E); - } - closedir(f); - done: - return make_obj_error(ctx, obj, err); -} - -#if !defined(_WIN32) -static int64_t timespec_to_ms(const struct timespec *tv) -{ - return (int64_t)tv->tv_sec * 1000 + (tv->tv_nsec / 1000000); -} -#endif - -/* return [obj, errcode] */ -static JSValue js_os_stat(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int is_lstat) -{ - const char *path; - int err, res; - struct stat st; - JSValue obj; - - path = JS_ToCString(ctx, argv[0]); - if (!path) - return JS_EXCEPTION; -#if defined(_WIN32) - res = stat(path, &st); -#else - if (is_lstat) - res = lstat(path, &st); - else - res = stat(path, &st); -#endif - if (res < 0) - err = errno; - else - err = 0; - JS_FreeCString(ctx, path); - if (res < 0) { - obj = JS_NULL; - } else { - obj = JS_NewObject(ctx); - if (JS_IsException(obj)) - return JS_EXCEPTION; - JS_DefinePropertyValueStr(ctx, obj, "dev", - JS_NewInt64(ctx, st.st_dev), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "ino", - JS_NewInt64(ctx, st.st_ino), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "mode", - JS_NewInt32(ctx, st.st_mode), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "nlink", - JS_NewInt64(ctx, st.st_nlink), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "uid", - JS_NewInt64(ctx, st.st_uid), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "gid", - JS_NewInt64(ctx, st.st_gid), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "rdev", - JS_NewInt64(ctx, st.st_rdev), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "size", - JS_NewInt64(ctx, st.st_size), - JS_PROP_C_W_E); -#if !defined(_WIN32) - JS_DefinePropertyValueStr(ctx, obj, "blocks", - JS_NewInt64(ctx, st.st_blocks), - JS_PROP_C_W_E); -#endif -#if defined(_WIN32) - JS_DefinePropertyValueStr(ctx, obj, "atime", - JS_NewInt64(ctx, (int64_t)st.st_atime * 1000), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "mtime", - JS_NewInt64(ctx, (int64_t)st.st_mtime * 1000), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "ctime", - JS_NewInt64(ctx, (int64_t)st.st_ctime * 1000), - JS_PROP_C_W_E); -#elif defined(__APPLE__) - JS_DefinePropertyValueStr(ctx, obj, "atime", - JS_NewInt64(ctx, timespec_to_ms(&st.st_atimespec)), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "mtime", - JS_NewInt64(ctx, timespec_to_ms(&st.st_mtimespec)), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "ctime", - JS_NewInt64(ctx, timespec_to_ms(&st.st_ctimespec)), - JS_PROP_C_W_E); -#else - JS_DefinePropertyValueStr(ctx, obj, "atime", - JS_NewInt64(ctx, timespec_to_ms(&st.st_atim)), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "mtime", - JS_NewInt64(ctx, timespec_to_ms(&st.st_mtim)), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "ctime", - JS_NewInt64(ctx, timespec_to_ms(&st.st_ctim)), - JS_PROP_C_W_E); -#endif - } - return make_obj_error(ctx, obj, err); -} - -#if !defined(_WIN32) -static void ms_to_timeval(struct timeval *tv, uint64_t v) -{ - tv->tv_sec = v / 1000; - tv->tv_usec = (v % 1000) * 1000; -} -#endif - -static JSValue js_os_utimes(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *path; - int64_t atime, mtime; - int ret; - - if (JS_ToInt64(ctx, &atime, argv[1])) - return JS_EXCEPTION; - if (JS_ToInt64(ctx, &mtime, argv[2])) - return JS_EXCEPTION; - path = JS_ToCString(ctx, argv[0]); - if (!path) - return JS_EXCEPTION; -#if defined(_WIN32) - { - struct _utimbuf times; - times.actime = atime / 1000; - times.modtime = mtime / 1000; - ret = js_get_errno(_utime(path, ×)); - } -#else - { - struct timeval times[2]; - ms_to_timeval(×[0], atime); - ms_to_timeval(×[1], mtime); - ret = js_get_errno(utimes(path, times)); - } -#endif - JS_FreeCString(ctx, path); - return JS_NewInt32(ctx, ret); -} - -/* sleep(delay_ms) */ -static JSValue js_os_sleep(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int64_t delay; - int ret; - - if (JS_ToInt64(ctx, &delay, argv[0])) - return JS_EXCEPTION; - if (delay < 0) - delay = 0; -#if defined(_WIN32) - { - if (delay > INT32_MAX) - delay = INT32_MAX; - Sleep(delay); - ret = 0; - } -#else - { - struct timespec ts; - - ts.tv_sec = delay / 1000; - ts.tv_nsec = (delay % 1000) * 1000000; - ret = js_get_errno(nanosleep(&ts, NULL)); - } -#endif - return JS_NewInt32(ctx, ret); -} - -#if defined(_WIN32) -static char *realpath(const char *path, char *buf) -{ - if (!_fullpath(buf, path, PATH_MAX)) { - errno = ENOENT; - return NULL; - } else { - return buf; - } -} -#endif - -/* return [path, errorcode] */ -static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *path; - char buf[PATH_MAX], *res; - int err; - - path = JS_ToCString(ctx, argv[0]); - if (!path) - return JS_EXCEPTION; - res = realpath(path, buf); - JS_FreeCString(ctx, path); - if (!res) { - buf[0] = '\0'; - err = errno; - } else { - err = 0; - } - return make_string_error(ctx, buf, err); -} - -#if !defined(_WIN32) -static JSValue js_os_symlink(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *target, *linkpath; - int err; - - target = JS_ToCString(ctx, argv[0]); - if (!target) - return JS_EXCEPTION; - linkpath = JS_ToCString(ctx, argv[1]); - if (!linkpath) { - JS_FreeCString(ctx, target); - return JS_EXCEPTION; - } - err = js_get_errno(symlink(target, linkpath)); - JS_FreeCString(ctx, target); - JS_FreeCString(ctx, linkpath); - return JS_NewInt32(ctx, err); -} - -/* return [path, errorcode] */ -static JSValue js_os_readlink(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *path; - char buf[PATH_MAX]; - int err; - ssize_t res; - - path = JS_ToCString(ctx, argv[0]); - if (!path) - return JS_EXCEPTION; - res = readlink(path, buf, sizeof(buf) - 1); - if (res < 0) { - buf[0] = '\0'; - err = errno; - } else { - buf[res] = '\0'; - err = 0; - } - JS_FreeCString(ctx, path); - return make_string_error(ctx, buf, err); -} - -static char **build_envp(JSContext *ctx, JSValueConst obj) -{ - uint32_t len, i; - JSPropertyEnum *tab; - char **envp, *pair; - const char *key, *str; - JSValue val; - size_t key_len, str_len; - - if (JS_GetOwnPropertyNames(ctx, &tab, &len, obj, - JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0) - return NULL; - envp = js_mallocz(ctx, sizeof(envp[0]) * ((size_t)len + 1)); - if (!envp) - goto fail; - for(i = 0; i < len; i++) { - val = JS_GetProperty(ctx, obj, tab[i].atom); - if (JS_IsException(val)) - goto fail; - str = JS_ToCString(ctx, val); - JS_FreeValue(ctx, val); - if (!str) - goto fail; - key = JS_AtomToCString(ctx, tab[i].atom); - if (!key) { - JS_FreeCString(ctx, str); - goto fail; - } - key_len = strlen(key); - str_len = strlen(str); - pair = js_malloc(ctx, key_len + str_len + 2); - if (!pair) { - JS_FreeCString(ctx, key); - JS_FreeCString(ctx, str); - goto fail; - } - memcpy(pair, key, key_len); - pair[key_len] = '='; - memcpy(pair + key_len + 1, str, str_len); - pair[key_len + 1 + str_len] = '\0'; - envp[i] = pair; - JS_FreeCString(ctx, key); - JS_FreeCString(ctx, str); - } - done: - JS_FreePropertyEnum(ctx, tab, len); - return envp; - fail: - if (envp) { - for(i = 0; i < len; i++) - js_free(ctx, envp[i]); - js_free(ctx, envp); - envp = NULL; - } - goto done; -} - -/* execvpe is not available on non GNU systems */ -static int my_execvpe(const char *filename, char **argv, char **envp) -{ - char *path, *p, *p_next, *p1; - char buf[PATH_MAX]; - size_t filename_len, path_len; - BOOL eacces_error; - - filename_len = strlen(filename); - if (filename_len == 0) { - errno = ENOENT; - return -1; - } - if (strchr(filename, '/')) - return execve(filename, argv, envp); - - path = getenv("PATH"); - if (!path) - path = (char *)"/bin:/usr/bin"; - eacces_error = FALSE; - p = path; - for(p = path; p != NULL; p = p_next) { - p1 = strchr(p, ':'); - if (!p1) { - p_next = NULL; - path_len = strlen(p); - } else { - p_next = p1 + 1; - path_len = p1 - p; - } - /* path too long */ - if ((path_len + 1 + filename_len + 1) > PATH_MAX) - continue; - memcpy(buf, p, path_len); - buf[path_len] = '/'; - memcpy(buf + path_len + 1, filename, filename_len); - buf[path_len + 1 + filename_len] = '\0'; - - execve(buf, argv, envp); - - switch(errno) { - case EACCES: - eacces_error = TRUE; - break; - case ENOENT: - case ENOTDIR: - break; - default: - return -1; - } - } - if (eacces_error) - errno = EACCES; - return -1; -} - -/* exec(args[, options]) -> exitcode */ -static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst options, args = argv[0]; - JSValue val, ret_val; - const char **exec_argv, *file = NULL, *str, *cwd = NULL; - char **envp = environ; - uint32_t exec_argc, i; - int ret, pid, status; - BOOL block_flag = TRUE, use_path = TRUE; - static const char *std_name[3] = { "stdin", "stdout", "stderr" }; - int std_fds[3]; - uint32_t uid = -1, gid = -1; - - val = JS_GetPropertyStr(ctx, args, "length"); - if (JS_IsException(val)) - return JS_EXCEPTION; - ret = JS_ToUint32(ctx, &exec_argc, val); - JS_FreeValue(ctx, val); - if (ret) - return JS_EXCEPTION; - /* arbitrary limit to avoid overflow */ - if (exec_argc < 1 || exec_argc > 65535) { - return JS_ThrowTypeError(ctx, "invalid number of arguments"); - } - exec_argv = js_mallocz(ctx, sizeof(exec_argv[0]) * (exec_argc + 1)); - if (!exec_argv) - return JS_EXCEPTION; - for(i = 0; i < exec_argc; i++) { - val = JS_GetPropertyUint32(ctx, args, i); - if (JS_IsException(val)) - goto exception; - str = JS_ToCString(ctx, val); - JS_FreeValue(ctx, val); - if (!str) - goto exception; - exec_argv[i] = str; - } - exec_argv[exec_argc] = NULL; - - for(i = 0; i < 3; i++) - std_fds[i] = i; - - /* get the options, if any */ - if (argc >= 2) { - options = argv[1]; - - if (get_bool_option(ctx, &block_flag, options, "block")) - goto exception; - if (get_bool_option(ctx, &use_path, options, "usePath")) - goto exception; - - val = JS_GetPropertyStr(ctx, options, "file"); - if (JS_IsException(val)) - goto exception; - if (!JS_IsUndefined(val)) { - file = JS_ToCString(ctx, val); - JS_FreeValue(ctx, val); - if (!file) - goto exception; - } - - val = JS_GetPropertyStr(ctx, options, "cwd"); - if (JS_IsException(val)) - goto exception; - if (!JS_IsUndefined(val)) { - cwd = JS_ToCString(ctx, val); - JS_FreeValue(ctx, val); - if (!cwd) - goto exception; - } - - /* stdin/stdout/stderr handles */ - for(i = 0; i < 3; i++) { - val = JS_GetPropertyStr(ctx, options, std_name[i]); - if (JS_IsException(val)) - goto exception; - if (!JS_IsUndefined(val)) { - int fd; - ret = JS_ToInt32(ctx, &fd, val); - JS_FreeValue(ctx, val); - if (ret) - goto exception; - std_fds[i] = fd; - } - } - - val = JS_GetPropertyStr(ctx, options, "env"); - if (JS_IsException(val)) - goto exception; - if (!JS_IsUndefined(val)) { - envp = build_envp(ctx, val); - JS_FreeValue(ctx, val); - if (!envp) - goto exception; - } - - val = JS_GetPropertyStr(ctx, options, "uid"); - if (JS_IsException(val)) - goto exception; - if (!JS_IsUndefined(val)) { - ret = JS_ToUint32(ctx, &uid, val); - JS_FreeValue(ctx, val); - if (ret) - goto exception; - } - - val = JS_GetPropertyStr(ctx, options, "gid"); - if (JS_IsException(val)) - goto exception; - if (!JS_IsUndefined(val)) { - ret = JS_ToUint32(ctx, &gid, val); - JS_FreeValue(ctx, val); - if (ret) - goto exception; - } - } - - pid = fork(); - if (pid < 0) { - JS_ThrowTypeError(ctx, "fork error"); - goto exception; - } - if (pid == 0) { - /* child */ - - /* remap the stdin/stdout/stderr handles if necessary */ - for(i = 0; i < 3; i++) { - if (std_fds[i] != i) { - if (dup2(std_fds[i], i) < 0) - _exit(127); - } - } -#if defined(HAVE_CLOSEFROM) - /* closefrom() is available on many recent unix systems: - Linux with glibc 2.34+, Solaris 9+, FreeBSD 7.3+, - NetBSD 3.0+, OpenBSD 3.5+. - Linux with the musl libc and macOS don't have it. - */ - - closefrom(3); -#else - { - /* Close the file handles manually, limit to 1024 to avoid - costly loop on linux Alpine where sysconf(_SC_OPEN_MAX) - returns a huge value 1048576. - Patch inspired by nicolas-duteil-nova. See also: - https://stackoverflow.com/questions/73229353/ - https://stackoverflow.com/questions/899038/#918469 - */ - int fd_max = min_int(sysconf(_SC_OPEN_MAX), 1024); - for(i = 3; i < fd_max; i++) - close(i); - } -#endif - if (cwd) { - if (chdir(cwd) < 0) - _exit(127); - } - if (uid != -1) { - if (setuid(uid) < 0) - _exit(127); - } - if (gid != -1) { - if (setgid(gid) < 0) - _exit(127); - } - - if (!file) - file = exec_argv[0]; - if (use_path) - ret = my_execvpe(file, (char **)exec_argv, envp); - else - ret = execve(file, (char **)exec_argv, envp); - _exit(127); - } - /* parent */ - if (block_flag) { - for(;;) { - ret = waitpid(pid, &status, 0); - if (ret == pid) { - if (WIFEXITED(status)) { - ret = WEXITSTATUS(status); - break; - } else if (WIFSIGNALED(status)) { - ret = -WTERMSIG(status); - break; - } - } - } - } else { - ret = pid; - } - ret_val = JS_NewInt32(ctx, ret); - done: - JS_FreeCString(ctx, file); - JS_FreeCString(ctx, cwd); - for(i = 0; i < exec_argc; i++) - JS_FreeCString(ctx, exec_argv[i]); - js_free(ctx, exec_argv); - if (envp != environ) { - char **p; - p = envp; - while (*p != NULL) { - js_free(ctx, *p); - p++; - } - js_free(ctx, envp); - } - return ret_val; - exception: - ret_val = JS_EXCEPTION; - goto done; -} - -/* getpid() -> pid */ -static JSValue js_os_getpid(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_NewInt32(ctx, getpid()); -} - -/* waitpid(pid, block) -> [pid, status] */ -static JSValue js_os_waitpid(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int pid, status, options, ret; - JSValue obj; - - if (JS_ToInt32(ctx, &pid, argv[0])) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &options, argv[1])) - return JS_EXCEPTION; - - ret = waitpid(pid, &status, options); - if (ret < 0) { - ret = -errno; - status = 0; - } - - obj = JS_NewArray(ctx); - if (JS_IsException(obj)) - return obj; - JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, ret), - JS_PROP_C_W_E); - JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, status), - JS_PROP_C_W_E); - return obj; -} - -/* pipe() -> [read_fd, write_fd] or null if error */ -static JSValue js_os_pipe(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int pipe_fds[2], ret; - JSValue obj; - - ret = pipe(pipe_fds); - if (ret < 0) - return JS_NULL; - obj = JS_NewArray(ctx); - if (JS_IsException(obj)) - return obj; - JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, pipe_fds[0]), - JS_PROP_C_W_E); - JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, pipe_fds[1]), - JS_PROP_C_W_E); - return obj; -} - -/* kill(pid, sig) */ -static JSValue js_os_kill(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int pid, sig, ret; - - if (JS_ToInt32(ctx, &pid, argv[0])) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &sig, argv[1])) - return JS_EXCEPTION; - ret = js_get_errno(kill(pid, sig)); - return JS_NewInt32(ctx, ret); -} - -/* dup(fd) */ -static JSValue js_os_dup(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int fd, ret; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - ret = js_get_errno(dup(fd)); - return JS_NewInt32(ctx, ret); -} - -/* dup2(fd) */ -static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int fd, fd2, ret; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &fd2, argv[1])) - return JS_EXCEPTION; - ret = js_get_errno(dup2(fd, fd2)); - return JS_NewInt32(ctx, ret); -} - -#endif /* !_WIN32 */ - -#ifdef USE_WORKER - -/* Worker */ - -typedef struct { - JSWorkerMessagePipe *recv_pipe; - JSWorkerMessagePipe *send_pipe; - JSWorkerMessageHandler *msg_handler; -} JSWorkerData; - -typedef struct { - char *filename; /* module filename */ - char *basename; /* module base name */ - JSWorkerMessagePipe *recv_pipe, *send_pipe; - int strip_flags; -} WorkerFuncArgs; - -typedef struct { - int ref_count; - uint64_t buf[0]; -} JSSABHeader; - -static JSClassID js_worker_class_id; -static JSContext *(*js_worker_new_context_func)(JSRuntime *rt); - -static int atomic_add_int(int *ptr, int v) -{ - return atomic_fetch_add((_Atomic(uint32_t) *)ptr, v) + v; -} - -/* shared array buffer allocator */ -static void *js_sab_alloc(void *opaque, size_t size) -{ - JSSABHeader *sab; - sab = malloc(sizeof(JSSABHeader) + size); - if (!sab) - return NULL; - sab->ref_count = 1; - return sab->buf; -} - -static void js_sab_free(void *opaque, void *ptr) -{ - JSSABHeader *sab; - int ref_count; - sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader)); - ref_count = atomic_add_int(&sab->ref_count, -1); - assert(ref_count >= 0); - if (ref_count == 0) { - free(sab); - } -} - -static void js_sab_dup(void *opaque, void *ptr) -{ - JSSABHeader *sab; - sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader)); - atomic_add_int(&sab->ref_count, 1); -} - -static JSWorkerMessagePipe *js_new_message_pipe(void) -{ - JSWorkerMessagePipe *ps; - - ps = malloc(sizeof(*ps)); - if (!ps) - return NULL; - if (js_waker_init(&ps->waker)) { - free(ps); - return NULL; - } - ps->ref_count = 1; - init_list_head(&ps->msg_queue); - pthread_mutex_init(&ps->mutex, NULL); - return ps; -} - -static JSWorkerMessagePipe *js_dup_message_pipe(JSWorkerMessagePipe *ps) -{ - atomic_add_int(&ps->ref_count, 1); - return ps; -} - -static void js_free_message(JSWorkerMessage *msg) -{ - size_t i; - /* free the SAB */ - for(i = 0; i < msg->sab_tab_len; i++) { - js_sab_free(NULL, msg->sab_tab[i]); - } - free(msg->sab_tab); - free(msg->data); - free(msg); -} - -static void js_free_message_pipe(JSWorkerMessagePipe *ps) -{ - struct list_head *el, *el1; - JSWorkerMessage *msg; - int ref_count; - - if (!ps) - return; - - ref_count = atomic_add_int(&ps->ref_count, -1); - assert(ref_count >= 0); - if (ref_count == 0) { - list_for_each_safe(el, el1, &ps->msg_queue) { - msg = list_entry(el, JSWorkerMessage, link); - js_free_message(msg); - } - pthread_mutex_destroy(&ps->mutex); - js_waker_close(&ps->waker); - free(ps); - } -} - -static void js_free_port(JSRuntime *rt, JSWorkerMessageHandler *port) -{ - if (port) { - js_free_message_pipe(port->recv_pipe); - JS_FreeValueRT(rt, port->on_message_func); - list_del(&port->link); - js_free_rt(rt, port); - } -} - -static void js_worker_finalizer(JSRuntime *rt, JSValue val) -{ - JSWorkerData *worker = JS_GetOpaque(val, js_worker_class_id); - if (worker) { - js_free_message_pipe(worker->recv_pipe); - js_free_message_pipe(worker->send_pipe); - js_free_port(rt, worker->msg_handler); - js_free_rt(rt, worker); - } -} - -static JSClassDef js_worker_class = { - "Worker", - .finalizer = js_worker_finalizer, -}; - -static void *worker_func(void *opaque) -{ - WorkerFuncArgs *args = opaque; - JSRuntime *rt; - JSThreadState *ts; - JSContext *ctx; - JSValue val; - - rt = JS_NewRuntime(); - if (rt == NULL) { - fprintf(stderr, "JS_NewRuntime failure"); - exit(1); - } - JS_SetStripInfo(rt, args->strip_flags); - js_std_init_handlers(rt); - - JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL); - - /* set the pipe to communicate with the parent */ - ts = JS_GetRuntimeOpaque(rt); - ts->recv_pipe = args->recv_pipe; - ts->send_pipe = args->send_pipe; - - /* function pointer to avoid linking the whole JS_NewContext() if - not needed */ - ctx = js_worker_new_context_func(rt); - if (ctx == NULL) { - fprintf(stderr, "JS_NewContext failure"); - } - - JS_SetCanBlock(rt, TRUE); - - js_std_add_helpers(ctx, -1, NULL); - - val = JS_LoadModule(ctx, args->basename, args->filename); - free(args->filename); - free(args->basename); - free(args); - val = js_std_await(ctx, val); - if (JS_IsException(val)) - js_std_dump_error(ctx); - JS_FreeValue(ctx, val); - - js_std_loop(ctx); - - JS_FreeContext(ctx); - js_std_free_handlers(rt); - JS_FreeRuntime(rt); - return NULL; -} - -static JSValue js_worker_ctor_internal(JSContext *ctx, JSValueConst new_target, - JSWorkerMessagePipe *recv_pipe, - JSWorkerMessagePipe *send_pipe) -{ - JSValue obj = JS_UNDEFINED, proto; - JSWorkerData *s; - - /* create the object */ - if (JS_IsUndefined(new_target)) { - proto = JS_GetClassProto(ctx, js_worker_class_id); - } else { - proto = JS_GetPropertyStr(ctx, new_target, "prototype"); - if (JS_IsException(proto)) - goto fail; - } - obj = JS_NewObjectProtoClass(ctx, proto, js_worker_class_id); - JS_FreeValue(ctx, proto); - if (JS_IsException(obj)) - goto fail; - s = js_mallocz(ctx, sizeof(*s)); - if (!s) - goto fail; - s->recv_pipe = js_dup_message_pipe(recv_pipe); - s->send_pipe = js_dup_message_pipe(send_pipe); - - JS_SetOpaque(obj, s); - return obj; - fail: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) -{ - JSRuntime *rt = JS_GetRuntime(ctx); - WorkerFuncArgs *args = NULL; - pthread_t tid; - pthread_attr_t attr; - JSValue obj = JS_UNDEFINED; - int ret; - const char *filename = NULL, *basename; - JSAtom basename_atom; - - /* XXX: in order to avoid problems with resource liberation, we - don't support creating workers inside workers */ - if (!is_main_thread(rt)) - return JS_ThrowTypeError(ctx, "cannot create a worker inside a worker"); - - /* base name, assuming the calling function is a normal JS - function */ - basename_atom = JS_GetScriptOrModuleName(ctx, 1); - if (basename_atom == JS_ATOM_NULL) { - return JS_ThrowTypeError(ctx, "could not determine calling script or module name"); - } - basename = JS_AtomToCString(ctx, basename_atom); - JS_FreeAtom(ctx, basename_atom); - if (!basename) - goto fail; - - /* module name */ - filename = JS_ToCString(ctx, argv[0]); - if (!filename) - goto fail; - - args = malloc(sizeof(*args)); - if (!args) - goto oom_fail; - memset(args, 0, sizeof(*args)); - args->filename = strdup(filename); - args->basename = strdup(basename); - - /* ports */ - args->recv_pipe = js_new_message_pipe(); - if (!args->recv_pipe) - goto oom_fail; - args->send_pipe = js_new_message_pipe(); - if (!args->send_pipe) - goto oom_fail; - - args->strip_flags = JS_GetStripInfo(rt); - - obj = js_worker_ctor_internal(ctx, new_target, - args->send_pipe, args->recv_pipe); - if (JS_IsException(obj)) - goto fail; - - pthread_attr_init(&attr); - /* no join at the end */ - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - ret = pthread_create(&tid, &attr, worker_func, args); - pthread_attr_destroy(&attr); - if (ret != 0) { - JS_ThrowTypeError(ctx, "could not create worker"); - goto fail; - } - JS_FreeCString(ctx, basename); - JS_FreeCString(ctx, filename); - return obj; - oom_fail: - JS_ThrowOutOfMemory(ctx); - fail: - JS_FreeCString(ctx, basename); - JS_FreeCString(ctx, filename); - if (args) { - free(args->filename); - free(args->basename); - js_free_message_pipe(args->recv_pipe); - js_free_message_pipe(args->send_pipe); - free(args); - } - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue js_worker_postMessage(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id); - JSWorkerMessagePipe *ps; - size_t data_len, sab_tab_len, i; - uint8_t *data; - JSWorkerMessage *msg; - uint8_t **sab_tab; - - if (!worker) - return JS_EXCEPTION; - - data = JS_WriteObject2(ctx, &data_len, argv[0], - JS_WRITE_OBJ_SAB | JS_WRITE_OBJ_REFERENCE, - &sab_tab, &sab_tab_len); - if (!data) - return JS_EXCEPTION; - - msg = malloc(sizeof(*msg)); - if (!msg) - goto fail; - msg->data = NULL; - msg->sab_tab = NULL; - - /* must reallocate because the allocator may be different */ - msg->data = malloc(data_len); - if (!msg->data) - goto fail; - memcpy(msg->data, data, data_len); - msg->data_len = data_len; - - if (sab_tab_len > 0) { - msg->sab_tab = malloc(sizeof(msg->sab_tab[0]) * sab_tab_len); - if (!msg->sab_tab) - goto fail; - memcpy(msg->sab_tab, sab_tab, sizeof(msg->sab_tab[0]) * sab_tab_len); - } - msg->sab_tab_len = sab_tab_len; - - js_free(ctx, data); - js_free(ctx, sab_tab); - - /* increment the SAB reference counts */ - for(i = 0; i < msg->sab_tab_len; i++) { - js_sab_dup(NULL, msg->sab_tab[i]); - } - - ps = worker->send_pipe; - pthread_mutex_lock(&ps->mutex); - /* indicate that data is present */ - if (list_empty(&ps->msg_queue)) - js_waker_signal(&ps->waker); - list_add_tail(&msg->link, &ps->msg_queue); - pthread_mutex_unlock(&ps->mutex); - return JS_UNDEFINED; - fail: - if (msg) { - free(msg->data); - free(msg->sab_tab); - free(msg); - } - js_free(ctx, data); - js_free(ctx, sab_tab); - return JS_EXCEPTION; - -} - -static JSValue js_worker_set_onmessage(JSContext *ctx, JSValueConst this_val, - JSValueConst func) -{ - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id); - JSWorkerMessageHandler *port; - - if (!worker) - return JS_EXCEPTION; - - port = worker->msg_handler; - if (JS_IsNull(func)) { - if (port) { - js_free_port(rt, port); - worker->msg_handler = NULL; - } - } else { - if (!JS_IsFunction(ctx, func)) - return JS_ThrowTypeError(ctx, "not a function"); - if (!port) { - port = js_mallocz(ctx, sizeof(*port)); - if (!port) - return JS_EXCEPTION; - port->recv_pipe = js_dup_message_pipe(worker->recv_pipe); - port->on_message_func = JS_NULL; - list_add_tail(&port->link, &ts->port_list); - worker->msg_handler = port; - } - JS_FreeValue(ctx, port->on_message_func); - port->on_message_func = JS_DupValue(ctx, func); - } - return JS_UNDEFINED; -} - -static JSValue js_worker_get_onmessage(JSContext *ctx, JSValueConst this_val) -{ - JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id); - JSWorkerMessageHandler *port; - if (!worker) - return JS_EXCEPTION; - port = worker->msg_handler; - if (port) { - return JS_DupValue(ctx, port->on_message_func); - } else { - return JS_NULL; - } -} - -static const JSCFunctionListEntry js_worker_proto_funcs[] = { - JS_CFUNC_DEF("postMessage", 1, js_worker_postMessage ), - JS_CGETSET_DEF("onmessage", js_worker_get_onmessage, js_worker_set_onmessage ), -}; - -#endif /* USE_WORKER */ - -void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt)) -{ -#ifdef USE_WORKER - js_worker_new_context_func = func; -#endif -} - -#if defined(_WIN32) -#define OS_PLATFORM "win32" -#elif defined(__APPLE__) -#define OS_PLATFORM "darwin" -#elif defined(EMSCRIPTEN) -#define OS_PLATFORM "js" -#else -#define OS_PLATFORM "linux" -#endif - -#define OS_FLAG(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE ) - -static const JSCFunctionListEntry js_os_funcs[] = { - JS_CFUNC_DEF("open", 2, js_os_open ), - OS_FLAG(O_RDONLY), - OS_FLAG(O_WRONLY), - OS_FLAG(O_RDWR), - OS_FLAG(O_APPEND), - OS_FLAG(O_CREAT), - OS_FLAG(O_EXCL), - OS_FLAG(O_TRUNC), -#if defined(_WIN32) - OS_FLAG(O_BINARY), - OS_FLAG(O_TEXT), -#endif - JS_CFUNC_DEF("close", 1, js_os_close ), - JS_CFUNC_DEF("seek", 3, js_os_seek ), - JS_CFUNC_MAGIC_DEF("read", 4, js_os_read_write, 0 ), - JS_CFUNC_MAGIC_DEF("write", 4, js_os_read_write, 1 ), - JS_CFUNC_DEF("isatty", 1, js_os_isatty ), - JS_CFUNC_DEF("ttyGetWinSize", 1, js_os_ttyGetWinSize ), - JS_CFUNC_DEF("ttySetRaw", 1, js_os_ttySetRaw ), - JS_CFUNC_DEF("remove", 1, js_os_remove ), - JS_CFUNC_DEF("rename", 2, js_os_rename ), - JS_CFUNC_MAGIC_DEF("setReadHandler", 2, js_os_setReadHandler, 0 ), - JS_CFUNC_MAGIC_DEF("setWriteHandler", 2, js_os_setReadHandler, 1 ), - JS_CFUNC_DEF("signal", 2, js_os_signal ), - OS_FLAG(SIGINT), - OS_FLAG(SIGABRT), - OS_FLAG(SIGFPE), - OS_FLAG(SIGILL), - OS_FLAG(SIGSEGV), - OS_FLAG(SIGTERM), -#if !defined(_WIN32) - OS_FLAG(SIGQUIT), - OS_FLAG(SIGPIPE), - OS_FLAG(SIGALRM), - OS_FLAG(SIGUSR1), - OS_FLAG(SIGUSR2), - OS_FLAG(SIGCHLD), - OS_FLAG(SIGCONT), - OS_FLAG(SIGSTOP), - OS_FLAG(SIGTSTP), - OS_FLAG(SIGTTIN), - OS_FLAG(SIGTTOU), -#endif - JS_CFUNC_DEF("now", 0, js_os_now ), - JS_CFUNC_DEF("setTimeout", 2, js_os_setTimeout ), - JS_CFUNC_DEF("clearTimeout", 1, js_os_clearTimeout ), - JS_CFUNC_DEF("sleepAsync", 1, js_os_sleepAsync ), - JS_PROP_STRING_DEF("platform", OS_PLATFORM, 0 ), - JS_CFUNC_DEF("getcwd", 0, js_os_getcwd ), - JS_CFUNC_DEF("chdir", 0, js_os_chdir ), - JS_CFUNC_DEF("mkdir", 1, js_os_mkdir ), - JS_CFUNC_DEF("readdir", 1, js_os_readdir ), - /* st_mode constants */ - OS_FLAG(S_IFMT), - OS_FLAG(S_IFIFO), - OS_FLAG(S_IFCHR), - OS_FLAG(S_IFDIR), - OS_FLAG(S_IFBLK), - OS_FLAG(S_IFREG), -#if !defined(_WIN32) - OS_FLAG(S_IFSOCK), - OS_FLAG(S_IFLNK), - OS_FLAG(S_ISGID), - OS_FLAG(S_ISUID), -#endif - JS_CFUNC_MAGIC_DEF("stat", 1, js_os_stat, 0 ), - JS_CFUNC_DEF("utimes", 3, js_os_utimes ), - JS_CFUNC_DEF("sleep", 1, js_os_sleep ), - JS_CFUNC_DEF("realpath", 1, js_os_realpath ), -#if !defined(_WIN32) - JS_CFUNC_MAGIC_DEF("lstat", 1, js_os_stat, 1 ), - JS_CFUNC_DEF("symlink", 2, js_os_symlink ), - JS_CFUNC_DEF("readlink", 1, js_os_readlink ), - JS_CFUNC_DEF("exec", 1, js_os_exec ), - JS_CFUNC_DEF("getpid", 0, js_os_getpid ), - JS_CFUNC_DEF("waitpid", 2, js_os_waitpid ), - OS_FLAG(WNOHANG), - JS_CFUNC_DEF("pipe", 0, js_os_pipe ), - JS_CFUNC_DEF("kill", 2, js_os_kill ), - JS_CFUNC_DEF("dup", 1, js_os_dup ), - JS_CFUNC_DEF("dup2", 2, js_os_dup2 ), -#endif -}; - -static int js_os_init(JSContext *ctx, JSModuleDef *m) -{ - os_poll_func = js_os_poll; - -#ifdef USE_WORKER - { - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - JSValue proto, obj; - /* Worker class */ - JS_NewClassID(&js_worker_class_id); - JS_NewClass(JS_GetRuntime(ctx), js_worker_class_id, &js_worker_class); - proto = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, proto, js_worker_proto_funcs, countof(js_worker_proto_funcs)); - - obj = JS_NewCFunction2(ctx, js_worker_ctor, "Worker", 1, - JS_CFUNC_constructor, 0); - JS_SetConstructor(ctx, obj, proto); - - JS_SetClassProto(ctx, js_worker_class_id, proto); - - /* set 'Worker.parent' if necessary */ - if (ts->recv_pipe && ts->send_pipe) { - JS_DefinePropertyValueStr(ctx, obj, "parent", - js_worker_ctor_internal(ctx, JS_UNDEFINED, ts->recv_pipe, ts->send_pipe), - JS_PROP_C_W_E); - } - - JS_SetModuleExport(ctx, m, "Worker", obj); - } -#endif /* USE_WORKER */ - - return JS_SetModuleExportList(ctx, m, js_os_funcs, - countof(js_os_funcs)); -} - -JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name) -{ - JSModuleDef *m; - m = JS_NewCModule(ctx, module_name, js_os_init); - if (!m) - return NULL; - JS_AddModuleExportList(ctx, m, js_os_funcs, countof(js_os_funcs)); -#ifdef USE_WORKER - JS_AddModuleExport(ctx, m, "Worker"); -#endif - return m; -} - -/**********************************************************/ - -static JSValue js_print(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int i; - JSValueConst v; - - for(i = 0; i < argc; i++) { - if (i != 0) - putchar(' '); - v = argv[i]; - if (JS_IsString(v)) { - const char *str; - size_t len; - str = JS_ToCStringLen(ctx, &len, v); - if (!str) - return JS_EXCEPTION; - fwrite(str, 1, len, stdout); - JS_FreeCString(ctx, str); - } else { - JS_PrintValue(ctx, js_print_value_write, stdout, v, NULL); - } - } - putchar('\n'); - return JS_UNDEFINED; -} - -static JSValue js_console_log(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue ret; - ret = js_print(ctx, this_val, argc, argv); - fflush(stdout); - return ret; -} - -void js_std_add_helpers(JSContext *ctx, int argc, char **argv) -{ - JSValue global_obj, console, args, performance; - int i; - - /* XXX: should these global definitions be enumerable? */ - global_obj = JS_GetGlobalObject(ctx); - - console = JS_NewObject(ctx); - JS_SetPropertyStr(ctx, console, "log", - JS_NewCFunction(ctx, js_console_log, "log", 1)); - JS_SetPropertyStr(ctx, global_obj, "console", console); - - performance = JS_NewObject(ctx); - JS_SetPropertyStr(ctx, performance, "now", - JS_NewCFunction(ctx, js_os_now, "now", 0)); - JS_SetPropertyStr(ctx, global_obj, "performance", performance); - - /* same methods as the mozilla JS shell */ - if (argc >= 0) { - args = JS_NewArray(ctx); - for(i = 0; i < argc; i++) { - JS_SetPropertyUint32(ctx, args, i, JS_NewString(ctx, argv[i])); - } - JS_SetPropertyStr(ctx, global_obj, "scriptArgs", args); - } - - JS_SetPropertyStr(ctx, global_obj, "print", - JS_NewCFunction(ctx, js_print, "print", 1)); - JS_SetPropertyStr(ctx, global_obj, "__loadScript", - JS_NewCFunction(ctx, js_loadScript, "__loadScript", 1)); - - JS_FreeValue(ctx, global_obj); -} - -void js_std_init_handlers(JSRuntime *rt) -{ - JSThreadState *ts; - - ts = malloc(sizeof(*ts)); - if (!ts) { - fprintf(stderr, "Could not allocate memory for the worker"); - exit(1); - } - memset(ts, 0, sizeof(*ts)); - init_list_head(&ts->os_rw_handlers); - init_list_head(&ts->os_signal_handlers); - init_list_head(&ts->os_timers); - init_list_head(&ts->port_list); - init_list_head(&ts->rejected_promise_list); - ts->next_timer_id = 1; - - JS_SetRuntimeOpaque(rt, ts); - -#ifdef USE_WORKER - /* set the SharedArrayBuffer memory handlers */ - { - JSSharedArrayBufferFunctions sf; - memset(&sf, 0, sizeof(sf)); - sf.sab_alloc = js_sab_alloc; - sf.sab_free = js_sab_free; - sf.sab_dup = js_sab_dup; - JS_SetSharedArrayBufferFunctions(rt, &sf); - } -#endif -} - -void js_std_free_handlers(JSRuntime *rt) -{ - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - struct list_head *el, *el1; - - list_for_each_safe(el, el1, &ts->os_rw_handlers) { - JSOSRWHandler *rh = list_entry(el, JSOSRWHandler, link); - free_rw_handler(rt, rh); - } - - list_for_each_safe(el, el1, &ts->os_signal_handlers) { - JSOSSignalHandler *sh = list_entry(el, JSOSSignalHandler, link); - free_sh(rt, sh); - } - - list_for_each_safe(el, el1, &ts->os_timers) { - JSOSTimer *th = list_entry(el, JSOSTimer, link); - free_timer(rt, th); - } - - list_for_each_safe(el, el1, &ts->rejected_promise_list) { - JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link); - JS_FreeValueRT(rt, rp->promise); - JS_FreeValueRT(rt, rp->reason); - free(rp); - } - -#ifdef USE_WORKER - /* XXX: free port_list ? */ - js_free_message_pipe(ts->recv_pipe); - js_free_message_pipe(ts->send_pipe); -#endif - - free(ts); - JS_SetRuntimeOpaque(rt, NULL); /* fail safe */ -} - -static void js_std_dump_error1(JSContext *ctx, JSValueConst exception_val) -{ - JS_PrintValue(ctx, js_print_value_write, stderr, exception_val, NULL); - fputc('\n', stderr); -} - -void js_std_dump_error(JSContext *ctx) -{ - JSValue exception_val; - - exception_val = JS_GetException(ctx); - js_std_dump_error1(ctx, exception_val); - JS_FreeValue(ctx, exception_val); -} - -static JSRejectedPromiseEntry *find_rejected_promise(JSContext *ctx, JSThreadState *ts, - JSValueConst promise) -{ - struct list_head *el; - - list_for_each(el, &ts->rejected_promise_list) { - JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link); - if (JS_SameValue(ctx, rp->promise, promise)) - return rp; - } - return NULL; -} - -void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise, - JSValueConst reason, - BOOL is_handled, void *opaque) -{ - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - JSRejectedPromiseEntry *rp; - - if (!is_handled) { - /* add a new entry if needed */ - rp = find_rejected_promise(ctx, ts, promise); - if (!rp) { - rp = malloc(sizeof(*rp)); - if (rp) { - rp->promise = JS_DupValue(ctx, promise); - rp->reason = JS_DupValue(ctx, reason); - list_add_tail(&rp->link, &ts->rejected_promise_list); - } - } - } else { - /* the rejection is handled, so the entry can be removed if present */ - rp = find_rejected_promise(ctx, ts, promise); - if (rp) { - JS_FreeValue(ctx, rp->promise); - JS_FreeValue(ctx, rp->reason); - list_del(&rp->link); - free(rp); - } - } -} - -/* check if there are pending promise rejections. It must be done - asynchrously in case a rejected promise is handled later. Currently - we do it once the application is about to sleep. It could be done - more often if needed. */ -static void js_std_promise_rejection_check(JSContext *ctx) -{ - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - struct list_head *el; - - if (unlikely(!list_empty(&ts->rejected_promise_list))) { - list_for_each(el, &ts->rejected_promise_list) { - JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link); - fprintf(stderr, "Possibly unhandled promise rejection: "); - js_std_dump_error1(ctx, rp->reason); - } - exit(1); - } -} - -/* main loop which calls the user JS callbacks */ -void js_std_loop(JSContext *ctx) -{ - int err; - - for(;;) { - /* execute the pending jobs */ - for(;;) { - err = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL); - if (err <= 0) { - if (err < 0) - js_std_dump_error(ctx); - break; - } - } - - js_std_promise_rejection_check(ctx); - - if (!os_poll_func || os_poll_func(ctx)) - break; - } -} - -/* Wait for a promise and execute pending jobs while waiting for - it. Return the promise result or JS_EXCEPTION in case of promise - rejection. */ -JSValue js_std_await(JSContext *ctx, JSValue obj) -{ - JSValue ret; - int state; - - for(;;) { - state = JS_PromiseState(ctx, obj); - if (state == JS_PROMISE_FULFILLED) { - ret = JS_PromiseResult(ctx, obj); - JS_FreeValue(ctx, obj); - break; - } else if (state == JS_PROMISE_REJECTED) { - ret = JS_Throw(ctx, JS_PromiseResult(ctx, obj)); - JS_FreeValue(ctx, obj); - break; - } else if (state == JS_PROMISE_PENDING) { - int err; - err = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL); - if (err < 0) { - js_std_dump_error(ctx); - } - if (err == 0) { - js_std_promise_rejection_check(ctx); - - if (os_poll_func) - os_poll_func(ctx); - } - } else { - /* not a promise */ - ret = obj; - break; - } - } - return ret; -} - -void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len, - int load_only) -{ - JSValue obj, val; - obj = JS_ReadObject(ctx, buf, buf_len, JS_READ_OBJ_BYTECODE); - if (JS_IsException(obj)) - goto exception; - if (load_only) { - if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) { - js_module_set_import_meta(ctx, obj, FALSE, FALSE); - } - JS_FreeValue(ctx, obj); - } else { - if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) { - if (JS_ResolveModule(ctx, obj) < 0) { - JS_FreeValue(ctx, obj); - goto exception; - } - js_module_set_import_meta(ctx, obj, FALSE, TRUE); - val = JS_EvalFunction(ctx, obj); - val = js_std_await(ctx, val); - } else { - val = JS_EvalFunction(ctx, obj); - } - if (JS_IsException(val)) { - exception: - js_std_dump_error(ctx); - exit(1); - } - JS_FreeValue(ctx, val); - } -} - -void js_std_eval_binary_json_module(JSContext *ctx, - const uint8_t *buf, size_t buf_len, - const char *module_name) -{ - JSValue obj; - JSModuleDef *m; - - obj = JS_ReadObject(ctx, buf, buf_len, 0); - if (JS_IsException(obj)) - goto exception; - m = create_json_module(ctx, module_name, obj); - if (!m) { - exception: - js_std_dump_error(ctx); - exit(1); - } -} - diff --git a/packages/javascript/javascript_android/cxx/quickjs/quickjs-libc.h b/packages/javascript/javascript_android/cxx/quickjs/quickjs-libc.h deleted file mode 100644 index 5c8301b..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/quickjs-libc.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * QuickJS C library - * - * Copyright (c) 2017-2018 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef QUICKJS_LIBC_H -#define QUICKJS_LIBC_H - -#include -#include - -#include "quickjs.h" - -#ifdef __cplusplus -extern "C" { -#endif - -JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name); -JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name); -void js_std_add_helpers(JSContext *ctx, int argc, char **argv); -void js_std_loop(JSContext *ctx); -JSValue js_std_await(JSContext *ctx, JSValue obj); -void js_std_init_handlers(JSRuntime *rt); -void js_std_free_handlers(JSRuntime *rt); -void js_std_dump_error(JSContext *ctx); -uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename); -int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, - JS_BOOL use_realpath, JS_BOOL is_main); -int js_module_test_json(JSContext *ctx, JSValueConst attributes); -int js_module_check_attributes(JSContext *ctx, void *opaque, JSValueConst attributes); -JSModuleDef *js_module_loader(JSContext *ctx, - const char *module_name, void *opaque, - JSValueConst attributes); -void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len, - int flags); -void js_std_eval_binary_json_module(JSContext *ctx, - const uint8_t *buf, size_t buf_len, - const char *module_name); -void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise, - JSValueConst reason, - JS_BOOL is_handled, void *opaque); -void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt)); - -#ifdef __cplusplus -} /* extern "C" { */ -#endif - -#endif /* QUICKJS_LIBC_H */ diff --git a/packages/javascript/javascript_android/cxx/quickjs/quickjs-opcode.h b/packages/javascript/javascript_android/cxx/quickjs/quickjs-opcode.h deleted file mode 100644 index 814a7cb..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/quickjs-opcode.h +++ /dev/null @@ -1,370 +0,0 @@ -/* - * QuickJS opcode definitions - * - * Copyright (c) 2017-2018 Fabrice Bellard - * Copyright (c) 2017-2018 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifdef FMT -FMT(none) -FMT(none_int) -FMT(none_loc) -FMT(none_arg) -FMT(none_var_ref) -FMT(u8) -FMT(i8) -FMT(loc8) -FMT(const8) -FMT(label8) -FMT(u16) -FMT(i16) -FMT(label16) -FMT(npop) -FMT(npopx) -FMT(npop_u16) -FMT(loc) -FMT(arg) -FMT(var_ref) -FMT(u32) -FMT(i32) -FMT(const) -FMT(label) -FMT(atom) -FMT(atom_u8) -FMT(atom_u16) -FMT(atom_label_u8) -FMT(atom_label_u16) -FMT(label_u16) -#undef FMT -#endif /* FMT */ - -#ifdef DEF - -#ifndef def -#define def(id, size, n_pop, n_push, f) DEF(id, size, n_pop, n_push, f) -#endif - -DEF(invalid, 1, 0, 0, none) /* never emitted */ - -/* push values */ -DEF( push_i32, 5, 0, 1, i32) -DEF( push_const, 5, 0, 1, const) -DEF( fclosure, 5, 0, 1, const) /* must follow push_const */ -DEF(push_atom_value, 5, 0, 1, atom) -DEF( private_symbol, 5, 0, 1, atom) -DEF( undefined, 1, 0, 1, none) -DEF( null, 1, 0, 1, none) -DEF( push_this, 1, 0, 1, none) /* only used at the start of a function */ -DEF( push_false, 1, 0, 1, none) -DEF( push_true, 1, 0, 1, none) -DEF( object, 1, 0, 1, none) -DEF( special_object, 2, 0, 1, u8) /* only used at the start of a function */ -DEF( rest, 3, 0, 1, u16) /* only used at the start of a function */ - -DEF( drop, 1, 1, 0, none) /* a -> */ -DEF( nip, 1, 2, 1, none) /* a b -> b */ -DEF( nip1, 1, 3, 2, none) /* a b c -> b c */ -DEF( dup, 1, 1, 2, none) /* a -> a a */ -DEF( dup1, 1, 2, 3, none) /* a b -> a a b */ -DEF( dup2, 1, 2, 4, none) /* a b -> a b a b */ -DEF( dup3, 1, 3, 6, none) /* a b c -> a b c a b c */ -DEF( insert2, 1, 2, 3, none) /* obj a -> a obj a (dup_x1) */ -DEF( insert3, 1, 3, 4, none) /* obj prop a -> a obj prop a (dup_x2) */ -DEF( insert4, 1, 4, 5, none) /* this obj prop a -> a this obj prop a */ -DEF( perm3, 1, 3, 3, none) /* obj a b -> a obj b */ -DEF( perm4, 1, 4, 4, none) /* obj prop a b -> a obj prop b */ -DEF( perm5, 1, 5, 5, none) /* this obj prop a b -> a this obj prop b */ -DEF( swap, 1, 2, 2, none) /* a b -> b a */ -DEF( swap2, 1, 4, 4, none) /* a b c d -> c d a b */ -DEF( rot3l, 1, 3, 3, none) /* x a b -> a b x */ -DEF( rot3r, 1, 3, 3, none) /* a b x -> x a b */ -DEF( rot4l, 1, 4, 4, none) /* x a b c -> a b c x */ -DEF( rot5l, 1, 5, 5, none) /* x a b c d -> a b c d x */ - -DEF(call_constructor, 3, 2, 1, npop) /* func new.target args -> ret. arguments are not counted in n_pop */ -DEF( call, 3, 1, 1, npop) /* arguments are not counted in n_pop */ -DEF( tail_call, 3, 1, 0, npop) /* arguments are not counted in n_pop */ -DEF( call_method, 3, 2, 1, npop) /* arguments are not counted in n_pop */ -DEF(tail_call_method, 3, 2, 0, npop) /* arguments are not counted in n_pop */ -DEF( array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */ -DEF( apply, 3, 3, 1, u16) -DEF( return, 1, 1, 0, none) -DEF( return_undef, 1, 0, 0, none) -DEF(check_ctor_return, 1, 1, 2, none) -DEF( check_ctor, 1, 0, 0, none) -DEF( init_ctor, 1, 0, 1, none) -DEF( check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */ -DEF( add_brand, 1, 2, 0, none) /* this_obj home_obj -> */ -DEF( return_async, 1, 1, 0, none) -DEF( throw, 1, 1, 0, none) -DEF( throw_error, 6, 0, 0, atom_u8) -DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */ -DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */ -DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a - bytecode string */ -DEF( get_super, 1, 1, 1, none) -DEF( import, 1, 2, 1, none) /* dynamic module import */ - -DEF( check_var, 5, 0, 1, atom) /* check if a variable exists */ -DEF( get_var_undef, 5, 0, 1, atom) /* push undefined if the variable does not exist */ -DEF( get_var, 5, 0, 1, atom) /* throw an exception if the variable does not exist */ -DEF( put_var, 5, 1, 0, atom) /* must come after get_var */ -DEF( put_var_init, 5, 1, 0, atom) /* must come after put_var. Used to initialize a global lexical variable */ -DEF( put_var_strict, 5, 2, 0, atom) /* for strict mode variable write */ - -DEF( get_ref_value, 1, 2, 3, none) -DEF( put_ref_value, 1, 3, 0, none) - -DEF( define_var, 6, 0, 0, atom_u8) -DEF(check_define_var, 6, 0, 0, atom_u8) -DEF( define_func, 6, 1, 0, atom_u8) -DEF( get_field, 5, 1, 1, atom) -DEF( get_field2, 5, 1, 2, atom) -DEF( put_field, 5, 2, 0, atom) -DEF( get_private_field, 1, 2, 1, none) /* obj prop -> value */ -DEF( put_private_field, 1, 3, 0, none) /* obj value prop -> */ -DEF(define_private_field, 1, 3, 1, none) /* obj prop value -> obj */ -DEF( get_array_el, 1, 2, 1, none) -DEF( get_array_el2, 1, 2, 2, none) /* obj prop -> obj value */ -DEF( get_array_el3, 1, 2, 3, none) /* obj prop -> obj prop1 value */ -DEF( put_array_el, 1, 3, 0, none) -DEF(get_super_value, 1, 3, 1, none) /* this obj prop -> value */ -DEF(put_super_value, 1, 4, 0, none) /* this obj prop value -> */ -DEF( define_field, 5, 2, 1, atom) -DEF( set_name, 5, 1, 1, atom) -DEF(set_name_computed, 1, 2, 2, none) -DEF( set_proto, 1, 2, 1, none) -DEF(set_home_object, 1, 2, 2, none) -DEF(define_array_el, 1, 3, 2, none) -DEF( append, 1, 3, 2, none) /* append enumerated object, update length */ -DEF(copy_data_properties, 2, 3, 3, u8) -DEF( define_method, 6, 2, 1, atom_u8) -DEF(define_method_computed, 2, 3, 1, u8) /* must come after define_method */ -DEF( define_class, 6, 2, 2, atom_u8) /* parent ctor -> ctor proto */ -DEF( define_class_computed, 6, 3, 3, atom_u8) /* field_name parent ctor -> field_name ctor proto (class with computed name) */ - -DEF( get_loc, 3, 0, 1, loc) -DEF( put_loc, 3, 1, 0, loc) /* must come after get_loc */ -DEF( set_loc, 3, 1, 1, loc) /* must come after put_loc */ -DEF( get_arg, 3, 0, 1, arg) -DEF( put_arg, 3, 1, 0, arg) /* must come after get_arg */ -DEF( set_arg, 3, 1, 1, arg) /* must come after put_arg */ -DEF( get_var_ref, 3, 0, 1, var_ref) -DEF( put_var_ref, 3, 1, 0, var_ref) /* must come after get_var_ref */ -DEF( set_var_ref, 3, 1, 1, var_ref) /* must come after put_var_ref */ -DEF(set_loc_uninitialized, 3, 0, 0, loc) -DEF( get_loc_check, 3, 0, 1, loc) -DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */ -DEF( put_loc_check_init, 3, 1, 0, loc) -DEF(get_loc_checkthis, 3, 0, 1, loc) -DEF(get_var_ref_check, 3, 0, 1, var_ref) -DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */ -DEF(put_var_ref_check_init, 3, 1, 0, var_ref) -DEF( close_loc, 3, 0, 0, loc) -DEF( if_false, 5, 1, 0, label) -DEF( if_true, 5, 1, 0, label) /* must come after if_false */ -DEF( goto, 5, 0, 0, label) /* must come after if_true */ -DEF( catch, 5, 0, 1, label) -DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */ -DEF( ret, 1, 1, 0, none) /* used to return from the finally block */ -DEF( nip_catch, 1, 2, 1, none) /* catch ... a -> a */ - -DEF( to_object, 1, 1, 1, none) -//DEF( to_string, 1, 1, 1, none) -DEF( to_propkey, 1, 1, 1, none) - -DEF( with_get_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ -DEF( with_put_var, 10, 2, 1, atom_label_u8) /* must be in the same order as scope_xxx */ -DEF(with_delete_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ -DEF( with_make_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ -DEF( with_get_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ - -DEF( make_loc_ref, 7, 0, 2, atom_u16) -DEF( make_arg_ref, 7, 0, 2, atom_u16) -DEF(make_var_ref_ref, 7, 0, 2, atom_u16) -DEF( make_var_ref, 5, 0, 2, atom) - -DEF( for_in_start, 1, 1, 1, none) -DEF( for_of_start, 1, 1, 3, none) -DEF(for_await_of_start, 1, 1, 3, none) -DEF( for_in_next, 1, 1, 3, none) -DEF( for_of_next, 2, 3, 5, u8) -DEF(for_await_of_next, 1, 3, 4, none) /* iter next catch_offset -> iter next catch_offset obj */ -DEF(iterator_check_object, 1, 1, 1, none) -DEF(iterator_get_value_done, 1, 2, 3, none) /* catch_offset obj -> catch_offset value done */ -DEF( iterator_close, 1, 3, 0, none) -DEF( iterator_next, 1, 4, 4, none) -DEF( iterator_call, 2, 4, 5, u8) -DEF( initial_yield, 1, 0, 0, none) -DEF( yield, 1, 1, 2, none) -DEF( yield_star, 1, 1, 2, none) -DEF(async_yield_star, 1, 1, 2, none) -DEF( await, 1, 1, 1, none) - -/* arithmetic/logic operations */ -DEF( neg, 1, 1, 1, none) -DEF( plus, 1, 1, 1, none) -DEF( dec, 1, 1, 1, none) -DEF( inc, 1, 1, 1, none) -DEF( post_dec, 1, 1, 2, none) -DEF( post_inc, 1, 1, 2, none) -DEF( dec_loc, 2, 0, 0, loc8) -DEF( inc_loc, 2, 0, 0, loc8) -DEF( add_loc, 2, 1, 0, loc8) -DEF( not, 1, 1, 1, none) -DEF( lnot, 1, 1, 1, none) -DEF( typeof, 1, 1, 1, none) -DEF( delete, 1, 2, 1, none) -DEF( delete_var, 5, 0, 1, atom) - -DEF( mul, 1, 2, 1, none) -DEF( div, 1, 2, 1, none) -DEF( mod, 1, 2, 1, none) -DEF( add, 1, 2, 1, none) -DEF( sub, 1, 2, 1, none) -DEF( pow, 1, 2, 1, none) -DEF( shl, 1, 2, 1, none) -DEF( sar, 1, 2, 1, none) -DEF( shr, 1, 2, 1, none) -DEF( lt, 1, 2, 1, none) -DEF( lte, 1, 2, 1, none) -DEF( gt, 1, 2, 1, none) -DEF( gte, 1, 2, 1, none) -DEF( instanceof, 1, 2, 1, none) -DEF( in, 1, 2, 1, none) -DEF( eq, 1, 2, 1, none) -DEF( neq, 1, 2, 1, none) -DEF( strict_eq, 1, 2, 1, none) -DEF( strict_neq, 1, 2, 1, none) -DEF( and, 1, 2, 1, none) -DEF( xor, 1, 2, 1, none) -DEF( or, 1, 2, 1, none) -DEF(is_undefined_or_null, 1, 1, 1, none) -DEF( private_in, 1, 2, 1, none) -DEF(push_bigint_i32, 5, 0, 1, i32) -/* must be the last non short and non temporary opcode */ -DEF( nop, 1, 0, 0, none) - -/* temporary opcodes: never emitted in the final bytecode */ - -def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ -def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ - -def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */ - -/* the following opcodes must be in the same order as the 'with_x' and - get_var_undef, get_var and put_var opcodes */ -def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ -def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ -def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */ -def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ -def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */ -def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ -def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ -def(scope_get_var_checkthis, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2, only used to return 'this' in derived class constructors */ -def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */ -def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */ -def(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */ -def(scope_in_private_field, 7, 1, 1, atom_u16) /* obj -> res emitted in phase 1, removed in phase 2 */ -def(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase 2 */ -def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */ -def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */ - -def( line_num, 5, 0, 0, u32) /* emitted in phase 1, removed in phase 3 */ - -#if SHORT_OPCODES -DEF( push_minus1, 1, 0, 1, none_int) -DEF( push_0, 1, 0, 1, none_int) -DEF( push_1, 1, 0, 1, none_int) -DEF( push_2, 1, 0, 1, none_int) -DEF( push_3, 1, 0, 1, none_int) -DEF( push_4, 1, 0, 1, none_int) -DEF( push_5, 1, 0, 1, none_int) -DEF( push_6, 1, 0, 1, none_int) -DEF( push_7, 1, 0, 1, none_int) -DEF( push_i8, 2, 0, 1, i8) -DEF( push_i16, 3, 0, 1, i16) -DEF( push_const8, 2, 0, 1, const8) -DEF( fclosure8, 2, 0, 1, const8) /* must follow push_const8 */ -DEF(push_empty_string, 1, 0, 1, none) - -DEF( get_loc8, 2, 0, 1, loc8) -DEF( put_loc8, 2, 1, 0, loc8) -DEF( set_loc8, 2, 1, 1, loc8) - -DEF( get_loc0, 1, 0, 1, none_loc) -DEF( get_loc1, 1, 0, 1, none_loc) -DEF( get_loc2, 1, 0, 1, none_loc) -DEF( get_loc3, 1, 0, 1, none_loc) -DEF( put_loc0, 1, 1, 0, none_loc) -DEF( put_loc1, 1, 1, 0, none_loc) -DEF( put_loc2, 1, 1, 0, none_loc) -DEF( put_loc3, 1, 1, 0, none_loc) -DEF( set_loc0, 1, 1, 1, none_loc) -DEF( set_loc1, 1, 1, 1, none_loc) -DEF( set_loc2, 1, 1, 1, none_loc) -DEF( set_loc3, 1, 1, 1, none_loc) -DEF( get_arg0, 1, 0, 1, none_arg) -DEF( get_arg1, 1, 0, 1, none_arg) -DEF( get_arg2, 1, 0, 1, none_arg) -DEF( get_arg3, 1, 0, 1, none_arg) -DEF( put_arg0, 1, 1, 0, none_arg) -DEF( put_arg1, 1, 1, 0, none_arg) -DEF( put_arg2, 1, 1, 0, none_arg) -DEF( put_arg3, 1, 1, 0, none_arg) -DEF( set_arg0, 1, 1, 1, none_arg) -DEF( set_arg1, 1, 1, 1, none_arg) -DEF( set_arg2, 1, 1, 1, none_arg) -DEF( set_arg3, 1, 1, 1, none_arg) -DEF( get_var_ref0, 1, 0, 1, none_var_ref) -DEF( get_var_ref1, 1, 0, 1, none_var_ref) -DEF( get_var_ref2, 1, 0, 1, none_var_ref) -DEF( get_var_ref3, 1, 0, 1, none_var_ref) -DEF( put_var_ref0, 1, 1, 0, none_var_ref) -DEF( put_var_ref1, 1, 1, 0, none_var_ref) -DEF( put_var_ref2, 1, 1, 0, none_var_ref) -DEF( put_var_ref3, 1, 1, 0, none_var_ref) -DEF( set_var_ref0, 1, 1, 1, none_var_ref) -DEF( set_var_ref1, 1, 1, 1, none_var_ref) -DEF( set_var_ref2, 1, 1, 1, none_var_ref) -DEF( set_var_ref3, 1, 1, 1, none_var_ref) - -DEF( get_length, 1, 1, 1, none) - -DEF( if_false8, 2, 1, 0, label8) -DEF( if_true8, 2, 1, 0, label8) /* must come after if_false8 */ -DEF( goto8, 2, 0, 0, label8) /* must come after if_true8 */ -DEF( goto16, 3, 0, 0, label16) - -DEF( call0, 1, 1, 1, npopx) -DEF( call1, 1, 1, 1, npopx) -DEF( call2, 1, 1, 1, npopx) -DEF( call3, 1, 1, 1, npopx) - -DEF( is_undefined, 1, 1, 1, none) -DEF( is_null, 1, 1, 1, none) -DEF(typeof_is_undefined, 1, 1, 1, none) -DEF( typeof_is_function, 1, 1, 1, none) -#endif - -#undef DEF -#undef def -#endif /* DEF */ diff --git a/packages/javascript/javascript_android/cxx/quickjs/quickjs.c b/packages/javascript/javascript_android/cxx/quickjs/quickjs.c deleted file mode 100644 index caad931..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/quickjs.c +++ /dev/null @@ -1,55899 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2025 Fabrice Bellard - * Copyright (c) 2017-2025 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__APPLE__) -#include -#elif defined(__linux__) || defined(__GLIBC__) -#include -#elif defined(__FreeBSD__) -#include -#endif - -#include "cutils.h" -#include "list.h" -#include "quickjs.h" -#include "libregexp.h" -#include "libunicode.h" -#include "dtoa.h" - -#define OPTIMIZE 1 -#define SHORT_OPCODES 1 -#if defined(EMSCRIPTEN) -#define DIRECT_DISPATCH 0 -#else -#define DIRECT_DISPATCH 1 -#endif - -#if defined(__APPLE__) -#define MALLOC_OVERHEAD 0 -#else -#define MALLOC_OVERHEAD 8 -#endif - -#if !defined(_WIN32) -/* define it if printf uses the RNDN rounding mode instead of RNDNA */ -#define CONFIG_PRINTF_RNDN -#endif - -/* define to include Atomics.* operations which depend on the OS - threads */ -#if !defined(EMSCRIPTEN) -#define CONFIG_ATOMICS -#endif - -#if !defined(EMSCRIPTEN) -/* enable stack limitation */ -#define CONFIG_STACK_CHECK -#endif - - -/* dump object free */ -//#define DUMP_FREE -//#define DUMP_CLOSURE -/* dump the bytecode of the compiled functions: combination of bits - 1: dump pass 3 final byte code - 2: dump pass 2 code - 4: dump pass 1 code - 8: dump stdlib functions - 16: dump bytecode in hex - 32: dump line number table - 64: dump compute_stack_size - */ -//#define DUMP_BYTECODE (1) -/* dump the occurence of the automatic GC */ -//#define DUMP_GC -/* dump objects freed by the garbage collector */ -//#define DUMP_GC_FREE -/* dump objects leaking when freeing the runtime */ -//#define DUMP_LEAKS 1 -/* dump memory usage before running the garbage collector */ -//#define DUMP_MEM -//#define DUMP_OBJECTS /* dump objects in JS_FreeContext */ -//#define DUMP_ATOMS /* dump atoms in JS_FreeContext */ -//#define DUMP_SHAPES /* dump shapes in JS_FreeContext */ -//#define DUMP_MODULE_RESOLVE -//#define DUMP_MODULE_EXEC -//#define DUMP_PROMISE -//#define DUMP_READ_OBJECT -//#define DUMP_ROPE_REBALANCE - -/* test the GC by forcing it before each object allocation */ -//#define FORCE_GC_AT_MALLOC - -#ifdef CONFIG_ATOMICS -#include -#include -#include -#endif - -enum { - /* classid tag */ /* union usage | properties */ - JS_CLASS_OBJECT = 1, /* must be first */ - JS_CLASS_ARRAY, /* u.array | length */ - JS_CLASS_ERROR, - JS_CLASS_NUMBER, /* u.object_data */ - JS_CLASS_STRING, /* u.object_data */ - JS_CLASS_BOOLEAN, /* u.object_data */ - JS_CLASS_SYMBOL, /* u.object_data */ - JS_CLASS_ARGUMENTS, /* u.array | length */ - JS_CLASS_MAPPED_ARGUMENTS, /* | length */ - JS_CLASS_DATE, /* u.object_data */ - JS_CLASS_MODULE_NS, - JS_CLASS_C_FUNCTION, /* u.cfunc */ - JS_CLASS_BYTECODE_FUNCTION, /* u.func */ - JS_CLASS_BOUND_FUNCTION, /* u.bound_function */ - JS_CLASS_C_FUNCTION_DATA, /* u.c_function_data_record */ - JS_CLASS_GENERATOR_FUNCTION, /* u.func */ - JS_CLASS_FOR_IN_ITERATOR, /* u.for_in_iterator */ - JS_CLASS_REGEXP, /* u.regexp */ - JS_CLASS_ARRAY_BUFFER, /* u.array_buffer */ - JS_CLASS_SHARED_ARRAY_BUFFER, /* u.array_buffer */ - JS_CLASS_UINT8C_ARRAY, /* u.array (typed_array) */ - JS_CLASS_INT8_ARRAY, /* u.array (typed_array) */ - JS_CLASS_UINT8_ARRAY, /* u.array (typed_array) */ - JS_CLASS_INT16_ARRAY, /* u.array (typed_array) */ - JS_CLASS_UINT16_ARRAY, /* u.array (typed_array) */ - JS_CLASS_INT32_ARRAY, /* u.array (typed_array) */ - JS_CLASS_UINT32_ARRAY, /* u.array (typed_array) */ - JS_CLASS_BIG_INT64_ARRAY, /* u.array (typed_array) */ - JS_CLASS_BIG_UINT64_ARRAY, /* u.array (typed_array) */ - JS_CLASS_FLOAT16_ARRAY, /* u.array (typed_array) */ - JS_CLASS_FLOAT32_ARRAY, /* u.array (typed_array) */ - JS_CLASS_FLOAT64_ARRAY, /* u.array (typed_array) */ - JS_CLASS_DATAVIEW, /* u.typed_array */ - JS_CLASS_BIG_INT, /* u.object_data */ - JS_CLASS_MAP, /* u.map_state */ - JS_CLASS_SET, /* u.map_state */ - JS_CLASS_WEAKMAP, /* u.map_state */ - JS_CLASS_WEAKSET, /* u.map_state */ - JS_CLASS_MAP_ITERATOR, /* u.map_iterator_data */ - JS_CLASS_SET_ITERATOR, /* u.map_iterator_data */ - JS_CLASS_ARRAY_ITERATOR, /* u.array_iterator_data */ - JS_CLASS_STRING_ITERATOR, /* u.array_iterator_data */ - JS_CLASS_REGEXP_STRING_ITERATOR, /* u.regexp_string_iterator_data */ - JS_CLASS_GENERATOR, /* u.generator_data */ - JS_CLASS_PROXY, /* u.proxy_data */ - JS_CLASS_PROMISE, /* u.promise_data */ - JS_CLASS_PROMISE_RESOLVE_FUNCTION, /* u.promise_function_data */ - JS_CLASS_PROMISE_REJECT_FUNCTION, /* u.promise_function_data */ - JS_CLASS_ASYNC_FUNCTION, /* u.func */ - JS_CLASS_ASYNC_FUNCTION_RESOLVE, /* u.async_function_data */ - JS_CLASS_ASYNC_FUNCTION_REJECT, /* u.async_function_data */ - JS_CLASS_ASYNC_FROM_SYNC_ITERATOR, /* u.async_from_sync_iterator_data */ - JS_CLASS_ASYNC_GENERATOR_FUNCTION, /* u.func */ - JS_CLASS_ASYNC_GENERATOR, /* u.async_generator_data */ - JS_CLASS_WEAK_REF, - JS_CLASS_FINALIZATION_REGISTRY, - - JS_CLASS_INIT_COUNT, /* last entry for predefined classes */ -}; - -/* number of typed array types */ -#define JS_TYPED_ARRAY_COUNT (JS_CLASS_FLOAT64_ARRAY - JS_CLASS_UINT8C_ARRAY + 1) -static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT]; -#define typed_array_size_log2(classid) (typed_array_size_log2[(classid)- JS_CLASS_UINT8C_ARRAY]) - -typedef enum JSErrorEnum { - JS_EVAL_ERROR, - JS_RANGE_ERROR, - JS_REFERENCE_ERROR, - JS_SYNTAX_ERROR, - JS_TYPE_ERROR, - JS_URI_ERROR, - JS_INTERNAL_ERROR, - JS_AGGREGATE_ERROR, - - JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */ -} JSErrorEnum; - -/* the variable and scope indexes must fit on 16 bits. The (-1) and - ARG_SCOPE_END values are reserved. */ -#define JS_MAX_LOCAL_VARS 65534 -#define JS_STACK_SIZE_MAX 65534 -#define JS_STRING_LEN_MAX ((1 << 30) - 1) - -/* strings <= this length are not concatenated using ropes. if too - small, the rope memory overhead becomes high. */ -#define JS_STRING_ROPE_SHORT_LEN 512 -/* specific threshold for initial rope use */ -#define JS_STRING_ROPE_SHORT2_LEN 8192 -/* rope depth at which we rebalance */ -#define JS_STRING_ROPE_MAX_DEPTH 60 - -#define __exception __attribute__((warn_unused_result)) - -typedef struct JSShape JSShape; -typedef struct JSString JSString; -typedef struct JSString JSAtomStruct; -typedef struct JSObject JSObject; - -#define JS_VALUE_GET_OBJ(v) ((JSObject *)JS_VALUE_GET_PTR(v)) -#define JS_VALUE_GET_STRING(v) ((JSString *)JS_VALUE_GET_PTR(v)) -#define JS_VALUE_GET_STRING_ROPE(v) ((JSStringRope *)JS_VALUE_GET_PTR(v)) - -typedef enum { - JS_GC_PHASE_NONE, - JS_GC_PHASE_DECREF, - JS_GC_PHASE_REMOVE_CYCLES, -} JSGCPhaseEnum; - -typedef enum OPCodeEnum OPCodeEnum; - -struct JSRuntime { - JSMallocFunctions mf; - JSMallocState malloc_state; - const char *rt_info; - - int atom_hash_size; /* power of two */ - int atom_count; - int atom_size; - int atom_count_resize; /* resize hash table at this count */ - uint32_t *atom_hash; - JSAtomStruct **atom_array; - int atom_free_index; /* 0 = none */ - - int class_count; /* size of class_array */ - JSClass *class_array; - - struct list_head context_list; /* list of JSContext.link */ - /* list of JSGCObjectHeader.link. List of allocated GC objects (used - by the garbage collector) */ - struct list_head gc_obj_list; - /* list of JSGCObjectHeader.link. Used during JS_FreeValueRT() */ - struct list_head gc_zero_ref_count_list; - struct list_head tmp_obj_list; /* used during GC */ - JSGCPhaseEnum gc_phase : 8; - size_t malloc_gc_threshold; - struct list_head weakref_list; /* list of JSWeakRefHeader.link */ -#ifdef DUMP_LEAKS - struct list_head string_list; /* list of JSString.link */ -#endif - /* stack limitation */ - uintptr_t stack_size; /* in bytes, 0 if no limit */ - uintptr_t stack_top; - uintptr_t stack_limit; /* lower stack limit */ - - JSValue current_exception; - /* true if the current exception cannot be catched */ - BOOL current_exception_is_uncatchable : 8; - /* true if inside an out of memory error, to avoid recursing */ - BOOL in_out_of_memory : 8; - - struct JSStackFrame *current_stack_frame; - - JSInterruptHandler *interrupt_handler; - void *interrupt_opaque; - - JSHostPromiseRejectionTracker *host_promise_rejection_tracker; - void *host_promise_rejection_tracker_opaque; - - struct list_head job_list; /* list of JSJobEntry.link */ - - JSModuleNormalizeFunc *module_normalize_func; - BOOL module_loader_has_attr; - union { - JSModuleLoaderFunc *module_loader_func; - JSModuleLoaderFunc2 *module_loader_func2; - } u; - JSModuleCheckSupportedImportAttributes *module_check_attrs; - void *module_loader_opaque; - /* timestamp for internal use in module evaluation */ - int64_t module_async_evaluation_next_timestamp; - - BOOL can_block : 8; /* TRUE if Atomics.wait can block */ - /* used to allocate, free and clone SharedArrayBuffers */ - JSSharedArrayBufferFunctions sab_funcs; - /* see JS_SetStripInfo() */ - uint8_t strip_flags; - - /* Shape hash table */ - int shape_hash_bits; - int shape_hash_size; - int shape_hash_count; /* number of hashed shapes */ - JSShape **shape_hash; - void *user_opaque; -}; - -struct JSClass { - uint32_t class_id; /* 0 means free entry */ - JSAtom class_name; - JSClassFinalizer *finalizer; - JSClassGCMark *gc_mark; - JSClassCall *call; - /* pointers for exotic behavior, can be NULL if none are present */ - const JSClassExoticMethods *exotic; -}; - -#define JS_MODE_STRICT (1 << 0) -#define JS_MODE_ASYNC (1 << 2) /* async function */ -#define JS_MODE_BACKTRACE_BARRIER (1 << 3) /* stop backtrace before this frame */ - -typedef struct JSStackFrame { - struct JSStackFrame *prev_frame; /* NULL if first stack frame */ - JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */ - JSValue *arg_buf; /* arguments */ - JSValue *var_buf; /* variables */ - struct list_head var_ref_list; /* list of JSVarRef.var_ref_link */ - const uint8_t *cur_pc; /* only used in bytecode functions : PC of the - instruction after the call */ - int arg_count; - int js_mode; /* not supported for C functions */ - /* only used in generators. Current stack pointer value. NULL if - the function is running. */ - JSValue *cur_sp; -} JSStackFrame; - -typedef enum { - JS_GC_OBJ_TYPE_JS_OBJECT, - JS_GC_OBJ_TYPE_FUNCTION_BYTECODE, - JS_GC_OBJ_TYPE_SHAPE, - JS_GC_OBJ_TYPE_VAR_REF, - JS_GC_OBJ_TYPE_ASYNC_FUNCTION, - JS_GC_OBJ_TYPE_JS_CONTEXT, - JS_GC_OBJ_TYPE_MODULE, -} JSGCObjectTypeEnum; - -/* header for GC objects. GC objects are C data structures with a - reference count that can reference other GC objects. JS Objects are - a particular type of GC object. */ -struct JSGCObjectHeader { - int ref_count; /* must come first, 32-bit */ - JSGCObjectTypeEnum gc_obj_type : 4; - uint8_t mark : 4; /* used by the GC */ - uint8_t dummy1; /* not used by the GC */ - uint16_t dummy2; /* not used by the GC */ - struct list_head link; -}; - -typedef enum { - JS_WEAKREF_TYPE_MAP, - JS_WEAKREF_TYPE_WEAKREF, - JS_WEAKREF_TYPE_FINREC, -} JSWeakRefHeaderTypeEnum; - -typedef struct { - struct list_head link; - JSWeakRefHeaderTypeEnum weakref_type; -} JSWeakRefHeader; - -typedef struct JSVarRef { - union { - JSGCObjectHeader header; /* must come first */ - struct { - int __gc_ref_count; /* corresponds to header.ref_count */ - uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */ - uint8_t is_detached; - }; - }; - JSValue *pvalue; /* pointer to the value, either on the stack or - to 'value' */ - union { - JSValue value; /* used when is_detached = TRUE */ - struct { - struct list_head var_ref_link; /* JSStackFrame.var_ref_list list */ - struct JSAsyncFunctionState *async_func; /* != NULL if async stack frame */ - }; /* used when is_detached = FALSE */ - }; -} JSVarRef; - -/* bigint */ - -#if JS_LIMB_BITS == 32 - -typedef int32_t js_slimb_t; -typedef uint32_t js_limb_t; -typedef int64_t js_sdlimb_t; -typedef uint64_t js_dlimb_t; - -#define JS_LIMB_DIGITS 9 - -#else - -typedef __int128 int128_t; -typedef unsigned __int128 uint128_t; -typedef int64_t js_slimb_t; -typedef uint64_t js_limb_t; -typedef int128_t js_sdlimb_t; -typedef uint128_t js_dlimb_t; - -#define JS_LIMB_DIGITS 19 - -#endif - -typedef struct JSBigInt { - JSRefCountHeader header; /* must come first, 32-bit */ - uint32_t len; /* number of limbs, >= 1 */ - js_limb_t tab[]; /* two's complement representation, always - normalized so that 'len' is the minimum - possible length >= 1 */ -} JSBigInt; - -/* this bigint structure can hold a 64 bit integer */ -typedef struct { - js_limb_t big_int_buf[sizeof(JSBigInt) / sizeof(js_limb_t)]; /* for JSBigInt */ - /* must come just after */ - js_limb_t tab[(64 + JS_LIMB_BITS - 1) / JS_LIMB_BITS]; -} JSBigIntBuf; - -typedef enum { - JS_AUTOINIT_ID_PROTOTYPE, - JS_AUTOINIT_ID_MODULE_NS, - JS_AUTOINIT_ID_PROP, -} JSAutoInitIDEnum; - -/* must be large enough to have a negligible runtime cost and small - enough to call the interrupt callback often. */ -#define JS_INTERRUPT_COUNTER_INIT 10000 - -struct JSContext { - JSGCObjectHeader header; /* must come first */ - JSRuntime *rt; - struct list_head link; - - uint16_t binary_object_count; - int binary_object_size; - - JSShape *array_shape; /* initial shape for Array objects */ - - JSValue *class_proto; - JSValue function_proto; - JSValue function_ctor; - JSValue array_ctor; - JSValue regexp_ctor; - JSValue promise_ctor; - JSValue native_error_proto[JS_NATIVE_ERROR_COUNT]; - JSValue iterator_proto; - JSValue async_iterator_proto; - JSValue array_proto_values; - JSValue throw_type_error; - JSValue eval_obj; - - JSValue global_obj; /* global object */ - JSValue global_var_obj; /* contains the global let/const definitions */ - - uint64_t random_state; - - /* when the counter reaches zero, JSRutime.interrupt_handler is called */ - int interrupt_counter; - - struct list_head loaded_modules; /* list of JSModuleDef.link */ - - /* if NULL, RegExp compilation is not supported */ - JSValue (*compile_regexp)(JSContext *ctx, JSValueConst pattern, - JSValueConst flags); - /* if NULL, eval is not supported */ - JSValue (*eval_internal)(JSContext *ctx, JSValueConst this_obj, - const char *input, size_t input_len, - const char *filename, int flags, int scope_idx); - void *user_opaque; -}; - -typedef union JSFloat64Union { - double d; - uint64_t u64; - uint32_t u32[2]; -} JSFloat64Union; - -enum { - JS_ATOM_TYPE_STRING = 1, - JS_ATOM_TYPE_GLOBAL_SYMBOL, - JS_ATOM_TYPE_SYMBOL, - JS_ATOM_TYPE_PRIVATE, -}; - -typedef enum { - JS_ATOM_KIND_STRING, - JS_ATOM_KIND_SYMBOL, - JS_ATOM_KIND_PRIVATE, -} JSAtomKindEnum; - -#define JS_ATOM_HASH_MASK ((1 << 30) - 1) -#define JS_ATOM_HASH_PRIVATE JS_ATOM_HASH_MASK - -struct JSString { - JSRefCountHeader header; /* must come first, 32-bit */ - uint32_t len : 31; - uint8_t is_wide_char : 1; /* 0 = 8 bits, 1 = 16 bits characters */ - /* for JS_ATOM_TYPE_SYMBOL: hash = weakref_count, atom_type = 3, - for JS_ATOM_TYPE_PRIVATE: hash = JS_ATOM_HASH_PRIVATE, atom_type = 3 - XXX: could change encoding to have one more bit in hash */ - uint32_t hash : 30; - uint8_t atom_type : 2; /* != 0 if atom, JS_ATOM_TYPE_x */ - uint32_t hash_next; /* atom_index for JS_ATOM_TYPE_SYMBOL */ -#ifdef DUMP_LEAKS - struct list_head link; /* string list */ -#endif - union { - uint8_t str8[0]; /* 8 bit strings will get an extra null terminator */ - uint16_t str16[0]; - } u; -}; - -typedef struct JSStringRope { - JSRefCountHeader header; /* must come first, 32-bit */ - uint32_t len; - uint8_t is_wide_char; /* 0 = 8 bits, 1 = 16 bits characters */ - uint8_t depth; /* max depth of the rope tree */ - /* XXX: could reduce memory usage by using a direct pointer with - bit 0 to select rope or string */ - JSValue left; - JSValue right; /* might be the empty string */ -} JSStringRope; - -typedef struct JSClosureVar { - uint8_t is_local : 1; - uint8_t is_arg : 1; - uint8_t is_const : 1; - uint8_t is_lexical : 1; - uint8_t var_kind : 4; /* see JSVarKindEnum */ - /* 8 bits available */ - uint16_t var_idx; /* is_local = TRUE: index to a normal variable of the - parent function. otherwise: index to a closure - variable of the parent function */ - JSAtom var_name; -} JSClosureVar; - -#define ARG_SCOPE_INDEX 1 -#define ARG_SCOPE_END (-2) - -typedef struct JSVarScope { - int parent; /* index into fd->scopes of the enclosing scope */ - int first; /* index into fd->vars of the last variable in this scope */ -} JSVarScope; - -typedef enum { - /* XXX: add more variable kinds here instead of using bit fields */ - JS_VAR_NORMAL, - JS_VAR_FUNCTION_DECL, /* lexical var with function declaration */ - JS_VAR_NEW_FUNCTION_DECL, /* lexical var with async/generator - function declaration */ - JS_VAR_CATCH, - JS_VAR_FUNCTION_NAME, /* function expression name */ - JS_VAR_PRIVATE_FIELD, - JS_VAR_PRIVATE_METHOD, - JS_VAR_PRIVATE_GETTER, - JS_VAR_PRIVATE_SETTER, /* must come after JS_VAR_PRIVATE_GETTER */ - JS_VAR_PRIVATE_GETTER_SETTER, /* must come after JS_VAR_PRIVATE_SETTER */ -} JSVarKindEnum; - -/* XXX: could use a different structure in bytecode functions to save - memory */ -typedef struct JSVarDef { - JSAtom var_name; - /* index into fd->scopes of this variable lexical scope */ - int scope_level; - /* during compilation: - - if scope_level = 0: scope in which the variable is defined - - if scope_level != 0: index into fd->vars of the next - variable in the same or enclosing lexical scope - in a bytecode function: - index into fd->vars of the next - variable in the same or enclosing lexical scope - */ - int scope_next; - uint8_t is_const : 1; - uint8_t is_lexical : 1; - uint8_t is_captured : 1; - uint8_t is_static_private : 1; /* only used during private class field parsing */ - uint8_t var_kind : 4; /* see JSVarKindEnum */ - /* only used during compilation: function pool index for lexical - variables with var_kind = - JS_VAR_FUNCTION_DECL/JS_VAR_NEW_FUNCTION_DECL or scope level of - the definition of the 'var' variables (they have scope_level = - 0) */ - int func_pool_idx : 24; /* only used during compilation : index in - the constant pool for hoisted function - definition */ -} JSVarDef; - -/* for the encoding of the pc2line table */ -#define PC2LINE_BASE (-1) -#define PC2LINE_RANGE 5 -#define PC2LINE_OP_FIRST 1 -#define PC2LINE_DIFF_PC_MAX ((255 - PC2LINE_OP_FIRST) / PC2LINE_RANGE) - -typedef enum JSFunctionKindEnum { - JS_FUNC_NORMAL = 0, - JS_FUNC_GENERATOR = (1 << 0), - JS_FUNC_ASYNC = (1 << 1), - JS_FUNC_ASYNC_GENERATOR = (JS_FUNC_GENERATOR | JS_FUNC_ASYNC), -} JSFunctionKindEnum; - -typedef struct JSFunctionBytecode { - JSGCObjectHeader header; /* must come first */ - uint8_t js_mode; - uint8_t has_prototype : 1; /* true if a prototype field is necessary */ - uint8_t has_simple_parameter_list : 1; - uint8_t is_derived_class_constructor : 1; - /* true if home_object needs to be initialized */ - uint8_t need_home_object : 1; - uint8_t func_kind : 2; - uint8_t new_target_allowed : 1; - uint8_t super_call_allowed : 1; - uint8_t super_allowed : 1; - uint8_t arguments_allowed : 1; - uint8_t has_debug : 1; - uint8_t read_only_bytecode : 1; - uint8_t is_direct_or_indirect_eval : 1; /* used by JS_GetScriptOrModuleName() */ - /* XXX: 10 bits available */ - uint8_t *byte_code_buf; /* (self pointer) */ - int byte_code_len; - JSAtom func_name; - JSVarDef *vardefs; /* arguments + local variables (arg_count + var_count) (self pointer) */ - JSClosureVar *closure_var; /* list of variables in the closure (self pointer) */ - uint16_t arg_count; - uint16_t var_count; - uint16_t defined_arg_count; /* for length function property */ - uint16_t stack_size; /* maximum stack size */ - JSContext *realm; /* function realm */ - JSValue *cpool; /* constant pool (self pointer) */ - int cpool_count; - int closure_var_count; - struct { - /* debug info, move to separate structure to save memory? */ - JSAtom filename; - int source_len; - int pc2line_len; - uint8_t *pc2line_buf; - char *source; - } debug; -} JSFunctionBytecode; - -typedef struct JSBoundFunction { - JSValue func_obj; - JSValue this_val; - int argc; - JSValue argv[0]; -} JSBoundFunction; - -typedef enum JSIteratorKindEnum { - JS_ITERATOR_KIND_KEY, - JS_ITERATOR_KIND_VALUE, - JS_ITERATOR_KIND_KEY_AND_VALUE, -} JSIteratorKindEnum; - -typedef struct JSForInIterator { - JSValue obj; - uint32_t idx; - uint32_t atom_count; - uint8_t in_prototype_chain; - uint8_t is_array; - JSPropertyEnum *tab_atom; /* is_array = FALSE */ -} JSForInIterator; - -typedef struct JSRegExp { - JSString *pattern; - JSString *bytecode; /* also contains the flags */ -} JSRegExp; - -typedef struct JSProxyData { - JSValue target; - JSValue handler; - uint8_t is_func; - uint8_t is_revoked; -} JSProxyData; - -typedef struct JSArrayBuffer { - int byte_length; /* 0 if detached */ - uint8_t detached; - uint8_t shared; /* if shared, the array buffer cannot be detached */ - uint8_t *data; /* NULL if detached */ - struct list_head array_list; - void *opaque; - JSFreeArrayBufferDataFunc *free_func; -} JSArrayBuffer; - -typedef struct JSTypedArray { - struct list_head link; /* link to arraybuffer */ - JSObject *obj; /* back pointer to the TypedArray/DataView object */ - JSObject *buffer; /* based array buffer */ - uint32_t offset; /* offset in the array buffer */ - uint32_t length; /* length in the array buffer */ -} JSTypedArray; - -typedef struct JSAsyncFunctionState { - JSGCObjectHeader header; - JSValue this_val; /* 'this' argument */ - int argc; /* number of function arguments */ - BOOL throw_flag; /* used to throw an exception in JS_CallInternal() */ - BOOL is_completed; /* TRUE if the function has returned. The stack - frame is no longer valid */ - JSValue resolving_funcs[2]; /* only used in JS async functions */ - JSStackFrame frame; -} JSAsyncFunctionState; - -typedef enum { - /* binary operators */ - JS_OVOP_ADD, - JS_OVOP_SUB, - JS_OVOP_MUL, - JS_OVOP_DIV, - JS_OVOP_MOD, - JS_OVOP_POW, - JS_OVOP_OR, - JS_OVOP_AND, - JS_OVOP_XOR, - JS_OVOP_SHL, - JS_OVOP_SAR, - JS_OVOP_SHR, - JS_OVOP_EQ, - JS_OVOP_LESS, - - JS_OVOP_BINARY_COUNT, - /* unary operators */ - JS_OVOP_POS = JS_OVOP_BINARY_COUNT, - JS_OVOP_NEG, - JS_OVOP_INC, - JS_OVOP_DEC, - JS_OVOP_NOT, - - JS_OVOP_COUNT, -} JSOverloadableOperatorEnum; - -typedef struct { - uint32_t operator_index; - JSObject *ops[JS_OVOP_BINARY_COUNT]; /* self operators */ -} JSBinaryOperatorDefEntry; - -typedef struct { - int count; - JSBinaryOperatorDefEntry *tab; -} JSBinaryOperatorDef; - -typedef struct { - uint32_t operator_counter; - BOOL is_primitive; /* OperatorSet for a primitive type */ - /* NULL if no operator is defined */ - JSObject *self_ops[JS_OVOP_COUNT]; /* self operators */ - JSBinaryOperatorDef left; - JSBinaryOperatorDef right; -} JSOperatorSetData; - -typedef struct JSReqModuleEntry { - JSAtom module_name; - JSModuleDef *module; /* used using resolution */ - JSValue attributes; /* JS_UNDEFINED or an object contains the attributes as key/value */ -} JSReqModuleEntry; - -typedef enum JSExportTypeEnum { - JS_EXPORT_TYPE_LOCAL, - JS_EXPORT_TYPE_INDIRECT, -} JSExportTypeEnum; - -typedef struct JSExportEntry { - union { - struct { - int var_idx; /* closure variable index */ - JSVarRef *var_ref; /* if != NULL, reference to the variable */ - } local; /* for local export */ - int req_module_idx; /* module for indirect export */ - } u; - JSExportTypeEnum export_type; - JSAtom local_name; /* '*' if export ns from. not used for local - export after compilation */ - JSAtom export_name; /* exported variable name */ -} JSExportEntry; - -typedef struct JSStarExportEntry { - int req_module_idx; /* in req_module_entries */ -} JSStarExportEntry; - -typedef struct JSImportEntry { - int var_idx; /* closure variable index */ - BOOL is_star; /* import_name = '*' is a valid import name, so need a flag */ - JSAtom import_name; - int req_module_idx; /* in req_module_entries */ -} JSImportEntry; - -typedef enum { - JS_MODULE_STATUS_UNLINKED, - JS_MODULE_STATUS_LINKING, - JS_MODULE_STATUS_LINKED, - JS_MODULE_STATUS_EVALUATING, - JS_MODULE_STATUS_EVALUATING_ASYNC, - JS_MODULE_STATUS_EVALUATED, -} JSModuleStatus; - -struct JSModuleDef { - JSGCObjectHeader header; /* must come first */ - JSAtom module_name; - struct list_head link; - - JSReqModuleEntry *req_module_entries; - int req_module_entries_count; - int req_module_entries_size; - - JSExportEntry *export_entries; - int export_entries_count; - int export_entries_size; - - JSStarExportEntry *star_export_entries; - int star_export_entries_count; - int star_export_entries_size; - - JSImportEntry *import_entries; - int import_entries_count; - int import_entries_size; - - JSValue module_ns; - JSValue func_obj; /* only used for JS modules */ - JSModuleInitFunc *init_func; /* only used for C modules */ - BOOL has_tla : 8; /* true if func_obj contains await */ - BOOL resolved : 8; - BOOL func_created : 8; - JSModuleStatus status : 8; - /* temp use during js_module_link() & js_module_evaluate() */ - int dfs_index, dfs_ancestor_index; - JSModuleDef *stack_prev; - /* temp use during js_module_evaluate() */ - JSModuleDef **async_parent_modules; - int async_parent_modules_count; - int async_parent_modules_size; - int pending_async_dependencies; - BOOL async_evaluation; /* true: async_evaluation_timestamp corresponds to [[AsyncEvaluationOrder]] - false: [[AsyncEvaluationOrder]] is UNSET or DONE */ - int64_t async_evaluation_timestamp; - JSModuleDef *cycle_root; - JSValue promise; /* corresponds to spec field: capability */ - JSValue resolving_funcs[2]; /* corresponds to spec field: capability */ - - /* true if evaluation yielded an exception. It is saved in - eval_exception */ - BOOL eval_has_exception : 8; - JSValue eval_exception; - JSValue meta_obj; /* for import.meta */ - JSValue private_value; /* private value for C modules */ -}; - -typedef struct JSJobEntry { - struct list_head link; - JSContext *realm; - JSJobFunc *job_func; - int argc; - JSValue argv[0]; -} JSJobEntry; - -typedef struct JSProperty { - union { - JSValue value; /* JS_PROP_NORMAL */ - struct { /* JS_PROP_GETSET */ - JSObject *getter; /* NULL if undefined */ - JSObject *setter; /* NULL if undefined */ - } getset; - JSVarRef *var_ref; /* JS_PROP_VARREF */ - struct { /* JS_PROP_AUTOINIT */ - /* in order to use only 2 pointers, we compress the realm - and the init function pointer */ - uintptr_t realm_and_id; /* realm and init_id (JS_AUTOINIT_ID_x) - in the 2 low bits */ - void *opaque; - } init; - } u; -} JSProperty; - -#define JS_PROP_INITIAL_SIZE 2 -#define JS_PROP_INITIAL_HASH_SIZE 4 /* must be a power of two */ -#define JS_ARRAY_INITIAL_SIZE 2 - -typedef struct JSShapeProperty { - uint32_t hash_next : 26; /* 0 if last in list */ - uint32_t flags : 6; /* JS_PROP_XXX */ - JSAtom atom; /* JS_ATOM_NULL = free property entry */ -} JSShapeProperty; - -struct JSShape { - /* hash table of size hash_mask + 1 before the start of the - structure (see prop_hash_end()). */ - JSGCObjectHeader header; - /* true if the shape is inserted in the shape hash table. If not, - JSShape.hash is not valid */ - uint8_t is_hashed; - /* If true, the shape may have small array index properties 'n' with 0 - <= n <= 2^31-1. If false, the shape is guaranteed not to have - small array index properties */ - uint8_t has_small_array_index; - uint32_t hash; /* current hash value */ - uint32_t prop_hash_mask; - int prop_size; /* allocated properties */ - int prop_count; /* include deleted properties */ - int deleted_prop_count; - JSShape *shape_hash_next; /* in JSRuntime.shape_hash[h] list */ - JSObject *proto; - JSShapeProperty prop[0]; /* prop_size elements */ -}; - -struct JSObject { - union { - JSGCObjectHeader header; - struct { - int __gc_ref_count; /* corresponds to header.ref_count */ - uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */ - - uint8_t extensible : 1; - uint8_t free_mark : 1; /* only used when freeing objects with cycles */ - uint8_t is_exotic : 1; /* TRUE if object has exotic property handlers */ - uint8_t fast_array : 1; /* TRUE if u.array is used for get/put (for JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS and typed arrays) */ - uint8_t is_constructor : 1; /* TRUE if object is a constructor function */ - uint8_t has_immutable_prototype : 1; /* cannot modify the prototype */ - uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */ - uint8_t is_HTMLDDA : 1; /* specific annex B IsHtmlDDA behavior */ - uint16_t class_id; /* see JS_CLASS_x */ - }; - }; - /* count the number of weak references to this object. The object - structure is freed only if header.ref_count = 0 and - weakref_count = 0 */ - uint32_t weakref_count; - JSShape *shape; /* prototype and property names + flag */ - JSProperty *prop; /* array of properties */ - union { - void *opaque; - struct JSBoundFunction *bound_function; /* JS_CLASS_BOUND_FUNCTION */ - struct JSCFunctionDataRecord *c_function_data_record; /* JS_CLASS_C_FUNCTION_DATA */ - struct JSForInIterator *for_in_iterator; /* JS_CLASS_FOR_IN_ITERATOR */ - struct JSArrayBuffer *array_buffer; /* JS_CLASS_ARRAY_BUFFER, JS_CLASS_SHARED_ARRAY_BUFFER */ - struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_DATAVIEW */ - struct JSMapState *map_state; /* JS_CLASS_MAP..JS_CLASS_WEAKSET */ - struct JSMapIteratorData *map_iterator_data; /* JS_CLASS_MAP_ITERATOR, JS_CLASS_SET_ITERATOR */ - struct JSArrayIteratorData *array_iterator_data; /* JS_CLASS_ARRAY_ITERATOR, JS_CLASS_STRING_ITERATOR */ - struct JSRegExpStringIteratorData *regexp_string_iterator_data; /* JS_CLASS_REGEXP_STRING_ITERATOR */ - struct JSGeneratorData *generator_data; /* JS_CLASS_GENERATOR */ - struct JSProxyData *proxy_data; /* JS_CLASS_PROXY */ - struct JSPromiseData *promise_data; /* JS_CLASS_PROMISE */ - struct JSPromiseFunctionData *promise_function_data; /* JS_CLASS_PROMISE_RESOLVE_FUNCTION, JS_CLASS_PROMISE_REJECT_FUNCTION */ - struct JSAsyncFunctionState *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */ - struct JSAsyncFromSyncIteratorData *async_from_sync_iterator_data; /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */ - struct JSAsyncGeneratorData *async_generator_data; /* JS_CLASS_ASYNC_GENERATOR */ - struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */ - /* also used by JS_CLASS_GENERATOR_FUNCTION, JS_CLASS_ASYNC_FUNCTION and JS_CLASS_ASYNC_GENERATOR_FUNCTION */ - struct JSFunctionBytecode *function_bytecode; - JSVarRef **var_refs; - JSObject *home_object; /* for 'super' access */ - } func; - struct { /* JS_CLASS_C_FUNCTION: 12/20 bytes */ - JSContext *realm; - JSCFunctionType c_function; - uint8_t length; - uint8_t cproto; - int16_t magic; - } cfunc; - /* array part for fast arrays and typed arrays */ - struct { /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS, JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */ - union { - uint32_t size; /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */ - struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */ - } u1; - union { - JSValue *values; /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */ - void *ptr; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */ - int8_t *int8_ptr; /* JS_CLASS_INT8_ARRAY */ - uint8_t *uint8_ptr; /* JS_CLASS_UINT8_ARRAY, JS_CLASS_UINT8C_ARRAY */ - int16_t *int16_ptr; /* JS_CLASS_INT16_ARRAY */ - uint16_t *uint16_ptr; /* JS_CLASS_UINT16_ARRAY */ - int32_t *int32_ptr; /* JS_CLASS_INT32_ARRAY */ - uint32_t *uint32_ptr; /* JS_CLASS_UINT32_ARRAY */ - int64_t *int64_ptr; /* JS_CLASS_INT64_ARRAY */ - uint64_t *uint64_ptr; /* JS_CLASS_UINT64_ARRAY */ - uint16_t *fp16_ptr; /* JS_CLASS_FLOAT16_ARRAY */ - float *float_ptr; /* JS_CLASS_FLOAT32_ARRAY */ - double *double_ptr; /* JS_CLASS_FLOAT64_ARRAY */ - } u; - uint32_t count; /* <= 2^31-1. 0 for a detached typed array */ - } array; /* 12/20 bytes */ - JSRegExp regexp; /* JS_CLASS_REGEXP: 8/16 bytes */ - JSValue object_data; /* for JS_SetObjectData(): 8/16/16 bytes */ - } u; -}; - -typedef struct JSMapRecord { - int ref_count; /* used during enumeration to avoid freeing the record */ - BOOL empty : 8; /* TRUE if the record is deleted */ - struct list_head link; - struct JSMapRecord *hash_next; - JSValue key; - JSValue value; -} JSMapRecord; - -typedef struct JSMapState { - BOOL is_weak; /* TRUE if WeakSet/WeakMap */ - struct list_head records; /* list of JSMapRecord.link */ - uint32_t record_count; - JSMapRecord **hash_table; - int hash_bits; - uint32_t hash_size; /* = 2 ^ hash_bits */ - uint32_t record_count_threshold; /* count at which a hash table - resize is needed */ - JSWeakRefHeader weakref_header; /* only used if is_weak = TRUE */ -} JSMapState; - -enum { - __JS_ATOM_NULL = JS_ATOM_NULL, -#define DEF(name, str) JS_ATOM_ ## name, -#include "quickjs-atom.h" -#undef DEF - JS_ATOM_END, -}; -#define JS_ATOM_LAST_KEYWORD JS_ATOM_super -#define JS_ATOM_LAST_STRICT_KEYWORD JS_ATOM_yield - -static const char js_atom_init[] = -#define DEF(name, str) str "\0" -#include "quickjs-atom.h" -#undef DEF -; - -typedef enum OPCodeFormat { -#define FMT(f) OP_FMT_ ## f, -#define DEF(id, size, n_pop, n_push, f) -#include "quickjs-opcode.h" -#undef DEF -#undef FMT -} OPCodeFormat; - -enum OPCodeEnum { -#define FMT(f) -#define DEF(id, size, n_pop, n_push, f) OP_ ## id, -#define def(id, size, n_pop, n_push, f) -#include "quickjs-opcode.h" -#undef def -#undef DEF -#undef FMT - OP_COUNT, /* excluding temporary opcodes */ - /* temporary opcodes : overlap with the short opcodes */ - OP_TEMP_START = OP_nop + 1, - OP___dummy = OP_TEMP_START - 1, -#define FMT(f) -#define DEF(id, size, n_pop, n_push, f) -#define def(id, size, n_pop, n_push, f) OP_ ## id, -#include "quickjs-opcode.h" -#undef def -#undef DEF -#undef FMT - OP_TEMP_END, -}; - -static int JS_InitAtoms(JSRuntime *rt); -static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len, - int atom_type); -static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p); -static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b); -static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, int flags); -static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, int flags); -static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, JSValueConst new_target, - int argc, JSValue *argv, int flags); -static JSValue JS_CallConstructorInternal(JSContext *ctx, - JSValueConst func_obj, - JSValueConst new_target, - int argc, JSValue *argv, int flags); -static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj, - int argc, JSValueConst *argv); -static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom, - int argc, JSValueConst *argv); -static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, - JSValue val, BOOL is_array_ctor); -static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj, - JSValueConst val, int flags, int scope_idx); -JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...); -static __maybe_unused void JS_DumpAtoms(JSRuntime *rt); -static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p); -static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt); -static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p); -static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p); -static __maybe_unused void JS_DumpValueRT(JSRuntime *rt, const char *str, JSValueConst val); -static __maybe_unused void JS_DumpValue(JSContext *ctx, const char *str, JSValueConst val); -static __maybe_unused void JS_DumpShapes(JSRuntime *rt); -static void js_dump_value_write(void *opaque, const char *buf, size_t len); -static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic); -static void js_array_finalizer(JSRuntime *rt, JSValue val); -static void js_array_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); -static void js_object_data_finalizer(JSRuntime *rt, JSValue val); -static void js_object_data_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); -static void js_c_function_finalizer(JSRuntime *rt, JSValue val); -static void js_c_function_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); -static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val); -static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func); -static void js_bound_function_finalizer(JSRuntime *rt, JSValue val); -static void js_bound_function_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func); -static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val); -static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func); -static void js_regexp_finalizer(JSRuntime *rt, JSValue val); -static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val); -static void js_typed_array_finalizer(JSRuntime *rt, JSValue val); -static void js_typed_array_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func); -static void js_proxy_finalizer(JSRuntime *rt, JSValue val); -static void js_proxy_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func); -static void js_map_finalizer(JSRuntime *rt, JSValue val); -static void js_map_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func); -static void js_map_iterator_finalizer(JSRuntime *rt, JSValue val); -static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func); -static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val); -static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func); -static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val); -static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func); -static void js_generator_finalizer(JSRuntime *rt, JSValue obj); -static void js_generator_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func); -static void js_promise_finalizer(JSRuntime *rt, JSValue val); -static void js_promise_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func); -static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val); -static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func); - -#define HINT_STRING 0 -#define HINT_NUMBER 1 -#define HINT_NONE 2 -#define HINT_FORCE_ORDINARY (1 << 4) // don't try Symbol.toPrimitive -static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint); -static JSValue JS_ToStringFree(JSContext *ctx, JSValue val); -static int JS_ToBoolFree(JSContext *ctx, JSValue val); -static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val); -static int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val); -static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val); -static JSValue js_new_string8_len(JSContext *ctx, const char *buf, int len); -static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern, - JSValueConst flags); -static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor, - JSValue pattern, JSValue bc); -static void gc_decref(JSRuntime *rt); -static int JS_NewClass1(JSRuntime *rt, JSClassID class_id, - const JSClassDef *class_def, JSAtom name); - -typedef enum JSStrictEqModeEnum { - JS_EQ_STRICT, - JS_EQ_SAME_VALUE, - JS_EQ_SAME_VALUE_ZERO, -} JSStrictEqModeEnum; - -static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, - JSStrictEqModeEnum eq_mode); -static BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2); -static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2); -static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2); -static JSValue JS_ToObject(JSContext *ctx, JSValueConst val); -static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val); -static JSProperty *add_property(JSContext *ctx, - JSObject *p, JSAtom prop, int prop_flags); -static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val); -JSValue JS_ThrowOutOfMemory(JSContext *ctx); -static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx); - -static int js_resolve_proxy(JSContext *ctx, JSValueConst *pval, int throw_exception); -static int JS_CreateProperty(JSContext *ctx, JSObject *p, - JSAtom prop, JSValueConst val, - JSValueConst getter, JSValueConst setter, - int flags); -static int js_string_memcmp(const JSString *p1, int pos1, const JSString *p2, - int pos2, int len); -static JSValue js_array_buffer_constructor3(JSContext *ctx, - JSValueConst new_target, - uint64_t len, JSClassID class_id, - uint8_t *buf, - JSFreeArrayBufferDataFunc *free_func, - void *opaque, BOOL alloc_flag); -static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj); -static JSValue js_typed_array_constructor(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, - int classid); -static JSValue js_typed_array_constructor_ta(JSContext *ctx, - JSValueConst new_target, - JSValueConst src_obj, - int classid); -static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p); -static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p); -static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx); -static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx, - BOOL is_arg); -static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s); -static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s); -static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, - int flags); -static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val); -static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func); -static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, - const char *input, size_t input_len, - const char *filename, int flags, int scope_idx); -static void js_free_module_def(JSRuntime *rt, JSModuleDef *m); -static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m, - JS_MarkFunc *mark_func); -static JSValue js_import_meta(JSContext *ctx); -static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier, JSValueConst options); -static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref); -static JSValue js_new_promise_capability(JSContext *ctx, - JSValue *resolving_funcs, - JSValueConst ctor); -static __exception int perform_promise_then(JSContext *ctx, - JSValueConst promise, - JSValueConst *resolve_reject, - JSValueConst *cap_resolving_funcs); -static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic); -static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv); -static int js_string_compare(JSContext *ctx, - const JSString *p1, const JSString *p2); -static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val); -static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, - JSValue prop, JSValue val, int flags); -static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val); -static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val); -static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val); -static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, - JSObject *p, JSAtom prop); -static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc); -static void JS_AddIntrinsicBasicObjects(JSContext *ctx); -static void js_free_shape(JSRuntime *rt, JSShape *sh); -static void js_free_shape_null(JSRuntime *rt, JSShape *sh); -static int js_shape_prepare_update(JSContext *ctx, JSObject *p, - JSShapeProperty **pprs); -static int init_shape_hash(JSRuntime *rt); -static __exception int js_get_length32(JSContext *ctx, uint32_t *pres, - JSValueConst obj); -static __exception int js_get_length64(JSContext *ctx, int64_t *pres, - JSValueConst obj); -static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len); -static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen, - JSValueConst array_arg); -static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj, - JSValue **arrpp, uint32_t *countp); -static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx, - JSValueConst sync_iter); -static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val); -static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func); -static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_val, - int argc, JSValueConst *argv, int flags); -static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val); -static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h, - JSGCObjectTypeEnum type); -static void remove_gc_object(JSGCObjectHeader *h); -static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); -static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom, - void *opaque); -static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p, - JSAtom atom, void *opaque); -static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int is_map); -static void map_delete_weakrefs(JSRuntime *rt, JSWeakRefHeader *wh); -static void weakref_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh); -static void finrec_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh); -static void JS_RunGCInternal(JSRuntime *rt, BOOL remove_weak_objects); -static JSValue js_array_from_iterator(JSContext *ctx, uint32_t *plen, - JSValueConst obj, JSValueConst method); -static int js_string_find_invalid_codepoint(JSString *p); -static JSValue js_regexp_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv); -static JSValue get_date_string(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic); -static JSValue js_error_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv); - -static const JSClassExoticMethods js_arguments_exotic_methods; -static const JSClassExoticMethods js_string_exotic_methods; -static const JSClassExoticMethods js_proxy_exotic_methods; -static const JSClassExoticMethods js_module_ns_exotic_methods; -static JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT; - -static void js_trigger_gc(JSRuntime *rt, size_t size) -{ - BOOL force_gc; -#ifdef FORCE_GC_AT_MALLOC - force_gc = TRUE; -#else - force_gc = ((rt->malloc_state.malloc_size + size) > - rt->malloc_gc_threshold); -#endif - if (force_gc) { -#ifdef DUMP_GC - printf("GC: size=%" PRIu64 "\n", - (uint64_t)rt->malloc_state.malloc_size); -#endif - JS_RunGC(rt); - rt->malloc_gc_threshold = rt->malloc_state.malloc_size + - (rt->malloc_state.malloc_size >> 1); - } -} - -static size_t js_malloc_usable_size_unknown(const void *ptr) -{ - return 0; -} - -void *js_malloc_rt(JSRuntime *rt, size_t size) -{ - return rt->mf.js_malloc(&rt->malloc_state, size); -} - -void js_free_rt(JSRuntime *rt, void *ptr) -{ - rt->mf.js_free(&rt->malloc_state, ptr); -} - -void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size) -{ - return rt->mf.js_realloc(&rt->malloc_state, ptr, size); -} - -size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr) -{ - return rt->mf.js_malloc_usable_size(ptr); -} - -void *js_mallocz_rt(JSRuntime *rt, size_t size) -{ - void *ptr; - ptr = js_malloc_rt(rt, size); - if (!ptr) - return NULL; - return memset(ptr, 0, size); -} - -/* Throw out of memory in case of error */ -void *js_malloc(JSContext *ctx, size_t size) -{ - void *ptr; - ptr = js_malloc_rt(ctx->rt, size); - if (unlikely(!ptr)) { - JS_ThrowOutOfMemory(ctx); - return NULL; - } - return ptr; -} - -/* Throw out of memory in case of error */ -void *js_mallocz(JSContext *ctx, size_t size) -{ - void *ptr; - ptr = js_mallocz_rt(ctx->rt, size); - if (unlikely(!ptr)) { - JS_ThrowOutOfMemory(ctx); - return NULL; - } - return ptr; -} - -void js_free(JSContext *ctx, void *ptr) -{ - js_free_rt(ctx->rt, ptr); -} - -/* Throw out of memory in case of error */ -void *js_realloc(JSContext *ctx, void *ptr, size_t size) -{ - void *ret; - ret = js_realloc_rt(ctx->rt, ptr, size); - if (unlikely(!ret && size != 0)) { - JS_ThrowOutOfMemory(ctx); - return NULL; - } - return ret; -} - -/* store extra allocated size in *pslack if successful */ -void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack) -{ - void *ret; - ret = js_realloc_rt(ctx->rt, ptr, size); - if (unlikely(!ret && size != 0)) { - JS_ThrowOutOfMemory(ctx); - return NULL; - } - if (pslack) { - size_t new_size = js_malloc_usable_size_rt(ctx->rt, ret); - *pslack = (new_size > size) ? new_size - size : 0; - } - return ret; -} - -size_t js_malloc_usable_size(JSContext *ctx, const void *ptr) -{ - return js_malloc_usable_size_rt(ctx->rt, ptr); -} - -/* Throw out of memory exception in case of error */ -char *js_strndup(JSContext *ctx, const char *s, size_t n) -{ - char *ptr; - ptr = js_malloc(ctx, n + 1); - if (ptr) { - memcpy(ptr, s, n); - ptr[n] = '\0'; - } - return ptr; -} - -char *js_strdup(JSContext *ctx, const char *str) -{ - return js_strndup(ctx, str, strlen(str)); -} - -static no_inline int js_realloc_array(JSContext *ctx, void **parray, - int elem_size, int *psize, int req_size) -{ - int new_size; - size_t slack; - void *new_array; - /* XXX: potential arithmetic overflow */ - new_size = max_int(req_size, *psize * 3 / 2); - new_array = js_realloc2(ctx, *parray, new_size * elem_size, &slack); - if (!new_array) - return -1; - new_size += slack / elem_size; - *psize = new_size; - *parray = new_array; - return 0; -} - -/* resize the array and update its size if req_size > *psize */ -static inline int js_resize_array(JSContext *ctx, void **parray, int elem_size, - int *psize, int req_size) -{ - if (unlikely(req_size > *psize)) - return js_realloc_array(ctx, parray, elem_size, psize, req_size); - else - return 0; -} - -static inline void js_dbuf_init(JSContext *ctx, DynBuf *s) -{ - dbuf_init2(s, ctx->rt, (DynBufReallocFunc *)js_realloc_rt); -} - -static inline int is_digit(int c) { - return c >= '0' && c <= '9'; -} - -static inline int string_get(const JSString *p, int idx) { - return p->is_wide_char ? p->u.str16[idx] : p->u.str8[idx]; -} - -typedef struct JSClassShortDef { - JSAtom class_name; - JSClassFinalizer *finalizer; - JSClassGCMark *gc_mark; -} JSClassShortDef; - -static JSClassShortDef const js_std_class_def[] = { - { JS_ATOM_Object, NULL, NULL }, /* JS_CLASS_OBJECT */ - { JS_ATOM_Array, js_array_finalizer, js_array_mark }, /* JS_CLASS_ARRAY */ - { JS_ATOM_Error, NULL, NULL }, /* JS_CLASS_ERROR */ - { JS_ATOM_Number, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_NUMBER */ - { JS_ATOM_String, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_STRING */ - { JS_ATOM_Boolean, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BOOLEAN */ - { JS_ATOM_Symbol, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_SYMBOL */ - { JS_ATOM_Arguments, js_array_finalizer, js_array_mark }, /* JS_CLASS_ARGUMENTS */ - { JS_ATOM_Arguments, NULL, NULL }, /* JS_CLASS_MAPPED_ARGUMENTS */ - { JS_ATOM_Date, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_DATE */ - { JS_ATOM_Object, NULL, NULL }, /* JS_CLASS_MODULE_NS */ - { JS_ATOM_Function, js_c_function_finalizer, js_c_function_mark }, /* JS_CLASS_C_FUNCTION */ - { JS_ATOM_Function, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_BYTECODE_FUNCTION */ - { JS_ATOM_Function, js_bound_function_finalizer, js_bound_function_mark }, /* JS_CLASS_BOUND_FUNCTION */ - { JS_ATOM_Function, js_c_function_data_finalizer, js_c_function_data_mark }, /* JS_CLASS_C_FUNCTION_DATA */ - { JS_ATOM_GeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_GENERATOR_FUNCTION */ - { JS_ATOM_ForInIterator, js_for_in_iterator_finalizer, js_for_in_iterator_mark }, /* JS_CLASS_FOR_IN_ITERATOR */ - { JS_ATOM_RegExp, js_regexp_finalizer, NULL }, /* JS_CLASS_REGEXP */ - { JS_ATOM_ArrayBuffer, js_array_buffer_finalizer, NULL }, /* JS_CLASS_ARRAY_BUFFER */ - { JS_ATOM_SharedArrayBuffer, js_array_buffer_finalizer, NULL }, /* JS_CLASS_SHARED_ARRAY_BUFFER */ - { JS_ATOM_Uint8ClampedArray, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT8C_ARRAY */ - { JS_ATOM_Int8Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_INT8_ARRAY */ - { JS_ATOM_Uint8Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT8_ARRAY */ - { JS_ATOM_Int16Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_INT16_ARRAY */ - { JS_ATOM_Uint16Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT16_ARRAY */ - { JS_ATOM_Int32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_INT32_ARRAY */ - { JS_ATOM_Uint32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT32_ARRAY */ - { JS_ATOM_BigInt64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_BIG_INT64_ARRAY */ - { JS_ATOM_BigUint64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_BIG_UINT64_ARRAY */ - { JS_ATOM_Float16Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT16_ARRAY */ - { JS_ATOM_Float32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT32_ARRAY */ - { JS_ATOM_Float64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT64_ARRAY */ - { JS_ATOM_DataView, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_DATAVIEW */ - { JS_ATOM_BigInt, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_INT */ - { JS_ATOM_Map, js_map_finalizer, js_map_mark }, /* JS_CLASS_MAP */ - { JS_ATOM_Set, js_map_finalizer, js_map_mark }, /* JS_CLASS_SET */ - { JS_ATOM_WeakMap, js_map_finalizer, js_map_mark }, /* JS_CLASS_WEAKMAP */ - { JS_ATOM_WeakSet, js_map_finalizer, js_map_mark }, /* JS_CLASS_WEAKSET */ - { JS_ATOM_Map_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_MAP_ITERATOR */ - { JS_ATOM_Set_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_SET_ITERATOR */ - { JS_ATOM_Array_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_ARRAY_ITERATOR */ - { JS_ATOM_String_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_STRING_ITERATOR */ - { JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, js_regexp_string_iterator_mark }, /* JS_CLASS_REGEXP_STRING_ITERATOR */ - { JS_ATOM_Generator, js_generator_finalizer, js_generator_mark }, /* JS_CLASS_GENERATOR */ -}; - -static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab, - int start, int count) -{ - JSClassDef cm_s, *cm = &cm_s; - int i, class_id; - - for(i = 0; i < count; i++) { - class_id = i + start; - memset(cm, 0, sizeof(*cm)); - cm->finalizer = tab[i].finalizer; - cm->gc_mark = tab[i].gc_mark; - if (JS_NewClass1(rt, class_id, cm, tab[i].class_name) < 0) - return -1; - } - return 0; -} - -#if !defined(CONFIG_STACK_CHECK) -/* no stack limitation */ -static inline uintptr_t js_get_stack_pointer(void) -{ - return 0; -} - -static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size) -{ - return FALSE; -} -#else -/* Note: OS and CPU dependent */ -static inline uintptr_t js_get_stack_pointer(void) -{ - return (uintptr_t)__builtin_frame_address(0); -} - -static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size) -{ - uintptr_t sp; - sp = js_get_stack_pointer() - alloca_size; - return unlikely(sp < rt->stack_limit); -} -#endif - -JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) -{ - JSRuntime *rt; - JSMallocState ms; - - memset(&ms, 0, sizeof(ms)); - ms.opaque = opaque; - ms.malloc_limit = -1; - - rt = mf->js_malloc(&ms, sizeof(JSRuntime)); - if (!rt) - return NULL; - memset(rt, 0, sizeof(*rt)); - rt->mf = *mf; - if (!rt->mf.js_malloc_usable_size) { - /* use dummy function if none provided */ - rt->mf.js_malloc_usable_size = js_malloc_usable_size_unknown; - } - rt->malloc_state = ms; - rt->malloc_gc_threshold = 256 * 1024; - - init_list_head(&rt->context_list); - init_list_head(&rt->gc_obj_list); - init_list_head(&rt->gc_zero_ref_count_list); - rt->gc_phase = JS_GC_PHASE_NONE; - init_list_head(&rt->weakref_list); - -#ifdef DUMP_LEAKS - init_list_head(&rt->string_list); -#endif - init_list_head(&rt->job_list); - - if (JS_InitAtoms(rt)) - goto fail; - - /* create the object, array and function classes */ - if (init_class_range(rt, js_std_class_def, JS_CLASS_OBJECT, - countof(js_std_class_def)) < 0) - goto fail; - rt->class_array[JS_CLASS_ARGUMENTS].exotic = &js_arguments_exotic_methods; - rt->class_array[JS_CLASS_STRING].exotic = &js_string_exotic_methods; - rt->class_array[JS_CLASS_MODULE_NS].exotic = &js_module_ns_exotic_methods; - - rt->class_array[JS_CLASS_C_FUNCTION].call = js_call_c_function; - rt->class_array[JS_CLASS_C_FUNCTION_DATA].call = js_c_function_data_call; - rt->class_array[JS_CLASS_BOUND_FUNCTION].call = js_call_bound_function; - rt->class_array[JS_CLASS_GENERATOR_FUNCTION].call = js_generator_function_call; - if (init_shape_hash(rt)) - goto fail; - - rt->stack_size = JS_DEFAULT_STACK_SIZE; - JS_UpdateStackTop(rt); - - rt->current_exception = JS_UNINITIALIZED; - - return rt; - fail: - JS_FreeRuntime(rt); - return NULL; -} - -void *JS_GetRuntimeOpaque(JSRuntime *rt) -{ - return rt->user_opaque; -} - -void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque) -{ - rt->user_opaque = opaque; -} - -/* default memory allocation functions with memory limitation */ -static size_t js_def_malloc_usable_size(const void *ptr) -{ -#if defined(__APPLE__) - return malloc_size(ptr); -#elif defined(_WIN32) - return _msize((void *)ptr); -#elif defined(EMSCRIPTEN) - return 0; -#elif defined(__linux__) || defined(__GLIBC__) - return malloc_usable_size((void *)ptr); -#else - /* change this to `return 0;` if compilation fails */ - return malloc_usable_size((void *)ptr); -#endif -} - -static void *js_def_malloc(JSMallocState *s, size_t size) -{ - void *ptr; - - /* Do not allocate zero bytes: behavior is platform dependent */ - assert(size != 0); - - if (unlikely(s->malloc_size + size > s->malloc_limit)) - return NULL; - - ptr = malloc(size); - if (!ptr) - return NULL; - - s->malloc_count++; - s->malloc_size += js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD; - return ptr; -} - -static void js_def_free(JSMallocState *s, void *ptr) -{ - if (!ptr) - return; - - s->malloc_count--; - s->malloc_size -= js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD; - free(ptr); -} - -static void *js_def_realloc(JSMallocState *s, void *ptr, size_t size) -{ - size_t old_size; - - if (!ptr) { - if (size == 0) - return NULL; - return js_def_malloc(s, size); - } - old_size = js_def_malloc_usable_size(ptr); - if (size == 0) { - s->malloc_count--; - s->malloc_size -= old_size + MALLOC_OVERHEAD; - free(ptr); - return NULL; - } - if (s->malloc_size + size - old_size > s->malloc_limit) - return NULL; - - ptr = realloc(ptr, size); - if (!ptr) - return NULL; - - s->malloc_size += js_def_malloc_usable_size(ptr) - old_size; - return ptr; -} - -static const JSMallocFunctions def_malloc_funcs = { - js_def_malloc, - js_def_free, - js_def_realloc, - js_def_malloc_usable_size, -}; - -JSRuntime *JS_NewRuntime(void) -{ - return JS_NewRuntime2(&def_malloc_funcs, NULL); -} - -void JS_SetMemoryLimit(JSRuntime *rt, size_t limit) -{ - rt->malloc_state.malloc_limit = limit; -} - -/* use -1 to disable automatic GC */ -void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold) -{ - rt->malloc_gc_threshold = gc_threshold; -} - -#define malloc(s) malloc_is_forbidden(s) -#define free(p) free_is_forbidden(p) -#define realloc(p,s) realloc_is_forbidden(p,s) - -void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque) -{ - rt->interrupt_handler = cb; - rt->interrupt_opaque = opaque; -} - -void JS_SetCanBlock(JSRuntime *rt, BOOL can_block) -{ - rt->can_block = can_block; -} - -void JS_SetSharedArrayBufferFunctions(JSRuntime *rt, - const JSSharedArrayBufferFunctions *sf) -{ - rt->sab_funcs = *sf; -} - -void JS_SetStripInfo(JSRuntime *rt, int flags) -{ - rt->strip_flags = flags; -} - -int JS_GetStripInfo(JSRuntime *rt) -{ - return rt->strip_flags; -} - -/* return 0 if OK, < 0 if exception */ -int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, - int argc, JSValueConst *argv) -{ - JSRuntime *rt = ctx->rt; - JSJobEntry *e; - int i; - - e = js_malloc(ctx, sizeof(*e) + argc * sizeof(JSValue)); - if (!e) - return -1; - e->realm = JS_DupContext(ctx); - e->job_func = job_func; - e->argc = argc; - for(i = 0; i < argc; i++) { - e->argv[i] = JS_DupValue(ctx, argv[i]); - } - list_add_tail(&e->link, &rt->job_list); - return 0; -} - -BOOL JS_IsJobPending(JSRuntime *rt) -{ - return !list_empty(&rt->job_list); -} - -/* return < 0 if exception, 0 if no job pending, 1 if a job was - executed successfully. The context of the job is stored in '*pctx' - if pctx != NULL. It may be NULL if the context was already - destroyed or if no job was pending. The 'pctx' parameter is now - absolete. */ -int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx) -{ - JSContext *ctx; - JSJobEntry *e; - JSValue res; - int i, ret; - - if (list_empty(&rt->job_list)) { - if (pctx) - *pctx = NULL; - return 0; - } - - /* get the first pending job and execute it */ - e = list_entry(rt->job_list.next, JSJobEntry, link); - list_del(&e->link); - ctx = e->realm; - res = e->job_func(ctx, e->argc, (JSValueConst *)e->argv); - for(i = 0; i < e->argc; i++) - JS_FreeValue(ctx, e->argv[i]); - if (JS_IsException(res)) - ret = -1; - else - ret = 1; - JS_FreeValue(ctx, res); - js_free(ctx, e); - if (pctx) { - if (ctx->header.ref_count > 1) - *pctx = ctx; - else - *pctx = NULL; - } - JS_FreeContext(ctx); - return ret; -} - -static inline uint32_t atom_get_free(const JSAtomStruct *p) -{ - return (uintptr_t)p >> 1; -} - -static inline BOOL atom_is_free(const JSAtomStruct *p) -{ - return (uintptr_t)p & 1; -} - -static inline JSAtomStruct *atom_set_free(uint32_t v) -{ - return (JSAtomStruct *)(((uintptr_t)v << 1) | 1); -} - -/* Note: the string contents are uninitialized */ -static JSString *js_alloc_string_rt(JSRuntime *rt, int max_len, int is_wide_char) -{ - JSString *str; - str = js_malloc_rt(rt, sizeof(JSString) + (max_len << is_wide_char) + 1 - is_wide_char); - if (unlikely(!str)) - return NULL; - str->header.ref_count = 1; - str->is_wide_char = is_wide_char; - str->len = max_len; - str->atom_type = 0; - str->hash = 0; /* optional but costless */ - str->hash_next = 0; /* optional */ -#ifdef DUMP_LEAKS - list_add_tail(&str->link, &rt->string_list); -#endif - return str; -} - -static JSString *js_alloc_string(JSContext *ctx, int max_len, int is_wide_char) -{ - JSString *p; - p = js_alloc_string_rt(ctx->rt, max_len, is_wide_char); - if (unlikely(!p)) { - JS_ThrowOutOfMemory(ctx); - return NULL; - } - return p; -} - -/* same as JS_FreeValueRT() but faster */ -static inline void js_free_string(JSRuntime *rt, JSString *str) -{ - if (--str->header.ref_count <= 0) { - if (str->atom_type) { - JS_FreeAtomStruct(rt, str); - } else { -#ifdef DUMP_LEAKS - list_del(&str->link); -#endif - js_free_rt(rt, str); - } - } -} - -void JS_SetRuntimeInfo(JSRuntime *rt, const char *s) -{ - if (rt) - rt->rt_info = s; -} - -void JS_FreeRuntime(JSRuntime *rt) -{ - struct list_head *el, *el1; - int i; - - JS_FreeValueRT(rt, rt->current_exception); - - list_for_each_safe(el, el1, &rt->job_list) { - JSJobEntry *e = list_entry(el, JSJobEntry, link); - for(i = 0; i < e->argc; i++) - JS_FreeValueRT(rt, e->argv[i]); - JS_FreeContext(e->realm); - js_free_rt(rt, e); - } - init_list_head(&rt->job_list); - - /* don't remove the weak objects to avoid create new jobs with - FinalizationRegistry */ - JS_RunGCInternal(rt, FALSE); - -#ifdef DUMP_LEAKS - /* leaking objects */ - { - BOOL header_done; - JSGCObjectHeader *p; - int count; - - /* remove the internal refcounts to display only the object - referenced externally */ - list_for_each(el, &rt->gc_obj_list) { - p = list_entry(el, JSGCObjectHeader, link); - p->mark = 0; - } - gc_decref(rt); - - header_done = FALSE; - list_for_each(el, &rt->gc_obj_list) { - p = list_entry(el, JSGCObjectHeader, link); - if (p->ref_count != 0) { - if (!header_done) { - printf("Object leaks:\n"); - JS_DumpObjectHeader(rt); - header_done = TRUE; - } - JS_DumpGCObject(rt, p); - } - } - - count = 0; - list_for_each(el, &rt->gc_obj_list) { - p = list_entry(el, JSGCObjectHeader, link); - if (p->ref_count == 0) { - count++; - } - } - if (count != 0) - printf("Secondary object leaks: %d\n", count); - } -#endif - assert(list_empty(&rt->gc_obj_list)); - assert(list_empty(&rt->weakref_list)); - - /* free the classes */ - for(i = 0; i < rt->class_count; i++) { - JSClass *cl = &rt->class_array[i]; - if (cl->class_id != 0) { - JS_FreeAtomRT(rt, cl->class_name); - } - } - js_free_rt(rt, rt->class_array); - -#ifdef DUMP_LEAKS - /* only the atoms defined in JS_InitAtoms() should be left */ - { - BOOL header_done = FALSE; - - for(i = 0; i < rt->atom_size; i++) { - JSAtomStruct *p = rt->atom_array[i]; - if (!atom_is_free(p) /* && p->str*/) { - if (i >= JS_ATOM_END || p->header.ref_count != 1) { - if (!header_done) { - header_done = TRUE; - if (rt->rt_info) { - printf("%s:1: atom leakage:", rt->rt_info); - } else { - printf("Atom leaks:\n" - " %6s %6s %s\n", - "ID", "REFCNT", "NAME"); - } - } - if (rt->rt_info) { - printf(" "); - } else { - printf(" %6u %6u ", i, p->header.ref_count); - } - switch (p->atom_type) { - case JS_ATOM_TYPE_STRING: - JS_DumpString(rt, p); - break; - case JS_ATOM_TYPE_GLOBAL_SYMBOL: - printf("Symbol.for("); - JS_DumpString(rt, p); - printf(")"); - break; - case JS_ATOM_TYPE_SYMBOL: - if (p->hash != JS_ATOM_HASH_PRIVATE) { - printf("Symbol("); - JS_DumpString(rt, p); - printf(")"); - } else { - printf("Private("); - JS_DumpString(rt, p); - printf(")"); - } - break; - } - if (rt->rt_info) { - printf(":%u", p->header.ref_count); - } else { - printf("\n"); - } - } - } - } - if (rt->rt_info && header_done) - printf("\n"); - } -#endif - - /* free the atoms */ - for(i = 0; i < rt->atom_size; i++) { - JSAtomStruct *p = rt->atom_array[i]; - if (!atom_is_free(p)) { -#ifdef DUMP_LEAKS - list_del(&p->link); -#endif - js_free_rt(rt, p); - } - } - js_free_rt(rt, rt->atom_array); - js_free_rt(rt, rt->atom_hash); - js_free_rt(rt, rt->shape_hash); -#ifdef DUMP_LEAKS - if (!list_empty(&rt->string_list)) { - if (rt->rt_info) { - printf("%s:1: string leakage:", rt->rt_info); - } else { - printf("String leaks:\n" - " %6s %s\n", - "REFCNT", "VALUE"); - } - list_for_each_safe(el, el1, &rt->string_list) { - JSString *str = list_entry(el, JSString, link); - if (rt->rt_info) { - printf(" "); - } else { - printf(" %6u ", str->header.ref_count); - } - JS_DumpString(rt, str); - if (rt->rt_info) { - printf(":%u", str->header.ref_count); - } else { - printf("\n"); - } - list_del(&str->link); - js_free_rt(rt, str); - } - if (rt->rt_info) - printf("\n"); - } - { - JSMallocState *s = &rt->malloc_state; - if (s->malloc_count > 1) { - if (rt->rt_info) - printf("%s:1: ", rt->rt_info); - printf("Memory leak: %"PRIu64" bytes lost in %"PRIu64" block%s\n", - (uint64_t)(s->malloc_size - sizeof(JSRuntime)), - (uint64_t)(s->malloc_count - 1), &"s"[s->malloc_count == 2]); - } - } -#endif - - { - JSMallocState ms = rt->malloc_state; - rt->mf.js_free(&ms, rt); - } -} - -JSContext *JS_NewContextRaw(JSRuntime *rt) -{ - JSContext *ctx; - int i; - - ctx = js_mallocz_rt(rt, sizeof(JSContext)); - if (!ctx) - return NULL; - ctx->header.ref_count = 1; - add_gc_object(rt, &ctx->header, JS_GC_OBJ_TYPE_JS_CONTEXT); - - ctx->class_proto = js_malloc_rt(rt, sizeof(ctx->class_proto[0]) * - rt->class_count); - if (!ctx->class_proto) { - js_free_rt(rt, ctx); - return NULL; - } - ctx->rt = rt; - list_add_tail(&ctx->link, &rt->context_list); - for(i = 0; i < rt->class_count; i++) - ctx->class_proto[i] = JS_NULL; - ctx->array_ctor = JS_NULL; - ctx->regexp_ctor = JS_NULL; - ctx->promise_ctor = JS_NULL; - init_list_head(&ctx->loaded_modules); - - JS_AddIntrinsicBasicObjects(ctx); - return ctx; -} - -JSContext *JS_NewContext(JSRuntime *rt) -{ - JSContext *ctx; - - ctx = JS_NewContextRaw(rt); - if (!ctx) - return NULL; - - JS_AddIntrinsicBaseObjects(ctx); - JS_AddIntrinsicDate(ctx); - JS_AddIntrinsicEval(ctx); - JS_AddIntrinsicStringNormalize(ctx); - JS_AddIntrinsicRegExp(ctx); - JS_AddIntrinsicJSON(ctx); - JS_AddIntrinsicProxy(ctx); - JS_AddIntrinsicMapSet(ctx); - JS_AddIntrinsicTypedArrays(ctx); - JS_AddIntrinsicPromise(ctx); - JS_AddIntrinsicWeakRef(ctx); - return ctx; -} - -void *JS_GetContextOpaque(JSContext *ctx) -{ - return ctx->user_opaque; -} - -void JS_SetContextOpaque(JSContext *ctx, void *opaque) -{ - ctx->user_opaque = opaque; -} - -/* set the new value and free the old value after (freeing the value - can reallocate the object data) */ -static inline void set_value(JSContext *ctx, JSValue *pval, JSValue new_val) -{ - JSValue old_val; - old_val = *pval; - *pval = new_val; - JS_FreeValue(ctx, old_val); -} - -void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj) -{ - JSRuntime *rt = ctx->rt; - assert(class_id < rt->class_count); - set_value(ctx, &ctx->class_proto[class_id], obj); -} - -JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id) -{ - JSRuntime *rt = ctx->rt; - assert(class_id < rt->class_count); - return JS_DupValue(ctx, ctx->class_proto[class_id]); -} - -typedef enum JSFreeModuleEnum { - JS_FREE_MODULE_ALL, - JS_FREE_MODULE_NOT_RESOLVED, -} JSFreeModuleEnum; - -/* XXX: would be more efficient with separate module lists */ -static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag) -{ - struct list_head *el, *el1; - list_for_each_safe(el, el1, &ctx->loaded_modules) { - JSModuleDef *m = list_entry(el, JSModuleDef, link); - if (flag == JS_FREE_MODULE_ALL || - (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved)) { - /* warning: the module may be referenced elsewhere. It - could be simpler to use an array instead of a list for - 'ctx->loaded_modules' */ - list_del(&m->link); - m->link.prev = NULL; - m->link.next = NULL; - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); - } - } -} - -JSContext *JS_DupContext(JSContext *ctx) -{ - ctx->header.ref_count++; - return ctx; -} - -/* used by the GC */ -static void JS_MarkContext(JSRuntime *rt, JSContext *ctx, - JS_MarkFunc *mark_func) -{ - int i; - struct list_head *el; - - list_for_each(el, &ctx->loaded_modules) { - JSModuleDef *m = list_entry(el, JSModuleDef, link); - JS_MarkValue(rt, JS_MKPTR(JS_TAG_MODULE, m), mark_func); - } - - JS_MarkValue(rt, ctx->global_obj, mark_func); - JS_MarkValue(rt, ctx->global_var_obj, mark_func); - - JS_MarkValue(rt, ctx->throw_type_error, mark_func); - JS_MarkValue(rt, ctx->eval_obj, mark_func); - - JS_MarkValue(rt, ctx->array_proto_values, mark_func); - for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) { - JS_MarkValue(rt, ctx->native_error_proto[i], mark_func); - } - for(i = 0; i < rt->class_count; i++) { - JS_MarkValue(rt, ctx->class_proto[i], mark_func); - } - JS_MarkValue(rt, ctx->iterator_proto, mark_func); - JS_MarkValue(rt, ctx->async_iterator_proto, mark_func); - JS_MarkValue(rt, ctx->promise_ctor, mark_func); - JS_MarkValue(rt, ctx->array_ctor, mark_func); - JS_MarkValue(rt, ctx->regexp_ctor, mark_func); - JS_MarkValue(rt, ctx->function_ctor, mark_func); - JS_MarkValue(rt, ctx->function_proto, mark_func); - - if (ctx->array_shape) - mark_func(rt, &ctx->array_shape->header); -} - -void JS_FreeContext(JSContext *ctx) -{ - JSRuntime *rt = ctx->rt; - int i; - - if (--ctx->header.ref_count > 0) - return; - assert(ctx->header.ref_count == 0); - -#ifdef DUMP_ATOMS - JS_DumpAtoms(ctx->rt); -#endif -#ifdef DUMP_SHAPES - JS_DumpShapes(ctx->rt); -#endif -#ifdef DUMP_OBJECTS - { - struct list_head *el; - JSGCObjectHeader *p; - printf("JSObjects: {\n"); - JS_DumpObjectHeader(ctx->rt); - list_for_each(el, &rt->gc_obj_list) { - p = list_entry(el, JSGCObjectHeader, link); - JS_DumpGCObject(rt, p); - } - printf("}\n"); - } -#endif -#ifdef DUMP_MEM - { - JSMemoryUsage stats; - JS_ComputeMemoryUsage(rt, &stats); - JS_DumpMemoryUsage(stdout, &stats, rt); - } -#endif - - js_free_modules(ctx, JS_FREE_MODULE_ALL); - - JS_FreeValue(ctx, ctx->global_obj); - JS_FreeValue(ctx, ctx->global_var_obj); - - JS_FreeValue(ctx, ctx->throw_type_error); - JS_FreeValue(ctx, ctx->eval_obj); - - JS_FreeValue(ctx, ctx->array_proto_values); - for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) { - JS_FreeValue(ctx, ctx->native_error_proto[i]); - } - for(i = 0; i < rt->class_count; i++) { - JS_FreeValue(ctx, ctx->class_proto[i]); - } - js_free_rt(rt, ctx->class_proto); - JS_FreeValue(ctx, ctx->iterator_proto); - JS_FreeValue(ctx, ctx->async_iterator_proto); - JS_FreeValue(ctx, ctx->promise_ctor); - JS_FreeValue(ctx, ctx->array_ctor); - JS_FreeValue(ctx, ctx->regexp_ctor); - JS_FreeValue(ctx, ctx->function_ctor); - JS_FreeValue(ctx, ctx->function_proto); - - js_free_shape_null(ctx->rt, ctx->array_shape); - - list_del(&ctx->link); - remove_gc_object(&ctx->header); - js_free_rt(ctx->rt, ctx); -} - -JSRuntime *JS_GetRuntime(JSContext *ctx) -{ - return ctx->rt; -} - -static void update_stack_limit(JSRuntime *rt) -{ - if (rt->stack_size == 0) { - rt->stack_limit = 0; /* no limit */ - } else { - rt->stack_limit = rt->stack_top - rt->stack_size; - } -} - -void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size) -{ - rt->stack_size = stack_size; - update_stack_limit(rt); -} - -void JS_UpdateStackTop(JSRuntime *rt) -{ - rt->stack_top = js_get_stack_pointer(); - update_stack_limit(rt); -} - -static inline BOOL is_strict_mode(JSContext *ctx) -{ - JSStackFrame *sf = ctx->rt->current_stack_frame; - return (sf && (sf->js_mode & JS_MODE_STRICT)); -} - -/* JSAtom support */ - -#define JS_ATOM_TAG_INT (1U << 31) -#define JS_ATOM_MAX_INT (JS_ATOM_TAG_INT - 1) -#define JS_ATOM_MAX ((1U << 30) - 1) - -/* return the max count from the hash size */ -#define JS_ATOM_COUNT_RESIZE(n) ((n) * 2) - -static inline BOOL __JS_AtomIsConst(JSAtom v) -{ -#if defined(DUMP_LEAKS) && DUMP_LEAKS > 1 - return (int32_t)v <= 0; -#else - return (int32_t)v < JS_ATOM_END; -#endif -} - -static inline BOOL __JS_AtomIsTaggedInt(JSAtom v) -{ - return (v & JS_ATOM_TAG_INT) != 0; -} - -static inline JSAtom __JS_AtomFromUInt32(uint32_t v) -{ - return v | JS_ATOM_TAG_INT; -} - -static inline uint32_t __JS_AtomToUInt32(JSAtom atom) -{ - return atom & ~JS_ATOM_TAG_INT; -} - -static inline int is_num(int c) -{ - return c >= '0' && c <= '9'; -} - -/* return TRUE if the string is a number n with 0 <= n <= 2^32-1 */ -static inline BOOL is_num_string(uint32_t *pval, const JSString *p) -{ - uint32_t n; - uint64_t n64; - int c, i, len; - - len = p->len; - if (len == 0 || len > 10) - return FALSE; - c = string_get(p, 0); - if (is_num(c)) { - if (c == '0') { - if (len != 1) - return FALSE; - n = 0; - } else { - n = c - '0'; - for(i = 1; i < len; i++) { - c = string_get(p, i); - if (!is_num(c)) - return FALSE; - n64 = (uint64_t)n * 10 + (c - '0'); - if ((n64 >> 32) != 0) - return FALSE; - n = n64; - } - } - *pval = n; - return TRUE; - } else { - return FALSE; - } -} - -/* XXX: could use faster version ? */ -static inline uint32_t hash_string8(const uint8_t *str, size_t len, uint32_t h) -{ - size_t i; - - for(i = 0; i < len; i++) - h = h * 263 + str[i]; - return h; -} - -static inline uint32_t hash_string16(const uint16_t *str, - size_t len, uint32_t h) -{ - size_t i; - - for(i = 0; i < len; i++) - h = h * 263 + str[i]; - return h; -} - -static uint32_t hash_string(const JSString *str, uint32_t h) -{ - if (str->is_wide_char) - h = hash_string16(str->u.str16, str->len, h); - else - h = hash_string8(str->u.str8, str->len, h); - return h; -} - -static uint32_t hash_string_rope(JSValueConst val, uint32_t h) -{ - if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) { - return hash_string(JS_VALUE_GET_STRING(val), h); - } else { - JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val); - h = hash_string_rope(r->left, h); - return hash_string_rope(r->right, h); - } -} - -static __maybe_unused void JS_DumpChar(FILE *fo, int c, int sep) -{ - if (c == sep || c == '\\') { - fputc('\\', fo); - fputc(c, fo); - } else if (c >= ' ' && c <= 126) { - fputc(c, fo); - } else if (c == '\n') { - fputc('\\', fo); - fputc('n', fo); - } else { - fprintf(fo, "\\u%04x", c); - } -} - -static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p) -{ - int i, sep; - - if (p == NULL) { - printf(""); - return; - } - printf("%d", p->header.ref_count); - sep = (p->header.ref_count == 1) ? '\"' : '\''; - putchar(sep); - for(i = 0; i < p->len; i++) { - JS_DumpChar(stdout, string_get(p, i), sep); - } - putchar(sep); -} - -static __maybe_unused void JS_DumpAtoms(JSRuntime *rt) -{ - JSAtomStruct *p; - int h, i; - /* This only dumps hashed atoms, not JS_ATOM_TYPE_SYMBOL atoms */ - printf("JSAtom count=%d size=%d hash_size=%d:\n", - rt->atom_count, rt->atom_size, rt->atom_hash_size); - printf("JSAtom hash table: {\n"); - for(i = 0; i < rt->atom_hash_size; i++) { - h = rt->atom_hash[i]; - if (h) { - printf(" %d:", i); - while (h) { - p = rt->atom_array[h]; - printf(" "); - JS_DumpString(rt, p); - h = p->hash_next; - } - printf("\n"); - } - } - printf("}\n"); - printf("JSAtom table: {\n"); - for(i = 0; i < rt->atom_size; i++) { - p = rt->atom_array[i]; - if (!atom_is_free(p)) { - printf(" %d: { %d %08x ", i, p->atom_type, p->hash); - if (!(p->len == 0 && p->is_wide_char != 0)) - JS_DumpString(rt, p); - printf(" %d }\n", p->hash_next); - } - } - printf("}\n"); -} - -static int JS_ResizeAtomHash(JSRuntime *rt, int new_hash_size) -{ - JSAtomStruct *p; - uint32_t new_hash_mask, h, i, hash_next1, j, *new_hash; - - assert((new_hash_size & (new_hash_size - 1)) == 0); /* power of two */ - new_hash_mask = new_hash_size - 1; - new_hash = js_mallocz_rt(rt, sizeof(rt->atom_hash[0]) * new_hash_size); - if (!new_hash) - return -1; - for(i = 0; i < rt->atom_hash_size; i++) { - h = rt->atom_hash[i]; - while (h != 0) { - p = rt->atom_array[h]; - hash_next1 = p->hash_next; - /* add in new hash table */ - j = p->hash & new_hash_mask; - p->hash_next = new_hash[j]; - new_hash[j] = h; - h = hash_next1; - } - } - js_free_rt(rt, rt->atom_hash); - rt->atom_hash = new_hash; - rt->atom_hash_size = new_hash_size; - rt->atom_count_resize = JS_ATOM_COUNT_RESIZE(new_hash_size); - // JS_DumpAtoms(rt); - return 0; -} - -static int JS_InitAtoms(JSRuntime *rt) -{ - int i, len, atom_type; - const char *p; - - rt->atom_hash_size = 0; - rt->atom_hash = NULL; - rt->atom_count = 0; - rt->atom_size = 0; - rt->atom_free_index = 0; - if (JS_ResizeAtomHash(rt, 256)) /* there are at least 195 predefined atoms */ - return -1; - - p = js_atom_init; - for(i = 1; i < JS_ATOM_END; i++) { - if (i == JS_ATOM_Private_brand) - atom_type = JS_ATOM_TYPE_PRIVATE; - else if (i >= JS_ATOM_Symbol_toPrimitive) - atom_type = JS_ATOM_TYPE_SYMBOL; - else - atom_type = JS_ATOM_TYPE_STRING; - len = strlen(p); - if (__JS_NewAtomInit(rt, p, len, atom_type) == JS_ATOM_NULL) - return -1; - p = p + len + 1; - } - return 0; -} - -static JSAtom JS_DupAtomRT(JSRuntime *rt, JSAtom v) -{ - JSAtomStruct *p; - - if (!__JS_AtomIsConst(v)) { - p = rt->atom_array[v]; - p->header.ref_count++; - } - return v; -} - -JSAtom JS_DupAtom(JSContext *ctx, JSAtom v) -{ - JSRuntime *rt; - JSAtomStruct *p; - - if (!__JS_AtomIsConst(v)) { - rt = ctx->rt; - p = rt->atom_array[v]; - p->header.ref_count++; - } - return v; -} - -static JSAtomKindEnum JS_AtomGetKind(JSContext *ctx, JSAtom v) -{ - JSRuntime *rt; - JSAtomStruct *p; - - rt = ctx->rt; - if (__JS_AtomIsTaggedInt(v)) - return JS_ATOM_KIND_STRING; - p = rt->atom_array[v]; - switch(p->atom_type) { - case JS_ATOM_TYPE_STRING: - return JS_ATOM_KIND_STRING; - case JS_ATOM_TYPE_GLOBAL_SYMBOL: - return JS_ATOM_KIND_SYMBOL; - case JS_ATOM_TYPE_SYMBOL: - if (p->hash == JS_ATOM_HASH_PRIVATE) - return JS_ATOM_KIND_PRIVATE; - else - return JS_ATOM_KIND_SYMBOL; - default: - abort(); - } -} - -static BOOL JS_AtomIsString(JSContext *ctx, JSAtom v) -{ - return JS_AtomGetKind(ctx, v) == JS_ATOM_KIND_STRING; -} - -static JSAtom js_get_atom_index(JSRuntime *rt, JSAtomStruct *p) -{ - uint32_t i = p->hash_next; /* atom_index */ - if (p->atom_type != JS_ATOM_TYPE_SYMBOL) { - JSAtomStruct *p1; - - i = rt->atom_hash[p->hash & (rt->atom_hash_size - 1)]; - p1 = rt->atom_array[i]; - while (p1 != p) { - assert(i != 0); - i = p1->hash_next; - p1 = rt->atom_array[i]; - } - } - return i; -} - -/* string case (internal). Return JS_ATOM_NULL if error. 'str' is - freed. */ -static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type) -{ - uint32_t h, h1, i; - JSAtomStruct *p; - int len; - -#if 0 - printf("__JS_NewAtom: "); JS_DumpString(rt, str); printf("\n"); -#endif - if (atom_type < JS_ATOM_TYPE_SYMBOL) { - /* str is not NULL */ - if (str->atom_type == atom_type) { - /* str is the atom, return its index */ - i = js_get_atom_index(rt, str); - /* reduce string refcount and increase atom's unless constant */ - if (__JS_AtomIsConst(i)) - str->header.ref_count--; - return i; - } - /* try and locate an already registered atom */ - len = str->len; - h = hash_string(str, atom_type); - h &= JS_ATOM_HASH_MASK; - h1 = h & (rt->atom_hash_size - 1); - i = rt->atom_hash[h1]; - while (i != 0) { - p = rt->atom_array[i]; - if (p->hash == h && - p->atom_type == atom_type && - p->len == len && - js_string_memcmp(p, 0, str, 0, len) == 0) { - if (!__JS_AtomIsConst(i)) - p->header.ref_count++; - goto done; - } - i = p->hash_next; - } - } else { - h1 = 0; /* avoid warning */ - if (atom_type == JS_ATOM_TYPE_SYMBOL) { - h = 0; - } else { - h = JS_ATOM_HASH_PRIVATE; - atom_type = JS_ATOM_TYPE_SYMBOL; - } - } - - if (rt->atom_free_index == 0) { - /* allow new atom entries */ - uint32_t new_size, start; - JSAtomStruct **new_array; - - /* alloc new with size progression 3/2: - 4 6 9 13 19 28 42 63 94 141 211 316 474 711 1066 1599 2398 3597 5395 8092 - preallocating space for predefined atoms (at least 195). - */ - new_size = max_int(211, rt->atom_size * 3 / 2); - if (new_size > JS_ATOM_MAX) - goto fail; - /* XXX: should use realloc2 to use slack space */ - new_array = js_realloc_rt(rt, rt->atom_array, sizeof(*new_array) * new_size); - if (!new_array) - goto fail; - /* Note: the atom 0 is not used */ - start = rt->atom_size; - if (start == 0) { - /* JS_ATOM_NULL entry */ - p = js_mallocz_rt(rt, sizeof(JSAtomStruct)); - if (!p) { - js_free_rt(rt, new_array); - goto fail; - } - p->header.ref_count = 1; /* not refcounted */ - p->atom_type = JS_ATOM_TYPE_SYMBOL; -#ifdef DUMP_LEAKS - list_add_tail(&p->link, &rt->string_list); -#endif - new_array[0] = p; - rt->atom_count++; - start = 1; - } - rt->atom_size = new_size; - rt->atom_array = new_array; - rt->atom_free_index = start; - for(i = start; i < new_size; i++) { - uint32_t next; - if (i == (new_size - 1)) - next = 0; - else - next = i + 1; - rt->atom_array[i] = atom_set_free(next); - } - } - - if (str) { - if (str->atom_type == 0) { - p = str; - p->atom_type = atom_type; - } else { - p = js_malloc_rt(rt, sizeof(JSString) + - (str->len << str->is_wide_char) + - 1 - str->is_wide_char); - if (unlikely(!p)) - goto fail; - p->header.ref_count = 1; - p->is_wide_char = str->is_wide_char; - p->len = str->len; -#ifdef DUMP_LEAKS - list_add_tail(&p->link, &rt->string_list); -#endif - memcpy(p->u.str8, str->u.str8, (str->len << str->is_wide_char) + - 1 - str->is_wide_char); - js_free_string(rt, str); - } - } else { - p = js_malloc_rt(rt, sizeof(JSAtomStruct)); /* empty wide string */ - if (!p) - return JS_ATOM_NULL; - p->header.ref_count = 1; - p->is_wide_char = 1; /* Hack to represent NULL as a JSString */ - p->len = 0; -#ifdef DUMP_LEAKS - list_add_tail(&p->link, &rt->string_list); -#endif - } - - /* use an already free entry */ - i = rt->atom_free_index; - rt->atom_free_index = atom_get_free(rt->atom_array[i]); - rt->atom_array[i] = p; - - p->hash = h; - p->hash_next = i; /* atom_index */ - p->atom_type = atom_type; - - rt->atom_count++; - - if (atom_type != JS_ATOM_TYPE_SYMBOL) { - p->hash_next = rt->atom_hash[h1]; - rt->atom_hash[h1] = i; - if (unlikely(rt->atom_count >= rt->atom_count_resize)) - JS_ResizeAtomHash(rt, rt->atom_hash_size * 2); - } - - // JS_DumpAtoms(rt); - return i; - - fail: - i = JS_ATOM_NULL; - done: - if (str) - js_free_string(rt, str); - return i; -} - -/* only works with zero terminated 8 bit strings */ -static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len, - int atom_type) -{ - JSString *p; - p = js_alloc_string_rt(rt, len, 0); - if (!p) - return JS_ATOM_NULL; - memcpy(p->u.str8, str, len); - p->u.str8[len] = '\0'; - return __JS_NewAtom(rt, p, atom_type); -} - -/* Warning: str must be ASCII only */ -static JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len, - int atom_type) -{ - uint32_t h, h1, i; - JSAtomStruct *p; - - h = hash_string8((const uint8_t *)str, len, JS_ATOM_TYPE_STRING); - h &= JS_ATOM_HASH_MASK; - h1 = h & (rt->atom_hash_size - 1); - i = rt->atom_hash[h1]; - while (i != 0) { - p = rt->atom_array[i]; - if (p->hash == h && - p->atom_type == JS_ATOM_TYPE_STRING && - p->len == len && - p->is_wide_char == 0 && - memcmp(p->u.str8, str, len) == 0) { - if (!__JS_AtomIsConst(i)) - p->header.ref_count++; - return i; - } - i = p->hash_next; - } - return JS_ATOM_NULL; -} - -static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p) -{ -#if 0 /* JS_ATOM_NULL is not refcounted: __JS_AtomIsConst() includes 0 */ - if (unlikely(i == JS_ATOM_NULL)) { - p->header.ref_count = INT32_MAX / 2; - return; - } -#endif - uint32_t i = p->hash_next; /* atom_index */ - if (p->atom_type != JS_ATOM_TYPE_SYMBOL) { - JSAtomStruct *p0, *p1; - uint32_t h0; - - h0 = p->hash & (rt->atom_hash_size - 1); - i = rt->atom_hash[h0]; - p1 = rt->atom_array[i]; - if (p1 == p) { - rt->atom_hash[h0] = p1->hash_next; - } else { - for(;;) { - assert(i != 0); - p0 = p1; - i = p1->hash_next; - p1 = rt->atom_array[i]; - if (p1 == p) { - p0->hash_next = p1->hash_next; - break; - } - } - } - } - /* insert in free atom list */ - rt->atom_array[i] = atom_set_free(rt->atom_free_index); - rt->atom_free_index = i; - /* free the string structure */ -#ifdef DUMP_LEAKS - list_del(&p->link); -#endif - if (p->atom_type == JS_ATOM_TYPE_SYMBOL && - p->hash != JS_ATOM_HASH_PRIVATE && p->hash != 0) { - /* live weak references are still present on this object: keep - it */ - } else { - js_free_rt(rt, p); - } - rt->atom_count--; - assert(rt->atom_count >= 0); -} - -static void __JS_FreeAtom(JSRuntime *rt, uint32_t i) -{ - JSAtomStruct *p; - - p = rt->atom_array[i]; - if (--p->header.ref_count > 0) - return; - JS_FreeAtomStruct(rt, p); -} - -/* Warning: 'p' is freed */ -static JSAtom JS_NewAtomStr(JSContext *ctx, JSString *p) -{ - JSRuntime *rt = ctx->rt; - uint32_t n; - if (is_num_string(&n, p)) { - if (n <= JS_ATOM_MAX_INT) { - js_free_string(rt, p); - return __JS_AtomFromUInt32(n); - } - } - /* XXX: should generate an exception */ - return __JS_NewAtom(rt, p, JS_ATOM_TYPE_STRING); -} - -/* XXX: optimize */ -static size_t count_ascii(const uint8_t *buf, size_t len) -{ - const uint8_t *p, *p_end; - p = buf; - p_end = buf + len; - while (p < p_end && *p < 128) - p++; - return p - buf; -} - -/* str is UTF-8 encoded */ -JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len) -{ - JSValue val; - - if (len == 0 || - (!is_digit(*str) && - count_ascii((const uint8_t *)str, len) == len)) { - JSAtom atom = __JS_FindAtom(ctx->rt, str, len, JS_ATOM_TYPE_STRING); - if (atom) - return atom; - } - val = JS_NewStringLen(ctx, str, len); - if (JS_IsException(val)) - return JS_ATOM_NULL; - return JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(val)); -} - -JSAtom JS_NewAtom(JSContext *ctx, const char *str) -{ - return JS_NewAtomLen(ctx, str, strlen(str)); -} - -JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n) -{ - if (n <= JS_ATOM_MAX_INT) { - return __JS_AtomFromUInt32(n); - } else { - char buf[11]; - JSValue val; - size_t len; - len = u32toa(buf, n); - val = js_new_string8_len(ctx, buf, len); - if (JS_IsException(val)) - return JS_ATOM_NULL; - return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val), - JS_ATOM_TYPE_STRING); - } -} - -static JSAtom JS_NewAtomInt64(JSContext *ctx, int64_t n) -{ - if ((uint64_t)n <= JS_ATOM_MAX_INT) { - return __JS_AtomFromUInt32((uint32_t)n); - } else { - char buf[24]; - JSValue val; - size_t len; - len = i64toa(buf, n); - val = js_new_string8_len(ctx, buf, len); - if (JS_IsException(val)) - return JS_ATOM_NULL; - return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val), - JS_ATOM_TYPE_STRING); - } -} - -/* 'p' is freed */ -static JSValue JS_NewSymbol(JSContext *ctx, JSString *p, int atom_type) -{ - JSRuntime *rt = ctx->rt; - JSAtom atom; - atom = __JS_NewAtom(rt, p, atom_type); - if (atom == JS_ATOM_NULL) - return JS_ThrowOutOfMemory(ctx); - return JS_MKPTR(JS_TAG_SYMBOL, rt->atom_array[atom]); -} - -/* descr must be a non-numeric string atom */ -static JSValue JS_NewSymbolFromAtom(JSContext *ctx, JSAtom descr, - int atom_type) -{ - JSRuntime *rt = ctx->rt; - JSString *p; - - assert(!__JS_AtomIsTaggedInt(descr)); - assert(descr < rt->atom_size); - p = rt->atom_array[descr]; - JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p)); - return JS_NewSymbol(ctx, p, atom_type); -} - -#define ATOM_GET_STR_BUF_SIZE 64 - -/* Should only be used for debug. */ -static const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size, - JSAtom atom) -{ - if (__JS_AtomIsTaggedInt(atom)) { - snprintf(buf, buf_size, "%u", __JS_AtomToUInt32(atom)); - } else { - JSAtomStruct *p; - assert(atom < rt->atom_size); - if (atom == JS_ATOM_NULL) { - snprintf(buf, buf_size, ""); - } else { - int i, c; - char *q; - JSString *str; - - q = buf; - p = rt->atom_array[atom]; - assert(!atom_is_free(p)); - str = p; - if (str) { - if (!str->is_wide_char) { - /* special case ASCII strings */ - c = 0; - for(i = 0; i < str->len; i++) { - c |= str->u.str8[i]; - } - if (c < 0x80) - return (const char *)str->u.str8; - } - for(i = 0; i < str->len; i++) { - c = string_get(str, i); - if ((q - buf) >= buf_size - UTF8_CHAR_LEN_MAX) - break; - if (c < 128) { - *q++ = c; - } else { - q += unicode_to_utf8((uint8_t *)q, c); - } - } - } - *q = '\0'; - } - } - return buf; -} - -static const char *JS_AtomGetStr(JSContext *ctx, char *buf, int buf_size, JSAtom atom) -{ - return JS_AtomGetStrRT(ctx->rt, buf, buf_size, atom); -} - -static JSValue __JS_AtomToValue(JSContext *ctx, JSAtom atom, BOOL force_string) -{ - char buf[ATOM_GET_STR_BUF_SIZE]; - - if (__JS_AtomIsTaggedInt(atom)) { - size_t len = u32toa(buf, __JS_AtomToUInt32(atom)); - return js_new_string8_len(ctx, buf, len); - } else { - JSRuntime *rt = ctx->rt; - JSAtomStruct *p; - assert(atom < rt->atom_size); - p = rt->atom_array[atom]; - if (p->atom_type == JS_ATOM_TYPE_STRING) { - goto ret_string; - } else if (force_string) { - if (p->len == 0 && p->is_wide_char != 0) { - /* no description string */ - p = rt->atom_array[JS_ATOM_empty_string]; - } - ret_string: - return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p)); - } else { - return JS_DupValue(ctx, JS_MKPTR(JS_TAG_SYMBOL, p)); - } - } -} - -JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom) -{ - return __JS_AtomToValue(ctx, atom, FALSE); -} - -JSValue JS_AtomToString(JSContext *ctx, JSAtom atom) -{ - return __JS_AtomToValue(ctx, atom, TRUE); -} - -/* return TRUE if the atom is an array index (i.e. 0 <= index <= - 2^32-2 and return its value */ -static BOOL JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom) -{ - if (__JS_AtomIsTaggedInt(atom)) { - *pval = __JS_AtomToUInt32(atom); - return TRUE; - } else { - JSRuntime *rt = ctx->rt; - JSAtomStruct *p; - uint32_t val; - - assert(atom < rt->atom_size); - p = rt->atom_array[atom]; - if (p->atom_type == JS_ATOM_TYPE_STRING && - is_num_string(&val, p) && val != -1) { - *pval = val; - return TRUE; - } else { - *pval = 0; - return FALSE; - } - } -} - -/* This test must be fast if atom is not a numeric index (e.g. a - method name). Return JS_UNDEFINED if not a numeric - index. JS_EXCEPTION can also be returned. */ -static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom) -{ - JSRuntime *rt = ctx->rt; - JSAtomStruct *p1; - JSString *p; - int c, ret; - JSValue num, str; - - if (__JS_AtomIsTaggedInt(atom)) - return JS_NewInt32(ctx, __JS_AtomToUInt32(atom)); - assert(atom < rt->atom_size); - p1 = rt->atom_array[atom]; - if (p1->atom_type != JS_ATOM_TYPE_STRING) - return JS_UNDEFINED; - switch(atom) { - case JS_ATOM_minus_zero: - return __JS_NewFloat64(ctx, -0.0); - case JS_ATOM_Infinity: - return __JS_NewFloat64(ctx, INFINITY); - case JS_ATOM_minus_Infinity: - return __JS_NewFloat64(ctx, -INFINITY); - case JS_ATOM_NaN: - return __JS_NewFloat64(ctx, NAN); - default: - break; - } - p = p1; - if (p->len == 0) - return JS_UNDEFINED; - c = string_get(p, 0); - if (!is_num(c) && c != '-') - return JS_UNDEFINED; - /* this is ECMA CanonicalNumericIndexString primitive */ - num = JS_ToNumber(ctx, JS_MKPTR(JS_TAG_STRING, p)); - if (JS_IsException(num)) - return num; - str = JS_ToString(ctx, num); - if (JS_IsException(str)) { - JS_FreeValue(ctx, num); - return str; - } - ret = js_string_compare(ctx, p, JS_VALUE_GET_STRING(str)); - JS_FreeValue(ctx, str); - if (ret == 0) { - return num; - } else { - JS_FreeValue(ctx, num); - return JS_UNDEFINED; - } -} - -/* return -1 if exception or TRUE/FALSE */ -static int JS_AtomIsNumericIndex(JSContext *ctx, JSAtom atom) -{ - JSValue num; - num = JS_AtomIsNumericIndex1(ctx, atom); - if (likely(JS_IsUndefined(num))) - return FALSE; - if (JS_IsException(num)) - return -1; - JS_FreeValue(ctx, num); - return TRUE; -} - -void JS_FreeAtom(JSContext *ctx, JSAtom v) -{ - if (!__JS_AtomIsConst(v)) - __JS_FreeAtom(ctx->rt, v); -} - -void JS_FreeAtomRT(JSRuntime *rt, JSAtom v) -{ - if (!__JS_AtomIsConst(v)) - __JS_FreeAtom(rt, v); -} - -/* return TRUE if 'v' is a symbol with a string description */ -static BOOL JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v) -{ - JSRuntime *rt; - JSAtomStruct *p; - - rt = ctx->rt; - if (__JS_AtomIsTaggedInt(v)) - return FALSE; - p = rt->atom_array[v]; - return (((p->atom_type == JS_ATOM_TYPE_SYMBOL && - p->hash != JS_ATOM_HASH_PRIVATE) || - p->atom_type == JS_ATOM_TYPE_GLOBAL_SYMBOL) && - !(p->len == 0 && p->is_wide_char != 0)); -} - -/* free with JS_FreeCString() */ -const char *JS_AtomToCStringLen(JSContext *ctx, size_t *plen, JSAtom atom) -{ - JSValue str; - const char *cstr; - - str = JS_AtomToString(ctx, atom); - if (JS_IsException(str)) { - if (plen) - *plen = 0; - return NULL; - } - cstr = JS_ToCStringLen(ctx, plen, str); - JS_FreeValue(ctx, str); - return cstr; -} - -/* return a string atom containing name concatenated with str1 */ -static JSAtom js_atom_concat_str(JSContext *ctx, JSAtom name, const char *str1) -{ - JSValue str; - JSAtom atom; - const char *cstr; - char *cstr2; - size_t len, len1; - - str = JS_AtomToString(ctx, name); - if (JS_IsException(str)) - return JS_ATOM_NULL; - cstr = JS_ToCStringLen(ctx, &len, str); - if (!cstr) - goto fail; - len1 = strlen(str1); - cstr2 = js_malloc(ctx, len + len1 + 1); - if (!cstr2) - goto fail; - memcpy(cstr2, cstr, len); - memcpy(cstr2 + len, str1, len1); - cstr2[len + len1] = '\0'; - atom = JS_NewAtomLen(ctx, cstr2, len + len1); - js_free(ctx, cstr2); - JS_FreeCString(ctx, cstr); - JS_FreeValue(ctx, str); - return atom; - fail: - JS_FreeCString(ctx, cstr); - JS_FreeValue(ctx, str); - return JS_ATOM_NULL; -} - -static JSAtom js_atom_concat_num(JSContext *ctx, JSAtom name, uint32_t n) -{ - char buf[16]; - size_t len; - len = u32toa(buf, n); - buf[len] = '\0'; - return js_atom_concat_str(ctx, name, buf); -} - -static inline BOOL JS_IsEmptyString(JSValueConst v) -{ - return JS_VALUE_GET_TAG(v) == JS_TAG_STRING && JS_VALUE_GET_STRING(v)->len == 0; -} - -/* JSClass support */ - -#ifdef CONFIG_ATOMICS -static pthread_mutex_t js_class_id_mutex = PTHREAD_MUTEX_INITIALIZER; -#endif - -/* a new class ID is allocated if *pclass_id != 0 */ -JSClassID JS_NewClassID(JSClassID *pclass_id) -{ - JSClassID class_id; -#ifdef CONFIG_ATOMICS - pthread_mutex_lock(&js_class_id_mutex); -#endif - class_id = *pclass_id; - if (class_id == 0) { - class_id = js_class_id_alloc++; - *pclass_id = class_id; - } -#ifdef CONFIG_ATOMICS - pthread_mutex_unlock(&js_class_id_mutex); -#endif - return class_id; -} - -JSClassID JS_GetClassID(JSValue v) -{ - JSObject *p; - if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT) - return JS_INVALID_CLASS_ID; - p = JS_VALUE_GET_OBJ(v); - return p->class_id; -} - -BOOL JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id) -{ - return (class_id < rt->class_count && - rt->class_array[class_id].class_id != 0); -} - -/* create a new object internal class. Return -1 if error, 0 if - OK. The finalizer can be NULL if none is needed. */ -static int JS_NewClass1(JSRuntime *rt, JSClassID class_id, - const JSClassDef *class_def, JSAtom name) -{ - int new_size, i; - JSClass *cl, *new_class_array; - struct list_head *el; - - if (class_id >= (1 << 16)) - return -1; - if (class_id < rt->class_count && - rt->class_array[class_id].class_id != 0) - return -1; - - if (class_id >= rt->class_count) { - new_size = max_int(JS_CLASS_INIT_COUNT, - max_int(class_id + 1, rt->class_count * 3 / 2)); - - /* reallocate the context class prototype array, if any */ - list_for_each(el, &rt->context_list) { - JSContext *ctx = list_entry(el, JSContext, link); - JSValue *new_tab; - new_tab = js_realloc_rt(rt, ctx->class_proto, - sizeof(ctx->class_proto[0]) * new_size); - if (!new_tab) - return -1; - for(i = rt->class_count; i < new_size; i++) - new_tab[i] = JS_NULL; - ctx->class_proto = new_tab; - } - /* reallocate the class array */ - new_class_array = js_realloc_rt(rt, rt->class_array, - sizeof(JSClass) * new_size); - if (!new_class_array) - return -1; - memset(new_class_array + rt->class_count, 0, - (new_size - rt->class_count) * sizeof(JSClass)); - rt->class_array = new_class_array; - rt->class_count = new_size; - } - cl = &rt->class_array[class_id]; - cl->class_id = class_id; - cl->class_name = JS_DupAtomRT(rt, name); - cl->finalizer = class_def->finalizer; - cl->gc_mark = class_def->gc_mark; - cl->call = class_def->call; - cl->exotic = class_def->exotic; - return 0; -} - -int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def) -{ - int ret, len; - JSAtom name; - - len = strlen(class_def->class_name); - name = __JS_FindAtom(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING); - if (name == JS_ATOM_NULL) { - name = __JS_NewAtomInit(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING); - if (name == JS_ATOM_NULL) - return -1; - } - ret = JS_NewClass1(rt, class_id, class_def, name); - JS_FreeAtomRT(rt, name); - return ret; -} - -static JSValue js_new_string8_len(JSContext *ctx, const char *buf, int len) -{ - JSString *str; - - if (len <= 0) { - return JS_AtomToString(ctx, JS_ATOM_empty_string); - } - str = js_alloc_string(ctx, len, 0); - if (!str) - return JS_EXCEPTION; - memcpy(str->u.str8, buf, len); - str->u.str8[len] = '\0'; - return JS_MKPTR(JS_TAG_STRING, str); -} - -static JSValue js_new_string8(JSContext *ctx, const char *buf) -{ - return js_new_string8_len(ctx, buf, strlen(buf)); -} - -static JSValue js_new_string16_len(JSContext *ctx, const uint16_t *buf, int len) -{ - JSString *str; - str = js_alloc_string(ctx, len, 1); - if (!str) - return JS_EXCEPTION; - memcpy(str->u.str16, buf, len * 2); - return JS_MKPTR(JS_TAG_STRING, str); -} - -static JSValue js_new_string_char(JSContext *ctx, uint16_t c) -{ - if (c < 0x100) { - uint8_t ch8 = c; - return js_new_string8_len(ctx, (const char *)&ch8, 1); - } else { - uint16_t ch16 = c; - return js_new_string16_len(ctx, &ch16, 1); - } -} - -static JSValue js_sub_string(JSContext *ctx, JSString *p, int start, int end) -{ - int len = end - start; - if (start == 0 && end == p->len) { - return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p)); - } - if (p->is_wide_char && len > 0) { - JSString *str; - int i; - uint16_t c = 0; - for (i = start; i < end; i++) { - c |= p->u.str16[i]; - } - if (c > 0xFF) - return js_new_string16_len(ctx, p->u.str16 + start, len); - - str = js_alloc_string(ctx, len, 0); - if (!str) - return JS_EXCEPTION; - for (i = 0; i < len; i++) { - str->u.str8[i] = p->u.str16[start + i]; - } - str->u.str8[len] = '\0'; - return JS_MKPTR(JS_TAG_STRING, str); - } else { - return js_new_string8_len(ctx, (const char *)(p->u.str8 + start), len); - } -} - -typedef struct StringBuffer { - JSContext *ctx; - JSString *str; - int len; - int size; - int is_wide_char; - int error_status; -} StringBuffer; - -/* It is valid to call string_buffer_end() and all string_buffer functions even - if string_buffer_init() or another string_buffer function returns an error. - If the error_status is set, string_buffer_end() returns JS_EXCEPTION. - */ -static int string_buffer_init2(JSContext *ctx, StringBuffer *s, int size, - int is_wide) -{ - s->ctx = ctx; - s->size = size; - s->len = 0; - s->is_wide_char = is_wide; - s->error_status = 0; - s->str = js_alloc_string(ctx, size, is_wide); - if (unlikely(!s->str)) { - s->size = 0; - return s->error_status = -1; - } -#ifdef DUMP_LEAKS - /* the StringBuffer may reallocate the JSString, only link it at the end */ - list_del(&s->str->link); -#endif - return 0; -} - -static inline int string_buffer_init(JSContext *ctx, StringBuffer *s, int size) -{ - return string_buffer_init2(ctx, s, size, 0); -} - -static void string_buffer_free(StringBuffer *s) -{ - js_free(s->ctx, s->str); - s->str = NULL; -} - -static int string_buffer_set_error(StringBuffer *s) -{ - js_free(s->ctx, s->str); - s->str = NULL; - s->size = 0; - s->len = 0; - return s->error_status = -1; -} - -static no_inline int string_buffer_widen(StringBuffer *s, int size) -{ - JSString *str; - size_t slack; - int i; - - if (s->error_status) - return -1; - - str = js_realloc2(s->ctx, s->str, sizeof(JSString) + (size << 1), &slack); - if (!str) - return string_buffer_set_error(s); - size += slack >> 1; - for(i = s->len; i-- > 0;) { - str->u.str16[i] = str->u.str8[i]; - } - s->is_wide_char = 1; - s->size = size; - s->str = str; - return 0; -} - -static no_inline int string_buffer_realloc(StringBuffer *s, int new_len, int c) -{ - JSString *new_str; - int new_size; - size_t new_size_bytes, slack; - - if (s->error_status) - return -1; - - if (new_len > JS_STRING_LEN_MAX) { - JS_ThrowInternalError(s->ctx, "string too long"); - return string_buffer_set_error(s); - } - new_size = min_int(max_int(new_len, s->size * 3 / 2), JS_STRING_LEN_MAX); - if (!s->is_wide_char && c >= 0x100) { - return string_buffer_widen(s, new_size); - } - new_size_bytes = sizeof(JSString) + (new_size << s->is_wide_char) + 1 - s->is_wide_char; - new_str = js_realloc2(s->ctx, s->str, new_size_bytes, &slack); - if (!new_str) - return string_buffer_set_error(s); - new_size = min_int(new_size + (slack >> s->is_wide_char), JS_STRING_LEN_MAX); - s->size = new_size; - s->str = new_str; - return 0; -} - -static no_inline int string_buffer_putc_slow(StringBuffer *s, uint32_t c) -{ - if (unlikely(s->len >= s->size)) { - if (string_buffer_realloc(s, s->len + 1, c)) - return -1; - } - if (s->is_wide_char) { - s->str->u.str16[s->len++] = c; - } else if (c < 0x100) { - s->str->u.str8[s->len++] = c; - } else { - if (string_buffer_widen(s, s->size)) - return -1; - s->str->u.str16[s->len++] = c; - } - return 0; -} - -/* 0 <= c <= 0xff */ -static int string_buffer_putc8(StringBuffer *s, uint32_t c) -{ - if (unlikely(s->len >= s->size)) { - if (string_buffer_realloc(s, s->len + 1, c)) - return -1; - } - if (s->is_wide_char) { - s->str->u.str16[s->len++] = c; - } else { - s->str->u.str8[s->len++] = c; - } - return 0; -} - -/* 0 <= c <= 0xffff */ -static int string_buffer_putc16(StringBuffer *s, uint32_t c) -{ - if (likely(s->len < s->size)) { - if (s->is_wide_char) { - s->str->u.str16[s->len++] = c; - return 0; - } else if (c < 0x100) { - s->str->u.str8[s->len++] = c; - return 0; - } - } - return string_buffer_putc_slow(s, c); -} - -/* 0 <= c <= 0x10ffff */ -static int string_buffer_putc(StringBuffer *s, uint32_t c) -{ - if (unlikely(c >= 0x10000)) { - /* surrogate pair */ - if (string_buffer_putc16(s, get_hi_surrogate(c))) - return -1; - c = get_lo_surrogate(c); - } - return string_buffer_putc16(s, c); -} - -static int string_getc(const JSString *p, int *pidx) -{ - int idx, c, c1; - idx = *pidx; - if (p->is_wide_char) { - c = p->u.str16[idx++]; - if (is_hi_surrogate(c) && idx < p->len) { - c1 = p->u.str16[idx]; - if (is_lo_surrogate(c1)) { - c = from_surrogate(c, c1); - idx++; - } - } - } else { - c = p->u.str8[idx++]; - } - *pidx = idx; - return c; -} - -static int string_buffer_write8(StringBuffer *s, const uint8_t *p, int len) -{ - int i; - - if (s->len + len > s->size) { - if (string_buffer_realloc(s, s->len + len, 0)) - return -1; - } - if (s->is_wide_char) { - for (i = 0; i < len; i++) { - s->str->u.str16[s->len + i] = p[i]; - } - s->len += len; - } else { - memcpy(&s->str->u.str8[s->len], p, len); - s->len += len; - } - return 0; -} - -static int string_buffer_write16(StringBuffer *s, const uint16_t *p, int len) -{ - int c = 0, i; - - for (i = 0; i < len; i++) { - c |= p[i]; - } - if (s->len + len > s->size) { - if (string_buffer_realloc(s, s->len + len, c)) - return -1; - } else if (!s->is_wide_char && c >= 0x100) { - if (string_buffer_widen(s, s->size)) - return -1; - } - if (s->is_wide_char) { - memcpy(&s->str->u.str16[s->len], p, len << 1); - s->len += len; - } else { - for (i = 0; i < len; i++) { - s->str->u.str8[s->len + i] = p[i]; - } - s->len += len; - } - return 0; -} - -/* appending an ASCII string */ -static int string_buffer_puts8(StringBuffer *s, const char *str) -{ - return string_buffer_write8(s, (const uint8_t *)str, strlen(str)); -} - -static int string_buffer_concat(StringBuffer *s, const JSString *p, - uint32_t from, uint32_t to) -{ - if (to <= from) - return 0; - if (p->is_wide_char) - return string_buffer_write16(s, p->u.str16 + from, to - from); - else - return string_buffer_write8(s, p->u.str8 + from, to - from); -} - -static int string_buffer_concat_value(StringBuffer *s, JSValueConst v) -{ - JSString *p; - JSValue v1; - int res; - - if (s->error_status) { - /* prevent exception overload */ - return -1; - } - if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) { - if (JS_VALUE_GET_TAG(v) == JS_TAG_STRING_ROPE) { - JSStringRope *r = JS_VALUE_GET_STRING_ROPE(v); - /* recursion is acceptable because the rope depth is bounded */ - if (string_buffer_concat_value(s, r->left)) - return -1; - return string_buffer_concat_value(s, r->right); - } else { - v1 = JS_ToString(s->ctx, v); - if (JS_IsException(v1)) - return string_buffer_set_error(s); - p = JS_VALUE_GET_STRING(v1); - res = string_buffer_concat(s, p, 0, p->len); - JS_FreeValue(s->ctx, v1); - return res; - } - } - p = JS_VALUE_GET_STRING(v); - return string_buffer_concat(s, p, 0, p->len); -} - -static int string_buffer_concat_value_free(StringBuffer *s, JSValue v) -{ - JSString *p; - int res; - - if (s->error_status) { - /* prevent exception overload */ - JS_FreeValue(s->ctx, v); - return -1; - } - if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) { - v = JS_ToStringFree(s->ctx, v); - if (JS_IsException(v)) - return string_buffer_set_error(s); - } - p = JS_VALUE_GET_STRING(v); - res = string_buffer_concat(s, p, 0, p->len); - JS_FreeValue(s->ctx, v); - return res; -} - -static int string_buffer_fill(StringBuffer *s, int c, int count) -{ - /* XXX: optimize */ - if (s->len + count > s->size) { - if (string_buffer_realloc(s, s->len + count, c)) - return -1; - } - while (count-- > 0) { - if (string_buffer_putc16(s, c)) - return -1; - } - return 0; -} - -static JSValue string_buffer_end(StringBuffer *s) -{ - JSString *str; - str = s->str; - if (s->error_status) - return JS_EXCEPTION; - if (s->len == 0) { - js_free(s->ctx, str); - s->str = NULL; - return JS_AtomToString(s->ctx, JS_ATOM_empty_string); - } - if (s->len < s->size) { - /* smaller size so js_realloc should not fail, but OK if it does */ - /* XXX: should add some slack to avoid unnecessary calls */ - /* XXX: might need to use malloc+free to ensure smaller size */ - str = js_realloc_rt(s->ctx->rt, str, sizeof(JSString) + - (s->len << s->is_wide_char) + 1 - s->is_wide_char); - if (str == NULL) - str = s->str; - s->str = str; - } - if (!s->is_wide_char) - str->u.str8[s->len] = 0; -#ifdef DUMP_LEAKS - list_add_tail(&str->link, &s->ctx->rt->string_list); -#endif - str->is_wide_char = s->is_wide_char; - str->len = s->len; - s->str = NULL; - return JS_MKPTR(JS_TAG_STRING, str); -} - -/* create a string from a UTF-8 buffer */ -JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len) -{ - const uint8_t *p, *p_end, *p_start, *p_next; - uint32_t c; - StringBuffer b_s, *b = &b_s; - size_t len1; - - p_start = (const uint8_t *)buf; - p_end = p_start + buf_len; - len1 = count_ascii(p_start, buf_len); - p = p_start + len1; - if (len1 > JS_STRING_LEN_MAX) - return JS_ThrowInternalError(ctx, "string too long"); - if (p == p_end) { - /* ASCII string */ - return js_new_string8_len(ctx, buf, buf_len); - } else { - if (string_buffer_init(ctx, b, buf_len)) - goto fail; - string_buffer_write8(b, p_start, len1); - while (p < p_end) { - if (*p < 128) { - string_buffer_putc8(b, *p++); - } else { - /* parse utf-8 sequence, return 0xFFFFFFFF for error */ - c = unicode_from_utf8(p, p_end - p, &p_next); - if (c < 0x10000) { - p = p_next; - } else if (c <= 0x10FFFF) { - p = p_next; - /* surrogate pair */ - string_buffer_putc16(b, get_hi_surrogate(c)); - c = get_lo_surrogate(c); - } else { - /* invalid char */ - c = 0xfffd; - /* skip the invalid chars */ - /* XXX: seems incorrect. Why not just use c = *p++; ? */ - while (p < p_end && (*p >= 0x80 && *p < 0xc0)) - p++; - if (p < p_end) { - p++; - while (p < p_end && (*p >= 0x80 && *p < 0xc0)) - p++; - } - } - string_buffer_putc16(b, c); - } - } - } - return string_buffer_end(b); - - fail: - string_buffer_free(b); - return JS_EXCEPTION; -} - -static JSValue JS_ConcatString3(JSContext *ctx, const char *str1, - JSValue str2, const char *str3) -{ - StringBuffer b_s, *b = &b_s; - int len1, len3; - JSString *p; - - if (unlikely(JS_VALUE_GET_TAG(str2) != JS_TAG_STRING)) { - str2 = JS_ToStringFree(ctx, str2); - if (JS_IsException(str2)) - goto fail; - } - p = JS_VALUE_GET_STRING(str2); - len1 = strlen(str1); - len3 = strlen(str3); - - if (string_buffer_init2(ctx, b, len1 + p->len + len3, p->is_wide_char)) - goto fail; - - string_buffer_write8(b, (const uint8_t *)str1, len1); - string_buffer_concat(b, p, 0, p->len); - string_buffer_write8(b, (const uint8_t *)str3, len3); - - JS_FreeValue(ctx, str2); - return string_buffer_end(b); - - fail: - JS_FreeValue(ctx, str2); - return JS_EXCEPTION; -} - -JSValue JS_NewAtomString(JSContext *ctx, const char *str) -{ - JSAtom atom = JS_NewAtom(ctx, str); - if (atom == JS_ATOM_NULL) - return JS_EXCEPTION; - JSValue val = JS_AtomToString(ctx, atom); - JS_FreeAtom(ctx, atom); - return val; -} - -/* return (NULL, 0) if exception. */ -/* return pointer into a JSString with a live ref_count */ -/* cesu8 determines if non-BMP1 codepoints are encoded as 1 or 2 utf-8 sequences */ -const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, BOOL cesu8) -{ - JSValue val; - JSString *str, *str_new; - int pos, len, c, c1; - uint8_t *q; - - if (JS_VALUE_GET_TAG(val1) != JS_TAG_STRING) { - val = JS_ToString(ctx, val1); - if (JS_IsException(val)) - goto fail; - } else { - val = JS_DupValue(ctx, val1); - } - - str = JS_VALUE_GET_STRING(val); - len = str->len; - if (!str->is_wide_char) { - const uint8_t *src = str->u.str8; - int count; - - /* count the number of non-ASCII characters */ - /* Scanning the whole string is required for ASCII strings, - and computing the number of non-ASCII bytes is less expensive - than testing each byte, hence this method is faster for ASCII - strings, which is the most common case. - */ - count = 0; - for (pos = 0; pos < len; pos++) { - count += src[pos] >> 7; - } - if (count == 0) { - if (plen) - *plen = len; - return (const char *)src; - } - str_new = js_alloc_string(ctx, len + count, 0); - if (!str_new) - goto fail; - q = str_new->u.str8; - for (pos = 0; pos < len; pos++) { - c = src[pos]; - if (c < 0x80) { - *q++ = c; - } else { - *q++ = (c >> 6) | 0xc0; - *q++ = (c & 0x3f) | 0x80; - } - } - } else { - const uint16_t *src = str->u.str16; - /* Allocate 3 bytes per 16 bit code point. Surrogate pairs may - produce 4 bytes but use 2 code points. - */ - str_new = js_alloc_string(ctx, len * 3, 0); - if (!str_new) - goto fail; - q = str_new->u.str8; - pos = 0; - while (pos < len) { - c = src[pos++]; - if (c < 0x80) { - *q++ = c; - } else { - if (is_hi_surrogate(c)) { - if (pos < len && !cesu8) { - c1 = src[pos]; - if (is_lo_surrogate(c1)) { - pos++; - c = from_surrogate(c, c1); - } else { - /* Keep unmatched surrogate code points */ - /* c = 0xfffd; */ /* error */ - } - } else { - /* Keep unmatched surrogate code points */ - /* c = 0xfffd; */ /* error */ - } - } - q += unicode_to_utf8(q, c); - } - } - } - - *q = '\0'; - str_new->len = q - str_new->u.str8; - JS_FreeValue(ctx, val); - if (plen) - *plen = str_new->len; - return (const char *)str_new->u.str8; - fail: - if (plen) - *plen = 0; - return NULL; -} - -void JS_FreeCString(JSContext *ctx, const char *ptr) -{ - JSString *p; - if (!ptr) - return; - /* purposely removing constness */ - p = container_of(ptr, JSString, u); - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, p)); -} - -static int memcmp16_8(const uint16_t *src1, const uint8_t *src2, int len) -{ - int c, i; - for(i = 0; i < len; i++) { - c = src1[i] - src2[i]; - if (c != 0) - return c; - } - return 0; -} - -static int memcmp16(const uint16_t *src1, const uint16_t *src2, int len) -{ - int c, i; - for(i = 0; i < len; i++) { - c = src1[i] - src2[i]; - if (c != 0) - return c; - } - return 0; -} - -static int js_string_memcmp(const JSString *p1, int pos1, const JSString *p2, - int pos2, int len) -{ - int res; - - if (likely(!p1->is_wide_char)) { - if (likely(!p2->is_wide_char)) - res = memcmp(p1->u.str8 + pos1, p2->u.str8 + pos2, len); - else - res = -memcmp16_8(p2->u.str16 + pos2, p1->u.str8 + pos1, len); - } else { - if (!p2->is_wide_char) - res = memcmp16_8(p1->u.str16 + pos1, p2->u.str8 + pos2, len); - else - res = memcmp16(p1->u.str16 + pos1, p2->u.str16 + pos2, len); - } - return res; -} - -/* return < 0, 0 or > 0 */ -static int js_string_compare(JSContext *ctx, - const JSString *p1, const JSString *p2) -{ - int res, len; - len = min_int(p1->len, p2->len); - res = js_string_memcmp(p1, 0, p2, 0, len); - if (res == 0) { - if (p1->len == p2->len) - res = 0; - else if (p1->len < p2->len) - res = -1; - else - res = 1; - } - return res; -} - -static void copy_str16(uint16_t *dst, const JSString *p, int offset, int len) -{ - if (p->is_wide_char) { - memcpy(dst, p->u.str16 + offset, len * 2); - } else { - const uint8_t *src1 = p->u.str8 + offset; - int i; - - for(i = 0; i < len; i++) - dst[i] = src1[i]; - } -} - -static JSValue JS_ConcatString1(JSContext *ctx, - const JSString *p1, const JSString *p2) -{ - JSString *p; - uint32_t len; - int is_wide_char; - - len = p1->len + p2->len; - if (len > JS_STRING_LEN_MAX) - return JS_ThrowInternalError(ctx, "string too long"); - is_wide_char = p1->is_wide_char | p2->is_wide_char; - p = js_alloc_string(ctx, len, is_wide_char); - if (!p) - return JS_EXCEPTION; - if (!is_wide_char) { - memcpy(p->u.str8, p1->u.str8, p1->len); - memcpy(p->u.str8 + p1->len, p2->u.str8, p2->len); - p->u.str8[len] = '\0'; - } else { - copy_str16(p->u.str16, p1, 0, p1->len); - copy_str16(p->u.str16 + p1->len, p2, 0, p2->len); - } - return JS_MKPTR(JS_TAG_STRING, p); -} - -static BOOL JS_ConcatStringInPlace(JSContext *ctx, JSString *p1, JSValueConst op2) { - if (JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) { - JSString *p2 = JS_VALUE_GET_STRING(op2); - size_t size1; - - if (p2->len == 0) - return TRUE; - if (p1->header.ref_count != 1) - return FALSE; - size1 = js_malloc_usable_size(ctx, p1); - if (p1->is_wide_char) { - if (size1 >= sizeof(*p1) + ((p1->len + p2->len) << 1)) { - if (p2->is_wide_char) { - memcpy(p1->u.str16 + p1->len, p2->u.str16, p2->len << 1); - p1->len += p2->len; - return TRUE; - } else { - size_t i; - for (i = 0; i < p2->len; i++) { - p1->u.str16[p1->len++] = p2->u.str8[i]; - } - return TRUE; - } - } - } else if (!p2->is_wide_char) { - if (size1 >= sizeof(*p1) + p1->len + p2->len + 1) { - memcpy(p1->u.str8 + p1->len, p2->u.str8, p2->len); - p1->len += p2->len; - p1->u.str8[p1->len] = '\0'; - return TRUE; - } - } - } - return FALSE; -} - -static JSValue JS_ConcatString2(JSContext *ctx, JSValue op1, JSValue op2) -{ - JSValue ret; - JSString *p1, *p2; - p1 = JS_VALUE_GET_STRING(op1); - if (JS_ConcatStringInPlace(ctx, p1, op2)) { - JS_FreeValue(ctx, op2); - return op1; - } - p2 = JS_VALUE_GET_STRING(op2); - ret = JS_ConcatString1(ctx, p1, p2); - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - return ret; -} - -/* Return the character at position 'idx'. 'val' must be a string or rope */ -static int string_rope_get(JSValueConst val, uint32_t idx) -{ - if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) { - return string_get(JS_VALUE_GET_STRING(val), idx); - } else { - JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val); - uint32_t len; - if (JS_VALUE_GET_TAG(r->left) == JS_TAG_STRING) - len = JS_VALUE_GET_STRING(r->left)->len; - else - len = JS_VALUE_GET_STRING_ROPE(r->left)->len; - if (idx < len) - return string_rope_get(r->left, idx); - else - return string_rope_get(r->right, idx - len); - } -} - -typedef struct { - JSValueConst stack[JS_STRING_ROPE_MAX_DEPTH]; - int stack_len; -} JSStringRopeIter; - -static void string_rope_iter_init(JSStringRopeIter *s, JSValueConst val) -{ - s->stack_len = 0; - s->stack[s->stack_len++] = val; -} - -/* iterate thru a rope and return the strings in order */ -static JSString *string_rope_iter_next(JSStringRopeIter *s) -{ - JSValueConst val; - JSStringRope *r; - - if (s->stack_len == 0) - return NULL; - val = s->stack[--s->stack_len]; - for(;;) { - if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) - return JS_VALUE_GET_STRING(val); - r = JS_VALUE_GET_STRING_ROPE(val); - assert(s->stack_len < JS_STRING_ROPE_MAX_DEPTH); - s->stack[s->stack_len++] = r->right; - val = r->left; - } -} - -static uint32_t string_rope_get_len(JSValueConst val) -{ - if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) - return JS_VALUE_GET_STRING(val)->len; - else - return JS_VALUE_GET_STRING_ROPE(val)->len; -} - -static int js_string_rope_compare(JSContext *ctx, JSValueConst op1, - JSValueConst op2, BOOL eq_only) -{ - uint32_t len1, len2, len, pos1, pos2, l; - int res; - JSStringRopeIter it1, it2; - JSString *p1, *p2; - - len1 = string_rope_get_len(op1); - len2 = string_rope_get_len(op2); - /* no need to go further for equality test if - different length */ - if (eq_only && len1 != len2) - return 1; - len = min_uint32(len1, len2); - string_rope_iter_init(&it1, op1); - string_rope_iter_init(&it2, op2); - p1 = string_rope_iter_next(&it1); - p2 = string_rope_iter_next(&it2); - pos1 = 0; - pos2 = 0; - while (len != 0) { - l = min_uint32(p1->len - pos1, p2->len - pos2); - l = min_uint32(l, len); - res = js_string_memcmp(p1, pos1, p2, pos2, l); - if (res != 0) - return res; - len -= l; - pos1 += l; - if (pos1 >= p1->len) { - p1 = string_rope_iter_next(&it1); - pos1 = 0; - } - pos2 += l; - if (pos2 >= p2->len) { - p2 = string_rope_iter_next(&it2); - pos2 = 0; - } - } - - if (len1 == len2) - res = 0; - else if (len1 < len2) - res = -1; - else - res = 1; - return res; -} - -/* 'rope' must be a rope. return a string and modify the rope so that - it won't need to be linearized again. */ -static JSValue js_linearize_string_rope(JSContext *ctx, JSValue rope) -{ - StringBuffer b_s, *b = &b_s; - JSStringRope *r; - JSValue ret; - - r = JS_VALUE_GET_STRING_ROPE(rope); - - /* check whether it is already linearized */ - if (JS_VALUE_GET_TAG(r->right) == JS_TAG_STRING && - JS_VALUE_GET_STRING(r->right)->len == 0) { - ret = JS_DupValue(ctx, r->left); - JS_FreeValue(ctx, rope); - return ret; - } - if (string_buffer_init2(ctx, b, r->len, r->is_wide_char)) - goto fail; - if (string_buffer_concat_value(b, rope)) - goto fail; - ret = string_buffer_end(b); - if (r->header.ref_count > 1) { - /* update the rope so that it won't need to be linearized again */ - JS_FreeValue(ctx, r->left); - JS_FreeValue(ctx, r->right); - r->left = JS_DupValue(ctx, ret); - r->right = JS_AtomToString(ctx, JS_ATOM_empty_string); - } - JS_FreeValue(ctx, rope); - return ret; - fail: - JS_FreeValue(ctx, rope); - return JS_EXCEPTION; -} - -static JSValue js_rebalancee_string_rope(JSContext *ctx, JSValueConst rope); - -/* op1 and op2 must be strings or string ropes */ -static JSValue js_new_string_rope(JSContext *ctx, JSValue op1, JSValue op2) -{ - uint32_t len; - int is_wide_char, depth; - JSStringRope *r; - JSValue res; - - if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING) { - JSString *p1 = JS_VALUE_GET_STRING(op1); - len = p1->len; - is_wide_char = p1->is_wide_char; - depth = 0; - } else { - JSStringRope *r1 = JS_VALUE_GET_STRING_ROPE(op1); - len = r1->len; - is_wide_char = r1->is_wide_char; - depth = r1->depth; - } - - if (JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) { - JSString *p2 = JS_VALUE_GET_STRING(op2); - len += p2->len; - is_wide_char |= p2->is_wide_char; - } else { - JSStringRope *r2 = JS_VALUE_GET_STRING_ROPE(op2); - len += r2->len; - is_wide_char |= r2->is_wide_char; - depth = max_int(depth, r2->depth); - } - if (len > JS_STRING_LEN_MAX) { - JS_ThrowInternalError(ctx, "string too long"); - goto fail; - } - r = js_malloc(ctx, sizeof(*r)); - if (!r) - goto fail; - r->header.ref_count = 1; - r->len = len; - r->is_wide_char = is_wide_char; - r->depth = depth + 1; - r->left = op1; - r->right = op2; - res = JS_MKPTR(JS_TAG_STRING_ROPE, r); - if (r->depth > JS_STRING_ROPE_MAX_DEPTH) { - JSValue res2; -#ifdef DUMP_ROPE_REBALANCE - printf("rebalance: initial depth=%d\n", r->depth); -#endif - res2 = js_rebalancee_string_rope(ctx, res); -#ifdef DUMP_ROPE_REBALANCE - if (JS_VALUE_GET_TAG(res2) == JS_TAG_STRING_ROPE) - printf("rebalance: final depth=%d\n", JS_VALUE_GET_STRING_ROPE(res2)->depth); -#endif - JS_FreeValue(ctx, res); - return res2; - } else { - return res; - } - fail: - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - return JS_EXCEPTION; -} - -#define ROPE_N_BUCKETS 44 - -/* Fibonacii numbers starting from F_2 */ -static const uint32_t rope_bucket_len[ROPE_N_BUCKETS] = { - 1, 2, 3, 5, - 8, 13, 21, 34, - 55, 89, 144, 233, - 377, 610, 987, 1597, - 2584, 4181, 6765, 10946, - 17711, 28657, 46368, 75025, - 121393, 196418, 317811, 514229, - 832040, 1346269, 2178309, 3524578, - 5702887, 9227465, 14930352, 24157817, - 39088169, 63245986, 102334155, 165580141, - 267914296, 433494437, 701408733, 1134903170, /* > JS_STRING_LEN_MAX */ -}; - -static int js_rebalancee_string_rope_rec(JSContext *ctx, JSValue *buckets, - JSValueConst val) -{ - if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) { - JSString *p = JS_VALUE_GET_STRING(val); - uint32_t len, i; - JSValue a, b; - - len = p->len; - if (len == 0) - return 0; /* nothing to do */ - /* find the bucket i so that rope_bucket_len[i] <= len < - rope_bucket_len[i + 1] and concatenate the ropes in the - buckets before */ - a = JS_NULL; - i = 0; - while (len >= rope_bucket_len[i + 1]) { - b = buckets[i]; - if (!JS_IsNull(b)) { - buckets[i] = JS_NULL; - if (JS_IsNull(a)) { - a = b; - } else { - a = js_new_string_rope(ctx, b, a); - if (JS_IsException(a)) - return -1; - } - } - i++; - } - if (!JS_IsNull(a)) { - a = js_new_string_rope(ctx, a, JS_DupValue(ctx, val)); - if (JS_IsException(a)) - return -1; - } else { - a = JS_DupValue(ctx, val); - } - while (!JS_IsNull(buckets[i])) { - a = js_new_string_rope(ctx, buckets[i], a); - buckets[i] = JS_NULL; - if (JS_IsException(a)) - return -1; - i++; - } - buckets[i] = a; - } else { - JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val); - js_rebalancee_string_rope_rec(ctx, buckets, r->left); - js_rebalancee_string_rope_rec(ctx, buckets, r->right); - } - return 0; -} - -/* Return a new rope which is balanced. Algorithm from "Ropes: an - Alternative to Strings", Hans-J. Boehm, Russ Atkinson and Michael - Plass. */ -static JSValue js_rebalancee_string_rope(JSContext *ctx, JSValueConst rope) -{ - JSValue buckets[ROPE_N_BUCKETS], a, b; - int i; - - for(i = 0; i < ROPE_N_BUCKETS; i++) - buckets[i] = JS_NULL; - if (js_rebalancee_string_rope_rec(ctx, buckets, rope)) - goto fail; - a = JS_NULL; - for(i = 0; i < ROPE_N_BUCKETS; i++) { - b = buckets[i]; - if (!JS_IsNull(b)) { - buckets[i] = JS_NULL; - if (JS_IsNull(a)) { - a = b; - } else { - a = js_new_string_rope(ctx, b, a); - if (JS_IsException(a)) - goto fail; - } - } - } - /* fail safe */ - if (JS_IsNull(a)) - return JS_AtomToString(ctx, JS_ATOM_empty_string); - else - return a; - fail: - for(i = 0; i < ROPE_N_BUCKETS; i++) { - JS_FreeValue(ctx, buckets[i]); - } - return JS_EXCEPTION; -} - -/* op1 and op2 are converted to strings. For convenience, op1 or op2 = - JS_EXCEPTION are accepted and return JS_EXCEPTION. */ -static JSValue JS_ConcatString(JSContext *ctx, JSValue op1, JSValue op2) -{ - JSString *p1, *p2; - - if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_STRING && - JS_VALUE_GET_TAG(op1) != JS_TAG_STRING_ROPE)) { - op1 = JS_ToStringFree(ctx, op1); - if (JS_IsException(op1)) { - JS_FreeValue(ctx, op2); - return JS_EXCEPTION; - } - } - if (unlikely(JS_VALUE_GET_TAG(op2) != JS_TAG_STRING && - JS_VALUE_GET_TAG(op2) != JS_TAG_STRING_ROPE)) { - op2 = JS_ToStringFree(ctx, op2); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - return JS_EXCEPTION; - } - } - - /* normal concatenation for short strings */ - if (JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) { - p2 = JS_VALUE_GET_STRING(op2); - if (p2->len == 0) { - JS_FreeValue(ctx, op2); - return op1; - } - if (p2->len <= JS_STRING_ROPE_SHORT_LEN) { - if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING) { - p1 = JS_VALUE_GET_STRING(op1); - if (p1->len <= JS_STRING_ROPE_SHORT2_LEN) { - return JS_ConcatString2(ctx, op1, op2); - } else { - return js_new_string_rope(ctx, op1, op2); - } - } else { - JSStringRope *r1; - r1 = JS_VALUE_GET_STRING_ROPE(op1); - if (JS_VALUE_GET_TAG(r1->right) == JS_TAG_STRING && - JS_VALUE_GET_STRING(r1->right)->len <= JS_STRING_ROPE_SHORT_LEN) { - JSValue val, ret; - val = JS_ConcatString2(ctx, JS_DupValue(ctx, r1->right), op2); - if (JS_IsException(val)) { - JS_FreeValue(ctx, op1); - return JS_EXCEPTION; - } - ret = js_new_string_rope(ctx, JS_DupValue(ctx, r1->left), val); - JS_FreeValue(ctx, op1); - return ret; - } - } - } - } else if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING) { - JSStringRope *r2; - p1 = JS_VALUE_GET_STRING(op1); - if (p1->len == 0) { - JS_FreeValue(ctx, op1); - return op2; - } - r2 = JS_VALUE_GET_STRING_ROPE(op2); - if (JS_VALUE_GET_TAG(r2->left) == JS_TAG_STRING && - JS_VALUE_GET_STRING(r2->left)->len <= JS_STRING_ROPE_SHORT_LEN) { - JSValue val, ret; - val = JS_ConcatString2(ctx, op1, JS_DupValue(ctx, r2->left)); - if (JS_IsException(val)) { - JS_FreeValue(ctx, op2); - return JS_EXCEPTION; - } - ret = js_new_string_rope(ctx, val, JS_DupValue(ctx, r2->right)); - JS_FreeValue(ctx, op2); - return ret; - } - } - return js_new_string_rope(ctx, op1, op2); -} - -/* Shape support */ - -static inline size_t get_shape_size(size_t hash_size, size_t prop_size) -{ - return hash_size * sizeof(uint32_t) + sizeof(JSShape) + - prop_size * sizeof(JSShapeProperty); -} - -static inline JSShape *get_shape_from_alloc(void *sh_alloc, size_t hash_size) -{ - return (JSShape *)(void *)((uint32_t *)sh_alloc + hash_size); -} - -static inline uint32_t *prop_hash_end(JSShape *sh) -{ - return (uint32_t *)sh; -} - -static inline void *get_alloc_from_shape(JSShape *sh) -{ - return prop_hash_end(sh) - ((intptr_t)sh->prop_hash_mask + 1); -} - -static inline JSShapeProperty *get_shape_prop(JSShape *sh) -{ - return sh->prop; -} - -static int init_shape_hash(JSRuntime *rt) -{ - rt->shape_hash_bits = 4; /* 16 shapes */ - rt->shape_hash_size = 1 << rt->shape_hash_bits; - rt->shape_hash_count = 0; - rt->shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) * - rt->shape_hash_size); - if (!rt->shape_hash) - return -1; - return 0; -} - -/* same magic hash multiplier as the Linux kernel */ -static uint32_t shape_hash(uint32_t h, uint32_t val) -{ - return (h + val) * 0x9e370001; -} - -/* truncate the shape hash to 'hash_bits' bits */ -static uint32_t get_shape_hash(uint32_t h, int hash_bits) -{ - return h >> (32 - hash_bits); -} - -static uint32_t shape_initial_hash(JSObject *proto) -{ - uint32_t h; - h = shape_hash(1, (uintptr_t)proto); - if (sizeof(proto) > 4) - h = shape_hash(h, (uint64_t)(uintptr_t)proto >> 32); - return h; -} - -static int resize_shape_hash(JSRuntime *rt, int new_shape_hash_bits) -{ - int new_shape_hash_size, i; - uint32_t h; - JSShape **new_shape_hash, *sh, *sh_next; - - new_shape_hash_size = 1 << new_shape_hash_bits; - new_shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) * - new_shape_hash_size); - if (!new_shape_hash) - return -1; - for(i = 0; i < rt->shape_hash_size; i++) { - for(sh = rt->shape_hash[i]; sh != NULL; sh = sh_next) { - sh_next = sh->shape_hash_next; - h = get_shape_hash(sh->hash, new_shape_hash_bits); - sh->shape_hash_next = new_shape_hash[h]; - new_shape_hash[h] = sh; - } - } - js_free_rt(rt, rt->shape_hash); - rt->shape_hash_bits = new_shape_hash_bits; - rt->shape_hash_size = new_shape_hash_size; - rt->shape_hash = new_shape_hash; - return 0; -} - -static void js_shape_hash_link(JSRuntime *rt, JSShape *sh) -{ - uint32_t h; - h = get_shape_hash(sh->hash, rt->shape_hash_bits); - sh->shape_hash_next = rt->shape_hash[h]; - rt->shape_hash[h] = sh; - rt->shape_hash_count++; -} - -static void js_shape_hash_unlink(JSRuntime *rt, JSShape *sh) -{ - uint32_t h; - JSShape **psh; - - h = get_shape_hash(sh->hash, rt->shape_hash_bits); - psh = &rt->shape_hash[h]; - while (*psh != sh) - psh = &(*psh)->shape_hash_next; - *psh = sh->shape_hash_next; - rt->shape_hash_count--; -} - -/* create a new empty shape with prototype 'proto' */ -static no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto, - int hash_size, int prop_size) -{ - JSRuntime *rt = ctx->rt; - void *sh_alloc; - JSShape *sh; - - /* resize the shape hash table if necessary */ - if (2 * (rt->shape_hash_count + 1) > rt->shape_hash_size) { - resize_shape_hash(rt, rt->shape_hash_bits + 1); - } - - sh_alloc = js_malloc(ctx, get_shape_size(hash_size, prop_size)); - if (!sh_alloc) - return NULL; - sh = get_shape_from_alloc(sh_alloc, hash_size); - sh->header.ref_count = 1; - add_gc_object(rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE); - if (proto) - JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, proto)); - sh->proto = proto; - memset(prop_hash_end(sh) - hash_size, 0, sizeof(prop_hash_end(sh)[0]) * - hash_size); - sh->prop_hash_mask = hash_size - 1; - sh->prop_size = prop_size; - sh->prop_count = 0; - sh->deleted_prop_count = 0; - - /* insert in the hash table */ - sh->hash = shape_initial_hash(proto); - sh->is_hashed = TRUE; - sh->has_small_array_index = FALSE; - js_shape_hash_link(ctx->rt, sh); - return sh; -} - -static JSShape *js_new_shape(JSContext *ctx, JSObject *proto) -{ - return js_new_shape2(ctx, proto, JS_PROP_INITIAL_HASH_SIZE, - JS_PROP_INITIAL_SIZE); -} - -/* The shape is cloned. The new shape is not inserted in the shape - hash table */ -static JSShape *js_clone_shape(JSContext *ctx, JSShape *sh1) -{ - JSShape *sh; - void *sh_alloc, *sh_alloc1; - size_t size; - JSShapeProperty *pr; - uint32_t i, hash_size; - - hash_size = sh1->prop_hash_mask + 1; - size = get_shape_size(hash_size, sh1->prop_size); - sh_alloc = js_malloc(ctx, size); - if (!sh_alloc) - return NULL; - sh_alloc1 = get_alloc_from_shape(sh1); - memcpy(sh_alloc, sh_alloc1, size); - sh = get_shape_from_alloc(sh_alloc, hash_size); - sh->header.ref_count = 1; - add_gc_object(ctx->rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE); - sh->is_hashed = FALSE; - if (sh->proto) { - JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto)); - } - for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) { - JS_DupAtom(ctx, pr->atom); - } - return sh; -} - -static JSShape *js_dup_shape(JSShape *sh) -{ - sh->header.ref_count++; - return sh; -} - -static void js_free_shape0(JSRuntime *rt, JSShape *sh) -{ - uint32_t i; - JSShapeProperty *pr; - - assert(sh->header.ref_count == 0); - if (sh->is_hashed) - js_shape_hash_unlink(rt, sh); - if (sh->proto != NULL) { - JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, sh->proto)); - } - pr = get_shape_prop(sh); - for(i = 0; i < sh->prop_count; i++) { - JS_FreeAtomRT(rt, pr->atom); - pr++; - } - remove_gc_object(&sh->header); - js_free_rt(rt, get_alloc_from_shape(sh)); -} - -static void js_free_shape(JSRuntime *rt, JSShape *sh) -{ - if (unlikely(--sh->header.ref_count <= 0)) { - js_free_shape0(rt, sh); - } -} - -static void js_free_shape_null(JSRuntime *rt, JSShape *sh) -{ - if (sh) - js_free_shape(rt, sh); -} - -/* make space to hold at least 'count' properties */ -static no_inline int resize_properties(JSContext *ctx, JSShape **psh, - JSObject *p, uint32_t count) -{ - JSShape *sh; - uint32_t new_size, new_hash_size, new_hash_mask, i; - JSShapeProperty *pr; - void *sh_alloc; - intptr_t h; - JSShape *old_sh; - - sh = *psh; - new_size = max_int(count, sh->prop_size * 3 / 2); - /* Reallocate prop array first to avoid crash or size inconsistency - in case of memory allocation failure */ - if (p) { - JSProperty *new_prop; - new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size); - if (unlikely(!new_prop)) - return -1; - p->prop = new_prop; - } - new_hash_size = sh->prop_hash_mask + 1; - while (new_hash_size < new_size) - new_hash_size = 2 * new_hash_size; - /* resize the property shapes. Using js_realloc() is not possible in - case the GC runs during the allocation */ - old_sh = sh; - sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size)); - if (!sh_alloc) - return -1; - sh = get_shape_from_alloc(sh_alloc, new_hash_size); - list_del(&old_sh->header.link); - /* copy all the shape properties */ - memcpy(sh, old_sh, - sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count); - list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); - - if (new_hash_size != (sh->prop_hash_mask + 1)) { - /* resize the hash table and the properties */ - new_hash_mask = new_hash_size - 1; - sh->prop_hash_mask = new_hash_mask; - memset(prop_hash_end(sh) - new_hash_size, 0, - sizeof(prop_hash_end(sh)[0]) * new_hash_size); - for(i = 0, pr = sh->prop; i < sh->prop_count; i++, pr++) { - if (pr->atom != JS_ATOM_NULL) { - h = ((uintptr_t)pr->atom & new_hash_mask); - pr->hash_next = prop_hash_end(sh)[-h - 1]; - prop_hash_end(sh)[-h - 1] = i + 1; - } - } - } else { - /* just copy the previous hash table */ - memcpy(prop_hash_end(sh) - new_hash_size, prop_hash_end(old_sh) - new_hash_size, - sizeof(prop_hash_end(sh)[0]) * new_hash_size); - } - js_free(ctx, get_alloc_from_shape(old_sh)); - *psh = sh; - sh->prop_size = new_size; - return 0; -} - -/* remove the deleted properties. */ -static int compact_properties(JSContext *ctx, JSObject *p) -{ - JSShape *sh, *old_sh; - void *sh_alloc; - intptr_t h; - uint32_t new_hash_size, i, j, new_hash_mask, new_size; - JSShapeProperty *old_pr, *pr; - JSProperty *prop, *new_prop; - - sh = p->shape; - assert(!sh->is_hashed); - - new_size = max_int(JS_PROP_INITIAL_SIZE, - sh->prop_count - sh->deleted_prop_count); - assert(new_size <= sh->prop_size); - - new_hash_size = sh->prop_hash_mask + 1; - while ((new_hash_size / 2) >= new_size) - new_hash_size = new_hash_size / 2; - new_hash_mask = new_hash_size - 1; - - /* resize the hash table and the properties */ - old_sh = sh; - sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size)); - if (!sh_alloc) - return -1; - sh = get_shape_from_alloc(sh_alloc, new_hash_size); - list_del(&old_sh->header.link); - memcpy(sh, old_sh, sizeof(JSShape)); - list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); - - memset(prop_hash_end(sh) - new_hash_size, 0, - sizeof(prop_hash_end(sh)[0]) * new_hash_size); - - j = 0; - old_pr = old_sh->prop; - pr = sh->prop; - prop = p->prop; - for(i = 0; i < sh->prop_count; i++) { - if (old_pr->atom != JS_ATOM_NULL) { - pr->atom = old_pr->atom; - pr->flags = old_pr->flags; - h = ((uintptr_t)old_pr->atom & new_hash_mask); - pr->hash_next = prop_hash_end(sh)[-h - 1]; - prop_hash_end(sh)[-h - 1] = j + 1; - prop[j] = prop[i]; - j++; - pr++; - } - old_pr++; - } - assert(j == (sh->prop_count - sh->deleted_prop_count)); - sh->prop_hash_mask = new_hash_mask; - sh->prop_size = new_size; - sh->deleted_prop_count = 0; - sh->prop_count = j; - - p->shape = sh; - js_free(ctx, get_alloc_from_shape(old_sh)); - - /* reduce the size of the object properties */ - new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size); - if (new_prop) - p->prop = new_prop; - return 0; -} - -static int add_shape_property(JSContext *ctx, JSShape **psh, - JSObject *p, JSAtom atom, int prop_flags) -{ - JSRuntime *rt = ctx->rt; - JSShape *sh = *psh; - JSShapeProperty *pr, *prop; - uint32_t hash_mask, new_shape_hash = 0; - intptr_t h; - - /* update the shape hash */ - if (sh->is_hashed) { - js_shape_hash_unlink(rt, sh); - new_shape_hash = shape_hash(shape_hash(sh->hash, atom), prop_flags); - } - - if (unlikely(sh->prop_count >= sh->prop_size)) { - if (resize_properties(ctx, psh, p, sh->prop_count + 1)) { - /* in case of error, reinsert in the hash table. - sh is still valid if resize_properties() failed */ - if (sh->is_hashed) - js_shape_hash_link(rt, sh); - return -1; - } - sh = *psh; - } - if (sh->is_hashed) { - sh->hash = new_shape_hash; - js_shape_hash_link(rt, sh); - } - /* Initialize the new shape property. - The object property at p->prop[sh->prop_count] is uninitialized */ - prop = get_shape_prop(sh); - pr = &prop[sh->prop_count++]; - pr->atom = JS_DupAtom(ctx, atom); - pr->flags = prop_flags; - sh->has_small_array_index |= __JS_AtomIsTaggedInt(atom); - /* add in hash table */ - hash_mask = sh->prop_hash_mask; - h = atom & hash_mask; - pr->hash_next = prop_hash_end(sh)[-h - 1]; - prop_hash_end(sh)[-h - 1] = sh->prop_count; - return 0; -} - -/* find a hashed empty shape matching the prototype. Return NULL if - not found */ -static JSShape *find_hashed_shape_proto(JSRuntime *rt, JSObject *proto) -{ - JSShape *sh1; - uint32_t h, h1; - - h = shape_initial_hash(proto); - h1 = get_shape_hash(h, rt->shape_hash_bits); - for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) { - if (sh1->hash == h && - sh1->proto == proto && - sh1->prop_count == 0) { - return sh1; - } - } - return NULL; -} - -/* find a hashed shape matching sh + (prop, prop_flags). Return NULL if - not found */ -static JSShape *find_hashed_shape_prop(JSRuntime *rt, JSShape *sh, - JSAtom atom, int prop_flags) -{ - JSShape *sh1; - uint32_t h, h1, i, n; - - h = sh->hash; - h = shape_hash(h, atom); - h = shape_hash(h, prop_flags); - h1 = get_shape_hash(h, rt->shape_hash_bits); - for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) { - /* we test the hash first so that the rest is done only if the - shapes really match */ - if (sh1->hash == h && - sh1->proto == sh->proto && - sh1->prop_count == ((n = sh->prop_count) + 1)) { - for(i = 0; i < n; i++) { - if (unlikely(sh1->prop[i].atom != sh->prop[i].atom) || - unlikely(sh1->prop[i].flags != sh->prop[i].flags)) - goto next; - } - if (unlikely(sh1->prop[n].atom != atom) || - unlikely(sh1->prop[n].flags != prop_flags)) - goto next; - return sh1; - } - next: ; - } - return NULL; -} - -static __maybe_unused void JS_DumpShape(JSRuntime *rt, int i, JSShape *sh) -{ - char atom_buf[ATOM_GET_STR_BUF_SIZE]; - int j; - - /* XXX: should output readable class prototype */ - printf("%5d %3d%c %14p %5d %5d", i, - sh->header.ref_count, " *"[sh->is_hashed], - (void *)sh->proto, sh->prop_size, sh->prop_count); - for(j = 0; j < sh->prop_count; j++) { - printf(" %s", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), - sh->prop[j].atom)); - } - printf("\n"); -} - -static __maybe_unused void JS_DumpShapes(JSRuntime *rt) -{ - int i; - JSShape *sh; - struct list_head *el; - JSObject *p; - JSGCObjectHeader *gp; - - printf("JSShapes: {\n"); - printf("%5s %4s %14s %5s %5s %s\n", "SLOT", "REFS", "PROTO", "SIZE", "COUNT", "PROPS"); - for(i = 0; i < rt->shape_hash_size; i++) { - for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) { - JS_DumpShape(rt, i, sh); - assert(sh->is_hashed); - } - } - /* dump non-hashed shapes */ - list_for_each(el, &rt->gc_obj_list) { - gp = list_entry(el, JSGCObjectHeader, link); - if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) { - p = (JSObject *)gp; - if (!p->shape->is_hashed) { - JS_DumpShape(rt, -1, p->shape); - } - } - } - printf("}\n"); -} - -static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID class_id) -{ - JSObject *p; - - js_trigger_gc(ctx->rt, sizeof(JSObject)); - p = js_malloc(ctx, sizeof(JSObject)); - if (unlikely(!p)) - goto fail; - p->class_id = class_id; - p->extensible = TRUE; - p->free_mark = 0; - p->is_exotic = 0; - p->fast_array = 0; - p->is_constructor = 0; - p->has_immutable_prototype = 0; - p->tmp_mark = 0; - p->is_HTMLDDA = 0; - p->weakref_count = 0; - p->u.opaque = NULL; - p->shape = sh; - p->prop = js_malloc(ctx, sizeof(JSProperty) * sh->prop_size); - if (unlikely(!p->prop)) { - js_free(ctx, p); - fail: - js_free_shape(ctx->rt, sh); - return JS_EXCEPTION; - } - - switch(class_id) { - case JS_CLASS_OBJECT: - break; - case JS_CLASS_ARRAY: - { - JSProperty *pr; - p->is_exotic = 1; - p->fast_array = 1; - p->u.array.u.values = NULL; - p->u.array.count = 0; - p->u.array.u1.size = 0; - /* the length property is always the first one */ - if (likely(sh == ctx->array_shape)) { - pr = &p->prop[0]; - } else { - /* only used for the first array */ - /* cannot fail */ - pr = add_property(ctx, p, JS_ATOM_length, - JS_PROP_WRITABLE | JS_PROP_LENGTH); - } - pr->u.value = JS_NewInt32(ctx, 0); - } - break; - case JS_CLASS_C_FUNCTION: - p->prop[0].u.value = JS_UNDEFINED; - break; - case JS_CLASS_ARGUMENTS: - case JS_CLASS_UINT8C_ARRAY: - case JS_CLASS_INT8_ARRAY: - case JS_CLASS_UINT8_ARRAY: - case JS_CLASS_INT16_ARRAY: - case JS_CLASS_UINT16_ARRAY: - case JS_CLASS_INT32_ARRAY: - case JS_CLASS_UINT32_ARRAY: - case JS_CLASS_BIG_INT64_ARRAY: - case JS_CLASS_BIG_UINT64_ARRAY: - case JS_CLASS_FLOAT16_ARRAY: - case JS_CLASS_FLOAT32_ARRAY: - case JS_CLASS_FLOAT64_ARRAY: - p->is_exotic = 1; - p->fast_array = 1; - p->u.array.u.ptr = NULL; - p->u.array.count = 0; - break; - case JS_CLASS_DATAVIEW: - p->u.array.u.ptr = NULL; - p->u.array.count = 0; - break; - case JS_CLASS_NUMBER: - case JS_CLASS_STRING: - case JS_CLASS_BOOLEAN: - case JS_CLASS_SYMBOL: - case JS_CLASS_DATE: - case JS_CLASS_BIG_INT: - p->u.object_data = JS_UNDEFINED; - goto set_exotic; - case JS_CLASS_REGEXP: - p->u.regexp.pattern = NULL; - p->u.regexp.bytecode = NULL; - goto set_exotic; - default: - set_exotic: - if (ctx->rt->class_array[class_id].exotic) { - p->is_exotic = 1; - } - break; - } - p->header.ref_count = 1; - add_gc_object(ctx->rt, &p->header, JS_GC_OBJ_TYPE_JS_OBJECT); - return JS_MKPTR(JS_TAG_OBJECT, p); -} - -static JSObject *get_proto_obj(JSValueConst proto_val) -{ - if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT) - return NULL; - else - return JS_VALUE_GET_OBJ(proto_val); -} - -/* WARNING: proto must be an object or JS_NULL */ -JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto_val, - JSClassID class_id) -{ - JSShape *sh; - JSObject *proto; - - proto = get_proto_obj(proto_val); - sh = find_hashed_shape_proto(ctx->rt, proto); - if (likely(sh)) { - sh = js_dup_shape(sh); - } else { - sh = js_new_shape(ctx, proto); - if (!sh) - return JS_EXCEPTION; - } - return JS_NewObjectFromShape(ctx, sh, class_id); -} - -#if 0 -static JSValue JS_GetObjectData(JSContext *ctx, JSValueConst obj) -{ - JSObject *p; - - if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { - p = JS_VALUE_GET_OBJ(obj); - switch(p->class_id) { - case JS_CLASS_NUMBER: - case JS_CLASS_STRING: - case JS_CLASS_BOOLEAN: - case JS_CLASS_SYMBOL: - case JS_CLASS_DATE: - case JS_CLASS_BIG_INT: - return JS_DupValue(ctx, p->u.object_data); - } - } - return JS_UNDEFINED; -} -#endif - -static int JS_SetObjectData(JSContext *ctx, JSValueConst obj, JSValue val) -{ - JSObject *p; - - if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { - p = JS_VALUE_GET_OBJ(obj); - switch(p->class_id) { - case JS_CLASS_NUMBER: - case JS_CLASS_STRING: - case JS_CLASS_BOOLEAN: - case JS_CLASS_SYMBOL: - case JS_CLASS_DATE: - case JS_CLASS_BIG_INT: - JS_FreeValue(ctx, p->u.object_data); - p->u.object_data = val; /* for JS_CLASS_STRING, 'val' must - be JS_TAG_STRING (and not a - rope) */ - return 0; - } - } - JS_FreeValue(ctx, val); - if (!JS_IsException(obj)) - JS_ThrowTypeError(ctx, "invalid object type"); - return -1; -} - -JSValue JS_NewObjectClass(JSContext *ctx, int class_id) -{ - return JS_NewObjectProtoClass(ctx, ctx->class_proto[class_id], class_id); -} - -JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto) -{ - return JS_NewObjectProtoClass(ctx, proto, JS_CLASS_OBJECT); -} - -JSValue JS_NewArray(JSContext *ctx) -{ - return JS_NewObjectFromShape(ctx, js_dup_shape(ctx->array_shape), - JS_CLASS_ARRAY); -} - -JSValue JS_NewObject(JSContext *ctx) -{ - /* inline JS_NewObjectClass(ctx, JS_CLASS_OBJECT); */ - return JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_OBJECT); -} - -static void js_function_set_properties(JSContext *ctx, JSValueConst func_obj, - JSAtom name, int len) -{ - /* ES6 feature non compatible with ES5.1: length is configurable */ - JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length, JS_NewInt32(ctx, len), - JS_PROP_CONFIGURABLE); - JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, - JS_AtomToString(ctx, name), JS_PROP_CONFIGURABLE); -} - -static BOOL js_class_has_bytecode(JSClassID class_id) -{ - return (class_id == JS_CLASS_BYTECODE_FUNCTION || - class_id == JS_CLASS_GENERATOR_FUNCTION || - class_id == JS_CLASS_ASYNC_FUNCTION || - class_id == JS_CLASS_ASYNC_GENERATOR_FUNCTION); -} - -/* return NULL without exception if not a function or no bytecode */ -static JSFunctionBytecode *JS_GetFunctionBytecode(JSValueConst val) -{ - JSObject *p; - if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) - return NULL; - p = JS_VALUE_GET_OBJ(val); - if (!js_class_has_bytecode(p->class_id)) - return NULL; - return p->u.func.function_bytecode; -} - -static void js_method_set_home_object(JSContext *ctx, JSValueConst func_obj, - JSValueConst home_obj) -{ - JSObject *p, *p1; - JSFunctionBytecode *b; - - if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT) - return; - p = JS_VALUE_GET_OBJ(func_obj); - if (!js_class_has_bytecode(p->class_id)) - return; - b = p->u.func.function_bytecode; - if (b->need_home_object) { - p1 = p->u.func.home_object; - if (p1) { - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1)); - } - if (JS_VALUE_GET_TAG(home_obj) == JS_TAG_OBJECT) - p1 = JS_VALUE_GET_OBJ(JS_DupValue(ctx, home_obj)); - else - p1 = NULL; - p->u.func.home_object = p1; - } -} - -static JSValue js_get_function_name(JSContext *ctx, JSAtom name) -{ - JSValue name_str; - - name_str = JS_AtomToString(ctx, name); - if (JS_AtomSymbolHasDescription(ctx, name)) { - name_str = JS_ConcatString3(ctx, "[", name_str, "]"); - } - return name_str; -} - -/* Modify the name of a method according to the atom and - 'flags'. 'flags' is a bitmask of JS_PROP_HAS_GET and - JS_PROP_HAS_SET. Also set the home object of the method. - Return < 0 if exception. */ -static int js_method_set_properties(JSContext *ctx, JSValueConst func_obj, - JSAtom name, int flags, JSValueConst home_obj) -{ - JSValue name_str; - - name_str = js_get_function_name(ctx, name); - if (flags & JS_PROP_HAS_GET) { - name_str = JS_ConcatString3(ctx, "get ", name_str, ""); - } else if (flags & JS_PROP_HAS_SET) { - name_str = JS_ConcatString3(ctx, "set ", name_str, ""); - } - if (JS_IsException(name_str)) - return -1; - if (JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name_str, - JS_PROP_CONFIGURABLE) < 0) - return -1; - js_method_set_home_object(ctx, func_obj, home_obj); - return 0; -} - -/* Note: at least 'length' arguments will be readable in 'argv' */ -static JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func, - const char *name, - int length, JSCFunctionEnum cproto, int magic, - JSValueConst proto_val) -{ - JSValue func_obj; - JSObject *p; - JSAtom name_atom; - - func_obj = JS_NewObjectProtoClass(ctx, proto_val, JS_CLASS_C_FUNCTION); - if (JS_IsException(func_obj)) - return func_obj; - p = JS_VALUE_GET_OBJ(func_obj); - p->u.cfunc.realm = JS_DupContext(ctx); - p->u.cfunc.c_function.generic = func; - p->u.cfunc.length = length; - p->u.cfunc.cproto = cproto; - p->u.cfunc.magic = magic; - p->is_constructor = (cproto == JS_CFUNC_constructor || - cproto == JS_CFUNC_constructor_magic || - cproto == JS_CFUNC_constructor_or_func || - cproto == JS_CFUNC_constructor_or_func_magic); - if (!name) - name = ""; - name_atom = JS_NewAtom(ctx, name); - if (name_atom == JS_ATOM_NULL) { - JS_FreeValue(ctx, func_obj); - return JS_EXCEPTION; - } - js_function_set_properties(ctx, func_obj, name_atom, length); - JS_FreeAtom(ctx, name_atom); - return func_obj; -} - -/* Note: at least 'length' arguments will be readable in 'argv' */ -JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func, - const char *name, - int length, JSCFunctionEnum cproto, int magic) -{ - return JS_NewCFunction3(ctx, func, name, length, cproto, magic, - ctx->function_proto); -} - -typedef struct JSCFunctionDataRecord { - JSCFunctionData *func; - uint8_t length; - uint8_t data_len; - uint16_t magic; - JSValue data[0]; -} JSCFunctionDataRecord; - -static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val) -{ - JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA); - int i; - - if (s) { - for(i = 0; i < s->data_len; i++) { - JS_FreeValueRT(rt, s->data[i]); - } - js_free_rt(rt, s); - } -} - -static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA); - int i; - - if (s) { - for(i = 0; i < s->data_len; i++) { - JS_MarkValue(rt, s->data[i], mark_func); - } - } -} - -static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_val, - int argc, JSValueConst *argv, int flags) -{ - JSCFunctionDataRecord *s = JS_GetOpaque(func_obj, JS_CLASS_C_FUNCTION_DATA); - JSValueConst *arg_buf; - int i; - - /* XXX: could add the function on the stack for debug */ - if (unlikely(argc < s->length)) { - arg_buf = alloca(sizeof(arg_buf[0]) * s->length); - for(i = 0; i < argc; i++) - arg_buf[i] = argv[i]; - for(i = argc; i < s->length; i++) - arg_buf[i] = JS_UNDEFINED; - } else { - arg_buf = argv; - } - - return s->func(ctx, this_val, argc, arg_buf, s->magic, s->data); -} - -JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, - int length, int magic, int data_len, - JSValueConst *data) -{ - JSCFunctionDataRecord *s; - JSValue func_obj; - int i; - - func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto, - JS_CLASS_C_FUNCTION_DATA); - if (JS_IsException(func_obj)) - return func_obj; - s = js_malloc(ctx, sizeof(*s) + data_len * sizeof(JSValue)); - if (!s) { - JS_FreeValue(ctx, func_obj); - return JS_EXCEPTION; - } - s->func = func; - s->length = length; - s->data_len = data_len; - s->magic = magic; - for(i = 0; i < data_len; i++) - s->data[i] = JS_DupValue(ctx, data[i]); - JS_SetOpaque(func_obj, s); - js_function_set_properties(ctx, func_obj, - JS_ATOM_empty_string, length); - return func_obj; -} - -static JSContext *js_autoinit_get_realm(JSProperty *pr) -{ - return (JSContext *)(pr->u.init.realm_and_id & ~3); -} - -static JSAutoInitIDEnum js_autoinit_get_id(JSProperty *pr) -{ - return pr->u.init.realm_and_id & 3; -} - -static void js_autoinit_free(JSRuntime *rt, JSProperty *pr) -{ - JS_FreeContext(js_autoinit_get_realm(pr)); -} - -static void js_autoinit_mark(JSRuntime *rt, JSProperty *pr, - JS_MarkFunc *mark_func) -{ - mark_func(rt, &js_autoinit_get_realm(pr)->header); -} - -static void free_property(JSRuntime *rt, JSProperty *pr, int prop_flags) -{ - if (unlikely(prop_flags & JS_PROP_TMASK)) { - if ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET) { - if (pr->u.getset.getter) - JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter)); - if (pr->u.getset.setter) - JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter)); - } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_VARREF) { - free_var_ref(rt, pr->u.var_ref); - } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { - js_autoinit_free(rt, pr); - } - } else { - JS_FreeValueRT(rt, pr->u.value); - } -} - -static force_inline JSShapeProperty *find_own_property1(JSObject *p, - JSAtom atom) -{ - JSShape *sh; - JSShapeProperty *pr, *prop; - intptr_t h; - sh = p->shape; - h = (uintptr_t)atom & sh->prop_hash_mask; - h = prop_hash_end(sh)[-h - 1]; - prop = get_shape_prop(sh); - while (h) { - pr = &prop[h - 1]; - if (likely(pr->atom == atom)) { - return pr; - } - h = pr->hash_next; - } - return NULL; -} - -static force_inline JSShapeProperty *find_own_property(JSProperty **ppr, - JSObject *p, - JSAtom atom) -{ - JSShape *sh; - JSShapeProperty *pr, *prop; - intptr_t h; - sh = p->shape; - h = (uintptr_t)atom & sh->prop_hash_mask; - h = prop_hash_end(sh)[-h - 1]; - prop = get_shape_prop(sh); - while (h) { - pr = &prop[h - 1]; - if (likely(pr->atom == atom)) { - *ppr = &p->prop[h - 1]; - /* the compiler should be able to assume that pr != NULL here */ - return pr; - } - h = pr->hash_next; - } - *ppr = NULL; - return NULL; -} - -/* indicate that the object may be part of a function prototype cycle */ -static void set_cycle_flag(JSContext *ctx, JSValueConst obj) -{ -} - -static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref) -{ - if (var_ref) { - assert(var_ref->header.ref_count > 0); - if (--var_ref->header.ref_count == 0) { - if (var_ref->is_detached) { - JS_FreeValueRT(rt, var_ref->value); - } else { - list_del(&var_ref->var_ref_link); /* still on the stack */ - if (var_ref->async_func) - async_func_free(rt, var_ref->async_func); - } - remove_gc_object(&var_ref->header); - js_free_rt(rt, var_ref); - } - } -} - -static void js_array_finalizer(JSRuntime *rt, JSValue val) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - int i; - - for(i = 0; i < p->u.array.count; i++) { - JS_FreeValueRT(rt, p->u.array.u.values[i]); - } - js_free_rt(rt, p->u.array.u.values); -} - -static void js_array_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - int i; - - for(i = 0; i < p->u.array.count; i++) { - JS_MarkValue(rt, p->u.array.u.values[i], mark_func); - } -} - -static void js_object_data_finalizer(JSRuntime *rt, JSValue val) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JS_FreeValueRT(rt, p->u.object_data); - p->u.object_data = JS_UNDEFINED; -} - -static void js_object_data_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JS_MarkValue(rt, p->u.object_data, mark_func); -} - -static void js_c_function_finalizer(JSRuntime *rt, JSValue val) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - - if (p->u.cfunc.realm) - JS_FreeContext(p->u.cfunc.realm); -} - -static void js_c_function_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - - if (p->u.cfunc.realm) - mark_func(rt, &p->u.cfunc.realm->header); -} - -static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val) -{ - JSObject *p1, *p = JS_VALUE_GET_OBJ(val); - JSFunctionBytecode *b; - JSVarRef **var_refs; - int i; - - p1 = p->u.func.home_object; - if (p1) { - JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, p1)); - } - b = p->u.func.function_bytecode; - if (b) { - var_refs = p->u.func.var_refs; - if (var_refs) { - for(i = 0; i < b->closure_var_count; i++) - free_var_ref(rt, var_refs[i]); - js_free_rt(rt, var_refs); - } - JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b)); - } -} - -static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JSVarRef **var_refs = p->u.func.var_refs; - JSFunctionBytecode *b = p->u.func.function_bytecode; - int i; - - if (p->u.func.home_object) { - JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object), - mark_func); - } - if (b) { - if (var_refs) { - for(i = 0; i < b->closure_var_count; i++) { - JSVarRef *var_ref = var_refs[i]; - if (var_ref) { - mark_func(rt, &var_ref->header); - } - } - } - /* must mark the function bytecode because template objects may be - part of a cycle */ - JS_MarkValue(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b), mark_func); - } -} - -static void js_bound_function_finalizer(JSRuntime *rt, JSValue val) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JSBoundFunction *bf = p->u.bound_function; - int i; - - JS_FreeValueRT(rt, bf->func_obj); - JS_FreeValueRT(rt, bf->this_val); - for(i = 0; i < bf->argc; i++) { - JS_FreeValueRT(rt, bf->argv[i]); - } - js_free_rt(rt, bf); -} - -static void js_bound_function_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JSBoundFunction *bf = p->u.bound_function; - int i; - - JS_MarkValue(rt, bf->func_obj, mark_func); - JS_MarkValue(rt, bf->this_val, mark_func); - for(i = 0; i < bf->argc; i++) - JS_MarkValue(rt, bf->argv[i], mark_func); -} - -static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JSForInIterator *it = p->u.for_in_iterator; - int i; - - JS_FreeValueRT(rt, it->obj); - if (!it->is_array) { - for(i = 0; i < it->atom_count; i++) { - JS_FreeAtomRT(rt, it->tab_atom[i].atom); - } - js_free_rt(rt, it->tab_atom); - } - js_free_rt(rt, it); -} - -static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JSForInIterator *it = p->u.for_in_iterator; - JS_MarkValue(rt, it->obj, mark_func); -} - -static void free_object(JSRuntime *rt, JSObject *p) -{ - int i; - JSClassFinalizer *finalizer; - JSShape *sh; - JSShapeProperty *pr; - - p->free_mark = 1; /* used to tell the object is invalid when - freeing cycles */ - /* free all the fields */ - sh = p->shape; - pr = get_shape_prop(sh); - for(i = 0; i < sh->prop_count; i++) { - free_property(rt, &p->prop[i], pr->flags); - pr++; - } - js_free_rt(rt, p->prop); - /* as an optimization we destroy the shape immediately without - putting it in gc_zero_ref_count_list */ - js_free_shape(rt, sh); - - /* fail safe */ - p->shape = NULL; - p->prop = NULL; - - finalizer = rt->class_array[p->class_id].finalizer; - if (finalizer) - (*finalizer)(rt, JS_MKPTR(JS_TAG_OBJECT, p)); - - /* fail safe */ - p->class_id = 0; - p->u.opaque = NULL; - p->u.func.var_refs = NULL; - p->u.func.home_object = NULL; - - remove_gc_object(&p->header); - if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES) { - if (p->header.ref_count == 0 && p->weakref_count == 0) { - js_free_rt(rt, p); - } else { - /* keep the object structure because there are may be - references to it */ - list_add_tail(&p->header.link, &rt->gc_zero_ref_count_list); - } - } else { - /* keep the object structure in case there are weak references to it */ - if (p->weakref_count == 0) { - js_free_rt(rt, p); - } else { - p->header.mark = 0; /* reset the mark so that the weakref can be freed */ - } - } -} - -static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp) -{ - switch(gp->gc_obj_type) { - case JS_GC_OBJ_TYPE_JS_OBJECT: - free_object(rt, (JSObject *)gp); - break; - case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: - free_function_bytecode(rt, (JSFunctionBytecode *)gp); - break; - case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: - __async_func_free(rt, (JSAsyncFunctionState *)gp); - break; - case JS_GC_OBJ_TYPE_MODULE: - js_free_module_def(rt, (JSModuleDef *)gp); - break; - default: - abort(); - } -} - -static void free_zero_refcount(JSRuntime *rt) -{ - struct list_head *el; - JSGCObjectHeader *p; - - rt->gc_phase = JS_GC_PHASE_DECREF; - for(;;) { - el = rt->gc_zero_ref_count_list.next; - if (el == &rt->gc_zero_ref_count_list) - break; - p = list_entry(el, JSGCObjectHeader, link); - assert(p->ref_count == 0); - free_gc_object(rt, p); - } - rt->gc_phase = JS_GC_PHASE_NONE; -} - -/* called with the ref_count of 'v' reaches zero. */ -void __JS_FreeValueRT(JSRuntime *rt, JSValue v) -{ - uint32_t tag = JS_VALUE_GET_TAG(v); - -#ifdef DUMP_FREE - { - printf("Freeing "); - if (tag == JS_TAG_OBJECT) { - JS_DumpObject(rt, JS_VALUE_GET_OBJ(v)); - } else { - JS_DumpValueShort(rt, v); - printf("\n"); - } - } -#endif - - switch(tag) { - case JS_TAG_STRING: - { - JSString *p = JS_VALUE_GET_STRING(v); - if (p->atom_type) { - JS_FreeAtomStruct(rt, p); - } else { -#ifdef DUMP_LEAKS - list_del(&p->link); -#endif - js_free_rt(rt, p); - } - } - break; - case JS_TAG_STRING_ROPE: - /* Note: recursion is acceptable because the rope depth is bounded */ - { - JSStringRope *p = JS_VALUE_GET_STRING_ROPE(v); - JS_FreeValueRT(rt, p->left); - JS_FreeValueRT(rt, p->right); - js_free_rt(rt, p); - } - break; - case JS_TAG_OBJECT: - case JS_TAG_FUNCTION_BYTECODE: - case JS_TAG_MODULE: - { - JSGCObjectHeader *p = JS_VALUE_GET_PTR(v); - if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) { - list_del(&p->link); - list_add(&p->link, &rt->gc_zero_ref_count_list); - p->mark = 1; /* indicate that the object is about to be freed */ - if (rt->gc_phase == JS_GC_PHASE_NONE) { - free_zero_refcount(rt); - } - } - } - break; - case JS_TAG_BIG_INT: - { - JSBigInt *p = JS_VALUE_GET_PTR(v); - js_free_rt(rt, p); - } - break; - case JS_TAG_SYMBOL: - { - JSAtomStruct *p = JS_VALUE_GET_PTR(v); - JS_FreeAtomStruct(rt, p); - } - break; - default: - abort(); - } -} - -void __JS_FreeValue(JSContext *ctx, JSValue v) -{ - __JS_FreeValueRT(ctx->rt, v); -} - -/* garbage collection */ - -static void gc_remove_weak_objects(JSRuntime *rt) -{ - struct list_head *el; - - /* add the freed objects to rt->gc_zero_ref_count_list so that - rt->weakref_list is not modified while we traverse it */ - rt->gc_phase = JS_GC_PHASE_DECREF; - - list_for_each(el, &rt->weakref_list) { - JSWeakRefHeader *wh = list_entry(el, JSWeakRefHeader, link); - switch(wh->weakref_type) { - case JS_WEAKREF_TYPE_MAP: - map_delete_weakrefs(rt, wh); - break; - case JS_WEAKREF_TYPE_WEAKREF: - weakref_delete_weakref(rt, wh); - break; - case JS_WEAKREF_TYPE_FINREC: - finrec_delete_weakref(rt, wh); - break; - default: - abort(); - } - } - - rt->gc_phase = JS_GC_PHASE_NONE; - /* free the freed objects here. */ - free_zero_refcount(rt); -} - -static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h, - JSGCObjectTypeEnum type) -{ - h->mark = 0; - h->gc_obj_type = type; - list_add_tail(&h->link, &rt->gc_obj_list); -} - -static void remove_gc_object(JSGCObjectHeader *h) -{ - list_del(&h->link); -} - -void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) -{ - if (JS_VALUE_HAS_REF_COUNT(val)) { - switch(JS_VALUE_GET_TAG(val)) { - case JS_TAG_OBJECT: - case JS_TAG_FUNCTION_BYTECODE: - case JS_TAG_MODULE: - mark_func(rt, JS_VALUE_GET_PTR(val)); - break; - default: - break; - } - } -} - -static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp, - JS_MarkFunc *mark_func) -{ - switch(gp->gc_obj_type) { - case JS_GC_OBJ_TYPE_JS_OBJECT: - { - JSObject *p = (JSObject *)gp; - JSShapeProperty *prs; - JSShape *sh; - int i; - sh = p->shape; - mark_func(rt, &sh->header); - /* mark all the fields */ - prs = get_shape_prop(sh); - for(i = 0; i < sh->prop_count; i++) { - JSProperty *pr = &p->prop[i]; - if (prs->atom != JS_ATOM_NULL) { - if (prs->flags & JS_PROP_TMASK) { - if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { - if (pr->u.getset.getter) - mark_func(rt, &pr->u.getset.getter->header); - if (pr->u.getset.setter) - mark_func(rt, &pr->u.getset.setter->header); - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { - /* Note: the tag does not matter - provided it is a GC object */ - mark_func(rt, &pr->u.var_ref->header); - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { - js_autoinit_mark(rt, pr, mark_func); - } - } else { - JS_MarkValue(rt, pr->u.value, mark_func); - } - } - prs++; - } - - if (p->class_id != JS_CLASS_OBJECT) { - JSClassGCMark *gc_mark; - gc_mark = rt->class_array[p->class_id].gc_mark; - if (gc_mark) - gc_mark(rt, JS_MKPTR(JS_TAG_OBJECT, p), mark_func); - } - } - break; - case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: - /* the template objects can be part of a cycle */ - { - JSFunctionBytecode *b = (JSFunctionBytecode *)gp; - int i; - for(i = 0; i < b->cpool_count; i++) { - JS_MarkValue(rt, b->cpool[i], mark_func); - } - if (b->realm) - mark_func(rt, &b->realm->header); - } - break; - case JS_GC_OBJ_TYPE_VAR_REF: - { - JSVarRef *var_ref = (JSVarRef *)gp; - if (var_ref->is_detached) { - JS_MarkValue(rt, *var_ref->pvalue, mark_func); - } else if (var_ref->async_func) { - mark_func(rt, &var_ref->async_func->header); - } - } - break; - case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: - { - JSAsyncFunctionState *s = (JSAsyncFunctionState *)gp; - JSStackFrame *sf = &s->frame; - JSValue *sp; - - if (!s->is_completed) { - JS_MarkValue(rt, sf->cur_func, mark_func); - JS_MarkValue(rt, s->this_val, mark_func); - /* sf->cur_sp = NULL if the function is running */ - if (sf->cur_sp) { - /* if the function is running, cur_sp is not known so we - cannot mark the stack. Marking the variables is not needed - because a running function cannot be part of a removable - cycle */ - for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) - JS_MarkValue(rt, *sp, mark_func); - } - } - JS_MarkValue(rt, s->resolving_funcs[0], mark_func); - JS_MarkValue(rt, s->resolving_funcs[1], mark_func); - } - break; - case JS_GC_OBJ_TYPE_SHAPE: - { - JSShape *sh = (JSShape *)gp; - if (sh->proto != NULL) { - mark_func(rt, &sh->proto->header); - } - } - break; - case JS_GC_OBJ_TYPE_JS_CONTEXT: - { - JSContext *ctx = (JSContext *)gp; - JS_MarkContext(rt, ctx, mark_func); - } - break; - case JS_GC_OBJ_TYPE_MODULE: - { - JSModuleDef *m = (JSModuleDef *)gp; - js_mark_module_def(rt, m, mark_func); - } - break; - default: - abort(); - } -} - -static void gc_decref_child(JSRuntime *rt, JSGCObjectHeader *p) -{ - assert(p->ref_count > 0); - p->ref_count--; - if (p->ref_count == 0 && p->mark == 1) { - list_del(&p->link); - list_add_tail(&p->link, &rt->tmp_obj_list); - } -} - -static void gc_decref(JSRuntime *rt) -{ - struct list_head *el, *el1; - JSGCObjectHeader *p; - - init_list_head(&rt->tmp_obj_list); - - /* decrement the refcount of all the children of all the GC - objects and move the GC objects with zero refcount to - tmp_obj_list */ - list_for_each_safe(el, el1, &rt->gc_obj_list) { - p = list_entry(el, JSGCObjectHeader, link); - assert(p->mark == 0); - mark_children(rt, p, gc_decref_child); - p->mark = 1; - if (p->ref_count == 0) { - list_del(&p->link); - list_add_tail(&p->link, &rt->tmp_obj_list); - } - } -} - -static void gc_scan_incref_child(JSRuntime *rt, JSGCObjectHeader *p) -{ - p->ref_count++; - if (p->ref_count == 1) { - /* ref_count was 0: remove from tmp_obj_list and add at the - end of gc_obj_list */ - list_del(&p->link); - list_add_tail(&p->link, &rt->gc_obj_list); - p->mark = 0; /* reset the mark for the next GC call */ - } -} - -static void gc_scan_incref_child2(JSRuntime *rt, JSGCObjectHeader *p) -{ - p->ref_count++; -} - -static void gc_scan(JSRuntime *rt) -{ - struct list_head *el; - JSGCObjectHeader *p; - - /* keep the objects with a refcount > 0 and their children. */ - list_for_each(el, &rt->gc_obj_list) { - p = list_entry(el, JSGCObjectHeader, link); - assert(p->ref_count > 0); - p->mark = 0; /* reset the mark for the next GC call */ - mark_children(rt, p, gc_scan_incref_child); - } - - /* restore the refcount of the objects to be deleted. */ - list_for_each(el, &rt->tmp_obj_list) { - p = list_entry(el, JSGCObjectHeader, link); - mark_children(rt, p, gc_scan_incref_child2); - } -} - -static void gc_free_cycles(JSRuntime *rt) -{ - struct list_head *el, *el1; - JSGCObjectHeader *p; -#ifdef DUMP_GC_FREE - BOOL header_done = FALSE; -#endif - - rt->gc_phase = JS_GC_PHASE_REMOVE_CYCLES; - - for(;;) { - el = rt->tmp_obj_list.next; - if (el == &rt->tmp_obj_list) - break; - p = list_entry(el, JSGCObjectHeader, link); - /* Only need to free the GC object associated with JS values - or async functions. The rest will be automatically removed - because they must be referenced by them. */ - switch(p->gc_obj_type) { - case JS_GC_OBJ_TYPE_JS_OBJECT: - case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: - case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: - case JS_GC_OBJ_TYPE_MODULE: -#ifdef DUMP_GC_FREE - if (!header_done) { - printf("Freeing cycles:\n"); - JS_DumpObjectHeader(rt); - header_done = TRUE; - } - JS_DumpGCObject(rt, p); -#endif - free_gc_object(rt, p); - break; - default: - list_del(&p->link); - list_add_tail(&p->link, &rt->gc_zero_ref_count_list); - break; - } - } - rt->gc_phase = JS_GC_PHASE_NONE; - - list_for_each_safe(el, el1, &rt->gc_zero_ref_count_list) { - p = list_entry(el, JSGCObjectHeader, link); - assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT || - p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE || - p->gc_obj_type == JS_GC_OBJ_TYPE_ASYNC_FUNCTION || - p->gc_obj_type == JS_GC_OBJ_TYPE_MODULE); - if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT && - ((JSObject *)p)->weakref_count != 0) { - /* keep the object because there are weak references to it */ - p->mark = 0; - } else { - js_free_rt(rt, p); - } - } - - init_list_head(&rt->gc_zero_ref_count_list); -} - -static void JS_RunGCInternal(JSRuntime *rt, BOOL remove_weak_objects) -{ - if (remove_weak_objects) { - /* free the weakly referenced object or symbol structures, delete - the associated Map/Set entries and queue the finalization - registry callbacks. */ - gc_remove_weak_objects(rt); - } - - /* decrement the reference of the children of each object. mark = - 1 after this pass. */ - gc_decref(rt); - - /* keep the GC objects with a non zero refcount and their childs */ - gc_scan(rt); - - /* free the GC objects in a cycle */ - gc_free_cycles(rt); -} - -void JS_RunGC(JSRuntime *rt) -{ - JS_RunGCInternal(rt, TRUE); -} - -/* Return false if not an object or if the object has already been - freed (zombie objects are visible in finalizers when freeing - cycles). */ -BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj) -{ - JSObject *p; - if (!JS_IsObject(obj)) - return FALSE; - p = JS_VALUE_GET_OBJ(obj); - return !p->free_mark; -} - -/* Compute memory used by various object types */ -/* XXX: poor man's approach to handling multiply referenced objects */ -typedef struct JSMemoryUsage_helper { - double memory_used_count; - double str_count; - double str_size; - int64_t js_func_count; - double js_func_size; - int64_t js_func_code_size; - int64_t js_func_pc2line_count; - int64_t js_func_pc2line_size; -} JSMemoryUsage_helper; - -static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp); - -static void compute_jsstring_size(JSString *str, JSMemoryUsage_helper *hp) -{ - if (!str->atom_type) { /* atoms are handled separately */ - double s_ref_count = str->header.ref_count; - hp->str_count += 1 / s_ref_count; - hp->str_size += ((sizeof(*str) + (str->len << str->is_wide_char) + - 1 - str->is_wide_char) / s_ref_count); - } -} - -static void compute_bytecode_size(JSFunctionBytecode *b, JSMemoryUsage_helper *hp) -{ - int memory_used_count, js_func_size, i; - - memory_used_count = 0; - js_func_size = offsetof(JSFunctionBytecode, debug); - if (b->vardefs) { - js_func_size += (b->arg_count + b->var_count) * sizeof(*b->vardefs); - } - if (b->cpool) { - js_func_size += b->cpool_count * sizeof(*b->cpool); - for (i = 0; i < b->cpool_count; i++) { - JSValueConst val = b->cpool[i]; - compute_value_size(val, hp); - } - } - if (b->closure_var) { - js_func_size += b->closure_var_count * sizeof(*b->closure_var); - } - if (!b->read_only_bytecode && b->byte_code_buf) { - hp->js_func_code_size += b->byte_code_len; - } - if (b->has_debug) { - js_func_size += sizeof(*b) - offsetof(JSFunctionBytecode, debug); - if (b->debug.source) { - memory_used_count++; - js_func_size += b->debug.source_len + 1; - } - if (b->debug.pc2line_len) { - memory_used_count++; - hp->js_func_pc2line_count += 1; - hp->js_func_pc2line_size += b->debug.pc2line_len; - } - } - hp->js_func_size += js_func_size; - hp->js_func_count += 1; - hp->memory_used_count += memory_used_count; -} - -static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp) -{ - switch(JS_VALUE_GET_TAG(val)) { - case JS_TAG_STRING: - compute_jsstring_size(JS_VALUE_GET_STRING(val), hp); - break; - case JS_TAG_BIG_INT: - /* should track JSBigInt usage */ - break; - } -} - -void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s) -{ - struct list_head *el, *el1; - int i; - JSMemoryUsage_helper mem = { 0 }, *hp = &mem; - - memset(s, 0, sizeof(*s)); - s->malloc_count = rt->malloc_state.malloc_count; - s->malloc_size = rt->malloc_state.malloc_size; - s->malloc_limit = rt->malloc_state.malloc_limit; - - s->memory_used_count = 2; /* rt + rt->class_array */ - s->memory_used_size = sizeof(JSRuntime) + sizeof(JSValue) * rt->class_count; - - list_for_each(el, &rt->context_list) { - JSContext *ctx = list_entry(el, JSContext, link); - JSShape *sh = ctx->array_shape; - s->memory_used_count += 2; /* ctx + ctx->class_proto */ - s->memory_used_size += sizeof(JSContext) + - sizeof(JSValue) * rt->class_count; - s->binary_object_count += ctx->binary_object_count; - s->binary_object_size += ctx->binary_object_size; - - /* the hashed shapes are counted separately */ - if (sh && !sh->is_hashed) { - int hash_size = sh->prop_hash_mask + 1; - s->shape_count++; - s->shape_size += get_shape_size(hash_size, sh->prop_size); - } - list_for_each(el1, &ctx->loaded_modules) { - JSModuleDef *m = list_entry(el1, JSModuleDef, link); - s->memory_used_count += 1; - s->memory_used_size += sizeof(*m); - if (m->req_module_entries) { - s->memory_used_count += 1; - s->memory_used_size += m->req_module_entries_count * sizeof(*m->req_module_entries); - } - if (m->export_entries) { - s->memory_used_count += 1; - s->memory_used_size += m->export_entries_count * sizeof(*m->export_entries); - for (i = 0; i < m->export_entries_count; i++) { - JSExportEntry *me = &m->export_entries[i]; - if (me->export_type == JS_EXPORT_TYPE_LOCAL && me->u.local.var_ref) { - /* potential multiple count */ - s->memory_used_count += 1; - compute_value_size(me->u.local.var_ref->value, hp); - } - } - } - if (m->star_export_entries) { - s->memory_used_count += 1; - s->memory_used_size += m->star_export_entries_count * sizeof(*m->star_export_entries); - } - if (m->import_entries) { - s->memory_used_count += 1; - s->memory_used_size += m->import_entries_count * sizeof(*m->import_entries); - } - compute_value_size(m->module_ns, hp); - compute_value_size(m->func_obj, hp); - } - } - - list_for_each(el, &rt->gc_obj_list) { - JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link); - JSObject *p; - JSShape *sh; - JSShapeProperty *prs; - - /* XXX: could count the other GC object types too */ - if (gp->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE) { - compute_bytecode_size((JSFunctionBytecode *)gp, hp); - continue; - } else if (gp->gc_obj_type != JS_GC_OBJ_TYPE_JS_OBJECT) { - continue; - } - p = (JSObject *)gp; - sh = p->shape; - s->obj_count++; - if (p->prop) { - s->memory_used_count++; - s->prop_size += sh->prop_size * sizeof(*p->prop); - s->prop_count += sh->prop_count; - prs = get_shape_prop(sh); - for(i = 0; i < sh->prop_count; i++) { - JSProperty *pr = &p->prop[i]; - if (prs->atom != JS_ATOM_NULL && !(prs->flags & JS_PROP_TMASK)) { - compute_value_size(pr->u.value, hp); - } - prs++; - } - } - /* the hashed shapes are counted separately */ - if (!sh->is_hashed) { - int hash_size = sh->prop_hash_mask + 1; - s->shape_count++; - s->shape_size += get_shape_size(hash_size, sh->prop_size); - } - - switch(p->class_id) { - case JS_CLASS_ARRAY: /* u.array | length */ - case JS_CLASS_ARGUMENTS: /* u.array | length */ - s->array_count++; - if (p->fast_array) { - s->fast_array_count++; - if (p->u.array.u.values) { - s->memory_used_count++; - s->memory_used_size += p->u.array.count * - sizeof(*p->u.array.u.values); - s->fast_array_elements += p->u.array.count; - for (i = 0; i < p->u.array.count; i++) { - compute_value_size(p->u.array.u.values[i], hp); - } - } - } - break; - case JS_CLASS_NUMBER: /* u.object_data */ - case JS_CLASS_STRING: /* u.object_data */ - case JS_CLASS_BOOLEAN: /* u.object_data */ - case JS_CLASS_SYMBOL: /* u.object_data */ - case JS_CLASS_DATE: /* u.object_data */ - case JS_CLASS_BIG_INT: /* u.object_data */ - compute_value_size(p->u.object_data, hp); - break; - case JS_CLASS_C_FUNCTION: /* u.cfunc */ - s->c_func_count++; - break; - case JS_CLASS_BYTECODE_FUNCTION: /* u.func */ - { - JSFunctionBytecode *b = p->u.func.function_bytecode; - JSVarRef **var_refs = p->u.func.var_refs; - /* home_object: object will be accounted for in list scan */ - if (var_refs) { - s->memory_used_count++; - s->js_func_size += b->closure_var_count * sizeof(*var_refs); - for (i = 0; i < b->closure_var_count; i++) { - if (var_refs[i]) { - double ref_count = var_refs[i]->header.ref_count; - s->memory_used_count += 1 / ref_count; - s->js_func_size += sizeof(*var_refs[i]) / ref_count; - /* handle non object closed values */ - if (var_refs[i]->pvalue == &var_refs[i]->value) { - /* potential multiple count */ - compute_value_size(var_refs[i]->value, hp); - } - } - } - } - } - break; - case JS_CLASS_BOUND_FUNCTION: /* u.bound_function */ - { - JSBoundFunction *bf = p->u.bound_function; - /* func_obj and this_val are objects */ - for (i = 0; i < bf->argc; i++) { - compute_value_size(bf->argv[i], hp); - } - s->memory_used_count += 1; - s->memory_used_size += sizeof(*bf) + bf->argc * sizeof(*bf->argv); - } - break; - case JS_CLASS_C_FUNCTION_DATA: /* u.c_function_data_record */ - { - JSCFunctionDataRecord *fd = p->u.c_function_data_record; - if (fd) { - for (i = 0; i < fd->data_len; i++) { - compute_value_size(fd->data[i], hp); - } - s->memory_used_count += 1; - s->memory_used_size += sizeof(*fd) + fd->data_len * sizeof(*fd->data); - } - } - break; - case JS_CLASS_REGEXP: /* u.regexp */ - compute_jsstring_size(p->u.regexp.pattern, hp); - compute_jsstring_size(p->u.regexp.bytecode, hp); - break; - - case JS_CLASS_FOR_IN_ITERATOR: /* u.for_in_iterator */ - { - JSForInIterator *it = p->u.for_in_iterator; - if (it) { - compute_value_size(it->obj, hp); - s->memory_used_count += 1; - s->memory_used_size += sizeof(*it); - } - } - break; - case JS_CLASS_ARRAY_BUFFER: /* u.array_buffer */ - case JS_CLASS_SHARED_ARRAY_BUFFER: /* u.array_buffer */ - { - JSArrayBuffer *abuf = p->u.array_buffer; - if (abuf) { - s->memory_used_count += 1; - s->memory_used_size += sizeof(*abuf); - if (abuf->data) { - s->memory_used_count += 1; - s->memory_used_size += abuf->byte_length; - } - } - } - break; - case JS_CLASS_GENERATOR: /* u.generator_data */ - case JS_CLASS_UINT8C_ARRAY: /* u.typed_array / u.array */ - case JS_CLASS_INT8_ARRAY: /* u.typed_array / u.array */ - case JS_CLASS_UINT8_ARRAY: /* u.typed_array / u.array */ - case JS_CLASS_INT16_ARRAY: /* u.typed_array / u.array */ - case JS_CLASS_UINT16_ARRAY: /* u.typed_array / u.array */ - case JS_CLASS_INT32_ARRAY: /* u.typed_array / u.array */ - case JS_CLASS_UINT32_ARRAY: /* u.typed_array / u.array */ - case JS_CLASS_BIG_INT64_ARRAY: /* u.typed_array / u.array */ - case JS_CLASS_BIG_UINT64_ARRAY: /* u.typed_array / u.array */ - case JS_CLASS_FLOAT16_ARRAY: /* u.typed_array / u.array */ - case JS_CLASS_FLOAT32_ARRAY: /* u.typed_array / u.array */ - case JS_CLASS_FLOAT64_ARRAY: /* u.typed_array / u.array */ - case JS_CLASS_DATAVIEW: /* u.typed_array */ - case JS_CLASS_MAP: /* u.map_state */ - case JS_CLASS_SET: /* u.map_state */ - case JS_CLASS_WEAKMAP: /* u.map_state */ - case JS_CLASS_WEAKSET: /* u.map_state */ - case JS_CLASS_MAP_ITERATOR: /* u.map_iterator_data */ - case JS_CLASS_SET_ITERATOR: /* u.map_iterator_data */ - case JS_CLASS_ARRAY_ITERATOR: /* u.array_iterator_data */ - case JS_CLASS_STRING_ITERATOR: /* u.array_iterator_data */ - case JS_CLASS_PROXY: /* u.proxy_data */ - case JS_CLASS_PROMISE: /* u.promise_data */ - case JS_CLASS_PROMISE_RESOLVE_FUNCTION: /* u.promise_function_data */ - case JS_CLASS_PROMISE_REJECT_FUNCTION: /* u.promise_function_data */ - case JS_CLASS_ASYNC_FUNCTION_RESOLVE: /* u.async_function_data */ - case JS_CLASS_ASYNC_FUNCTION_REJECT: /* u.async_function_data */ - case JS_CLASS_ASYNC_FROM_SYNC_ITERATOR: /* u.async_from_sync_iterator_data */ - case JS_CLASS_ASYNC_GENERATOR: /* u.async_generator_data */ - /* TODO */ - default: - /* XXX: class definition should have an opaque block size */ - if (p->u.opaque) { - s->memory_used_count += 1; - } - break; - } - } - s->obj_size += s->obj_count * sizeof(JSObject); - - /* hashed shapes */ - s->memory_used_count++; /* rt->shape_hash */ - s->memory_used_size += sizeof(rt->shape_hash[0]) * rt->shape_hash_size; - for(i = 0; i < rt->shape_hash_size; i++) { - JSShape *sh; - for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) { - int hash_size = sh->prop_hash_mask + 1; - s->shape_count++; - s->shape_size += get_shape_size(hash_size, sh->prop_size); - } - } - - /* atoms */ - s->memory_used_count += 2; /* rt->atom_array, rt->atom_hash */ - s->atom_count = rt->atom_count; - s->atom_size = sizeof(rt->atom_array[0]) * rt->atom_size + - sizeof(rt->atom_hash[0]) * rt->atom_hash_size; - for(i = 0; i < rt->atom_size; i++) { - JSAtomStruct *p = rt->atom_array[i]; - if (!atom_is_free(p)) { - s->atom_size += (sizeof(*p) + (p->len << p->is_wide_char) + - 1 - p->is_wide_char); - } - } - s->str_count = round(mem.str_count); - s->str_size = round(mem.str_size); - s->js_func_count = mem.js_func_count; - s->js_func_size = round(mem.js_func_size); - s->js_func_code_size = mem.js_func_code_size; - s->js_func_pc2line_count = mem.js_func_pc2line_count; - s->js_func_pc2line_size = mem.js_func_pc2line_size; - s->memory_used_count += round(mem.memory_used_count) + - s->atom_count + s->str_count + - s->obj_count + s->shape_count + - s->js_func_count + s->js_func_pc2line_count; - s->memory_used_size += s->atom_size + s->str_size + - s->obj_size + s->prop_size + s->shape_size + - s->js_func_size + s->js_func_code_size + s->js_func_pc2line_size; -} - -void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt) -{ - fprintf(fp, "QuickJS memory usage -- " CONFIG_VERSION " version, %d-bit, malloc limit: %"PRId64"\n\n", - (int)sizeof(void *) * 8, s->malloc_limit); -#if 1 - if (rt) { - static const struct { - const char *name; - size_t size; - } object_types[] = { - { "JSRuntime", sizeof(JSRuntime) }, - { "JSContext", sizeof(JSContext) }, - { "JSObject", sizeof(JSObject) }, - { "JSString", sizeof(JSString) }, - { "JSFunctionBytecode", sizeof(JSFunctionBytecode) }, - }; - int i, usage_size_ok = 0; - for(i = 0; i < countof(object_types); i++) { - unsigned int size = object_types[i].size; - void *p = js_malloc_rt(rt, size); - if (p) { - unsigned int size1 = js_malloc_usable_size_rt(rt, p); - if (size1 >= size) { - usage_size_ok = 1; - fprintf(fp, " %3u + %-2u %s\n", - size, size1 - size, object_types[i].name); - } - js_free_rt(rt, p); - } - } - if (!usage_size_ok) { - fprintf(fp, " malloc_usable_size unavailable\n"); - } - { - int obj_classes[JS_CLASS_INIT_COUNT + 1] = { 0 }; - int class_id; - struct list_head *el; - list_for_each(el, &rt->gc_obj_list) { - JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link); - JSObject *p; - if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) { - p = (JSObject *)gp; - obj_classes[min_uint32(p->class_id, JS_CLASS_INIT_COUNT)]++; - } - } - fprintf(fp, "\n" "JSObject classes\n"); - if (obj_classes[0]) - fprintf(fp, " %5d %2.0d %s\n", obj_classes[0], 0, "none"); - for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) { - if (obj_classes[class_id] && class_id < rt->class_count) { - char buf[ATOM_GET_STR_BUF_SIZE]; - fprintf(fp, " %5d %2.0d %s\n", obj_classes[class_id], class_id, - JS_AtomGetStrRT(rt, buf, sizeof(buf), rt->class_array[class_id].class_name)); - } - } - if (obj_classes[JS_CLASS_INIT_COUNT]) - fprintf(fp, " %5d %2.0d %s\n", obj_classes[JS_CLASS_INIT_COUNT], 0, "other"); - } - fprintf(fp, "\n"); - } -#endif - fprintf(fp, "%-20s %8s %8s\n", "NAME", "COUNT", "SIZE"); - - if (s->malloc_count) { - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per block)\n", - "memory allocated", s->malloc_count, s->malloc_size, - (double)s->malloc_size / s->malloc_count); - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%d overhead, %0.1f average slack)\n", - "memory used", s->memory_used_count, s->memory_used_size, - MALLOC_OVERHEAD, ((double)(s->malloc_size - s->memory_used_size) / - s->memory_used_count)); - } - if (s->atom_count) { - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per atom)\n", - "atoms", s->atom_count, s->atom_size, - (double)s->atom_size / s->atom_count); - } - if (s->str_count) { - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per string)\n", - "strings", s->str_count, s->str_size, - (double)s->str_size / s->str_count); - } - if (s->obj_count) { - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n", - "objects", s->obj_count, s->obj_size, - (double)s->obj_size / s->obj_count); - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n", - " properties", s->prop_count, s->prop_size, - (double)s->prop_count / s->obj_count); - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per shape)\n", - " shapes", s->shape_count, s->shape_size, - (double)s->shape_size / s->shape_count); - } - if (s->js_func_count) { - fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n", - "bytecode functions", s->js_func_count, s->js_func_size); - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n", - " bytecode", s->js_func_count, s->js_func_code_size, - (double)s->js_func_code_size / s->js_func_count); - if (s->js_func_pc2line_count) { - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n", - " pc2line", s->js_func_pc2line_count, - s->js_func_pc2line_size, - (double)s->js_func_pc2line_size / s->js_func_pc2line_count); - } - } - if (s->c_func_count) { - fprintf(fp, "%-20s %8"PRId64"\n", "C functions", s->c_func_count); - } - if (s->array_count) { - fprintf(fp, "%-20s %8"PRId64"\n", "arrays", s->array_count); - if (s->fast_array_count) { - fprintf(fp, "%-20s %8"PRId64"\n", " fast arrays", s->fast_array_count); - fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per fast array)\n", - " elements", s->fast_array_elements, - s->fast_array_elements * (int)sizeof(JSValue), - (double)s->fast_array_elements / s->fast_array_count); - } - } - if (s->binary_object_count) { - fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n", - "binary objects", s->binary_object_count, s->binary_object_size); - } -} - -JSValue JS_GetGlobalObject(JSContext *ctx) -{ - return JS_DupValue(ctx, ctx->global_obj); -} - -/* WARNING: obj is freed */ -JSValue JS_Throw(JSContext *ctx, JSValue obj) -{ - JSRuntime *rt = ctx->rt; - JS_FreeValue(ctx, rt->current_exception); - rt->current_exception = obj; - rt->current_exception_is_uncatchable = FALSE; - return JS_EXCEPTION; -} - -/* return the pending exception (cannot be called twice). */ -JSValue JS_GetException(JSContext *ctx) -{ - JSValue val; - JSRuntime *rt = ctx->rt; - val = rt->current_exception; - rt->current_exception = JS_UNINITIALIZED; - return val; -} - -JS_BOOL JS_HasException(JSContext *ctx) -{ - return !JS_IsUninitialized(ctx->rt->current_exception); -} - -static void dbuf_put_leb128(DynBuf *s, uint32_t v) -{ - uint32_t a; - for(;;) { - a = v & 0x7f; - v >>= 7; - if (v != 0) { - dbuf_putc(s, a | 0x80); - } else { - dbuf_putc(s, a); - break; - } - } -} - -static void dbuf_put_sleb128(DynBuf *s, int32_t v1) -{ - uint32_t v = v1; - dbuf_put_leb128(s, (2 * v) ^ -(v >> 31)); -} - -static int get_leb128(uint32_t *pval, const uint8_t *buf, - const uint8_t *buf_end) -{ - const uint8_t *ptr = buf; - uint32_t v, a, i; - v = 0; - for(i = 0; i < 5; i++) { - if (unlikely(ptr >= buf_end)) - break; - a = *ptr++; - v |= (a & 0x7f) << (i * 7); - if (!(a & 0x80)) { - *pval = v; - return ptr - buf; - } - } - *pval = 0; - return -1; -} - -static int get_sleb128(int32_t *pval, const uint8_t *buf, - const uint8_t *buf_end) -{ - int ret; - uint32_t val; - ret = get_leb128(&val, buf, buf_end); - if (ret < 0) { - *pval = 0; - return -1; - } - *pval = (val >> 1) ^ -(val & 1); - return ret; -} - -/* use pc_value = -1 to get the position of the function definition */ -static int find_line_num(JSContext *ctx, JSFunctionBytecode *b, - uint32_t pc_value, int *pcol_num) -{ - const uint8_t *p_end, *p; - int new_line_num, line_num, pc, v, ret, new_col_num, col_num; - uint32_t val; - unsigned int op; - - if (!b->has_debug || !b->debug.pc2line_buf) - goto fail; /* function was stripped */ - - p = b->debug.pc2line_buf; - p_end = p + b->debug.pc2line_len; - - /* get the function line and column numbers */ - ret = get_leb128(&val, p, p_end); - if (ret < 0) - goto fail; - p += ret; - line_num = val + 1; - - ret = get_leb128(&val, p, p_end); - if (ret < 0) - goto fail; - p += ret; - col_num = val + 1; - - if (pc_value != -1) { - pc = 0; - while (p < p_end) { - op = *p++; - if (op == 0) { - ret = get_leb128(&val, p, p_end); - if (ret < 0) - goto fail; - pc += val; - p += ret; - ret = get_sleb128(&v, p, p_end); - if (ret < 0) - goto fail; - p += ret; - new_line_num = line_num + v; - } else { - op -= PC2LINE_OP_FIRST; - pc += (op / PC2LINE_RANGE); - new_line_num = line_num + (op % PC2LINE_RANGE) + PC2LINE_BASE; - } - ret = get_sleb128(&v, p, p_end); - if (ret < 0) - goto fail; - p += ret; - new_col_num = col_num + v; - - if (pc_value < pc) - goto done; - line_num = new_line_num; - col_num = new_col_num; - } - } - done: - *pcol_num = col_num; - return line_num; - fail: - *pcol_num = 0; - return 0; -} - -/* in order to avoid executing arbitrary code during the stack trace - generation, we only look at simple 'name' properties containing a - string. */ -static const char *get_func_name(JSContext *ctx, JSValueConst func) -{ - JSProperty *pr; - JSShapeProperty *prs; - JSValueConst val; - - if (JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT) - return NULL; - prs = find_own_property(&pr, JS_VALUE_GET_OBJ(func), JS_ATOM_name); - if (!prs) - return NULL; - if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL) - return NULL; - val = pr->u.value; - if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING) - return NULL; - return JS_ToCString(ctx, val); -} - -#define JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL (1 << 0) - -/* if filename != NULL, an additional level is added with the filename - and line number information (used for parse error). */ -static void build_backtrace(JSContext *ctx, JSValueConst error_obj, - const char *filename, int line_num, int col_num, - int backtrace_flags) -{ - JSStackFrame *sf; - JSValue str; - DynBuf dbuf; - const char *func_name_str; - const char *str1; - JSObject *p; - - if (!JS_IsObject(error_obj)) - return; /* protection in the out of memory case */ - - js_dbuf_init(ctx, &dbuf); - if (filename) { - dbuf_printf(&dbuf, " at %s", filename); - if (line_num != -1) - dbuf_printf(&dbuf, ":%d:%d", line_num, col_num); - dbuf_putc(&dbuf, '\n'); - str = JS_NewString(ctx, filename); - if (JS_IsException(str)) - return; - /* Note: SpiderMonkey does that, could update once there is a standard */ - if (JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, str, - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0 || - JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, JS_NewInt32(ctx, line_num), - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0 || - JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_columnNumber, JS_NewInt32(ctx, col_num), - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0) { - return; - } - } - for(sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) { - if (sf->js_mode & JS_MODE_BACKTRACE_BARRIER) - break; - if (backtrace_flags & JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL) { - backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL; - continue; - } - func_name_str = get_func_name(ctx, sf->cur_func); - if (!func_name_str || func_name_str[0] == '\0') - str1 = ""; - else - str1 = func_name_str; - dbuf_printf(&dbuf, " at %s", str1); - JS_FreeCString(ctx, func_name_str); - - p = JS_VALUE_GET_OBJ(sf->cur_func); - if (js_class_has_bytecode(p->class_id)) { - JSFunctionBytecode *b; - const char *atom_str; - int line_num1, col_num1; - - b = p->u.func.function_bytecode; - if (b->has_debug) { - line_num1 = find_line_num(ctx, b, - sf->cur_pc - b->byte_code_buf - 1, &col_num1); - atom_str = JS_AtomToCString(ctx, b->debug.filename); - dbuf_printf(&dbuf, " (%s", - atom_str ? atom_str : ""); - JS_FreeCString(ctx, atom_str); - if (line_num1 != 0) - dbuf_printf(&dbuf, ":%d:%d", line_num1, col_num1); - dbuf_putc(&dbuf, ')'); - } - } else { - dbuf_printf(&dbuf, " (native)"); - } - dbuf_putc(&dbuf, '\n'); - } - dbuf_putc(&dbuf, '\0'); - if (dbuf_error(&dbuf)) - str = JS_NULL; - else - str = JS_NewString(ctx, (char *)dbuf.buf); - dbuf_free(&dbuf); - JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, str, - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); -} - -/* Note: it is important that no exception is returned by this function */ -static BOOL is_backtrace_needed(JSContext *ctx, JSValueConst obj) -{ - JSObject *p; - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - return FALSE; - p = JS_VALUE_GET_OBJ(obj); - if (p->class_id != JS_CLASS_ERROR) - return FALSE; - if (find_own_property1(p, JS_ATOM_stack)) - return FALSE; - return TRUE; -} - -JSValue JS_NewError(JSContext *ctx) -{ - return JS_NewObjectClass(ctx, JS_CLASS_ERROR); -} - -static JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num, - const char *fmt, va_list ap, BOOL add_backtrace) -{ - char buf[256]; - JSValue obj, ret; - - vsnprintf(buf, sizeof(buf), fmt, ap); - obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[error_num], - JS_CLASS_ERROR); - if (unlikely(JS_IsException(obj))) { - /* out of memory: throw JS_NULL to avoid recursing */ - obj = JS_NULL; - } else { - JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, - JS_NewString(ctx, buf), - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - if (add_backtrace) { - build_backtrace(ctx, obj, NULL, 0, 0, 0); - } - } - ret = JS_Throw(ctx, obj); - return ret; -} - -static JSValue JS_ThrowError(JSContext *ctx, JSErrorEnum error_num, - const char *fmt, va_list ap) -{ - JSRuntime *rt = ctx->rt; - JSStackFrame *sf; - BOOL add_backtrace; - - /* the backtrace is added later if called from a bytecode function */ - sf = rt->current_stack_frame; - add_backtrace = !rt->in_out_of_memory && - (!sf || (JS_GetFunctionBytecode(sf->cur_func) == NULL)); - return JS_ThrowError2(ctx, error_num, fmt, ap, add_backtrace); -} - -JSValue __attribute__((format(printf, 2, 3))) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...) -{ - JSValue val; - va_list ap; - - va_start(ap, fmt); - val = JS_ThrowError(ctx, JS_SYNTAX_ERROR, fmt, ap); - va_end(ap); - return val; -} - -JSValue __attribute__((format(printf, 2, 3))) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...) -{ - JSValue val; - va_list ap; - - va_start(ap, fmt); - val = JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap); - va_end(ap); - return val; -} - -static int __attribute__((format(printf, 3, 4))) JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, const char *fmt, ...) -{ - va_list ap; - - if ((flags & JS_PROP_THROW) || - ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) { - va_start(ap, fmt); - JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap); - va_end(ap); - return -1; - } else { - return FALSE; - } -} - -/* never use it directly */ -static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...) -{ - char buf[ATOM_GET_STR_BUF_SIZE]; - return JS_ThrowTypeError(ctx, fmt, - JS_AtomGetStr(ctx, buf, sizeof(buf), atom)); -} - -/* never use it directly */ -static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowSyntaxErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...) -{ - char buf[ATOM_GET_STR_BUF_SIZE]; - return JS_ThrowSyntaxError(ctx, fmt, - JS_AtomGetStr(ctx, buf, sizeof(buf), atom)); -} - -/* %s is replaced by 'atom'. The macro is used so that gcc can check - the format string. */ -#define JS_ThrowTypeErrorAtom(ctx, fmt, atom) __JS_ThrowTypeErrorAtom(ctx, atom, fmt, "") -#define JS_ThrowSyntaxErrorAtom(ctx, fmt, atom) __JS_ThrowSyntaxErrorAtom(ctx, atom, fmt, "") - -static int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom) -{ - if ((flags & JS_PROP_THROW) || - ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) { - JS_ThrowTypeErrorAtom(ctx, "'%s' is read-only", atom); - return -1; - } else { - return FALSE; - } -} - -JSValue __attribute__((format(printf, 2, 3))) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...) -{ - JSValue val; - va_list ap; - - va_start(ap, fmt); - val = JS_ThrowError(ctx, JS_REFERENCE_ERROR, fmt, ap); - va_end(ap); - return val; -} - -JSValue __attribute__((format(printf, 2, 3))) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...) -{ - JSValue val; - va_list ap; - - va_start(ap, fmt); - val = JS_ThrowError(ctx, JS_RANGE_ERROR, fmt, ap); - va_end(ap); - return val; -} - -JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...) -{ - JSValue val; - va_list ap; - - va_start(ap, fmt); - val = JS_ThrowError(ctx, JS_INTERNAL_ERROR, fmt, ap); - va_end(ap); - return val; -} - -JSValue JS_ThrowOutOfMemory(JSContext *ctx) -{ - JSRuntime *rt = ctx->rt; - if (!rt->in_out_of_memory) { - rt->in_out_of_memory = TRUE; - JS_ThrowInternalError(ctx, "out of memory"); - rt->in_out_of_memory = FALSE; - } - return JS_EXCEPTION; -} - -static JSValue JS_ThrowStackOverflow(JSContext *ctx) -{ - return JS_ThrowInternalError(ctx, "stack overflow"); -} - -static JSValue JS_ThrowTypeErrorNotAnObject(JSContext *ctx) -{ - return JS_ThrowTypeError(ctx, "not an object"); -} - -static JSValue JS_ThrowTypeErrorNotASymbol(JSContext *ctx) -{ - return JS_ThrowTypeError(ctx, "not a symbol"); -} - -static JSValue JS_ThrowReferenceErrorNotDefined(JSContext *ctx, JSAtom name) -{ - char buf[ATOM_GET_STR_BUF_SIZE]; - return JS_ThrowReferenceError(ctx, "'%s' is not defined", - JS_AtomGetStr(ctx, buf, sizeof(buf), name)); -} - -static JSValue JS_ThrowReferenceErrorUninitialized(JSContext *ctx, JSAtom name) -{ - char buf[ATOM_GET_STR_BUF_SIZE]; - return JS_ThrowReferenceError(ctx, "%s is not initialized", - name == JS_ATOM_NULL ? "lexical variable" : - JS_AtomGetStr(ctx, buf, sizeof(buf), name)); -} - -static JSValue JS_ThrowReferenceErrorUninitialized2(JSContext *ctx, - JSFunctionBytecode *b, - int idx, BOOL is_ref) -{ - JSAtom atom = JS_ATOM_NULL; - if (is_ref) { - atom = b->closure_var[idx].var_name; - } else { - /* not present if the function is stripped and contains no eval() */ - if (b->vardefs) - atom = b->vardefs[b->arg_count + idx].var_name; - } - return JS_ThrowReferenceErrorUninitialized(ctx, atom); -} - -static JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id) -{ - JSRuntime *rt = ctx->rt; - JSAtom name; - name = rt->class_array[class_id].class_name; - return JS_ThrowTypeErrorAtom(ctx, "%s object expected", name); -} - -static void JS_ThrowInterrupted(JSContext *ctx) -{ - JS_ThrowInternalError(ctx, "interrupted"); - JS_SetUncatchableException(ctx, TRUE); -} - -static no_inline __exception int __js_poll_interrupts(JSContext *ctx) -{ - JSRuntime *rt = ctx->rt; - ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT; - if (rt->interrupt_handler) { - if (rt->interrupt_handler(rt, rt->interrupt_opaque)) { - JS_ThrowInterrupted(ctx); - return -1; - } - } - return 0; -} - -static inline __exception int js_poll_interrupts(JSContext *ctx) -{ - if (unlikely(--ctx->interrupt_counter <= 0)) { - return __js_poll_interrupts(ctx); - } else { - return 0; - } -} - -static void JS_SetImmutablePrototype(JSContext *ctx, JSValueConst obj) -{ - JSObject *p; - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - return; - p = JS_VALUE_GET_OBJ(obj); - p->has_immutable_prototype = TRUE; -} - -/* Return -1 (exception) or TRUE/FALSE. 'throw_flag' = FALSE indicates - that it is called from Reflect.setPrototypeOf(). */ -static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj, - JSValueConst proto_val, - BOOL throw_flag) -{ - JSObject *proto, *p, *p1; - JSShape *sh; - - if (throw_flag) { - if (JS_VALUE_GET_TAG(obj) == JS_TAG_NULL || - JS_VALUE_GET_TAG(obj) == JS_TAG_UNDEFINED) - goto not_obj; - } else { - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - goto not_obj; - } - p = JS_VALUE_GET_OBJ(obj); - if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT) { - if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_NULL) { - not_obj: - JS_ThrowTypeErrorNotAnObject(ctx); - return -1; - } - proto = NULL; - } else { - proto = JS_VALUE_GET_OBJ(proto_val); - } - - if (throw_flag && JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - return TRUE; - - if (unlikely(p->is_exotic)) { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - int ret; - if (em && em->set_prototype) { - ret = em->set_prototype(ctx, obj, proto_val); - if (ret == 0 && throw_flag) { - JS_ThrowTypeError(ctx, "proxy: bad prototype"); - return -1; - } else { - return ret; - } - } - } - - sh = p->shape; - if (sh->proto == proto) - return TRUE; - if (unlikely(p->has_immutable_prototype)) { - if (throw_flag) { - JS_ThrowTypeError(ctx, "prototype is immutable"); - return -1; - } else { - return FALSE; - } - } - if (unlikely(!p->extensible)) { - if (throw_flag) { - JS_ThrowTypeError(ctx, "object is not extensible"); - return -1; - } else { - return FALSE; - } - } - if (proto) { - /* check if there is a cycle */ - p1 = proto; - do { - if (p1 == p) { - if (throw_flag) { - JS_ThrowTypeError(ctx, "circular prototype chain"); - return -1; - } else { - return FALSE; - } - } - /* Note: for Proxy objects, proto is NULL */ - p1 = p1->shape->proto; - } while (p1 != NULL); - JS_DupValue(ctx, proto_val); - } - - if (js_shape_prepare_update(ctx, p, NULL)) - return -1; - sh = p->shape; - if (sh->proto) - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto)); - sh->proto = proto; - return TRUE; -} - -/* return -1 (exception) or TRUE/FALSE */ -int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val) -{ - return JS_SetPrototypeInternal(ctx, obj, proto_val, TRUE); -} - -/* Only works for primitive types, otherwise return JS_NULL. */ -static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val) -{ - switch(JS_VALUE_GET_NORM_TAG(val)) { - case JS_TAG_SHORT_BIG_INT: - case JS_TAG_BIG_INT: - val = ctx->class_proto[JS_CLASS_BIG_INT]; - break; - case JS_TAG_INT: - case JS_TAG_FLOAT64: - val = ctx->class_proto[JS_CLASS_NUMBER]; - break; - case JS_TAG_BOOL: - val = ctx->class_proto[JS_CLASS_BOOLEAN]; - break; - case JS_TAG_STRING: - case JS_TAG_STRING_ROPE: - val = ctx->class_proto[JS_CLASS_STRING]; - break; - case JS_TAG_SYMBOL: - val = ctx->class_proto[JS_CLASS_SYMBOL]; - break; - case JS_TAG_OBJECT: - case JS_TAG_NULL: - case JS_TAG_UNDEFINED: - default: - val = JS_NULL; - break; - } - return val; -} - -/* Return an Object, JS_NULL or JS_EXCEPTION in case of exotic object. */ -JSValue JS_GetPrototype(JSContext *ctx, JSValueConst obj) -{ - JSValue val; - if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { - JSObject *p; - p = JS_VALUE_GET_OBJ(obj); - if (unlikely(p->is_exotic)) { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em && em->get_prototype) { - return em->get_prototype(ctx, obj); - } - } - p = p->shape->proto; - if (!p) - val = JS_NULL; - else - val = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); - } else { - val = JS_DupValue(ctx, JS_GetPrototypePrimitive(ctx, obj)); - } - return val; -} - -static JSValue JS_GetPrototypeFree(JSContext *ctx, JSValue obj) -{ - JSValue obj1; - obj1 = JS_GetPrototype(ctx, obj); - JS_FreeValue(ctx, obj); - return obj1; -} - -/* return TRUE, FALSE or (-1) in case of exception */ -static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val, - JSValueConst obj) -{ - JSValue obj_proto; - JSObject *proto; - const JSObject *p, *proto1; - BOOL ret; - - if (!JS_IsFunction(ctx, obj)) - return FALSE; - p = JS_VALUE_GET_OBJ(obj); - if (p->class_id == JS_CLASS_BOUND_FUNCTION) { - JSBoundFunction *s = p->u.bound_function; - return JS_IsInstanceOf(ctx, val, s->func_obj); - } - - /* Only explicitly boxed values are instances of constructors */ - if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) - return FALSE; - obj_proto = JS_GetProperty(ctx, obj, JS_ATOM_prototype); - if (JS_VALUE_GET_TAG(obj_proto) != JS_TAG_OBJECT) { - if (!JS_IsException(obj_proto)) - JS_ThrowTypeError(ctx, "operand 'prototype' property is not an object"); - ret = -1; - goto done; - } - proto = JS_VALUE_GET_OBJ(obj_proto); - p = JS_VALUE_GET_OBJ(val); - for(;;) { - proto1 = p->shape->proto; - if (!proto1) { - /* slow case if exotic object in the prototype chain */ - if (unlikely(p->is_exotic && !p->fast_array)) { - JSValue obj1; - obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, (JSObject *)p)); - for(;;) { - obj1 = JS_GetPrototypeFree(ctx, obj1); - if (JS_IsException(obj1)) { - ret = -1; - break; - } - if (JS_IsNull(obj1)) { - ret = FALSE; - break; - } - if (proto == JS_VALUE_GET_OBJ(obj1)) { - JS_FreeValue(ctx, obj1); - ret = TRUE; - break; - } - /* must check for timeout to avoid infinite loop */ - if (js_poll_interrupts(ctx)) { - JS_FreeValue(ctx, obj1); - ret = -1; - break; - } - } - } else { - ret = FALSE; - } - break; - } - p = proto1; - if (proto == p) { - ret = TRUE; - break; - } - } -done: - JS_FreeValue(ctx, obj_proto); - return ret; -} - -/* return TRUE, FALSE or (-1) in case of exception */ -int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj) -{ - JSValue method; - - if (!JS_IsObject(obj)) - goto fail; - method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_hasInstance); - if (JS_IsException(method)) - return -1; - if (!JS_IsNull(method) && !JS_IsUndefined(method)) { - JSValue ret; - ret = JS_CallFree(ctx, method, obj, 1, &val); - return JS_ToBoolFree(ctx, ret); - } - - /* legacy case */ - if (!JS_IsFunction(ctx, obj)) { - fail: - JS_ThrowTypeError(ctx, "invalid 'instanceof' right operand"); - return -1; - } - return JS_OrdinaryIsInstanceOf(ctx, val, obj); -} - -/* return the value associated to the autoinit property or an exception */ -typedef JSValue JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); - -static JSAutoInitFunc *js_autoinit_func_table[] = { - js_instantiate_prototype, /* JS_AUTOINIT_ID_PROTOTYPE */ - js_module_ns_autoinit, /* JS_AUTOINIT_ID_MODULE_NS */ - JS_InstantiateFunctionListItem2, /* JS_AUTOINIT_ID_PROP */ -}; - -/* warning: 'prs' is reallocated after it */ -static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop, - JSProperty *pr, JSShapeProperty *prs) -{ - JSValue val; - JSContext *realm; - JSAutoInitFunc *func; - JSAutoInitIDEnum id; - - if (js_shape_prepare_update(ctx, p, &prs)) - return -1; - - realm = js_autoinit_get_realm(pr); - id = js_autoinit_get_id(pr); - func = js_autoinit_func_table[id]; - /* 'func' shall not modify the object properties 'pr' */ - val = func(realm, p, prop, pr->u.init.opaque); - js_autoinit_free(ctx->rt, pr); - prs->flags &= ~JS_PROP_TMASK; - pr->u.value = JS_UNDEFINED; - if (JS_IsException(val)) - return -1; - if (id == JS_AUTOINIT_ID_MODULE_NS && - JS_VALUE_GET_TAG(val) == JS_TAG_STRING) { - /* WARNING: a varref is returned as a string ! */ - prs->flags |= JS_PROP_VARREF; - pr->u.var_ref = JS_VALUE_GET_PTR(val); - pr->u.var_ref->header.ref_count++; - } else { - pr->u.value = val; - } - return 0; -} - -JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, - JSAtom prop, JSValueConst this_obj, - BOOL throw_ref_error) -{ - JSObject *p; - JSProperty *pr; - JSShapeProperty *prs; - uint32_t tag; - - tag = JS_VALUE_GET_TAG(obj); - if (unlikely(tag != JS_TAG_OBJECT)) { - switch(tag) { - case JS_TAG_NULL: - return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", prop); - case JS_TAG_UNDEFINED: - return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of undefined", prop); - case JS_TAG_EXCEPTION: - return JS_EXCEPTION; - case JS_TAG_STRING: - { - JSString *p1 = JS_VALUE_GET_STRING(obj); - if (__JS_AtomIsTaggedInt(prop)) { - uint32_t idx; - idx = __JS_AtomToUInt32(prop); - if (idx < p1->len) { - return js_new_string_char(ctx, string_get(p1, idx)); - } - } else if (prop == JS_ATOM_length) { - return JS_NewInt32(ctx, p1->len); - } - } - break; - case JS_TAG_STRING_ROPE: - { - JSStringRope *p1 = JS_VALUE_GET_STRING_ROPE(obj); - if (__JS_AtomIsTaggedInt(prop)) { - uint32_t idx; - idx = __JS_AtomToUInt32(prop); - if (idx < p1->len) { - return js_new_string_char(ctx, string_rope_get(obj, idx)); - } - } else if (prop == JS_ATOM_length) { - return JS_NewInt32(ctx, p1->len); - } - } - break; - default: - break; - } - /* cannot raise an exception */ - p = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj)); - if (!p) - return JS_UNDEFINED; - } else { - p = JS_VALUE_GET_OBJ(obj); - } - - for(;;) { - prs = find_own_property(&pr, p, prop); - if (prs) { - /* found */ - if (unlikely(prs->flags & JS_PROP_TMASK)) { - if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { - if (unlikely(!pr->u.getset.getter)) { - return JS_UNDEFINED; - } else { - JSValue func = JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter); - /* Note: the field could be removed in the getter */ - func = JS_DupValue(ctx, func); - return JS_CallFree(ctx, func, this_obj, 0, NULL); - } - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { - JSValue val = *pr->u.var_ref->pvalue; - if (unlikely(JS_IsUninitialized(val))) - return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); - return JS_DupValue(ctx, val); - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { - /* Instantiate property and retry */ - if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) - return JS_EXCEPTION; - continue; - } - } else { - return JS_DupValue(ctx, pr->u.value); - } - } - if (unlikely(p->is_exotic)) { - /* exotic behaviors */ - if (p->fast_array) { - if (__JS_AtomIsTaggedInt(prop)) { - uint32_t idx = __JS_AtomToUInt32(prop); - if (idx < p->u.array.count) { - /* we avoid duplicating the code */ - return JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx); - } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) { - return JS_UNDEFINED; - } - } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) { - int ret; - ret = JS_AtomIsNumericIndex(ctx, prop); - if (ret != 0) { - if (ret < 0) - return JS_EXCEPTION; - return JS_UNDEFINED; - } - } - } else { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em) { - if (em->get_property) { - JSValue obj1, retval; - /* XXX: should pass throw_ref_error */ - /* Note: if 'p' is a prototype, it can be - freed in the called function */ - obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); - retval = em->get_property(ctx, obj1, prop, this_obj); - JS_FreeValue(ctx, obj1); - return retval; - } - if (em->get_own_property) { - JSPropertyDescriptor desc; - int ret; - JSValue obj1; - - /* Note: if 'p' is a prototype, it can be - freed in the called function */ - obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); - ret = em->get_own_property(ctx, &desc, obj1, prop); - JS_FreeValue(ctx, obj1); - if (ret < 0) - return JS_EXCEPTION; - if (ret) { - if (desc.flags & JS_PROP_GETSET) { - JS_FreeValue(ctx, desc.setter); - return JS_CallFree(ctx, desc.getter, this_obj, 0, NULL); - } else { - return desc.value; - } - } - } - } - } - } - p = p->shape->proto; - if (!p) - break; - } - if (unlikely(throw_ref_error)) { - return JS_ThrowReferenceErrorNotDefined(ctx, prop); - } else { - return JS_UNDEFINED; - } -} - -static JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom) -{ - return JS_ThrowTypeErrorAtom(ctx, "private class field '%s' does not exist", - atom); -} - -/* Private fields can be added even on non extensible objects or - Proxies */ -static int JS_DefinePrivateField(JSContext *ctx, JSValueConst obj, - JSValueConst name, JSValue val) -{ - JSObject *p; - JSShapeProperty *prs; - JSProperty *pr; - JSAtom prop; - - if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) { - JS_ThrowTypeErrorNotAnObject(ctx); - goto fail; - } - /* safety check */ - if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) { - JS_ThrowTypeErrorNotASymbol(ctx); - goto fail; - } - prop = js_symbol_to_atom(ctx, (JSValue)name); - p = JS_VALUE_GET_OBJ(obj); - prs = find_own_property(&pr, p, prop); - if (prs) { - JS_ThrowTypeErrorAtom(ctx, "private class field '%s' already exists", - prop); - goto fail; - } - pr = add_property(ctx, p, prop, JS_PROP_C_W_E); - if (unlikely(!pr)) { - fail: - JS_FreeValue(ctx, val); - return -1; - } - pr->u.value = val; - return 0; -} - -static JSValue JS_GetPrivateField(JSContext *ctx, JSValueConst obj, - JSValueConst name) -{ - JSObject *p; - JSShapeProperty *prs; - JSProperty *pr; - JSAtom prop; - - if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) - return JS_ThrowTypeErrorNotAnObject(ctx); - /* safety check */ - if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) - return JS_ThrowTypeErrorNotASymbol(ctx); - prop = js_symbol_to_atom(ctx, (JSValue)name); - p = JS_VALUE_GET_OBJ(obj); - prs = find_own_property(&pr, p, prop); - if (!prs) { - JS_ThrowTypeErrorPrivateNotFound(ctx, prop); - return JS_EXCEPTION; - } - return JS_DupValue(ctx, pr->u.value); -} - -static int JS_SetPrivateField(JSContext *ctx, JSValueConst obj, - JSValueConst name, JSValue val) -{ - JSObject *p; - JSShapeProperty *prs; - JSProperty *pr; - JSAtom prop; - - if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) { - JS_ThrowTypeErrorNotAnObject(ctx); - goto fail; - } - /* safety check */ - if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) { - JS_ThrowTypeErrorNotASymbol(ctx); - goto fail; - } - prop = js_symbol_to_atom(ctx, (JSValue)name); - p = JS_VALUE_GET_OBJ(obj); - prs = find_own_property(&pr, p, prop); - if (!prs) { - JS_ThrowTypeErrorPrivateNotFound(ctx, prop); - fail: - JS_FreeValue(ctx, val); - return -1; - } - set_value(ctx, &pr->u.value, val); - return 0; -} - -/* add a private brand field to 'home_obj' if not already present and - if obj is != null add a private brand to it */ -static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj) -{ - JSObject *p, *p1; - JSShapeProperty *prs; - JSProperty *pr; - JSValue brand; - JSAtom brand_atom; - - if (unlikely(JS_VALUE_GET_TAG(home_obj) != JS_TAG_OBJECT)) { - JS_ThrowTypeErrorNotAnObject(ctx); - return -1; - } - p = JS_VALUE_GET_OBJ(home_obj); - prs = find_own_property(&pr, p, JS_ATOM_Private_brand); - if (!prs) { - /* if the brand is not present, add it */ - brand = JS_NewSymbolFromAtom(ctx, JS_ATOM_brand, JS_ATOM_TYPE_PRIVATE); - if (JS_IsException(brand)) - return -1; - pr = add_property(ctx, p, JS_ATOM_Private_brand, JS_PROP_C_W_E); - if (!pr) { - JS_FreeValue(ctx, brand); - return -1; - } - pr->u.value = JS_DupValue(ctx, brand); - } else { - brand = JS_DupValue(ctx, pr->u.value); - } - brand_atom = js_symbol_to_atom(ctx, brand); - - if (JS_IsObject(obj)) { - p1 = JS_VALUE_GET_OBJ(obj); - prs = find_own_property(&pr, p1, brand_atom); - if (unlikely(prs)) { - JS_FreeAtom(ctx, brand_atom); - JS_ThrowTypeError(ctx, "private method is already present"); - return -1; - } - pr = add_property(ctx, p1, brand_atom, JS_PROP_C_W_E); - JS_FreeAtom(ctx, brand_atom); - if (!pr) - return -1; - pr->u.value = JS_UNDEFINED; - } else { - JS_FreeAtom(ctx, brand_atom); - } - return 0; -} - -/* return a boolean telling if the brand of the home object of 'func' - is present on 'obj' or -1 in case of exception */ -static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func) -{ - JSObject *p, *p1, *home_obj; - JSShapeProperty *prs; - JSProperty *pr; - JSValueConst brand; - - /* get the home object of 'func' */ - if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)) - goto not_obj; - p1 = JS_VALUE_GET_OBJ(func); - if (!js_class_has_bytecode(p1->class_id)) - goto not_obj; - home_obj = p1->u.func.home_object; - if (!home_obj) - goto not_obj; - prs = find_own_property(&pr, home_obj, JS_ATOM_Private_brand); - if (!prs) { - JS_ThrowTypeError(ctx, "expecting private field"); - return -1; - } - brand = pr->u.value; - /* safety check */ - if (unlikely(JS_VALUE_GET_TAG(brand) != JS_TAG_SYMBOL)) - goto not_obj; - - /* get the brand array of 'obj' */ - if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) { - not_obj: - JS_ThrowTypeErrorNotAnObject(ctx); - return -1; - } - p = JS_VALUE_GET_OBJ(obj); - prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, (JSValue)brand)); - return (prs != NULL); -} - -static uint32_t js_string_obj_get_length(JSContext *ctx, - JSValueConst obj) -{ - JSObject *p; - uint32_t len = 0; - - /* This is a class exotic method: obj class_id is JS_CLASS_STRING */ - p = JS_VALUE_GET_OBJ(obj); - if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) { - JSString *p1 = JS_VALUE_GET_STRING(p->u.object_data); - len = p1->len; - } - return len; -} - -static int num_keys_cmp(const void *p1, const void *p2, void *opaque) -{ - JSContext *ctx = opaque; - JSAtom atom1 = ((const JSPropertyEnum *)p1)->atom; - JSAtom atom2 = ((const JSPropertyEnum *)p2)->atom; - uint32_t v1, v2; - BOOL atom1_is_integer, atom2_is_integer; - - atom1_is_integer = JS_AtomIsArrayIndex(ctx, &v1, atom1); - atom2_is_integer = JS_AtomIsArrayIndex(ctx, &v2, atom2); - assert(atom1_is_integer && atom2_is_integer); - if (v1 < v2) - return -1; - else if (v1 == v2) - return 0; - else - return 1; -} - -void JS_FreePropertyEnum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len) -{ - uint32_t i; - if (tab) { - for(i = 0; i < len; i++) - JS_FreeAtom(ctx, tab[i].atom); - js_free(ctx, tab); - } -} - -/* return < 0 in case if exception, 0 if OK. ptab and its atoms must - be freed by the user. */ -static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, - JSPropertyEnum **ptab, - uint32_t *plen, - JSObject *p, int flags) -{ - int i, j; - JSShape *sh; - JSShapeProperty *prs; - JSPropertyEnum *tab_atom, *tab_exotic; - JSAtom atom; - uint32_t num_keys_count, str_keys_count, sym_keys_count, atom_count; - uint32_t num_index, str_index, sym_index, exotic_count, exotic_keys_count; - BOOL is_enumerable, num_sorted; - uint32_t num_key; - JSAtomKindEnum kind; - - /* clear pointer for consistency in case of failure */ - *ptab = NULL; - *plen = 0; - - /* compute the number of returned properties */ - num_keys_count = 0; - str_keys_count = 0; - sym_keys_count = 0; - exotic_keys_count = 0; - exotic_count = 0; - tab_exotic = NULL; - sh = p->shape; - for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { - atom = prs->atom; - if (atom != JS_ATOM_NULL) { - is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0); - kind = JS_AtomGetKind(ctx, atom); - if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) && - ((flags >> kind) & 1) != 0) { - /* need to raise an exception in case of the module - name space (implicit GetOwnProperty) */ - if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) && - (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY))) { - JSVarRef *var_ref = p->prop[i].u.var_ref; - if (unlikely(JS_IsUninitialized(*var_ref->pvalue))) { - JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); - return -1; - } - } - if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) { - num_keys_count++; - } else if (kind == JS_ATOM_KIND_STRING) { - str_keys_count++; - } else { - sym_keys_count++; - } - } - } - } - - if (p->is_exotic) { - if (p->fast_array) { - if (flags & JS_GPN_STRING_MASK) { - num_keys_count += p->u.array.count; - } - } else if (p->class_id == JS_CLASS_STRING) { - if (flags & JS_GPN_STRING_MASK) { - num_keys_count += js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); - } - } else { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em && em->get_own_property_names) { - if (em->get_own_property_names(ctx, &tab_exotic, &exotic_count, - JS_MKPTR(JS_TAG_OBJECT, p))) - return -1; - for(i = 0; i < exotic_count; i++) { - atom = tab_exotic[i].atom; - kind = JS_AtomGetKind(ctx, atom); - if (((flags >> kind) & 1) != 0) { - is_enumerable = FALSE; - if (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY)) { - JSPropertyDescriptor desc; - int res; - /* set the "is_enumerable" field if necessary */ - res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom); - if (res < 0) { - JS_FreePropertyEnum(ctx, tab_exotic, exotic_count); - return -1; - } - if (res) { - is_enumerable = - ((desc.flags & JS_PROP_ENUMERABLE) != 0); - js_free_desc(ctx, &desc); - } - tab_exotic[i].is_enumerable = is_enumerable; - } - if (!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) { - exotic_keys_count++; - } - } - } - } - } - } - - /* fill them */ - - atom_count = num_keys_count + str_keys_count; - if (atom_count < str_keys_count) - goto add_overflow; - atom_count += sym_keys_count; - if (atom_count < sym_keys_count) - goto add_overflow; - atom_count += exotic_keys_count; - if (atom_count < exotic_keys_count || atom_count > INT32_MAX) { - add_overflow: - JS_ThrowOutOfMemory(ctx); - JS_FreePropertyEnum(ctx, tab_exotic, exotic_count); - return -1; - } - /* XXX: need generic way to test for js_malloc(ctx, a * b) overflow */ - - /* avoid allocating 0 bytes */ - tab_atom = js_malloc(ctx, sizeof(tab_atom[0]) * max_int(atom_count, 1)); - if (!tab_atom) { - JS_FreePropertyEnum(ctx, tab_exotic, exotic_count); - return -1; - } - - num_index = 0; - str_index = num_keys_count; - sym_index = str_index + str_keys_count; - - num_sorted = TRUE; - sh = p->shape; - for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { - atom = prs->atom; - if (atom != JS_ATOM_NULL) { - is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0); - kind = JS_AtomGetKind(ctx, atom); - if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) && - ((flags >> kind) & 1) != 0) { - if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) { - j = num_index++; - num_sorted = FALSE; - } else if (kind == JS_ATOM_KIND_STRING) { - j = str_index++; - } else { - j = sym_index++; - } - tab_atom[j].atom = JS_DupAtom(ctx, atom); - tab_atom[j].is_enumerable = is_enumerable; - } - } - } - - if (p->is_exotic) { - int len; - if (p->fast_array) { - if (flags & JS_GPN_STRING_MASK) { - len = p->u.array.count; - goto add_array_keys; - } - } else if (p->class_id == JS_CLASS_STRING) { - if (flags & JS_GPN_STRING_MASK) { - len = js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); - add_array_keys: - for(i = 0; i < len; i++) { - tab_atom[num_index].atom = __JS_AtomFromUInt32(i); - if (tab_atom[num_index].atom == JS_ATOM_NULL) { - JS_FreePropertyEnum(ctx, tab_atom, num_index); - return -1; - } - tab_atom[num_index].is_enumerable = TRUE; - num_index++; - } - } - } else { - /* Note: exotic keys are not reordered and comes after the object own properties. */ - for(i = 0; i < exotic_count; i++) { - atom = tab_exotic[i].atom; - is_enumerable = tab_exotic[i].is_enumerable; - kind = JS_AtomGetKind(ctx, atom); - if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) && - ((flags >> kind) & 1) != 0) { - tab_atom[sym_index].atom = atom; - tab_atom[sym_index].is_enumerable = is_enumerable; - sym_index++; - } else { - JS_FreeAtom(ctx, atom); - } - } - js_free(ctx, tab_exotic); - } - } - - assert(num_index == num_keys_count); - assert(str_index == num_keys_count + str_keys_count); - assert(sym_index == atom_count); - - if (num_keys_count != 0 && !num_sorted) { - rqsort(tab_atom, num_keys_count, sizeof(tab_atom[0]), num_keys_cmp, - ctx); - } - *ptab = tab_atom; - *plen = atom_count; - return 0; -} - -int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, - uint32_t *plen, JSValueConst obj, int flags) -{ - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) { - JS_ThrowTypeErrorNotAnObject(ctx); - return -1; - } - return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen, - JS_VALUE_GET_OBJ(obj), flags); -} - -/* Return -1 if exception, - FALSE if the property does not exist, TRUE if it exists. If TRUE is - returned, the property descriptor 'desc' is filled present. */ -static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, - JSObject *p, JSAtom prop) -{ - JSShapeProperty *prs; - JSProperty *pr; - -retry: - prs = find_own_property(&pr, p, prop); - if (prs) { - if (desc) { - desc->flags = prs->flags & JS_PROP_C_W_E; - desc->getter = JS_UNDEFINED; - desc->setter = JS_UNDEFINED; - desc->value = JS_UNDEFINED; - if (unlikely(prs->flags & JS_PROP_TMASK)) { - if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { - desc->flags |= JS_PROP_GETSET; - if (pr->u.getset.getter) - desc->getter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter)); - if (pr->u.getset.setter) - desc->setter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter)); - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { - JSValue val = *pr->u.var_ref->pvalue; - if (unlikely(JS_IsUninitialized(val))) { - JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); - return -1; - } - desc->value = JS_DupValue(ctx, val); - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { - /* Instantiate property and retry */ - if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) - return -1; - goto retry; - } - } else { - desc->value = JS_DupValue(ctx, pr->u.value); - } - } else { - /* for consistency, send the exception even if desc is NULL */ - if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF)) { - if (unlikely(JS_IsUninitialized(*pr->u.var_ref->pvalue))) { - JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); - return -1; - } - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { - /* nothing to do: delay instantiation until actual value and/or attributes are read */ - } - } - return TRUE; - } - if (p->is_exotic) { - if (p->fast_array) { - /* specific case for fast arrays */ - if (__JS_AtomIsTaggedInt(prop)) { - uint32_t idx; - idx = __JS_AtomToUInt32(prop); - if (idx < p->u.array.count) { - if (desc) { - desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE | - JS_PROP_CONFIGURABLE; - desc->getter = JS_UNDEFINED; - desc->setter = JS_UNDEFINED; - desc->value = JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx); - } - return TRUE; - } - } - } else { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em && em->get_own_property) { - return em->get_own_property(ctx, desc, - JS_MKPTR(JS_TAG_OBJECT, p), prop); - } - } - } - return FALSE; -} - -int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc, - JSValueConst obj, JSAtom prop) -{ - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) { - JS_ThrowTypeErrorNotAnObject(ctx); - return -1; - } - return JS_GetOwnPropertyInternal(ctx, desc, JS_VALUE_GET_OBJ(obj), prop); -} - -/* return -1 if exception (exotic object only) or TRUE/FALSE */ -int JS_IsExtensible(JSContext *ctx, JSValueConst obj) -{ - JSObject *p; - - if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) - return FALSE; - p = JS_VALUE_GET_OBJ(obj); - if (unlikely(p->is_exotic)) { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em && em->is_extensible) { - return em->is_extensible(ctx, obj); - } - } - return p->extensible; -} - -/* return -1 if exception (exotic object only) or TRUE/FALSE */ -int JS_PreventExtensions(JSContext *ctx, JSValueConst obj) -{ - JSObject *p; - - if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) - return FALSE; - p = JS_VALUE_GET_OBJ(obj); - if (unlikely(p->is_exotic)) { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em && em->prevent_extensions) { - return em->prevent_extensions(ctx, obj); - } - } - p->extensible = FALSE; - return TRUE; -} - -/* return -1 if exception otherwise TRUE or FALSE */ -int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop) -{ - JSObject *p; - int ret; - JSValue obj1; - - if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) - return FALSE; - p = JS_VALUE_GET_OBJ(obj); - for(;;) { - if (p->is_exotic) { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em && em->has_property) { - /* has_property can free the prototype */ - obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); - ret = em->has_property(ctx, obj1, prop); - JS_FreeValue(ctx, obj1); - return ret; - } - } - /* JS_GetOwnPropertyInternal can free the prototype */ - JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); - ret = JS_GetOwnPropertyInternal(ctx, NULL, p, prop); - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); - if (ret != 0) - return ret; - if (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) { - ret = JS_AtomIsNumericIndex(ctx, prop); - if (ret != 0) { - if (ret < 0) - return -1; - return FALSE; - } - } - p = p->shape->proto; - if (!p) - break; - } - return FALSE; -} - -/* val must be a symbol */ -static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val) -{ - JSAtomStruct *p = JS_VALUE_GET_PTR(val); - return js_get_atom_index(ctx->rt, p); -} - -/* return JS_ATOM_NULL in case of exception */ -JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val) -{ - JSAtom atom; - uint32_t tag; - tag = JS_VALUE_GET_TAG(val); - if (tag == JS_TAG_INT && - (uint32_t)JS_VALUE_GET_INT(val) <= JS_ATOM_MAX_INT) { - /* fast path for integer values */ - atom = __JS_AtomFromUInt32(JS_VALUE_GET_INT(val)); - } else if (tag == JS_TAG_SYMBOL) { - JSAtomStruct *p = JS_VALUE_GET_PTR(val); - atom = JS_DupAtom(ctx, js_get_atom_index(ctx->rt, p)); - } else { - JSValue str; - str = JS_ToPropertyKey(ctx, val); - if (JS_IsException(str)) - return JS_ATOM_NULL; - if (JS_VALUE_GET_TAG(str) == JS_TAG_SYMBOL) { - atom = js_symbol_to_atom(ctx, str); - } else { - atom = JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(str)); - } - } - return atom; -} - -static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj, - JSValue prop) -{ - JSAtom atom; - JSValue ret; - - if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT && - JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) { - JSObject *p; - uint32_t idx; - /* fast path for array access */ - p = JS_VALUE_GET_OBJ(this_obj); - idx = JS_VALUE_GET_INT(prop); - switch(p->class_id) { - case JS_CLASS_ARRAY: - case JS_CLASS_ARGUMENTS: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_DupValue(ctx, p->u.array.u.values[idx]); - case JS_CLASS_INT8_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_NewInt32(ctx, p->u.array.u.int8_ptr[idx]); - case JS_CLASS_UINT8C_ARRAY: - case JS_CLASS_UINT8_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_NewInt32(ctx, p->u.array.u.uint8_ptr[idx]); - case JS_CLASS_INT16_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_NewInt32(ctx, p->u.array.u.int16_ptr[idx]); - case JS_CLASS_UINT16_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_NewInt32(ctx, p->u.array.u.uint16_ptr[idx]); - case JS_CLASS_INT32_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_NewInt32(ctx, p->u.array.u.int32_ptr[idx]); - case JS_CLASS_UINT32_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_NewUint32(ctx, p->u.array.u.uint32_ptr[idx]); - case JS_CLASS_BIG_INT64_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]); - case JS_CLASS_BIG_UINT64_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]); - case JS_CLASS_FLOAT16_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return __JS_NewFloat64(ctx, fromfp16(p->u.array.u.fp16_ptr[idx])); - case JS_CLASS_FLOAT32_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return __JS_NewFloat64(ctx, p->u.array.u.float_ptr[idx]); - case JS_CLASS_FLOAT64_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return __JS_NewFloat64(ctx, p->u.array.u.double_ptr[idx]); - default: - goto slow_path; - } - } else { - slow_path: - /* ToObject() must be done before ToPropertyKey() */ - if (JS_IsNull(this_obj) || JS_IsUndefined(this_obj)) { - JS_FreeValue(ctx, prop); - return JS_ThrowTypeError(ctx, "cannot read property of %s", JS_IsNull(this_obj) ? "null" : "undefined"); - } - atom = JS_ValueToAtom(ctx, prop); - JS_FreeValue(ctx, prop); - if (unlikely(atom == JS_ATOM_NULL)) - return JS_EXCEPTION; - ret = JS_GetProperty(ctx, this_obj, atom); - JS_FreeAtom(ctx, atom); - return ret; - } -} - -JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj, - uint32_t idx) -{ - return JS_GetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx)); -} - -/* Check if an object has a generalized numeric property. Return value: - -1 for exception, - TRUE if property exists, stored into *pval, - FALSE if proprty does not exist. - */ -static int JS_TryGetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, JSValue *pval) -{ - JSValue val = JS_UNDEFINED; - JSAtom prop; - int present; - - if (likely((uint64_t)idx <= JS_ATOM_MAX_INT)) { - /* fast path */ - present = JS_HasProperty(ctx, obj, __JS_AtomFromUInt32(idx)); - if (present > 0) { - val = JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx)); - if (unlikely(JS_IsException(val))) - present = -1; - } - } else { - prop = JS_NewAtomInt64(ctx, idx); - present = -1; - if (likely(prop != JS_ATOM_NULL)) { - present = JS_HasProperty(ctx, obj, prop); - if (present > 0) { - val = JS_GetProperty(ctx, obj, prop); - if (unlikely(JS_IsException(val))) - present = -1; - } - JS_FreeAtom(ctx, prop); - } - } - *pval = val; - return present; -} - -static JSValue JS_GetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx) -{ - JSAtom prop; - JSValue val; - - if ((uint64_t)idx <= INT32_MAX) { - /* fast path for fast arrays */ - return JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx)); - } - prop = JS_NewAtomInt64(ctx, idx); - if (prop == JS_ATOM_NULL) - return JS_EXCEPTION; - - val = JS_GetProperty(ctx, obj, prop); - JS_FreeAtom(ctx, prop); - return val; -} - -JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj, - const char *prop) -{ - JSAtom atom; - JSValue ret; - atom = JS_NewAtom(ctx, prop); - if (atom == JS_ATOM_NULL) - return JS_EXCEPTION; - ret = JS_GetProperty(ctx, this_obj, atom); - JS_FreeAtom(ctx, atom); - return ret; -} - -/* Note: the property value is not initialized. Return NULL if memory - error. */ -static JSProperty *add_property(JSContext *ctx, - JSObject *p, JSAtom prop, int prop_flags) -{ - JSShape *sh, *new_sh; - - sh = p->shape; - if (sh->is_hashed) { - /* try to find an existing shape */ - new_sh = find_hashed_shape_prop(ctx->rt, sh, prop, prop_flags); - if (new_sh) { - /* matching shape found: use it */ - /* the property array may need to be resized */ - if (new_sh->prop_size != sh->prop_size) { - JSProperty *new_prop; - new_prop = js_realloc(ctx, p->prop, sizeof(p->prop[0]) * - new_sh->prop_size); - if (!new_prop) - return NULL; - p->prop = new_prop; - } - p->shape = js_dup_shape(new_sh); - js_free_shape(ctx->rt, sh); - return &p->prop[new_sh->prop_count - 1]; - } else if (sh->header.ref_count != 1) { - /* if the shape is shared, clone it */ - new_sh = js_clone_shape(ctx, sh); - if (!new_sh) - return NULL; - /* hash the cloned shape */ - new_sh->is_hashed = TRUE; - js_shape_hash_link(ctx->rt, new_sh); - js_free_shape(ctx->rt, p->shape); - p->shape = new_sh; - } - } - assert(p->shape->header.ref_count == 1); - if (add_shape_property(ctx, &p->shape, p, prop, prop_flags)) - return NULL; - return &p->prop[p->shape->prop_count - 1]; -} - -/* can be called on Array or Arguments objects. return < 0 if - memory alloc error. */ -static no_inline __exception int convert_fast_array_to_array(JSContext *ctx, - JSObject *p) -{ - JSProperty *pr; - JSShape *sh; - JSValue *tab; - uint32_t i, len, new_count; - - if (js_shape_prepare_update(ctx, p, NULL)) - return -1; - len = p->u.array.count; - /* resize the properties once to simplify the error handling */ - sh = p->shape; - new_count = sh->prop_count + len; - if (new_count > sh->prop_size) { - if (resize_properties(ctx, &p->shape, p, new_count)) - return -1; - } - - tab = p->u.array.u.values; - for(i = 0; i < len; i++) { - /* add_property cannot fail here but - __JS_AtomFromUInt32(i) fails for i > INT32_MAX */ - pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E); - pr->u.value = *tab++; - } - js_free(ctx, p->u.array.u.values); - p->u.array.count = 0; - p->u.array.u.values = NULL; /* fail safe */ - p->u.array.u1.size = 0; - p->fast_array = 0; - return 0; -} - -static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom) -{ - JSShape *sh; - JSShapeProperty *pr, *lpr, *prop; - JSProperty *pr1; - uint32_t lpr_idx; - intptr_t h, h1; - - redo: - sh = p->shape; - h1 = atom & sh->prop_hash_mask; - h = prop_hash_end(sh)[-h1 - 1]; - prop = get_shape_prop(sh); - lpr = NULL; - lpr_idx = 0; /* prevent warning */ - while (h != 0) { - pr = &prop[h - 1]; - if (likely(pr->atom == atom)) { - /* found ! */ - if (!(pr->flags & JS_PROP_CONFIGURABLE)) - return FALSE; - /* realloc the shape if needed */ - if (lpr) - lpr_idx = lpr - get_shape_prop(sh); - if (js_shape_prepare_update(ctx, p, &pr)) - return -1; - sh = p->shape; - /* remove property */ - if (lpr) { - lpr = get_shape_prop(sh) + lpr_idx; - lpr->hash_next = pr->hash_next; - } else { - prop_hash_end(sh)[-h1 - 1] = pr->hash_next; - } - sh->deleted_prop_count++; - /* free the entry */ - pr1 = &p->prop[h - 1]; - free_property(ctx->rt, pr1, pr->flags); - JS_FreeAtom(ctx, pr->atom); - /* put default values */ - pr->flags = 0; - pr->atom = JS_ATOM_NULL; - pr1->u.value = JS_UNDEFINED; - - /* compact the properties if too many deleted properties */ - if (sh->deleted_prop_count >= 8 && - sh->deleted_prop_count >= ((unsigned)sh->prop_count / 2)) { - compact_properties(ctx, p); - } - return TRUE; - } - lpr = pr; - h = pr->hash_next; - } - - if (p->is_exotic) { - if (p->fast_array) { - uint32_t idx; - if (JS_AtomIsArrayIndex(ctx, &idx, atom) && - idx < p->u.array.count) { - if (p->class_id == JS_CLASS_ARRAY || - p->class_id == JS_CLASS_ARGUMENTS) { - /* Special case deleting the last element of a fast Array */ - if (idx == p->u.array.count - 1) { - JS_FreeValue(ctx, p->u.array.u.values[idx]); - p->u.array.count = idx; - return TRUE; - } - if (convert_fast_array_to_array(ctx, p)) - return -1; - goto redo; - } else { - return FALSE; - } - } - } else { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em && em->delete_property) { - return em->delete_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), atom); - } - } - } - /* not found */ - return TRUE; -} - -static int call_setter(JSContext *ctx, JSObject *setter, - JSValueConst this_obj, JSValue val, int flags) -{ - JSValue ret, func; - if (likely(setter)) { - func = JS_MKPTR(JS_TAG_OBJECT, setter); - /* Note: the field could be removed in the setter */ - func = JS_DupValue(ctx, func); - ret = JS_CallFree(ctx, func, this_obj, 1, (JSValueConst *)&val); - JS_FreeValue(ctx, val); - if (JS_IsException(ret)) - return -1; - JS_FreeValue(ctx, ret); - return TRUE; - } else { - JS_FreeValue(ctx, val); - if ((flags & JS_PROP_THROW) || - ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) { - JS_ThrowTypeError(ctx, "no setter for property"); - return -1; - } - return FALSE; - } -} - -/* set the array length and remove the array elements if necessary. */ -static int set_array_length(JSContext *ctx, JSObject *p, JSValue val, - int flags) -{ - uint32_t len, idx, cur_len; - int i, ret; - - /* Note: this call can reallocate the properties of 'p' */ - ret = JS_ToArrayLengthFree(ctx, &len, val, FALSE); - if (ret) - return -1; - /* JS_ToArrayLengthFree() must be done before the read-only test */ - if (unlikely(!(p->shape->prop[0].flags & JS_PROP_WRITABLE))) - return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length); - - if (likely(p->fast_array)) { - uint32_t old_len = p->u.array.count; - if (len < old_len) { - for(i = len; i < old_len; i++) { - JS_FreeValue(ctx, p->u.array.u.values[i]); - } - p->u.array.count = len; - } - p->prop[0].u.value = JS_NewUint32(ctx, len); - } else { - /* Note: length is always a uint32 because the object is an - array */ - JS_ToUint32(ctx, &cur_len, p->prop[0].u.value); - if (len < cur_len) { - uint32_t d; - JSShape *sh; - JSShapeProperty *pr; - - d = cur_len - len; - sh = p->shape; - if (d <= sh->prop_count) { - JSAtom atom; - - /* faster to iterate */ - while (cur_len > len) { - atom = JS_NewAtomUInt32(ctx, cur_len - 1); - ret = delete_property(ctx, p, atom); - JS_FreeAtom(ctx, atom); - if (unlikely(!ret)) { - /* unlikely case: property is not - configurable */ - break; - } - cur_len--; - } - } else { - /* faster to iterate thru all the properties. Need two - passes in case one of the property is not - configurable */ - cur_len = len; - for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; - i++, pr++) { - if (pr->atom != JS_ATOM_NULL && - JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) { - if (idx >= cur_len && - !(pr->flags & JS_PROP_CONFIGURABLE)) { - cur_len = idx + 1; - } - } - } - - for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; - i++, pr++) { - if (pr->atom != JS_ATOM_NULL && - JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) { - if (idx >= cur_len) { - /* remove the property */ - delete_property(ctx, p, pr->atom); - /* WARNING: the shape may have been modified */ - sh = p->shape; - pr = get_shape_prop(sh) + i; - } - } - } - } - } else { - cur_len = len; - } - set_value(ctx, &p->prop[0].u.value, JS_NewUint32(ctx, cur_len)); - if (unlikely(cur_len > len)) { - return JS_ThrowTypeErrorOrFalse(ctx, flags, "not configurable"); - } - } - return TRUE; -} - -/* return -1 if exception */ -static int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len) -{ - uint32_t new_size; - size_t slack; - JSValue *new_array_prop; - /* XXX: potential arithmetic overflow */ - new_size = max_int(new_len, p->u.array.u1.size * 3 / 2); - new_array_prop = js_realloc2(ctx, p->u.array.u.values, sizeof(JSValue) * new_size, &slack); - if (!new_array_prop) - return -1; - new_size += slack / sizeof(*new_array_prop); - p->u.array.u.values = new_array_prop; - p->u.array.u1.size = new_size; - return 0; -} - -/* Preconditions: 'p' must be of class JS_CLASS_ARRAY, p->fast_array = - TRUE and p->extensible = TRUE */ -static int add_fast_array_element(JSContext *ctx, JSObject *p, - JSValue val, int flags) -{ - uint32_t new_len, array_len; - /* extend the array by one */ - /* XXX: convert to slow array if new_len > 2^31-1 elements */ - new_len = p->u.array.count + 1; - /* update the length if necessary. We assume that if the length is - not an integer, then if it >= 2^31. */ - if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT)) { - array_len = JS_VALUE_GET_INT(p->prop[0].u.value); - if (new_len > array_len) { - if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE))) { - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length); - } - p->prop[0].u.value = JS_NewInt32(ctx, new_len); - } - } - if (unlikely(new_len > p->u.array.u1.size)) { - if (expand_fast_array(ctx, p, new_len)) { - JS_FreeValue(ctx, val); - return -1; - } - } - p->u.array.u.values[new_len - 1] = val; - p->u.array.count = new_len; - return TRUE; -} - -/* Allocate a new fast array. Its 'length' property is set to zero. It - maximum size is 2^31-1 elements. For convenience, 'len' is a 64 bit - integer. WARNING: the content of the array is not initialized. */ -static JSValue js_allocate_fast_array(JSContext *ctx, int64_t len) -{ - JSValue arr; - JSObject *p; - - if (len > INT32_MAX) - return JS_ThrowRangeError(ctx, "invalid array length"); - arr = JS_NewArray(ctx); - if (JS_IsException(arr)) - return arr; - if (len > 0) { - p = JS_VALUE_GET_OBJ(arr); - if (expand_fast_array(ctx, p, len) < 0) { - JS_FreeValue(ctx, arr); - return JS_EXCEPTION; - } - p->u.array.count = len; - } - return arr; -} - -static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc) -{ - JS_FreeValue(ctx, desc->getter); - JS_FreeValue(ctx, desc->setter); - JS_FreeValue(ctx, desc->value); -} - -/* return -1 in case of exception or TRUE or FALSE. Warning: 'val' is - freed by the function. 'flags' is a bitmask of JS_PROP_NO_ADD, - JS_PROP_THROW or JS_PROP_THROW_STRICT. If JS_PROP_NO_ADD is set, - the new property is not added and an error is raised. 'this_obj' is - the receiver. If obj != this_obj, then obj must be an object - (Reflect.set case). */ -int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj, - JSAtom prop, JSValue val, JSValueConst this_obj, int flags) -{ - JSObject *p, *p1; - JSShapeProperty *prs; - JSProperty *pr; - uint32_t tag; - JSPropertyDescriptor desc; - int ret; -#if 0 - printf("JS_SetPropertyInternal: "); print_atom(ctx, prop); printf("\n"); -#endif - tag = JS_VALUE_GET_TAG(this_obj); - if (unlikely(tag != JS_TAG_OBJECT)) { - if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { - p = NULL; - p1 = JS_VALUE_GET_OBJ(obj); - goto prototype_lookup; - } else { - switch(tag) { - case JS_TAG_NULL: - JS_FreeValue(ctx, val); - JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop); - return -1; - case JS_TAG_UNDEFINED: - JS_FreeValue(ctx, val); - JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop); - return -1; - default: - /* even on a primitive type we can have setters on the prototype */ - p = NULL; - p1 = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj)); - goto prototype_lookup; - } - } - } else { - p = JS_VALUE_GET_OBJ(this_obj); - p1 = JS_VALUE_GET_OBJ(obj); - if (unlikely(p != p1)) - goto retry2; - } - - /* fast path if obj == this_obj */ - retry: - prs = find_own_property(&pr, p1, prop); - if (prs) { - if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE | - JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) { - /* fast case */ - set_value(ctx, &pr->u.value, val); - return TRUE; - } else if (prs->flags & JS_PROP_LENGTH) { - assert(p->class_id == JS_CLASS_ARRAY); - assert(prop == JS_ATOM_length); - return set_array_length(ctx, p, val, flags); - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { - return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags); - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { - /* JS_PROP_WRITABLE is always true for variable - references, but they are write protected in module name - spaces. */ - if (p->class_id == JS_CLASS_MODULE_NS) - goto read_only_prop; - set_value(ctx, pr->u.var_ref->pvalue, val); - return TRUE; - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { - /* Instantiate property and retry (potentially useless) */ - if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) { - JS_FreeValue(ctx, val); - return -1; - } - goto retry; - } else { - goto read_only_prop; - } - } - - for(;;) { - if (p1->is_exotic) { - if (p1->fast_array) { - if (__JS_AtomIsTaggedInt(prop)) { - uint32_t idx = __JS_AtomToUInt32(prop); - if (idx < p1->u.array.count) { - if (unlikely(p == p1)) - return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val, flags); - else - break; - } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY && - p1->class_id <= JS_CLASS_FLOAT64_ARRAY) { - goto typed_array_oob; - } - } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY && - p1->class_id <= JS_CLASS_FLOAT64_ARRAY) { - ret = JS_AtomIsNumericIndex(ctx, prop); - if (ret != 0) { - if (ret < 0) { - JS_FreeValue(ctx, val); - return -1; - } - typed_array_oob: - if (p == p1) { - /* must convert the argument even if out of bound access */ - if (p1->class_id == JS_CLASS_BIG_INT64_ARRAY || - p1->class_id == JS_CLASS_BIG_UINT64_ARRAY) { - int64_t v; - if (JS_ToBigInt64Free(ctx, &v, val)) - return -1; - } else { - val = JS_ToNumberFree(ctx, val); - JS_FreeValue(ctx, val); - if (JS_IsException(val)) - return -1; - } - } else { - JS_FreeValue(ctx, val); - } - return TRUE; - } - } - } else { - const JSClassExoticMethods *em = ctx->rt->class_array[p1->class_id].exotic; - if (em) { - JSValue obj1; - if (em->set_property) { - /* set_property can free the prototype */ - obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1)); - ret = em->set_property(ctx, obj1, prop, - val, this_obj, flags); - JS_FreeValue(ctx, obj1); - JS_FreeValue(ctx, val); - return ret; - } - if (em->get_own_property) { - /* get_own_property can free the prototype */ - obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1)); - ret = em->get_own_property(ctx, &desc, - obj1, prop); - JS_FreeValue(ctx, obj1); - if (ret < 0) { - JS_FreeValue(ctx, val); - return ret; - } - if (ret) { - if (desc.flags & JS_PROP_GETSET) { - JSObject *setter; - if (JS_IsUndefined(desc.setter)) - setter = NULL; - else - setter = JS_VALUE_GET_OBJ(desc.setter); - ret = call_setter(ctx, setter, this_obj, val, flags); - JS_FreeValue(ctx, desc.getter); - JS_FreeValue(ctx, desc.setter); - return ret; - } else { - JS_FreeValue(ctx, desc.value); - if (!(desc.flags & JS_PROP_WRITABLE)) - goto read_only_prop; - if (likely(p == p1)) { - ret = JS_DefineProperty(ctx, this_obj, prop, val, - JS_UNDEFINED, JS_UNDEFINED, - JS_PROP_HAS_VALUE); - JS_FreeValue(ctx, val); - return ret; - } else { - break; - } - } - } - } - } - } - } - p1 = p1->shape->proto; - prototype_lookup: - if (!p1) - break; - - retry2: - prs = find_own_property(&pr, p1, prop); - if (prs) { - if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { - return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags); - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { - /* Instantiate property and retry (potentially useless) */ - if (JS_AutoInitProperty(ctx, p1, prop, pr, prs)) - return -1; - goto retry2; - } else if (!(prs->flags & JS_PROP_WRITABLE)) { - goto read_only_prop; - } else { - break; - } - } - } - - if (unlikely(flags & JS_PROP_NO_ADD)) { - JS_FreeValue(ctx, val); - JS_ThrowReferenceErrorNotDefined(ctx, prop); - return -1; - } - - if (unlikely(!p)) { - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorOrFalse(ctx, flags, "not an object"); - } - - if (unlikely(!p->extensible)) { - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible"); - } - - if (likely(p == JS_VALUE_GET_OBJ(obj))) { - if (p->is_exotic) { - if (p->class_id == JS_CLASS_ARRAY && p->fast_array && - __JS_AtomIsTaggedInt(prop)) { - uint32_t idx = __JS_AtomToUInt32(prop); - if (idx == p->u.array.count) { - /* fast case */ - return add_fast_array_element(ctx, p, val, flags); - } else { - goto generic_create_prop; - } - } else { - goto generic_create_prop; - } - } else { - pr = add_property(ctx, p, prop, JS_PROP_C_W_E); - if (unlikely(!pr)) { - JS_FreeValue(ctx, val); - return -1; - } - pr->u.value = val; - return TRUE; - } - } else { - /* generic case: modify the property in this_obj if it already exists */ - ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop); - if (ret < 0) { - JS_FreeValue(ctx, val); - return ret; - } - if (ret) { - if (desc.flags & JS_PROP_GETSET) { - JS_FreeValue(ctx, desc.getter); - JS_FreeValue(ctx, desc.setter); - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden"); - } else { - JS_FreeValue(ctx, desc.value); - if (!(desc.flags & JS_PROP_WRITABLE) || - p->class_id == JS_CLASS_MODULE_NS) { - read_only_prop: - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorReadOnly(ctx, flags, prop); - } - } - ret = JS_DefineProperty(ctx, this_obj, prop, val, - JS_UNDEFINED, JS_UNDEFINED, - JS_PROP_HAS_VALUE); - JS_FreeValue(ctx, val); - return ret; - } else { - generic_create_prop: - ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED, - flags | - JS_PROP_HAS_VALUE | - JS_PROP_HAS_ENUMERABLE | - JS_PROP_HAS_WRITABLE | - JS_PROP_HAS_CONFIGURABLE | - JS_PROP_C_W_E); - JS_FreeValue(ctx, val); - return ret; - } - } -} - -/* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */ -static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, - JSValue prop, JSValue val, int flags) -{ - if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT && - JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) { - JSObject *p; - uint32_t idx; - double d; - int32_t v; - - /* fast path for array access */ - p = JS_VALUE_GET_OBJ(this_obj); - idx = JS_VALUE_GET_INT(prop); - switch(p->class_id) { - case JS_CLASS_ARRAY: - if (unlikely(idx >= (uint32_t)p->u.array.count)) { - JSObject *p1; - JSShape *sh1; - - /* fast path to add an element to the array */ - if (idx != (uint32_t)p->u.array.count || - !p->fast_array || !p->extensible) - goto slow_path; - /* check if prototype chain has a numeric property */ - p1 = p->shape->proto; - while (p1 != NULL) { - sh1 = p1->shape; - if (p1->class_id == JS_CLASS_ARRAY) { - if (unlikely(!p1->fast_array)) - goto slow_path; - } else if (p1->class_id == JS_CLASS_OBJECT) { - if (unlikely(sh1->has_small_array_index)) - goto slow_path; - } else { - goto slow_path; - } - p1 = sh1->proto; - } - /* add element */ - return add_fast_array_element(ctx, p, val, flags); - } - set_value(ctx, &p->u.array.u.values[idx], val); - break; - case JS_CLASS_ARGUMENTS: - if (unlikely(idx >= (uint32_t)p->u.array.count)) - goto slow_path; - set_value(ctx, &p->u.array.u.values[idx], val); - break; - case JS_CLASS_UINT8C_ARRAY: - if (JS_ToUint8ClampFree(ctx, &v, val)) - return -1; - /* Note: the conversion can detach the typed array, so the - array bound check must be done after */ - if (unlikely(idx >= (uint32_t)p->u.array.count)) - goto ta_out_of_bound; - p->u.array.u.uint8_ptr[idx] = v; - break; - case JS_CLASS_INT8_ARRAY: - case JS_CLASS_UINT8_ARRAY: - if (JS_ToInt32Free(ctx, &v, val)) - return -1; - if (unlikely(idx >= (uint32_t)p->u.array.count)) - goto ta_out_of_bound; - p->u.array.u.uint8_ptr[idx] = v; - break; - case JS_CLASS_INT16_ARRAY: - case JS_CLASS_UINT16_ARRAY: - if (JS_ToInt32Free(ctx, &v, val)) - return -1; - if (unlikely(idx >= (uint32_t)p->u.array.count)) - goto ta_out_of_bound; - p->u.array.u.uint16_ptr[idx] = v; - break; - case JS_CLASS_INT32_ARRAY: - case JS_CLASS_UINT32_ARRAY: - if (JS_ToInt32Free(ctx, &v, val)) - return -1; - if (unlikely(idx >= (uint32_t)p->u.array.count)) - goto ta_out_of_bound; - p->u.array.u.uint32_ptr[idx] = v; - break; - case JS_CLASS_BIG_INT64_ARRAY: - case JS_CLASS_BIG_UINT64_ARRAY: - /* XXX: need specific conversion function */ - { - int64_t v; - if (JS_ToBigInt64Free(ctx, &v, val)) - return -1; - if (unlikely(idx >= (uint32_t)p->u.array.count)) - goto ta_out_of_bound; - p->u.array.u.uint64_ptr[idx] = v; - } - break; - case JS_CLASS_FLOAT16_ARRAY: - if (JS_ToFloat64Free(ctx, &d, val)) - return -1; - if (unlikely(idx >= (uint32_t)p->u.array.count)) - goto ta_out_of_bound; - p->u.array.u.fp16_ptr[idx] = tofp16(d); - break; - case JS_CLASS_FLOAT32_ARRAY: - if (JS_ToFloat64Free(ctx, &d, val)) - return -1; - if (unlikely(idx >= (uint32_t)p->u.array.count)) - goto ta_out_of_bound; - p->u.array.u.float_ptr[idx] = d; - break; - case JS_CLASS_FLOAT64_ARRAY: - if (JS_ToFloat64Free(ctx, &d, val)) - return -1; - if (unlikely(idx >= (uint32_t)p->u.array.count)) { - ta_out_of_bound: - return TRUE; - } - p->u.array.u.double_ptr[idx] = d; - break; - default: - goto slow_path; - } - return TRUE; - } else { - JSAtom atom; - int ret; - slow_path: - atom = JS_ValueToAtom(ctx, prop); - JS_FreeValue(ctx, prop); - if (unlikely(atom == JS_ATOM_NULL)) { - JS_FreeValue(ctx, val); - return -1; - } - ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, flags); - JS_FreeAtom(ctx, atom); - return ret; - } -} - -int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj, - uint32_t idx, JSValue val) -{ - return JS_SetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx), val, - JS_PROP_THROW); -} - -int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj, - int64_t idx, JSValue val) -{ - JSAtom prop; - int res; - - if ((uint64_t)idx <= INT32_MAX) { - /* fast path for fast arrays */ - return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val, - JS_PROP_THROW); - } - prop = JS_NewAtomInt64(ctx, idx); - if (prop == JS_ATOM_NULL) { - JS_FreeValue(ctx, val); - return -1; - } - res = JS_SetProperty(ctx, this_obj, prop, val); - JS_FreeAtom(ctx, prop); - return res; -} - -int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj, - const char *prop, JSValue val) -{ - JSAtom atom; - int ret; - atom = JS_NewAtom(ctx, prop); - if (atom == JS_ATOM_NULL) { - JS_FreeValue(ctx, val); - return -1; - } - ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, JS_PROP_THROW); - JS_FreeAtom(ctx, atom); - return ret; -} - -/* compute the property flags. For each flag: (JS_PROP_HAS_x forces - it, otherwise def_flags is used) - Note: makes assumption about the bit pattern of the flags -*/ -static int get_prop_flags(int flags, int def_flags) -{ - int mask; - mask = (flags >> JS_PROP_HAS_SHIFT) & JS_PROP_C_W_E; - return (flags & mask) | (def_flags & ~mask); -} - -static int JS_CreateProperty(JSContext *ctx, JSObject *p, - JSAtom prop, JSValueConst val, - JSValueConst getter, JSValueConst setter, - int flags) -{ - JSProperty *pr; - int ret, prop_flags; - - /* add a new property or modify an existing exotic one */ - if (p->is_exotic) { - if (p->class_id == JS_CLASS_ARRAY) { - uint32_t idx, len; - - if (p->fast_array) { - if (__JS_AtomIsTaggedInt(prop)) { - idx = __JS_AtomToUInt32(prop); - if (idx == p->u.array.count) { - if (!p->extensible) - goto not_extensible; - if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) - goto convert_to_array; - prop_flags = get_prop_flags(flags, 0); - if (prop_flags != JS_PROP_C_W_E) - goto convert_to_array; - return add_fast_array_element(ctx, p, - JS_DupValue(ctx, val), flags); - } else { - goto convert_to_array; - } - } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) { - /* convert the fast array to normal array */ - convert_to_array: - if (convert_fast_array_to_array(ctx, p)) - return -1; - goto generic_array; - } - } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) { - JSProperty *plen; - JSShapeProperty *pslen; - generic_array: - /* update the length field */ - plen = &p->prop[0]; - JS_ToUint32(ctx, &len, plen->u.value); - if ((idx + 1) > len) { - pslen = get_shape_prop(p->shape); - if (unlikely(!(pslen->flags & JS_PROP_WRITABLE))) - return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length); - /* XXX: should update the length after defining - the property */ - len = idx + 1; - set_value(ctx, &plen->u.value, JS_NewUint32(ctx, len)); - } - } - } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) { - ret = JS_AtomIsNumericIndex(ctx, prop); - if (ret != 0) { - if (ret < 0) - return -1; - return JS_ThrowTypeErrorOrFalse(ctx, flags, "cannot create numeric index in typed array"); - } - } else if (!(flags & JS_PROP_NO_EXOTIC)) { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em) { - if (em->define_own_property) { - return em->define_own_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), - prop, val, getter, setter, flags); - } - ret = JS_IsExtensible(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); - if (ret < 0) - return -1; - if (!ret) - goto not_extensible; - } - } - } - - if (!p->extensible) { - not_extensible: - return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible"); - } - - if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { - prop_flags = (flags & (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) | - JS_PROP_GETSET; - } else { - prop_flags = flags & JS_PROP_C_W_E; - } - pr = add_property(ctx, p, prop, prop_flags); - if (unlikely(!pr)) - return -1; - if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { - pr->u.getset.getter = NULL; - if ((flags & JS_PROP_HAS_GET) && JS_IsFunction(ctx, getter)) { - pr->u.getset.getter = - JS_VALUE_GET_OBJ(JS_DupValue(ctx, getter)); - } - pr->u.getset.setter = NULL; - if ((flags & JS_PROP_HAS_SET) && JS_IsFunction(ctx, setter)) { - pr->u.getset.setter = - JS_VALUE_GET_OBJ(JS_DupValue(ctx, setter)); - } - } else { - if (flags & JS_PROP_HAS_VALUE) { - pr->u.value = JS_DupValue(ctx, val); - } else { - pr->u.value = JS_UNDEFINED; - } - } - return TRUE; -} - -/* return FALSE if not OK */ -static BOOL check_define_prop_flags(int prop_flags, int flags) -{ - BOOL has_accessor, is_getset; - - if (!(prop_flags & JS_PROP_CONFIGURABLE)) { - if ((flags & (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) == - (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) { - return FALSE; - } - if ((flags & JS_PROP_HAS_ENUMERABLE) && - (flags & JS_PROP_ENUMERABLE) != (prop_flags & JS_PROP_ENUMERABLE)) - return FALSE; - if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | - JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { - has_accessor = ((flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) != 0); - is_getset = ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET); - if (has_accessor != is_getset) - return FALSE; - if (!is_getset && !(prop_flags & JS_PROP_WRITABLE)) { - /* not writable: cannot set the writable bit */ - if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == - (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) - return FALSE; - } - } - } - return TRUE; -} - -/* ensure that the shape can be safely modified */ -static int js_shape_prepare_update(JSContext *ctx, JSObject *p, - JSShapeProperty **pprs) -{ - JSShape *sh; - uint32_t idx = 0; /* prevent warning */ - - sh = p->shape; - if (sh->is_hashed) { - if (sh->header.ref_count != 1) { - if (pprs) - idx = *pprs - get_shape_prop(sh); - /* clone the shape (the resulting one is no longer hashed) */ - sh = js_clone_shape(ctx, sh); - if (!sh) - return -1; - js_free_shape(ctx->rt, p->shape); - p->shape = sh; - if (pprs) - *pprs = get_shape_prop(sh) + idx; - } else { - js_shape_hash_unlink(ctx->rt, sh); - sh->is_hashed = FALSE; - } - } - return 0; -} - -static int js_update_property_flags(JSContext *ctx, JSObject *p, - JSShapeProperty **pprs, int flags) -{ - if (flags != (*pprs)->flags) { - if (js_shape_prepare_update(ctx, p, pprs)) - return -1; - (*pprs)->flags = flags; - } - return 0; -} - -/* allowed flags: - JS_PROP_CONFIGURABLE, JS_PROP_WRITABLE, JS_PROP_ENUMERABLE - JS_PROP_HAS_GET, JS_PROP_HAS_SET, JS_PROP_HAS_VALUE, - JS_PROP_HAS_CONFIGURABLE, JS_PROP_HAS_WRITABLE, JS_PROP_HAS_ENUMERABLE, - JS_PROP_THROW, JS_PROP_NO_EXOTIC. - If JS_PROP_THROW is set, return an exception instead of FALSE. - if JS_PROP_NO_EXOTIC is set, do not call the exotic - define_own_property callback. - return -1 (exception), FALSE or TRUE. -*/ -int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValueConst val, - JSValueConst getter, JSValueConst setter, int flags) -{ - JSObject *p; - JSShapeProperty *prs; - JSProperty *pr; - int mask, res; - - if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT) { - JS_ThrowTypeErrorNotAnObject(ctx); - return -1; - } - p = JS_VALUE_GET_OBJ(this_obj); - - redo_prop_update: - prs = find_own_property(&pr, p, prop); - if (prs) { - /* the range of the Array length property is always tested before */ - if ((prs->flags & JS_PROP_LENGTH) && (flags & JS_PROP_HAS_VALUE)) { - uint32_t array_length; - if (JS_ToArrayLengthFree(ctx, &array_length, - JS_DupValue(ctx, val), FALSE)) { - return -1; - } - /* this code relies on the fact that Uint32 are never allocated */ - val = (JSValueConst)JS_NewUint32(ctx, array_length); - /* prs may have been modified */ - prs = find_own_property(&pr, p, prop); - assert(prs != NULL); - } - /* property already exists */ - if (!check_define_prop_flags(prs->flags, flags)) { - not_configurable: - return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable"); - } - - if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { - /* Instantiate property and retry */ - if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) - return -1; - goto redo_prop_update; - } - - if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | - JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { - if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { - JSObject *new_getter, *new_setter; - - if (JS_IsFunction(ctx, getter)) { - new_getter = JS_VALUE_GET_OBJ(getter); - } else { - new_getter = NULL; - } - if (JS_IsFunction(ctx, setter)) { - new_setter = JS_VALUE_GET_OBJ(setter); - } else { - new_setter = NULL; - } - - if ((prs->flags & JS_PROP_TMASK) != JS_PROP_GETSET) { - if (js_shape_prepare_update(ctx, p, &prs)) - return -1; - /* convert to getset */ - if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { - free_var_ref(ctx->rt, pr->u.var_ref); - } else { - JS_FreeValue(ctx, pr->u.value); - } - prs->flags = (prs->flags & - (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) | - JS_PROP_GETSET; - pr->u.getset.getter = NULL; - pr->u.getset.setter = NULL; - } else { - if (!(prs->flags & JS_PROP_CONFIGURABLE)) { - if ((flags & JS_PROP_HAS_GET) && - new_getter != pr->u.getset.getter) { - goto not_configurable; - } - if ((flags & JS_PROP_HAS_SET) && - new_setter != pr->u.getset.setter) { - goto not_configurable; - } - } - } - if (flags & JS_PROP_HAS_GET) { - if (pr->u.getset.getter) - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter)); - if (new_getter) - JS_DupValue(ctx, getter); - pr->u.getset.getter = new_getter; - } - if (flags & JS_PROP_HAS_SET) { - if (pr->u.getset.setter) - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter)); - if (new_setter) - JS_DupValue(ctx, setter); - pr->u.getset.setter = new_setter; - } - } else { - if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { - /* convert to data descriptor */ - if (js_shape_prepare_update(ctx, p, &prs)) - return -1; - if (pr->u.getset.getter) - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter)); - if (pr->u.getset.setter) - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter)); - prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE); - pr->u.value = JS_UNDEFINED; - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { - /* Note: JS_PROP_VARREF is always writable */ - } else { - if ((prs->flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 && - (flags & JS_PROP_HAS_VALUE)) { - if (!js_same_value(ctx, val, pr->u.value)) { - goto not_configurable; - } else { - return TRUE; - } - } - } - if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { - if (flags & JS_PROP_HAS_VALUE) { - if (p->class_id == JS_CLASS_MODULE_NS) { - /* JS_PROP_WRITABLE is always true for variable - references, but they are write protected in module name - spaces. */ - if (!js_same_value(ctx, val, *pr->u.var_ref->pvalue)) - goto not_configurable; - } else { - /* update the reference */ - set_value(ctx, pr->u.var_ref->pvalue, - JS_DupValue(ctx, val)); - } - } - /* if writable is set to false, no longer a - reference (for mapped arguments) */ - if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) { - JSValue val1; - if (p->class_id == JS_CLASS_MODULE_NS) { - return JS_ThrowTypeErrorOrFalse(ctx, flags, "module namespace properties have writable = false"); - } - if (js_shape_prepare_update(ctx, p, &prs)) - return -1; - val1 = JS_DupValue(ctx, *pr->u.var_ref->pvalue); - free_var_ref(ctx->rt, pr->u.var_ref); - pr->u.value = val1; - prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE); - } - } else if (prs->flags & JS_PROP_LENGTH) { - if (flags & JS_PROP_HAS_VALUE) { - /* Note: no JS code is executable because - 'val' is guaranted to be a Uint32 */ - res = set_array_length(ctx, p, JS_DupValue(ctx, val), - flags); - } else { - res = TRUE; - } - /* still need to reset the writable flag if - needed. The JS_PROP_LENGTH is kept because the - Uint32 test is still done if the length - property is read-only. */ - if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == - JS_PROP_HAS_WRITABLE) { - prs = get_shape_prop(p->shape); - if (js_update_property_flags(ctx, p, &prs, - prs->flags & ~JS_PROP_WRITABLE)) - return -1; - } - return res; - } else { - if (flags & JS_PROP_HAS_VALUE) { - JS_FreeValue(ctx, pr->u.value); - pr->u.value = JS_DupValue(ctx, val); - } - if (flags & JS_PROP_HAS_WRITABLE) { - if (js_update_property_flags(ctx, p, &prs, - (prs->flags & ~JS_PROP_WRITABLE) | - (flags & JS_PROP_WRITABLE))) - return -1; - } - } - } - } - mask = 0; - if (flags & JS_PROP_HAS_CONFIGURABLE) - mask |= JS_PROP_CONFIGURABLE; - if (flags & JS_PROP_HAS_ENUMERABLE) - mask |= JS_PROP_ENUMERABLE; - if (js_update_property_flags(ctx, p, &prs, - (prs->flags & ~mask) | (flags & mask))) - return -1; - return TRUE; - } - - /* handle modification of fast array elements */ - if (p->fast_array) { - uint32_t idx; - uint32_t prop_flags; - if (p->class_id == JS_CLASS_ARRAY) { - if (__JS_AtomIsTaggedInt(prop)) { - idx = __JS_AtomToUInt32(prop); - if (idx < p->u.array.count) { - prop_flags = get_prop_flags(flags, JS_PROP_C_W_E); - if (prop_flags != JS_PROP_C_W_E) - goto convert_to_slow_array; - if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { - convert_to_slow_array: - if (convert_fast_array_to_array(ctx, p)) - return -1; - else - goto redo_prop_update; - } - if (flags & JS_PROP_HAS_VALUE) { - set_value(ctx, &p->u.array.u.values[idx], JS_DupValue(ctx, val)); - } - return TRUE; - } - } - } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) { - JSValue num; - int ret; - - if (!__JS_AtomIsTaggedInt(prop)) { - /* slow path with to handle all numeric indexes */ - num = JS_AtomIsNumericIndex1(ctx, prop); - if (JS_IsUndefined(num)) - goto typed_array_done; - if (JS_IsException(num)) - return -1; - ret = JS_NumberIsInteger(ctx, num); - if (ret < 0) { - JS_FreeValue(ctx, num); - return -1; - } - if (!ret) { - JS_FreeValue(ctx, num); - return JS_ThrowTypeErrorOrFalse(ctx, flags, "non integer index in typed array"); - } - ret = JS_NumberIsNegativeOrMinusZero(ctx, num); - JS_FreeValue(ctx, num); - if (ret) { - return JS_ThrowTypeErrorOrFalse(ctx, flags, "negative index in typed array"); - } - if (!__JS_AtomIsTaggedInt(prop)) - goto typed_array_oob; - } - idx = __JS_AtomToUInt32(prop); - /* if the typed array is detached, p->u.array.count = 0 */ - if (idx >= p->u.array.count) { - typed_array_oob: - return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound index in typed array"); - } - prop_flags = get_prop_flags(flags, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET) || - prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE)) { - return JS_ThrowTypeErrorOrFalse(ctx, flags, "invalid descriptor flags"); - } - if (flags & JS_PROP_HAS_VALUE) { - return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), JS_DupValue(ctx, val), flags); - } - return TRUE; - typed_array_done: ; - } - } - - return JS_CreateProperty(ctx, p, prop, val, getter, setter, flags); -} - -static int JS_DefineAutoInitProperty(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSAutoInitIDEnum id, - void *opaque, int flags) -{ - JSObject *p; - JSProperty *pr; - - if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT) - return FALSE; - - p = JS_VALUE_GET_OBJ(this_obj); - - if (find_own_property(&pr, p, prop)) { - /* property already exists */ - abort(); - return FALSE; - } - - /* Specialized CreateProperty */ - pr = add_property(ctx, p, prop, (flags & JS_PROP_C_W_E) | JS_PROP_AUTOINIT); - if (unlikely(!pr)) - return -1; - pr->u.init.realm_and_id = (uintptr_t)JS_DupContext(ctx); - assert((pr->u.init.realm_and_id & 3) == 0); - assert(id <= 3); - pr->u.init.realm_and_id |= id; - pr->u.init.opaque = opaque; - return TRUE; -} - -/* shortcut to add or redefine a new property value */ -int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValue val, int flags) -{ - int ret; - ret = JS_DefineProperty(ctx, this_obj, prop, val, JS_UNDEFINED, JS_UNDEFINED, - flags | JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE); - JS_FreeValue(ctx, val); - return ret; -} - -int JS_DefinePropertyValueValue(JSContext *ctx, JSValueConst this_obj, - JSValue prop, JSValue val, int flags) -{ - JSAtom atom; - int ret; - atom = JS_ValueToAtom(ctx, prop); - JS_FreeValue(ctx, prop); - if (unlikely(atom == JS_ATOM_NULL)) { - JS_FreeValue(ctx, val); - return -1; - } - ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags); - JS_FreeAtom(ctx, atom); - return ret; -} - -int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj, - uint32_t idx, JSValue val, int flags) -{ - return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewUint32(ctx, idx), - val, flags); -} - -int JS_DefinePropertyValueInt64(JSContext *ctx, JSValueConst this_obj, - int64_t idx, JSValue val, int flags) -{ - return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx), - val, flags); -} - -int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj, - const char *prop, JSValue val, int flags) -{ - JSAtom atom; - int ret; - atom = JS_NewAtom(ctx, prop); - if (atom == JS_ATOM_NULL) { - JS_FreeValue(ctx, val); - return -1; - } - ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags); - JS_FreeAtom(ctx, atom); - return ret; -} - -/* shortcut to add getter & setter */ -int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValue getter, JSValue setter, - int flags) -{ - int ret; - ret = JS_DefineProperty(ctx, this_obj, prop, JS_UNDEFINED, getter, setter, - flags | JS_PROP_HAS_GET | JS_PROP_HAS_SET | - JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE); - JS_FreeValue(ctx, getter); - JS_FreeValue(ctx, setter); - return ret; -} - -static int JS_CreateDataPropertyUint32(JSContext *ctx, JSValueConst this_obj, - int64_t idx, JSValue val, int flags) -{ - return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx), - val, flags | JS_PROP_CONFIGURABLE | - JS_PROP_ENUMERABLE | JS_PROP_WRITABLE); -} - - -/* return TRUE if 'obj' has a non empty 'name' string */ -static BOOL js_object_has_name(JSContext *ctx, JSValueConst obj) -{ - JSProperty *pr; - JSShapeProperty *prs; - JSValueConst val; - JSString *p; - - prs = find_own_property(&pr, JS_VALUE_GET_OBJ(obj), JS_ATOM_name); - if (!prs) - return FALSE; - if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL) - return TRUE; - val = pr->u.value; - if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING) - return TRUE; - p = JS_VALUE_GET_STRING(val); - return (p->len != 0); -} - -static int JS_DefineObjectName(JSContext *ctx, JSValueConst obj, - JSAtom name, int flags) -{ - if (name != JS_ATOM_NULL - && JS_IsObject(obj) - && !js_object_has_name(ctx, obj) - && JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, JS_AtomToString(ctx, name), flags) < 0) { - return -1; - } - return 0; -} - -static int JS_DefineObjectNameComputed(JSContext *ctx, JSValueConst obj, - JSValueConst str, int flags) -{ - if (JS_IsObject(obj) && - !js_object_has_name(ctx, obj)) { - JSAtom prop; - JSValue name_str; - prop = JS_ValueToAtom(ctx, str); - if (prop == JS_ATOM_NULL) - return -1; - name_str = js_get_function_name(ctx, prop); - JS_FreeAtom(ctx, prop); - if (JS_IsException(name_str)) - return -1; - if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, name_str, flags) < 0) - return -1; - } - return 0; -} - -#define DEFINE_GLOBAL_LEX_VAR (1 << 7) -#define DEFINE_GLOBAL_FUNC_VAR (1 << 6) - -static JSValue JS_ThrowSyntaxErrorVarRedeclaration(JSContext *ctx, JSAtom prop) -{ - return JS_ThrowSyntaxErrorAtom(ctx, "redeclaration of '%s'", prop); -} - -/* flags is 0, DEFINE_GLOBAL_LEX_VAR or DEFINE_GLOBAL_FUNC_VAR */ -/* XXX: could support exotic global object. */ -static int JS_CheckDefineGlobalVar(JSContext *ctx, JSAtom prop, int flags) -{ - JSObject *p; - JSShapeProperty *prs; - - p = JS_VALUE_GET_OBJ(ctx->global_obj); - prs = find_own_property1(p, prop); - /* XXX: should handle JS_PROP_AUTOINIT */ - if (flags & DEFINE_GLOBAL_LEX_VAR) { - if (prs && !(prs->flags & JS_PROP_CONFIGURABLE)) - goto fail_redeclaration; - } else { - if (!prs && !p->extensible) - goto define_error; - if (flags & DEFINE_GLOBAL_FUNC_VAR) { - if (prs) { - if (!(prs->flags & JS_PROP_CONFIGURABLE) && - ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET || - ((prs->flags & (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)) != - (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)))) { - define_error: - JS_ThrowTypeErrorAtom(ctx, "cannot define variable '%s'", - prop); - return -1; - } - } - } - } - /* check if there already is a lexical declaration */ - p = JS_VALUE_GET_OBJ(ctx->global_var_obj); - prs = find_own_property1(p, prop); - if (prs) { - fail_redeclaration: - JS_ThrowSyntaxErrorVarRedeclaration(ctx, prop); - return -1; - } - return 0; -} - -/* def_flags is (0, DEFINE_GLOBAL_LEX_VAR) | - JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE */ -/* XXX: could support exotic global object. */ -static int JS_DefineGlobalVar(JSContext *ctx, JSAtom prop, int def_flags) -{ - JSObject *p; - JSShapeProperty *prs; - JSProperty *pr; - JSValue val; - int flags; - - if (def_flags & DEFINE_GLOBAL_LEX_VAR) { - p = JS_VALUE_GET_OBJ(ctx->global_var_obj); - flags = JS_PROP_ENUMERABLE | (def_flags & JS_PROP_WRITABLE) | - JS_PROP_CONFIGURABLE; - val = JS_UNINITIALIZED; - } else { - p = JS_VALUE_GET_OBJ(ctx->global_obj); - flags = JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | - (def_flags & JS_PROP_CONFIGURABLE); - val = JS_UNDEFINED; - } - prs = find_own_property1(p, prop); - if (prs) - return 0; - if (!p->extensible) - return 0; - pr = add_property(ctx, p, prop, flags); - if (unlikely(!pr)) - return -1; - pr->u.value = val; - return 0; -} - -/* 'def_flags' is 0 or JS_PROP_CONFIGURABLE. */ -/* XXX: could support exotic global object. */ -static int JS_DefineGlobalFunction(JSContext *ctx, JSAtom prop, - JSValueConst func, int def_flags) -{ - - JSObject *p; - JSShapeProperty *prs; - int flags; - - p = JS_VALUE_GET_OBJ(ctx->global_obj); - prs = find_own_property1(p, prop); - flags = JS_PROP_HAS_VALUE | JS_PROP_THROW; - if (!prs || (prs->flags & JS_PROP_CONFIGURABLE)) { - flags |= JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | def_flags | - JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE; - } - if (JS_DefineProperty(ctx, ctx->global_obj, prop, func, - JS_UNDEFINED, JS_UNDEFINED, flags) < 0) - return -1; - return 0; -} - -static JSValue JS_GetGlobalVar(JSContext *ctx, JSAtom prop, - BOOL throw_ref_error) -{ - JSObject *p; - JSShapeProperty *prs; - JSProperty *pr; - - /* no exotic behavior is possible in global_var_obj */ - p = JS_VALUE_GET_OBJ(ctx->global_var_obj); - prs = find_own_property(&pr, p, prop); - if (prs) { - /* XXX: should handle JS_PROP_TMASK properties */ - if (unlikely(JS_IsUninitialized(pr->u.value))) - return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); - return JS_DupValue(ctx, pr->u.value); - } - return JS_GetPropertyInternal(ctx, ctx->global_obj, prop, - ctx->global_obj, throw_ref_error); -} - -/* construct a reference to a global variable */ -static int JS_GetGlobalVarRef(JSContext *ctx, JSAtom prop, JSValue *sp) -{ - JSObject *p; - JSShapeProperty *prs; - JSProperty *pr; - - /* no exotic behavior is possible in global_var_obj */ - p = JS_VALUE_GET_OBJ(ctx->global_var_obj); - prs = find_own_property(&pr, p, prop); - if (prs) { - /* XXX: should handle JS_PROP_AUTOINIT properties? */ - /* XXX: conformance: do these tests in - OP_put_var_ref/OP_get_var_ref ? */ - if (unlikely(JS_IsUninitialized(pr->u.value))) { - JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); - return -1; - } - if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) { - return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop); - } - sp[0] = JS_DupValue(ctx, ctx->global_var_obj); - } else { - int ret; - ret = JS_HasProperty(ctx, ctx->global_obj, prop); - if (ret < 0) - return -1; - if (ret) { - sp[0] = JS_DupValue(ctx, ctx->global_obj); - } else { - sp[0] = JS_UNDEFINED; - } - } - sp[1] = JS_AtomToValue(ctx, prop); - return 0; -} - -/* use for strict variable access: test if the variable exists */ -static int JS_CheckGlobalVar(JSContext *ctx, JSAtom prop) -{ - JSObject *p; - JSShapeProperty *prs; - int ret; - - /* no exotic behavior is possible in global_var_obj */ - p = JS_VALUE_GET_OBJ(ctx->global_var_obj); - prs = find_own_property1(p, prop); - if (prs) { - ret = TRUE; - } else { - ret = JS_HasProperty(ctx, ctx->global_obj, prop); - if (ret < 0) - return -1; - } - return ret; -} - -/* flag = 0: normal variable write - flag = 1: initialize lexical variable - flag = 2: normal variable write, strict check was done before -*/ -static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val, - int flag) -{ - JSObject *p; - JSShapeProperty *prs; - JSProperty *pr; - int flags; - - /* no exotic behavior is possible in global_var_obj */ - p = JS_VALUE_GET_OBJ(ctx->global_var_obj); - prs = find_own_property(&pr, p, prop); - if (prs) { - /* XXX: should handle JS_PROP_AUTOINIT properties? */ - if (flag != 1) { - if (unlikely(JS_IsUninitialized(pr->u.value))) { - JS_FreeValue(ctx, val); - JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); - return -1; - } - if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) { - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop); - } - } - set_value(ctx, &pr->u.value, val); - return 0; - } - /* XXX: add a fast path where the property exists and the object - is not exotic. Otherwise do as in OP_put_ref_value and remove - JS_PROP_NO_ADD which is no longer necessary */ - flags = JS_PROP_THROW_STRICT; - if (is_strict_mode(ctx)) - flags |= JS_PROP_NO_ADD; - return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, ctx->global_obj, flags); -} - -/* return -1, FALSE or TRUE */ -static int JS_DeleteGlobalVar(JSContext *ctx, JSAtom prop) -{ - JSObject *p; - JSShapeProperty *prs; - JSProperty *pr; - int ret; - - /* 9.1.1.4.7 DeleteBinding ( N ) */ - p = JS_VALUE_GET_OBJ(ctx->global_var_obj); - prs = find_own_property(&pr, p, prop); - if (prs) - return FALSE; /* lexical variables cannot be deleted */ - ret = JS_HasProperty(ctx, ctx->global_obj, prop); - if (ret < 0) - return -1; - if (ret) { - return JS_DeleteProperty(ctx, ctx->global_obj, prop, 0); - } else { - return TRUE; - } -} - -/* return -1, FALSE or TRUE. return FALSE if not configurable or - invalid object. return -1 in case of exception. - flags can be 0, JS_PROP_THROW or JS_PROP_THROW_STRICT */ -int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags) -{ - JSValue obj1; - JSObject *p; - int res; - - obj1 = JS_ToObject(ctx, obj); - if (JS_IsException(obj1)) - return -1; - p = JS_VALUE_GET_OBJ(obj1); - res = delete_property(ctx, p, prop); - JS_FreeValue(ctx, obj1); - if (res != FALSE) - return res; - if ((flags & JS_PROP_THROW) || - ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) { - JS_ThrowTypeError(ctx, "could not delete property"); - return -1; - } - return FALSE; -} - -int JS_DeletePropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, int flags) -{ - JSAtom prop; - int res; - - if ((uint64_t)idx <= JS_ATOM_MAX_INT) { - /* fast path for fast arrays */ - return JS_DeleteProperty(ctx, obj, __JS_AtomFromUInt32(idx), flags); - } - prop = JS_NewAtomInt64(ctx, idx); - if (prop == JS_ATOM_NULL) - return -1; - res = JS_DeleteProperty(ctx, obj, prop, flags); - JS_FreeAtom(ctx, prop); - return res; -} - -BOOL JS_IsFunction(JSContext *ctx, JSValueConst val) -{ - JSObject *p; - if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) - return FALSE; - p = JS_VALUE_GET_OBJ(val); - switch(p->class_id) { - case JS_CLASS_BYTECODE_FUNCTION: - return TRUE; - case JS_CLASS_PROXY: - return p->u.proxy_data->is_func; - default: - return (ctx->rt->class_array[p->class_id].call != NULL); - } -} - -BOOL JS_IsCFunction(JSContext *ctx, JSValueConst val, JSCFunction *func, int magic) -{ - JSObject *p; - if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) - return FALSE; - p = JS_VALUE_GET_OBJ(val); - if (p->class_id == JS_CLASS_C_FUNCTION) - return (p->u.cfunc.c_function.generic == func && p->u.cfunc.magic == magic); - else - return FALSE; -} - -BOOL JS_IsConstructor(JSContext *ctx, JSValueConst val) -{ - JSObject *p; - if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) - return FALSE; - p = JS_VALUE_GET_OBJ(val); - return p->is_constructor; -} - -BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, BOOL val) -{ - JSObject *p; - if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT) - return FALSE; - p = JS_VALUE_GET_OBJ(func_obj); - p->is_constructor = val; - return TRUE; -} - -BOOL JS_IsError(JSContext *ctx, JSValueConst val) -{ - JSObject *p; - if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) - return FALSE; - p = JS_VALUE_GET_OBJ(val); - return (p->class_id == JS_CLASS_ERROR); -} - -/* must be called after JS_Throw() */ -void JS_SetUncatchableException(JSContext *ctx, BOOL flag) -{ - ctx->rt->current_exception_is_uncatchable = flag; -} - -void JS_SetOpaque(JSValue obj, void *opaque) -{ - JSObject *p; - if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { - p = JS_VALUE_GET_OBJ(obj); - p->u.opaque = opaque; - } -} - -/* return NULL if not an object of class class_id */ -void *JS_GetOpaque(JSValueConst obj, JSClassID class_id) -{ - JSObject *p; - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - return NULL; - p = JS_VALUE_GET_OBJ(obj); - if (p->class_id != class_id) - return NULL; - return p->u.opaque; -} - -void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id) -{ - void *p = JS_GetOpaque(obj, class_id); - if (unlikely(!p)) { - JS_ThrowTypeErrorInvalidClass(ctx, class_id); - } - return p; -} - -void *JS_GetAnyOpaque(JSValueConst obj, JSClassID *class_id) -{ - JSObject *p; - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) { - *class_id = 0; - return NULL; - } - p = JS_VALUE_GET_OBJ(obj); - *class_id = p->class_id; - return p->u.opaque; -} - -static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint) -{ - int i; - BOOL force_ordinary; - - JSAtom method_name; - JSValue method, ret; - if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) - return val; - force_ordinary = hint & HINT_FORCE_ORDINARY; - hint &= ~HINT_FORCE_ORDINARY; - if (!force_ordinary) { - method = JS_GetProperty(ctx, val, JS_ATOM_Symbol_toPrimitive); - if (JS_IsException(method)) - goto exception; - /* ECMA says *If exoticToPrim is not undefined* but tests in - test262 use null as a non callable converter */ - if (!JS_IsUndefined(method) && !JS_IsNull(method)) { - JSAtom atom; - JSValue arg; - switch(hint) { - case HINT_STRING: - atom = JS_ATOM_string; - break; - case HINT_NUMBER: - atom = JS_ATOM_number; - break; - default: - case HINT_NONE: - atom = JS_ATOM_default; - break; - } - arg = JS_AtomToString(ctx, atom); - ret = JS_CallFree(ctx, method, val, 1, (JSValueConst *)&arg); - JS_FreeValue(ctx, arg); - if (JS_IsException(ret)) - goto exception; - JS_FreeValue(ctx, val); - if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) - return ret; - JS_FreeValue(ctx, ret); - return JS_ThrowTypeError(ctx, "toPrimitive"); - } - } - if (hint != HINT_STRING) - hint = HINT_NUMBER; - for(i = 0; i < 2; i++) { - if ((i ^ hint) == 0) { - method_name = JS_ATOM_toString; - } else { - method_name = JS_ATOM_valueOf; - } - method = JS_GetProperty(ctx, val, method_name); - if (JS_IsException(method)) - goto exception; - if (JS_IsFunction(ctx, method)) { - ret = JS_CallFree(ctx, method, val, 0, NULL); - if (JS_IsException(ret)) - goto exception; - if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) { - JS_FreeValue(ctx, val); - return ret; - } - JS_FreeValue(ctx, ret); - } else { - JS_FreeValue(ctx, method); - } - } - JS_ThrowTypeError(ctx, "toPrimitive"); -exception: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static JSValue JS_ToPrimitive(JSContext *ctx, JSValueConst val, int hint) -{ - return JS_ToPrimitiveFree(ctx, JS_DupValue(ctx, val), hint); -} - -void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj) -{ - JSObject *p; - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - return; - p = JS_VALUE_GET_OBJ(obj); - p->is_HTMLDDA = TRUE; -} - -static inline BOOL JS_IsHTMLDDA(JSContext *ctx, JSValueConst obj) -{ - JSObject *p; - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - return FALSE; - p = JS_VALUE_GET_OBJ(obj); - return p->is_HTMLDDA; -} - -static int JS_ToBoolFree(JSContext *ctx, JSValue val) -{ - uint32_t tag = JS_VALUE_GET_TAG(val); - switch(tag) { - case JS_TAG_INT: - return JS_VALUE_GET_INT(val) != 0; - case JS_TAG_BOOL: - case JS_TAG_NULL: - case JS_TAG_UNDEFINED: - return JS_VALUE_GET_INT(val); - case JS_TAG_EXCEPTION: - return -1; - case JS_TAG_STRING: - { - BOOL ret = JS_VALUE_GET_STRING(val)->len != 0; - JS_FreeValue(ctx, val); - return ret; - } - case JS_TAG_STRING_ROPE: - { - BOOL ret = JS_VALUE_GET_STRING_ROPE(val)->len != 0; - JS_FreeValue(ctx, val); - return ret; - } - case JS_TAG_SHORT_BIG_INT: - return JS_VALUE_GET_SHORT_BIG_INT(val) != 0; - case JS_TAG_BIG_INT: - { - JSBigInt *p = JS_VALUE_GET_PTR(val); - BOOL ret; - int i; - - /* fail safe: we assume it is not necessarily - normalized. Beginning from the MSB ensures that the - test is fast. */ - ret = FALSE; - for(i = p->len - 1; i >= 0; i--) { - if (p->tab[i] != 0) { - ret = TRUE; - break; - } - } - JS_FreeValue(ctx, val); - return ret; - } - case JS_TAG_OBJECT: - { - JSObject *p = JS_VALUE_GET_OBJ(val); - BOOL ret; - ret = !p->is_HTMLDDA; - JS_FreeValue(ctx, val); - return ret; - } - break; - default: - if (JS_TAG_IS_FLOAT64(tag)) { - double d = JS_VALUE_GET_FLOAT64(val); - return !isnan(d) && d != 0; - } else { - JS_FreeValue(ctx, val); - return TRUE; - } - } -} - -int JS_ToBool(JSContext *ctx, JSValueConst val) -{ - return JS_ToBoolFree(ctx, JS_DupValue(ctx, val)); -} - -static int skip_spaces(const char *pc) -{ - const uint8_t *p, *p_next, *p_start; - uint32_t c; - - p = p_start = (const uint8_t *)pc; - for (;;) { - c = *p; - if (c < 128) { - if (!((c >= 0x09 && c <= 0x0d) || (c == 0x20))) - break; - p++; - } else { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next); - if (!lre_is_space(c)) - break; - p = p_next; - } - } - return p - p_start; -} - -static inline int to_digit(int c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - else if (c >= 'A' && c <= 'Z') - return c - 'A' + 10; - else if (c >= 'a' && c <= 'z') - return c - 'a' + 10; - else - return 36; -} - -/* bigint support */ - -#define JS_BIGINT_MAX_SIZE ((1024 * 1024) / JS_LIMB_BITS) /* in limbs */ - -/* it is currently assumed that JS_SHORT_BIG_INT_BITS = JS_LIMB_BITS */ -#if JS_SHORT_BIG_INT_BITS == 32 -#define JS_SHORT_BIG_INT_MIN INT32_MIN -#define JS_SHORT_BIG_INT_MAX INT32_MAX -#elif JS_SHORT_BIG_INT_BITS == 64 -#define JS_SHORT_BIG_INT_MIN INT64_MIN -#define JS_SHORT_BIG_INT_MAX INT64_MAX -#else -#error unsupported -#endif - -#define ADDC(res, carry_out, op1, op2, carry_in) \ -do { \ - js_limb_t __v, __a, __k, __k1; \ - __v = (op1); \ - __a = __v + (op2); \ - __k1 = __a < __v; \ - __k = (carry_in); \ - __a = __a + __k; \ - carry_out = (__a < __k) | __k1; \ - res = __a; \ -} while (0) - -#if JS_LIMB_BITS == 32 -/* a != 0 */ -static inline js_limb_t js_limb_clz(js_limb_t a) -{ - return clz32(a); -} -#else -static inline js_limb_t js_limb_clz(js_limb_t a) -{ - return clz64(a); -} -#endif - -/* handle a = 0 too */ -static inline js_limb_t js_limb_safe_clz(js_limb_t a) -{ - if (a == 0) - return JS_LIMB_BITS; - else - return js_limb_clz(a); -} - -static js_limb_t mp_add(js_limb_t *res, const js_limb_t *op1, const js_limb_t *op2, - js_limb_t n, js_limb_t carry) -{ - int i; - for(i = 0;i < n; i++) { - ADDC(res[i], carry, op1[i], op2[i], carry); - } - return carry; -} - -static js_limb_t mp_sub(js_limb_t *res, const js_limb_t *op1, const js_limb_t *op2, - int n, js_limb_t carry) -{ - int i; - js_limb_t k, a, v, k1; - - k = carry; - for(i=0;i v; - v = a - k; - k = (v > a) | k1; - res[i] = v; - } - return k; -} - -/* compute 0 - op2. carry = 0 or 1. */ -static js_limb_t mp_neg(js_limb_t *res, const js_limb_t *op2, int n) -{ - int i; - js_limb_t v, carry; - - carry = 1; - for(i=0;i> JS_LIMB_BITS; - } - return l; -} - -static js_limb_t mp_div1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n, - js_limb_t b, js_limb_t r) -{ - js_slimb_t i; - js_dlimb_t a1; - for(i = n - 1; i >= 0; i--) { - a1 = ((js_dlimb_t)r << JS_LIMB_BITS) | taba[i]; - tabr[i] = a1 / b; - r = a1 % b; - } - return r; -} - -/* tabr[] += taba[] * b, return the high word. */ -static js_limb_t mp_add_mul1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n, - js_limb_t b) -{ - js_limb_t i, l; - js_dlimb_t t; - - l = 0; - for(i = 0; i < n; i++) { - t = (js_dlimb_t)taba[i] * (js_dlimb_t)b + l + tabr[i]; - tabr[i] = t; - l = t >> JS_LIMB_BITS; - } - return l; -} - -/* size of the result : op1_size + op2_size. */ -static void mp_mul_basecase(js_limb_t *result, - const js_limb_t *op1, js_limb_t op1_size, - const js_limb_t *op2, js_limb_t op2_size) -{ - int i; - js_limb_t r; - - result[op1_size] = mp_mul1(result, op1, op1_size, op2[0], 0); - for(i=1;i> JS_LIMB_BITS); - } - return l; -} - -/* WARNING: d must be >= 2^(JS_LIMB_BITS-1) */ -static inline js_limb_t udiv1norm_init(js_limb_t d) -{ - js_limb_t a0, a1; - a1 = -d - 1; - a0 = -1; - return (((js_dlimb_t)a1 << JS_LIMB_BITS) | a0) / d; -} - -/* return the quotient and the remainder in '*pr'of 'a1*2^JS_LIMB_BITS+a0 - / d' with 0 <= a1 < d. */ -static inline js_limb_t udiv1norm(js_limb_t *pr, js_limb_t a1, js_limb_t a0, - js_limb_t d, js_limb_t d_inv) -{ - js_limb_t n1m, n_adj, q, r, ah; - js_dlimb_t a; - n1m = ((js_slimb_t)a0 >> (JS_LIMB_BITS - 1)); - n_adj = a0 + (n1m & d); - a = (js_dlimb_t)d_inv * (a1 - n1m) + n_adj; - q = (a >> JS_LIMB_BITS) + a1; - /* compute a - q * r and update q so that the remainder is\ - between 0 and d - 1 */ - a = ((js_dlimb_t)a1 << JS_LIMB_BITS) | a0; - a = a - (js_dlimb_t)q * d - d; - ah = a >> JS_LIMB_BITS; - q += 1 + ah; - r = (js_limb_t)a + (ah & d); - *pr = r; - return q; -} - -#define UDIV1NORM_THRESHOLD 3 - -/* b must be >= 1 << (JS_LIMB_BITS - 1) */ -static js_limb_t mp_div1norm(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n, - js_limb_t b, js_limb_t r) -{ - js_slimb_t i; - - if (n >= UDIV1NORM_THRESHOLD) { - js_limb_t b_inv; - b_inv = udiv1norm_init(b); - for(i = n - 1; i >= 0; i--) { - tabr[i] = udiv1norm(&r, r, taba[i], b, b_inv); - } - } else { - js_dlimb_t a1; - for(i = n - 1; i >= 0; i--) { - a1 = ((js_dlimb_t)r << JS_LIMB_BITS) | taba[i]; - tabr[i] = a1 / b; - r = a1 % b; - } - } - return r; -} - -/* base case division: divides taba[0..na-1] by tabb[0..nb-1]. tabb[nb - - 1] must be >= 1 << (JS_LIMB_BITS - 1). na - nb must be >= 0. 'taba' - is modified and contains the remainder (nb limbs). tabq[0..na-nb] - contains the quotient with tabq[na - nb] <= 1. */ -static void mp_divnorm(js_limb_t *tabq, js_limb_t *taba, js_limb_t na, - const js_limb_t *tabb, js_limb_t nb) -{ - js_limb_t r, a, c, q, v, b1, b1_inv, n, dummy_r; - int i, j; - - b1 = tabb[nb - 1]; - if (nb == 1) { - taba[0] = mp_div1norm(tabq, taba, na, b1, 0); - return; - } - n = na - nb; - - if (n >= UDIV1NORM_THRESHOLD) - b1_inv = udiv1norm_init(b1); - else - b1_inv = 0; - - /* first iteration: the quotient is only 0 or 1 */ - q = 1; - for(j = nb - 1; j >= 0; j--) { - if (taba[n + j] != tabb[j]) { - if (taba[n + j] < tabb[j]) - q = 0; - break; - } - } - tabq[n] = q; - if (q) { - mp_sub(taba + n, taba + n, tabb, nb, 0); - } - - for(i = n - 1; i >= 0; i--) { - if (unlikely(taba[i + nb] >= b1)) { - q = -1; - } else if (b1_inv) { - q = udiv1norm(&dummy_r, taba[i + nb], taba[i + nb - 1], b1, b1_inv); - } else { - js_dlimb_t al; - al = ((js_dlimb_t)taba[i + nb] << JS_LIMB_BITS) | taba[i + nb - 1]; - q = al / b1; - r = al % b1; - } - r = mp_sub_mul1(taba + i, tabb, nb, q); - - v = taba[i + nb]; - a = v - r; - c = (a > v); - taba[i + nb] = a; - - if (c != 0) { - /* negative result */ - for(;;) { - q--; - c = mp_add(taba + i, taba + i, tabb, nb, 0); - /* propagate carry and test if positive result */ - if (c != 0) { - if (++taba[i + nb] == 0) { - break; - } - } - } - } - tabq[i] = q; - } -} - -/* 1 <= shift <= JS_LIMB_BITS - 1 */ -static js_limb_t mp_shl(js_limb_t *tabr, const js_limb_t *taba, int n, - int shift) -{ - int i; - js_limb_t l, v; - l = 0; - for(i = 0; i < n; i++) { - v = taba[i]; - tabr[i] = (v << shift) | l; - l = v >> (JS_LIMB_BITS - shift); - } - return l; -} - -/* r = (a + high*B^n) >> shift. Return the remainder r (0 <= r < 2^shift). - 1 <= shift <= LIMB_BITS - 1 */ -static js_limb_t mp_shr(js_limb_t *tab_r, const js_limb_t *tab, int n, - int shift, js_limb_t high) -{ - int i; - js_limb_t l, a; - - l = high; - for(i = n - 1; i >= 0; i--) { - a = tab[i]; - tab_r[i] = (a >> shift) | (l << (JS_LIMB_BITS - shift)); - l = a; - } - return l & (((js_limb_t)1 << shift) - 1); -} - -static JSBigInt *js_bigint_new(JSContext *ctx, int len) -{ - JSBigInt *r; - if (len > JS_BIGINT_MAX_SIZE) { - JS_ThrowRangeError(ctx, "BigInt is too large to allocate"); - return NULL; - } - r = js_malloc(ctx, sizeof(JSBigInt) + len * sizeof(js_limb_t)); - if (!r) - return NULL; - r->header.ref_count = 1; - r->len = len; - return r; -} - -static JSBigInt *js_bigint_set_si(JSBigIntBuf *buf, js_slimb_t a) -{ - JSBigInt *r = (JSBigInt *)buf->big_int_buf; - r->header.ref_count = 0; /* fail safe */ - r->len = 1; - r->tab[0] = a; - return r; -} - -static JSBigInt *js_bigint_set_si64(JSBigIntBuf *buf, int64_t a) -{ -#if JS_LIMB_BITS == 64 - return js_bigint_set_si(buf, a); -#else - JSBigInt *r = (JSBigInt *)buf->big_int_buf; - r->header.ref_count = 0; /* fail safe */ - if (a >= INT32_MIN && a <= INT32_MAX) { - r->len = 1; - r->tab[0] = a; - } else { - r->len = 2; - r->tab[0] = a; - r->tab[1] = a >> JS_LIMB_BITS; - } - return r; -#endif -} - -/* val must be a short big int */ -static JSBigInt *js_bigint_set_short(JSBigIntBuf *buf, JSValueConst val) -{ - return js_bigint_set_si(buf, JS_VALUE_GET_SHORT_BIG_INT(val)); -} - -static __maybe_unused void js_bigint_dump1(JSContext *ctx, const char *str, - const js_limb_t *tab, int len) -{ - int i; - printf("%s: ", str); - for(i = len - 1; i >= 0; i--) { -#if JS_LIMB_BITS == 32 - printf(" %08x", tab[i]); -#else - printf(" %016" PRIx64, tab[i]); -#endif - } - printf("\n"); -} - -static __maybe_unused void js_bigint_dump(JSContext *ctx, const char *str, - const JSBigInt *p) -{ - js_bigint_dump1(ctx, str, p->tab, p->len); -} - -static JSBigInt *js_bigint_new_si(JSContext *ctx, js_slimb_t a) -{ - JSBigInt *r; - r = js_bigint_new(ctx, 1); - if (!r) - return NULL; - r->tab[0] = a; - return r; -} - -static JSBigInt *js_bigint_new_si64(JSContext *ctx, int64_t a) -{ -#if JS_LIMB_BITS == 64 - return js_bigint_new_si(ctx, a); -#else - if (a >= INT32_MIN && a <= INT32_MAX) { - return js_bigint_new_si(ctx, a); - } else { - JSBigInt *r; - r = js_bigint_new(ctx, 2); - if (!r) - return NULL; - r->tab[0] = a; - r->tab[1] = a >> 32; - return r; - } -#endif -} - -static JSBigInt *js_bigint_new_ui64(JSContext *ctx, uint64_t a) -{ - if (a <= INT64_MAX) { - return js_bigint_new_si64(ctx, a); - } else { - JSBigInt *r; - r = js_bigint_new(ctx, (65 + JS_LIMB_BITS - 1) / JS_LIMB_BITS); - if (!r) - return NULL; -#if JS_LIMB_BITS == 64 - r->tab[0] = a; - r->tab[1] = 0; -#else - r->tab[0] = a; - r->tab[1] = a >> 32; - r->tab[2] = 0; -#endif - return r; - } -} - -static JSBigInt *js_bigint_new_di(JSContext *ctx, js_sdlimb_t a) -{ - JSBigInt *r; - if (a == (js_slimb_t)a) { - r = js_bigint_new(ctx, 1); - if (!r) - return NULL; - r->tab[0] = a; - } else { - r = js_bigint_new(ctx, 2); - if (!r) - return NULL; - r->tab[0] = a; - r->tab[1] = a >> JS_LIMB_BITS; - } - return r; -} - -/* Remove redundant high order limbs. Warning: 'a' may be - reallocated. Can never fail. -*/ -static JSBigInt *js_bigint_normalize1(JSContext *ctx, JSBigInt *a, int l) -{ - js_limb_t v; - - assert(a->header.ref_count == 1); - while (l > 1) { - v = a->tab[l - 1]; - if ((v != 0 && v != -1) || - (v & 1) != (a->tab[l - 2] >> (JS_LIMB_BITS - 1))) { - break; - } - l--; - } - if (l != a->len) { - JSBigInt *a1; - /* realloc to reduce the size */ - a->len = l; - a1 = js_realloc(ctx, a, sizeof(JSBigInt) + l * sizeof(js_limb_t)); - if (a1) - a = a1; - } - return a; -} - -static JSBigInt *js_bigint_normalize(JSContext *ctx, JSBigInt *a) -{ - return js_bigint_normalize1(ctx, a, a->len); -} - -/* return 0 or 1 depending on the sign */ -static inline int js_bigint_sign(const JSBigInt *a) -{ - return a->tab[a->len - 1] >> (JS_LIMB_BITS - 1); -} - -static js_slimb_t js_bigint_get_si_sat(const JSBigInt *a) -{ - if (a->len == 1) { - return a->tab[0]; - } else { -#if JS_LIMB_BITS == 32 - if (js_bigint_sign(a)) - return INT32_MIN; - else - return INT32_MAX; -#else - if (js_bigint_sign(a)) - return INT64_MIN; - else - return INT64_MAX; -#endif - } -} - -/* add the op1 limb */ -static JSBigInt *js_bigint_extend(JSContext *ctx, JSBigInt *r, - js_limb_t op1) -{ - int n2 = r->len; - if ((op1 != 0 && op1 != -1) || - (op1 & 1) != r->tab[n2 - 1] >> (JS_LIMB_BITS - 1)) { - JSBigInt *r1; - r1 = js_realloc(ctx, r, - sizeof(JSBigInt) + (n2 + 1) * sizeof(js_limb_t)); - if (!r1) { - js_free(ctx, r); - return NULL; - } - r = r1; - r->len = n2 + 1; - r->tab[n2] = op1; - } else { - /* otherwise still need to normalize the result */ - r = js_bigint_normalize(ctx, r); - } - return r; -} - -/* return NULL in case of error. Compute a + b (b_neg = 0) or a - b - (b_neg = 1) */ -/* XXX: optimize */ -static JSBigInt *js_bigint_add(JSContext *ctx, const JSBigInt *a, - const JSBigInt *b, int b_neg) -{ - JSBigInt *r; - int n1, n2, i; - js_limb_t carry, op1, op2, a_sign, b_sign; - - n2 = max_int(a->len, b->len); - n1 = min_int(a->len, b->len); - r = js_bigint_new(ctx, n2); - if (!r) - return NULL; - /* XXX: optimize */ - /* common part */ - carry = b_neg; - for(i = 0; i < n1; i++) { - op1 = a->tab[i]; - op2 = b->tab[i] ^ (-b_neg); - ADDC(r->tab[i], carry, op1, op2, carry); - } - a_sign = -js_bigint_sign(a); - b_sign = (-js_bigint_sign(b)) ^ (-b_neg); - /* part with sign extension of one operand */ - if (a->len > b->len) { - for(i = n1; i < n2; i++) { - op1 = a->tab[i]; - ADDC(r->tab[i], carry, op1, b_sign, carry); - } - } else if (a->len < b->len) { - for(i = n1; i < n2; i++) { - op2 = b->tab[i] ^ (-b_neg); - ADDC(r->tab[i], carry, a_sign, op2, carry); - } - } - - /* part with sign extension for both operands. Extend the result - if necessary */ - return js_bigint_extend(ctx, r, a_sign + b_sign + carry); -} - -/* XXX: optimize */ -static JSBigInt *js_bigint_neg(JSContext *ctx, const JSBigInt *a) -{ - JSBigIntBuf buf; - JSBigInt *b; - b = js_bigint_set_si(&buf, 0); - return js_bigint_add(ctx, b, a, 1); -} - -static JSBigInt *js_bigint_mul(JSContext *ctx, const JSBigInt *a, - const JSBigInt *b) -{ - JSBigInt *r; - - r = js_bigint_new(ctx, a->len + b->len); - if (!r) - return NULL; - mp_mul_basecase(r->tab, a->tab, a->len, b->tab, b->len); - /* correct the result if negative operands (no overflow is - possible) */ - if (js_bigint_sign(a)) - mp_sub(r->tab + a->len, r->tab + a->len, b->tab, b->len, 0); - if (js_bigint_sign(b)) - mp_sub(r->tab + b->len, r->tab + b->len, a->tab, a->len, 0); - return js_bigint_normalize(ctx, r); -} - -/* return the division or the remainder. 'b' must be != 0. return NULL - in case of exception (division by zero or memory error) */ -static JSBigInt *js_bigint_divrem(JSContext *ctx, const JSBigInt *a, - const JSBigInt *b, BOOL is_rem) -{ - JSBigInt *r, *q; - js_limb_t *tabb, h; - int na, nb, a_sign, b_sign, shift; - - if (b->len == 1 && b->tab[0] == 0) { - JS_ThrowRangeError(ctx, "BigInt division by zero"); - return NULL; - } - - a_sign = js_bigint_sign(a); - b_sign = js_bigint_sign(b); - na = a->len; - nb = b->len; - - r = js_bigint_new(ctx, na + 2); - if (!r) - return NULL; - if (a_sign) { - mp_neg(r->tab, a->tab, na); - } else { - memcpy(r->tab, a->tab, na * sizeof(a->tab[0])); - } - /* normalize */ - while (na > 1 && r->tab[na - 1] == 0) - na--; - - tabb = js_malloc(ctx, nb * sizeof(tabb[0])); - if (!tabb) { - js_free(ctx, r); - return NULL; - } - if (b_sign) { - mp_neg(tabb, b->tab, nb); - } else { - memcpy(tabb, b->tab, nb * sizeof(tabb[0])); - } - /* normalize */ - while (nb > 1 && tabb[nb - 1] == 0) - nb--; - - /* trivial case if 'a' is small */ - if (na < nb) { - js_free(ctx, r); - js_free(ctx, tabb); - if (is_rem) { - /* r = a */ - r = js_bigint_new(ctx, a->len); - if (!r) - return NULL; - memcpy(r->tab, a->tab, a->len * sizeof(a->tab[0])); - return r; - } else { - /* q = 0 */ - return js_bigint_new_si(ctx, 0); - } - } - - /* normalize 'b' */ - shift = js_limb_clz(tabb[nb - 1]); - if (shift != 0) { - mp_shl(tabb, tabb, nb, shift); - h = mp_shl(r->tab, r->tab, na, shift); - if (h != 0) - r->tab[na++] = h; - } - - q = js_bigint_new(ctx, na - nb + 2); /* one more limb for the sign */ - if (!q) { - js_free(ctx, r); - js_free(ctx, tabb); - return NULL; - } - - // js_bigint_dump1(ctx, "a", r->tab, na); - // js_bigint_dump1(ctx, "b", tabb, nb); - mp_divnorm(q->tab, r->tab, na, tabb, nb); - js_free(ctx, tabb); - - if (is_rem) { - js_free(ctx, q); - if (shift != 0) - mp_shr(r->tab, r->tab, nb, shift, 0); - r->tab[nb++] = 0; - if (a_sign) - mp_neg(r->tab, r->tab, nb); - r = js_bigint_normalize1(ctx, r, nb); - return r; - } else { - js_free(ctx, r); - q->tab[na - nb + 1] = 0; - if (a_sign ^ b_sign) { - mp_neg(q->tab, q->tab, q->len); - } - q = js_bigint_normalize(ctx, q); - return q; - } -} - -/* and, or, xor */ -static JSBigInt *js_bigint_logic(JSContext *ctx, const JSBigInt *a, - const JSBigInt *b, OPCodeEnum op) -{ - JSBigInt *r; - js_limb_t b_sign; - int a_len, b_len, i; - - if (a->len < b->len) { - const JSBigInt *tmp; - tmp = a; - a = b; - b = tmp; - } - /* a_len >= b_len */ - a_len = a->len; - b_len = b->len; - b_sign = -js_bigint_sign(b); - - r = js_bigint_new(ctx, a_len); - if (!r) - return NULL; - switch(op) { - case OP_or: - for(i = 0; i < b_len; i++) { - r->tab[i] = a->tab[i] | b->tab[i]; - } - for(i = b_len; i < a_len; i++) { - r->tab[i] = a->tab[i] | b_sign; - } - break; - case OP_and: - for(i = 0; i < b_len; i++) { - r->tab[i] = a->tab[i] & b->tab[i]; - } - for(i = b_len; i < a_len; i++) { - r->tab[i] = a->tab[i] & b_sign; - } - break; - case OP_xor: - for(i = 0; i < b_len; i++) { - r->tab[i] = a->tab[i] ^ b->tab[i]; - } - for(i = b_len; i < a_len; i++) { - r->tab[i] = a->tab[i] ^ b_sign; - } - break; - default: - abort(); - } - return js_bigint_normalize(ctx, r); -} - -static JSBigInt *js_bigint_not(JSContext *ctx, const JSBigInt *a) -{ - JSBigInt *r; - int i; - - r = js_bigint_new(ctx, a->len); - if (!r) - return NULL; - for(i = 0; i < a->len; i++) { - r->tab[i] = ~a->tab[i]; - } - /* no normalization is needed */ - return r; -} - -static JSBigInt *js_bigint_shl(JSContext *ctx, const JSBigInt *a, - unsigned int shift1) -{ - int d, i, shift; - JSBigInt *r; - js_limb_t l; - - if (a->len == 1 && a->tab[0] == 0) - return js_bigint_new_si(ctx, 0); /* zero case */ - d = shift1 / JS_LIMB_BITS; - shift = shift1 % JS_LIMB_BITS; - r = js_bigint_new(ctx, a->len + d); - if (!r) - return NULL; - for(i = 0; i < d; i++) - r->tab[i] = 0; - if (shift == 0) { - for(i = 0; i < a->len; i++) { - r->tab[i + d] = a->tab[i]; - } - } else { - l = mp_shl(r->tab + d, a->tab, a->len, shift); - if (js_bigint_sign(a)) - l |= (js_limb_t)(-1) << shift; - r = js_bigint_extend(ctx, r, l); - } - return r; -} - -static JSBigInt *js_bigint_shr(JSContext *ctx, const JSBigInt *a, - unsigned int shift1) -{ - int d, i, shift, a_sign, n1; - JSBigInt *r; - - d = shift1 / JS_LIMB_BITS; - shift = shift1 % JS_LIMB_BITS; - a_sign = js_bigint_sign(a); - if (d >= a->len) - return js_bigint_new_si(ctx, -a_sign); - n1 = a->len - d; - r = js_bigint_new(ctx, n1); - if (!r) - return NULL; - if (shift == 0) { - for(i = 0; i < n1; i++) { - r->tab[i] = a->tab[i + d]; - } - /* no normalization is needed */ - } else { - mp_shr(r->tab, a->tab + d, n1, shift, -a_sign); - r = js_bigint_normalize(ctx, r); - } - return r; -} - -static JSBigInt *js_bigint_pow(JSContext *ctx, const JSBigInt *a, JSBigInt *b) -{ - uint32_t e; - int n_bits, i; - JSBigInt *r, *r1; - - /* b must be >= 0 */ - if (js_bigint_sign(b)) { - JS_ThrowRangeError(ctx, "BigInt negative exponent"); - return NULL; - } - if (b->len == 1 && b->tab[0] == 0) { - /* a^0 = 1 */ - return js_bigint_new_si(ctx, 1); - } else if (a->len == 1) { - js_limb_t v; - BOOL is_neg; - - v = a->tab[0]; - if (v <= 1) - return js_bigint_new_si(ctx, v); - else if (v == -1) - return js_bigint_new_si(ctx, 1 - 2 * (b->tab[0] & 1)); - is_neg = (js_slimb_t)v < 0; - if (is_neg) - v = -v; - if ((v & (v - 1)) == 0) { - uint64_t e1; - int n; - /* v = 2^n */ - n = JS_LIMB_BITS - 1 - js_limb_clz(v); - if (b->len > 1) - goto overflow; - if (b->tab[0] > INT32_MAX) - goto overflow; - e = b->tab[0]; - e1 = (uint64_t)e * n; - if (e1 > JS_BIGINT_MAX_SIZE * JS_LIMB_BITS) - goto overflow; - e = e1; - if (is_neg) - is_neg = b->tab[0] & 1; - r = js_bigint_new(ctx, - (e + JS_LIMB_BITS + 1 - is_neg) / JS_LIMB_BITS); - if (!r) - return NULL; - memset(r->tab, 0, sizeof(r->tab[0]) * r->len); - r->tab[e / JS_LIMB_BITS] = - (js_limb_t)(1 - 2 * is_neg) << (e % JS_LIMB_BITS); - return r; - } - } - if (b->len > 1) - goto overflow; - if (b->tab[0] > INT32_MAX) - goto overflow; - e = b->tab[0]; - n_bits = 32 - clz32(e); - - r = js_bigint_new(ctx, a->len); - if (!r) - return NULL; - memcpy(r->tab, a->tab, a->len * sizeof(a->tab[0])); - for(i = n_bits - 2; i >= 0; i--) { - r1 = js_bigint_mul(ctx, r, r); - if (!r1) - return NULL; - js_free(ctx, r); - r = r1; - if ((e >> i) & 1) { - r1 = js_bigint_mul(ctx, r, a); - if (!r1) - return NULL; - js_free(ctx, r); - r = r1; - } - } - return r; - overflow: - JS_ThrowRangeError(ctx, "BigInt is too large"); - return NULL; -} - -/* return (mant, exp) so that abs(a) ~ mant*2^(exp - (limb_bits - - 1). a must be != 0. */ -static uint64_t js_bigint_get_mant_exp(JSContext *ctx, - int *pexp, const JSBigInt *a) -{ - js_limb_t t[4 - JS_LIMB_BITS / 32], carry, v, low_bits; - int n1, n2, sgn, shift, i, j, e; - uint64_t a1, a0; - - n2 = 4 - JS_LIMB_BITS / 32; - n1 = a->len - n2; - sgn = js_bigint_sign(a); - - /* low_bits != 0 if there are a non zero low bit in abs(a) */ - low_bits = 0; - carry = sgn; - for(i = 0; i < n1; i++) { - v = (a->tab[i] ^ (-sgn)) + carry; - carry = v < carry; - low_bits |= v; - } - /* get the n2 high limbs of abs(a) */ - for(j = 0; j < n2; j++) { - i = j + n1; - if (i < 0) { - v = 0; - } else { - v = (a->tab[i] ^ (-sgn)) + carry; - carry = v < carry; - } - t[j] = v; - } - -#if JS_LIMB_BITS == 32 - a1 = ((uint64_t)t[2] << 32) | t[1]; - a0 = (uint64_t)t[0] << 32; -#else - a1 = t[1]; - a0 = t[0]; -#endif - a0 |= (low_bits != 0); - /* normalize */ - if (a1 == 0) { - /* JS_LIMB_BITS = 64 bit only */ - shift = 64; - a1 = a0; - a0 = 0; - } else { - shift = clz64(a1); - if (shift != 0) { - a1 = (a1 << shift) | (a0 >> (64 - shift)); - a0 <<= shift; - } - } - a1 |= (a0 != 0); /* keep the bits for the final rounding */ - /* compute the exponent */ - e = a->len * JS_LIMB_BITS - shift - 1; - *pexp = e; - return a1; -} - -/* shift left with round to nearest, ties to even. n >= 1 */ -static uint64_t shr_rndn(uint64_t a, int n) -{ - uint64_t addend = ((a >> n) & 1) + ((1 << (n - 1)) - 1); - return (a + addend) >> n; -} - -/* convert to float64 with round to nearest, ties to even. Return - +/-infinity if too large. */ -static double js_bigint_to_float64(JSContext *ctx, const JSBigInt *a) -{ - int sgn, e; - uint64_t mant; - - if (a->len == 1) { - /* fast case, including zero */ - return (double)(js_slimb_t)a->tab[0]; - } - - sgn = js_bigint_sign(a); - mant = js_bigint_get_mant_exp(ctx, &e, a); - if (e > 1023) { - /* overflow: return infinity */ - mant = 0; - e = 1024; - } else { - mant = (mant >> 1) | (mant & 1); /* avoid overflow in rounding */ - mant = shr_rndn(mant, 10); - /* rounding can cause an overflow */ - if (mant >= ((uint64_t)1 << 53)) { - mant >>= 1; - e++; - } - mant &= (((uint64_t)1 << 52) - 1); - } - return uint64_as_float64(((uint64_t)sgn << 63) | - ((uint64_t)(e + 1023) << 52) | - mant); -} - -/* return (1, NULL) if not an integer, (2, NULL) if NaN or Infinity, - (0, n) if an integer, (0, NULL) in case of memory error */ -static JSBigInt *js_bigint_from_float64(JSContext *ctx, int *pres, double a1) -{ - uint64_t a = float64_as_uint64(a1); - int sgn, e, shift; - uint64_t mant; - JSBigIntBuf buf; - JSBigInt *r; - - sgn = a >> 63; - e = (a >> 52) & ((1 << 11) - 1); - mant = a & (((uint64_t)1 << 52) - 1); - if (e == 2047) { - /* NaN, Infinity */ - *pres = 2; - return NULL; - } - if (e == 0 && mant == 0) { - /* zero */ - *pres = 0; - return js_bigint_new_si(ctx, 0); - } - e -= 1023; - /* 0 < a < 1 : not an integer */ - if (e < 0) - goto not_an_integer; - mant |= (uint64_t)1 << 52; - if (e < 52) { - shift = 52 - e; - /* check that there is no fractional part */ - if (mant & (((uint64_t)1 << shift) - 1)) { - not_an_integer: - *pres = 1; - return NULL; - } - mant >>= shift; - e = 0; - } else { - e -= 52; - } - if (sgn) - mant = -mant; - /* the integer is mant*2^e */ - r = js_bigint_set_si64(&buf, (int64_t)mant); - *pres = 0; - return js_bigint_shl(ctx, r, e); -} - -/* return -1, 0, 1 or (2) (unordered) */ -static int js_bigint_float64_cmp(JSContext *ctx, const JSBigInt *a, - double b) -{ - int b_sign, a_sign, e, f; - uint64_t mant, b1, a_mant; - - b1 = float64_as_uint64(b); - b_sign = b1 >> 63; - e = (b1 >> 52) & ((1 << 11) - 1); - mant = b1 & (((uint64_t)1 << 52) - 1); - a_sign = js_bigint_sign(a); - if (e == 2047) { - if (mant != 0) { - /* NaN */ - return 2; - } else { - /* +/- infinity */ - return 2 * b_sign - 1; - } - } else if (e == 0 && mant == 0) { - /* b = +/-0 */ - if (a->len == 1 && a->tab[0] == 0) - return 0; - else - return 1 - 2 * a_sign; - } else if (a->len == 1 && a->tab[0] == 0) { - /* a = 0, b != 0 */ - return 2 * b_sign - 1; - } else if (a_sign != b_sign) { - return 1 - 2 * a_sign; - } else { - e -= 1023; - /* Note: handling denormals is not necessary because we - compare to integers hence f >= 0 */ - /* compute f so that 2^f <= abs(a) < 2^(f+1) */ - a_mant = js_bigint_get_mant_exp(ctx, &f, a); - if (f != e) { - if (f < e) - return -1; - else - return 1; - } else { - mant = (mant | ((uint64_t)1 << 52)) << 11; /* align to a_mant */ - if (a_mant < mant) - return 2 * a_sign - 1; - else if (a_mant > mant) - return 1 - 2 * a_sign; - else - return 0; - } - } -} - -/* return -1, 0 or 1 */ -static int js_bigint_cmp(JSContext *ctx, const JSBigInt *a, - const JSBigInt *b) -{ - int a_sign, b_sign, res, i; - a_sign = js_bigint_sign(a); - b_sign = js_bigint_sign(b); - if (a_sign != b_sign) { - res = 1 - 2 * a_sign; - } else { - /* we assume the numbers are normalized */ - if (a->len != b->len) { - if (a->len < b->len) - res = 2 * a_sign - 1; - else - res = 1 - 2 * a_sign; - } else { - res = 0; - for(i = a->len -1; i >= 0; i--) { - if (a->tab[i] != b->tab[i]) { - if (a->tab[i] < b->tab[i]) - res = -1; - else - res = 1; - break; - } - } - } - } - return res; -} - -/* contains 10^i */ -static const js_limb_t js_pow_dec[JS_LIMB_DIGITS + 1] = { - 1U, - 10U, - 100U, - 1000U, - 10000U, - 100000U, - 1000000U, - 10000000U, - 100000000U, - 1000000000U, -#if JS_LIMB_BITS == 64 - 10000000000U, - 100000000000U, - 1000000000000U, - 10000000000000U, - 100000000000000U, - 1000000000000000U, - 10000000000000000U, - 100000000000000000U, - 1000000000000000000U, - 10000000000000000000U, -#endif -}; - -/* syntax: [-]digits in base radix. Return NULL if memory error. radix - = 10, 2, 8 or 16. */ -static JSBigInt *js_bigint_from_string(JSContext *ctx, - const char *str, int radix) -{ - const char *p = str; - int is_neg, n_digits, n_limbs, len, log2_radix, n_bits, i; - JSBigInt *r; - js_limb_t v, c, h; - - is_neg = 0; - if (*p == '-') { - is_neg = 1; - p++; - } - while (*p == '0') - p++; - n_digits = strlen(p); - log2_radix = 32 - clz32(radix - 1); /* ceil(log2(radix)) */ - /* compute the maximum number of limbs */ - /* XXX: overflow */ - if (radix == 10) { - n_bits = (n_digits * 27 + 7) / 8; /* >= ceil(n_digits * log2(10)) */ - } else { - n_bits = n_digits * log2_radix; - } - /* we add one extra bit for the sign */ - n_limbs = max_int(1, n_bits / JS_LIMB_BITS + 1); - r = js_bigint_new(ctx, n_limbs); - if (!r) - return NULL; - if (radix == 10) { - int digits_per_limb = JS_LIMB_DIGITS; - len = 1; - r->tab[0] = 0; - for(;;) { - /* XXX: slow */ - v = 0; - for(i = 0; i < digits_per_limb; i++) { - c = to_digit(*p); - if (c >= radix) - break; - p++; - v = v * 10 + c; - } - if (i == 0) - break; - if (len == 1 && r->tab[0] == 0) { - r->tab[0] = v; - } else { - h = mp_mul1(r->tab, r->tab, len, js_pow_dec[i], v); - if (h != 0) { - r->tab[len++] = h; - } - } - } - /* add one extra limb to have the correct sign*/ - if ((r->tab[len - 1] >> (JS_LIMB_BITS - 1)) != 0) - r->tab[len++] = 0; - r->len = len; - } else { - unsigned int bit_pos, shift, pos; - - /* power of two base: no multiplication is needed */ - r->len = n_limbs; - memset(r->tab, 0, sizeof(r->tab[0]) * n_limbs); - for(i = 0; i < n_digits; i++) { - c = to_digit(p[n_digits - 1 - i]); - assert(c < radix); - bit_pos = i * log2_radix; - shift = bit_pos & (JS_LIMB_BITS - 1); - pos = bit_pos / JS_LIMB_BITS; - r->tab[pos] |= c << shift; - /* if log2_radix does not divide JS_LIMB_BITS, needed an - additional op */ - if (shift + log2_radix > JS_LIMB_BITS) { - r->tab[pos + 1] |= c >> (JS_LIMB_BITS - shift); - } - } - } - r = js_bigint_normalize(ctx, r); - /* XXX: could do it in place */ - if (is_neg) { - JSBigInt *r1; - r1 = js_bigint_neg(ctx, r); - js_free(ctx, r); - r = r1; - } - return r; -} - -/* 2 <= base <= 36 */ -static char const digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz"; - -/* special version going backwards */ -/* XXX: use dtoa.c */ -static char *js_u64toa(char *q, int64_t n, unsigned int base) -{ - int digit; - if (base == 10) { - /* division by known base uses multiplication */ - do { - digit = (uint64_t)n % 10; - n = (uint64_t)n / 10; - *--q = '0' + digit; - } while (n != 0); - } else { - do { - digit = (uint64_t)n % base; - n = (uint64_t)n / base; - *--q = digits[digit]; - } while (n != 0); - } - return q; -} - -/* len >= 1. 2 <= radix <= 36 */ -static char *limb_to_a(char *q, js_limb_t n, unsigned int radix, int len) -{ - int digit, i; - - if (radix == 10) { - /* specific case with constant divisor */ - /* XXX: optimize */ - for(i = 0; i < len; i++) { - digit = (js_limb_t)n % 10; - n = (js_limb_t)n / 10; - *--q = digit + '0'; - } - } else { - for(i = 0; i < len; i++) { - digit = (js_limb_t)n % radix; - n = (js_limb_t)n / radix; - *--q = digits[digit]; - } - } - return q; -} - -#define JS_RADIX_MAX 36 - -static const uint8_t digits_per_limb_table[JS_RADIX_MAX - 1] = { -#if JS_LIMB_BITS == 32 -32,20,16,13,12,11,10,10, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -#else -64,40,32,27,24,22,21,20,19,18,17,17,16,16,16,15,15,15,14,14,14,14,13,13,13,13,13,13,13,12,12,12,12,12,12, -#endif -}; - -static const js_limb_t radix_base_table[JS_RADIX_MAX - 1] = { -#if JS_LIMB_BITS == 32 - 0x00000000, 0xcfd41b91, 0x00000000, 0x48c27395, - 0x81bf1000, 0x75db9c97, 0x40000000, 0xcfd41b91, - 0x3b9aca00, 0x8c8b6d2b, 0x19a10000, 0x309f1021, - 0x57f6c100, 0x98c29b81, 0x00000000, 0x18754571, - 0x247dbc80, 0x3547667b, 0x4c4b4000, 0x6b5a6e1d, - 0x94ace180, 0xcaf18367, 0x0b640000, 0x0e8d4a51, - 0x1269ae40, 0x17179149, 0x1cb91000, 0x23744899, - 0x2b73a840, 0x34e63b41, 0x40000000, 0x4cfa3cc1, - 0x5c13d840, 0x6d91b519, 0x81bf1000, -#else - 0x0000000000000000, 0xa8b8b452291fe821, 0x0000000000000000, 0x6765c793fa10079d, - 0x41c21cb8e1000000, 0x3642798750226111, 0x8000000000000000, 0xa8b8b452291fe821, - 0x8ac7230489e80000, 0x4d28cb56c33fa539, 0x1eca170c00000000, 0x780c7372621bd74d, - 0x1e39a5057d810000, 0x5b27ac993df97701, 0x0000000000000000, 0x27b95e997e21d9f1, - 0x5da0e1e53c5c8000, 0xd2ae3299c1c4aedb, 0x16bcc41e90000000, 0x2d04b7fdd9c0ef49, - 0x5658597bcaa24000, 0xa0e2073737609371, 0x0c29e98000000000, 0x14adf4b7320334b9, - 0x226ed36478bfa000, 0x383d9170b85ff80b, 0x5a3c23e39c000000, 0x8e65137388122bcd, - 0xdd41bb36d259e000, 0x0aee5720ee830681, 0x1000000000000000, 0x172588ad4f5f0981, - 0x211e44f7d02c1000, 0x2ee56725f06e5c71, 0x41c21cb8e1000000, -#endif -}; - -static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix) -{ - if (JS_VALUE_GET_TAG(val) == JS_TAG_SHORT_BIG_INT) { - char buf[66]; - int len; - len = i64toa_radix(buf, JS_VALUE_GET_SHORT_BIG_INT(val), radix); - return js_new_string8_len(ctx, buf, len); - } else { - JSBigInt *r, *tmp = NULL; - char *buf, *q, *buf_end; - int is_neg, n_bits, log2_radix, n_digits; - BOOL is_binary_radix; - JSValue res; - - assert(JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT); - r = JS_VALUE_GET_PTR(val); - if (r->len == 1 && r->tab[0] == 0) { - /* '0' case */ - return js_new_string8_len(ctx, "0", 1); - } - is_binary_radix = ((radix & (radix - 1)) == 0); - is_neg = js_bigint_sign(r); - if (is_neg) { - tmp = js_bigint_neg(ctx, r); - if (!tmp) - return JS_EXCEPTION; - r = tmp; - } else if (!is_binary_radix) { - /* need to modify 'r' */ - tmp = js_bigint_new(ctx, r->len); - if (!tmp) - return JS_EXCEPTION; - memcpy(tmp->tab, r->tab, r->len * sizeof(r->tab[0])); - r = tmp; - } - log2_radix = 31 - clz32(radix); /* floor(log2(radix)) */ - n_bits = r->len * JS_LIMB_BITS - js_limb_safe_clz(r->tab[r->len - 1]); - /* n_digits is exact only if radix is a power of - two. Otherwise it is >= the exact number of digits */ - n_digits = (n_bits + log2_radix - 1) / log2_radix; - /* XXX: could directly build the JSString */ - buf = js_malloc(ctx, n_digits + is_neg + 1); - if (!buf) { - js_free(ctx, tmp); - return JS_EXCEPTION; - } - q = buf + n_digits + is_neg + 1; - *--q = '\0'; - buf_end = q; - if (!is_binary_radix) { - int len; - js_limb_t radix_base, v; - radix_base = radix_base_table[radix - 2]; - len = r->len; - for(;;) { - /* remove leading zero limbs */ - while (len > 1 && r->tab[len - 1] == 0) - len--; - if (len == 1 && r->tab[0] < radix_base) { - v = r->tab[0]; - if (v != 0) { - q = js_u64toa(q, v, radix); - } - break; - } else { - v = mp_div1(r->tab, r->tab, len, radix_base, 0); - q = limb_to_a(q, v, radix, digits_per_limb_table[radix - 2]); - } - } - } else { - int i, shift; - unsigned int bit_pos, pos, c; - - /* radix is a power of two */ - for(i = 0; i < n_digits; i++) { - bit_pos = i * log2_radix; - pos = bit_pos / JS_LIMB_BITS; - shift = bit_pos % JS_LIMB_BITS; - if (likely((shift + log2_radix) <= JS_LIMB_BITS)) { - c = r->tab[pos] >> shift; - } else { - c = (r->tab[pos] >> shift) | - (r->tab[pos + 1] << (JS_LIMB_BITS - shift)); - } - c &= (radix - 1); - *--q = digits[c]; - } - } - if (is_neg) - *--q = '-'; - js_free(ctx, tmp); - res = js_new_string8_len(ctx, q, buf_end - q); - js_free(ctx, buf); - return res; - } -} - -/* if possible transform a BigInt to short big and free it, otherwise - return a normal bigint */ -static JSValue JS_CompactBigInt(JSContext *ctx, JSBigInt *p) -{ - JSValue res; - if (p->len == 1) { - res = __JS_NewShortBigInt(ctx, (js_slimb_t)p->tab[0]); - js_free(ctx, p); - return res; - } else { - return JS_MKPTR(JS_TAG_BIG_INT, p); - } -} - -#define ATOD_INT_ONLY (1 << 0) -/* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */ -#define ATOD_ACCEPT_BIN_OCT (1 << 2) -/* accept O prefix as octal if radix == 0 and properly formed (Annex B) */ -#define ATOD_ACCEPT_LEGACY_OCTAL (1 << 4) -/* accept _ between digits as a digit separator */ -#define ATOD_ACCEPT_UNDERSCORES (1 << 5) -/* allow a suffix to override the type */ -#define ATOD_ACCEPT_SUFFIX (1 << 6) -/* default type */ -#define ATOD_TYPE_MASK (3 << 7) -#define ATOD_TYPE_FLOAT64 (0 << 7) -#define ATOD_TYPE_BIG_INT (1 << 7) -/* accept -0x1 */ -#define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10) - -/* return an exception in case of memory error. Return JS_NAN if - invalid syntax */ -/* XXX: directly use js_atod() */ -static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, - int radix, int flags) -{ - const char *p, *p_start; - int sep, is_neg; - BOOL is_float, has_legacy_octal; - int atod_type = flags & ATOD_TYPE_MASK; - char buf1[64], *buf; - int i, j, len; - BOOL buf_allocated = FALSE; - JSValue val; - JSATODTempMem atod_mem; - - /* optional separator between digits */ - sep = (flags & ATOD_ACCEPT_UNDERSCORES) ? '_' : 256; - has_legacy_octal = FALSE; - - p = str; - p_start = p; - is_neg = 0; - if (p[0] == '+') { - p++; - p_start++; - if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN)) - goto no_radix_prefix; - } else if (p[0] == '-') { - p++; - p_start++; - is_neg = 1; - if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN)) - goto no_radix_prefix; - } - if (p[0] == '0') { - if ((p[1] == 'x' || p[1] == 'X') && - (radix == 0 || radix == 16)) { - p += 2; - radix = 16; - } else if ((p[1] == 'o' || p[1] == 'O') && - radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) { - p += 2; - radix = 8; - } else if ((p[1] == 'b' || p[1] == 'B') && - radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) { - p += 2; - radix = 2; - } else if ((p[1] >= '0' && p[1] <= '9') && - radix == 0 && (flags & ATOD_ACCEPT_LEGACY_OCTAL)) { - int i; - has_legacy_octal = TRUE; - sep = 256; - for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++) - continue; - if (p[i] == '8' || p[i] == '9') - goto no_prefix; - p += 1; - radix = 8; - } else { - goto no_prefix; - } - /* there must be a digit after the prefix */ - if (to_digit((uint8_t)*p) >= radix) - goto fail; - no_prefix: ; - } else { - no_radix_prefix: - if (!(flags & ATOD_INT_ONLY) && - (atod_type == ATOD_TYPE_FLOAT64) && - strstart(p, "Infinity", &p)) { - double d = 1.0 / 0.0; - if (is_neg) - d = -d; - val = JS_NewFloat64(ctx, d); - goto done; - } - } - if (radix == 0) - radix = 10; - is_float = FALSE; - p_start = p; - while (to_digit((uint8_t)*p) < radix - || (*p == sep && (radix != 10 || - p != p_start + 1 || p[-1] != '0') && - to_digit((uint8_t)p[1]) < radix)) { - p++; - } - if (!(flags & ATOD_INT_ONLY)) { - if (*p == '.' && (p > p_start || to_digit((uint8_t)p[1]) < radix)) { - is_float = TRUE; - p++; - if (*p == sep) - goto fail; - while (to_digit((uint8_t)*p) < radix || - (*p == sep && to_digit((uint8_t)p[1]) < radix)) - p++; - } - if (p > p_start && - (((*p == 'e' || *p == 'E') && radix == 10) || - ((*p == 'p' || *p == 'P') && (radix == 2 || radix == 8 || radix == 16)))) { - const char *p1 = p + 1; - is_float = TRUE; - if (*p1 == '+') { - p1++; - } else if (*p1 == '-') { - p1++; - } - if (is_digit((uint8_t)*p1)) { - p = p1 + 1; - while (is_digit((uint8_t)*p) || (*p == sep && is_digit((uint8_t)p[1]))) - p++; - } - } - } - if (p == p_start) - goto fail; - - buf = buf1; - buf_allocated = FALSE; - len = p - p_start; - if (unlikely((len + 2) > sizeof(buf1))) { - buf = js_malloc_rt(ctx->rt, len + 2); /* no exception raised */ - if (!buf) - goto mem_error; - buf_allocated = TRUE; - } - /* remove the separators and the radix prefixes */ - j = 0; - if (is_neg) - buf[j++] = '-'; - for (i = 0; i < len; i++) { - if (p_start[i] != '_') - buf[j++] = p_start[i]; - } - buf[j] = '\0'; - - if (flags & ATOD_ACCEPT_SUFFIX) { - if (*p == 'n') { - p++; - atod_type = ATOD_TYPE_BIG_INT; - } else { - if (is_float && radix != 10) - goto fail; - } - } else { - if (atod_type == ATOD_TYPE_FLOAT64) { - if (is_float && radix != 10) - goto fail; - } - } - - switch(atod_type) { - case ATOD_TYPE_FLOAT64: - { - double d; - d = js_atod(buf, NULL, radix, is_float ? 0 : JS_ATOD_INT_ONLY, - &atod_mem); - /* return int or float64 */ - val = JS_NewFloat64(ctx, d); - } - break; - case ATOD_TYPE_BIG_INT: - { - JSBigInt *r; - if (has_legacy_octal || is_float) - goto fail; - r = js_bigint_from_string(ctx, buf, radix); - if (!r) - goto mem_error; - val = JS_CompactBigInt(ctx, r); - } - break; - default: - abort(); - } - -done: - if (buf_allocated) - js_free_rt(ctx->rt, buf); - if (pp) - *pp = p; - return val; - fail: - val = JS_NAN; - goto done; - mem_error: - val = JS_ThrowOutOfMemory(ctx); - goto done; -} - -typedef enum JSToNumberHintEnum { - TON_FLAG_NUMBER, - TON_FLAG_NUMERIC, -} JSToNumberHintEnum; - -static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val, - JSToNumberHintEnum flag) -{ - uint32_t tag; - JSValue ret; - - redo: - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_BIG_INT: - case JS_TAG_SHORT_BIG_INT: - if (flag != TON_FLAG_NUMERIC) { - JS_FreeValue(ctx, val); - return JS_ThrowTypeError(ctx, "cannot convert bigint to number"); - } - ret = val; - break; - case JS_TAG_FLOAT64: - case JS_TAG_INT: - case JS_TAG_EXCEPTION: - ret = val; - break; - case JS_TAG_BOOL: - case JS_TAG_NULL: - ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val)); - break; - case JS_TAG_UNDEFINED: - ret = JS_NAN; - break; - case JS_TAG_OBJECT: - val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER); - if (JS_IsException(val)) - return JS_EXCEPTION; - goto redo; - case JS_TAG_STRING: - case JS_TAG_STRING_ROPE: - { - const char *str; - const char *p; - size_t len; - - str = JS_ToCStringLen(ctx, &len, val); - JS_FreeValue(ctx, val); - if (!str) - return JS_EXCEPTION; - p = str; - p += skip_spaces(p); - if ((p - str) == len) { - ret = JS_NewInt32(ctx, 0); - } else { - int flags = ATOD_ACCEPT_BIN_OCT; - ret = js_atof(ctx, p, &p, 0, flags); - if (!JS_IsException(ret)) { - p += skip_spaces(p); - if ((p - str) != len) { - JS_FreeValue(ctx, ret); - ret = JS_NAN; - } - } - } - JS_FreeCString(ctx, str); - } - break; - case JS_TAG_SYMBOL: - JS_FreeValue(ctx, val); - return JS_ThrowTypeError(ctx, "cannot convert symbol to number"); - default: - JS_FreeValue(ctx, val); - ret = JS_NAN; - break; - } - return ret; -} - -static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val) -{ - return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER); -} - -static JSValue JS_ToNumericFree(JSContext *ctx, JSValue val) -{ - return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC); -} - -static JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val) -{ - return JS_ToNumericFree(ctx, JS_DupValue(ctx, val)); -} - -static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres, - JSValue val) -{ - double d; - uint32_t tag; - - val = JS_ToNumberFree(ctx, val); - if (JS_IsException(val)) - goto fail; - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_INT: - d = JS_VALUE_GET_INT(val); - break; - case JS_TAG_FLOAT64: - d = JS_VALUE_GET_FLOAT64(val); - break; - default: - abort(); - } - *pres = d; - return 0; - fail: - *pres = JS_FLOAT64_NAN; - return -1; -} - -static inline int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val) -{ - uint32_t tag; - - tag = JS_VALUE_GET_TAG(val); - if (tag <= JS_TAG_NULL) { - *pres = JS_VALUE_GET_INT(val); - return 0; - } else if (JS_TAG_IS_FLOAT64(tag)) { - *pres = JS_VALUE_GET_FLOAT64(val); - return 0; - } else { - return __JS_ToFloat64Free(ctx, pres, val); - } -} - -int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val) -{ - return JS_ToFloat64Free(ctx, pres, JS_DupValue(ctx, val)); -} - -static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val) -{ - return JS_ToNumberFree(ctx, JS_DupValue(ctx, val)); -} - -/* same as JS_ToNumber() but return 0 in case of NaN/Undefined */ -static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val) -{ - uint32_t tag; - JSValue ret; - - redo: - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_INT: - case JS_TAG_BOOL: - case JS_TAG_NULL: - case JS_TAG_UNDEFINED: - ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val)); - break; - case JS_TAG_FLOAT64: - { - double d = JS_VALUE_GET_FLOAT64(val); - if (isnan(d)) { - ret = JS_NewInt32(ctx, 0); - } else { - /* convert -0 to +0 */ - d = trunc(d) + 0.0; - ret = JS_NewFloat64(ctx, d); - } - } - break; - default: - val = JS_ToNumberFree(ctx, val); - if (JS_IsException(val)) - return val; - goto redo; - } - return ret; -} - -/* Note: the integer value is satured to 32 bits */ -static int JS_ToInt32SatFree(JSContext *ctx, int *pres, JSValue val) -{ - uint32_t tag; - int ret; - - redo: - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_INT: - case JS_TAG_BOOL: - case JS_TAG_NULL: - case JS_TAG_UNDEFINED: - ret = JS_VALUE_GET_INT(val); - break; - case JS_TAG_EXCEPTION: - *pres = 0; - return -1; - case JS_TAG_FLOAT64: - { - double d = JS_VALUE_GET_FLOAT64(val); - if (isnan(d)) { - ret = 0; - } else { - if (d < INT32_MIN) - ret = INT32_MIN; - else if (d > INT32_MAX) - ret = INT32_MAX; - else - ret = (int)d; - } - } - break; - default: - val = JS_ToNumberFree(ctx, val); - if (JS_IsException(val)) { - *pres = 0; - return -1; - } - goto redo; - } - *pres = ret; - return 0; -} - -int JS_ToInt32Sat(JSContext *ctx, int *pres, JSValueConst val) -{ - return JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val)); -} - -int JS_ToInt32Clamp(JSContext *ctx, int *pres, JSValueConst val, - int min, int max, int min_offset) -{ - int res = JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val)); - if (res == 0) { - if (*pres < min) { - *pres += min_offset; - if (*pres < min) - *pres = min; - } else { - if (*pres > max) - *pres = max; - } - } - return res; -} - -static int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val) -{ - uint32_t tag; - - redo: - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_INT: - case JS_TAG_BOOL: - case JS_TAG_NULL: - case JS_TAG_UNDEFINED: - *pres = JS_VALUE_GET_INT(val); - return 0; - case JS_TAG_EXCEPTION: - *pres = 0; - return -1; - case JS_TAG_FLOAT64: - { - double d = JS_VALUE_GET_FLOAT64(val); - if (isnan(d)) { - *pres = 0; - } else { - if (d < INT64_MIN) - *pres = INT64_MIN; - else if (d >= 0x1p63) /* must use INT64_MAX + 1 because INT64_MAX cannot be exactly represented as a double */ - *pres = INT64_MAX; - else - *pres = (int64_t)d; - } - } - return 0; - default: - val = JS_ToNumberFree(ctx, val); - if (JS_IsException(val)) { - *pres = 0; - return -1; - } - goto redo; - } -} - -int JS_ToInt64Sat(JSContext *ctx, int64_t *pres, JSValueConst val) -{ - return JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val)); -} - -int JS_ToInt64Clamp(JSContext *ctx, int64_t *pres, JSValueConst val, - int64_t min, int64_t max, int64_t neg_offset) -{ - int res = JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val)); - if (res == 0) { - if (*pres < 0) - *pres += neg_offset; - if (*pres < min) - *pres = min; - else if (*pres > max) - *pres = max; - } - return res; -} - -/* Same as JS_ToInt32Free() but with a 64 bit result. Return (<0, 0) - in case of exception */ -static int JS_ToInt64Free(JSContext *ctx, int64_t *pres, JSValue val) -{ - uint32_t tag; - int64_t ret; - - redo: - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_INT: - case JS_TAG_BOOL: - case JS_TAG_NULL: - case JS_TAG_UNDEFINED: - ret = JS_VALUE_GET_INT(val); - break; - case JS_TAG_FLOAT64: - { - JSFloat64Union u; - double d; - int e; - d = JS_VALUE_GET_FLOAT64(val); - u.d = d; - /* we avoid doing fmod(x, 2^64) */ - e = (u.u64 >> 52) & 0x7ff; - if (likely(e <= (1023 + 62))) { - /* fast case */ - ret = (int64_t)d; - } else if (e <= (1023 + 62 + 53)) { - uint64_t v; - /* remainder modulo 2^64 */ - v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52); - ret = v << ((e - 1023) - 52); - /* take the sign into account */ - if (u.u64 >> 63) - ret = -ret; - } else { - ret = 0; /* also handles NaN and +inf */ - } - } - break; - default: - val = JS_ToNumberFree(ctx, val); - if (JS_IsException(val)) { - *pres = 0; - return -1; - } - goto redo; - } - *pres = ret; - return 0; -} - -int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val) -{ - return JS_ToInt64Free(ctx, pres, JS_DupValue(ctx, val)); -} - -int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val) -{ - if (JS_IsBigInt(ctx, val)) - return JS_ToBigInt64(ctx, pres, val); - else - return JS_ToInt64(ctx, pres, val); -} - -/* return (<0, 0) in case of exception */ -static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val) -{ - uint32_t tag; - int32_t ret; - - redo: - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_INT: - case JS_TAG_BOOL: - case JS_TAG_NULL: - case JS_TAG_UNDEFINED: - ret = JS_VALUE_GET_INT(val); - break; - case JS_TAG_FLOAT64: - { - JSFloat64Union u; - double d; - int e; - d = JS_VALUE_GET_FLOAT64(val); - u.d = d; - /* we avoid doing fmod(x, 2^32) */ - e = (u.u64 >> 52) & 0x7ff; - if (likely(e <= (1023 + 30))) { - /* fast case */ - ret = (int32_t)d; - } else if (e <= (1023 + 30 + 53)) { - uint64_t v; - /* remainder modulo 2^32 */ - v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52); - v = v << ((e - 1023) - 52 + 32); - ret = v >> 32; - /* take the sign into account */ - if (u.u64 >> 63) - ret = -ret; - } else { - ret = 0; /* also handles NaN and +inf */ - } - } - break; - default: - val = JS_ToNumberFree(ctx, val); - if (JS_IsException(val)) { - *pres = 0; - return -1; - } - goto redo; - } - *pres = ret; - return 0; -} - -int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val) -{ - return JS_ToInt32Free(ctx, pres, JS_DupValue(ctx, val)); -} - -static inline int JS_ToUint32Free(JSContext *ctx, uint32_t *pres, JSValue val) -{ - return JS_ToInt32Free(ctx, (int32_t *)pres, val); -} - -static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val) -{ - uint32_t tag; - int res; - - redo: - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_INT: - case JS_TAG_BOOL: - case JS_TAG_NULL: - case JS_TAG_UNDEFINED: - res = JS_VALUE_GET_INT(val); - res = max_int(0, min_int(255, res)); - break; - case JS_TAG_FLOAT64: - { - double d = JS_VALUE_GET_FLOAT64(val); - if (isnan(d)) { - res = 0; - } else { - if (d < 0) - res = 0; - else if (d > 255) - res = 255; - else - res = lrint(d); - } - } - break; - default: - val = JS_ToNumberFree(ctx, val); - if (JS_IsException(val)) { - *pres = 0; - return -1; - } - goto redo; - } - *pres = res; - return 0; -} - -static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, - JSValue val, BOOL is_array_ctor) -{ - uint32_t tag, len; - - tag = JS_VALUE_GET_TAG(val); - switch(tag) { - case JS_TAG_INT: - case JS_TAG_BOOL: - case JS_TAG_NULL: - { - int v; - v = JS_VALUE_GET_INT(val); - if (v < 0) - goto fail; - len = v; - } - break; - default: - if (JS_TAG_IS_FLOAT64(tag)) { - double d; - d = JS_VALUE_GET_FLOAT64(val); - if (!(d >= 0 && d <= UINT32_MAX)) - goto fail; - len = (uint32_t)d; - if (len != d) - goto fail; - } else { - uint32_t len1; - - if (is_array_ctor) { - val = JS_ToNumberFree(ctx, val); - if (JS_IsException(val)) - return -1; - /* cannot recurse because val is a number */ - if (JS_ToArrayLengthFree(ctx, &len, val, TRUE)) - return -1; - } else { - /* legacy behavior: must do the conversion twice and compare */ - if (JS_ToUint32(ctx, &len, val)) { - JS_FreeValue(ctx, val); - return -1; - } - val = JS_ToNumberFree(ctx, val); - if (JS_IsException(val)) - return -1; - /* cannot recurse because val is a number */ - if (JS_ToArrayLengthFree(ctx, &len1, val, FALSE)) - return -1; - if (len1 != len) { - fail: - JS_ThrowRangeError(ctx, "invalid array length"); - return -1; - } - } - } - break; - } - *plen = len; - return 0; -} - -#define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1) - -static BOOL is_safe_integer(double d) -{ - return isfinite(d) && floor(d) == d && - fabs(d) <= (double)MAX_SAFE_INTEGER; -} - -int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val) -{ - int64_t v; - if (JS_ToInt64Sat(ctx, &v, val)) - return -1; - if (v < 0 || v > MAX_SAFE_INTEGER) { - JS_ThrowRangeError(ctx, "invalid array index"); - *plen = 0; - return -1; - } - *plen = v; - return 0; -} - -/* convert a value to a length between 0 and MAX_SAFE_INTEGER. - return -1 for exception */ -static __exception int JS_ToLengthFree(JSContext *ctx, int64_t *plen, - JSValue val) -{ - int res = JS_ToInt64Clamp(ctx, plen, val, 0, MAX_SAFE_INTEGER, 0); - JS_FreeValue(ctx, val); - return res; -} - -/* Note: can return an exception */ -static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val) -{ - double d; - if (!JS_IsNumber(val)) - return FALSE; - if (unlikely(JS_ToFloat64(ctx, &d, val))) - return -1; - return isfinite(d) && floor(d) == d; -} - -static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val) -{ - uint32_t tag; - - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_INT: - { - int v; - v = JS_VALUE_GET_INT(val); - return (v < 0); - } - case JS_TAG_FLOAT64: - { - JSFloat64Union u; - u.d = JS_VALUE_GET_FLOAT64(val); - return (u.u64 >> 63); - } - case JS_TAG_SHORT_BIG_INT: - return (JS_VALUE_GET_SHORT_BIG_INT(val) < 0); - case JS_TAG_BIG_INT: - { - JSBigInt *p = JS_VALUE_GET_PTR(val); - return js_bigint_sign(p); - } - default: - return FALSE; - } -} - -static JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val) -{ - return js_bigint_to_string1(ctx, val, 10); -} - -static JSValue js_dtoa2(JSContext *ctx, - double d, int radix, int n_digits, int flags) -{ - char static_buf[128], *buf, *tmp_buf; - int len, len_max; - JSValue res; - JSDTOATempMem dtoa_mem; - len_max = js_dtoa_max_len(d, radix, n_digits, flags); - - /* longer buffer may be used if radix != 10 */ - if (len_max > sizeof(static_buf) - 1) { - tmp_buf = js_malloc(ctx, len_max + 1); - if (!tmp_buf) - return JS_EXCEPTION; - buf = tmp_buf; - } else { - tmp_buf = NULL; - buf = static_buf; - } - len = js_dtoa(buf, d, radix, n_digits, flags, &dtoa_mem); - res = js_new_string8_len(ctx, buf, len); - js_free(ctx, tmp_buf); - return res; -} - -static JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToPropertyKey) -{ - uint32_t tag; - char buf[32]; - - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_STRING: - return JS_DupValue(ctx, val); - case JS_TAG_STRING_ROPE: - return js_linearize_string_rope(ctx, JS_DupValue(ctx, val)); - case JS_TAG_INT: - { - size_t len; - len = i32toa(buf, JS_VALUE_GET_INT(val)); - return js_new_string8_len(ctx, buf, len); - } - break; - case JS_TAG_BOOL: - return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ? - JS_ATOM_true : JS_ATOM_false); - case JS_TAG_NULL: - return JS_AtomToString(ctx, JS_ATOM_null); - case JS_TAG_UNDEFINED: - return JS_AtomToString(ctx, JS_ATOM_undefined); - case JS_TAG_EXCEPTION: - return JS_EXCEPTION; - case JS_TAG_OBJECT: - { - JSValue val1, ret; - val1 = JS_ToPrimitive(ctx, val, HINT_STRING); - if (JS_IsException(val1)) - return val1; - ret = JS_ToStringInternal(ctx, val1, is_ToPropertyKey); - JS_FreeValue(ctx, val1); - return ret; - } - break; - case JS_TAG_FUNCTION_BYTECODE: - return js_new_string8(ctx, "[function bytecode]"); - case JS_TAG_SYMBOL: - if (is_ToPropertyKey) { - return JS_DupValue(ctx, val); - } else { - return JS_ThrowTypeError(ctx, "cannot convert symbol to string"); - } - case JS_TAG_FLOAT64: - return js_dtoa2(ctx, JS_VALUE_GET_FLOAT64(val), 10, 0, - JS_DTOA_FORMAT_FREE); - case JS_TAG_SHORT_BIG_INT: - case JS_TAG_BIG_INT: - return js_bigint_to_string(ctx, val); - default: - return js_new_string8(ctx, "[unsupported type]"); - } -} - -JSValue JS_ToString(JSContext *ctx, JSValueConst val) -{ - return JS_ToStringInternal(ctx, val, FALSE); -} - -static JSValue JS_ToStringFree(JSContext *ctx, JSValue val) -{ - JSValue ret; - ret = JS_ToString(ctx, val); - JS_FreeValue(ctx, val); - return ret; -} - -static JSValue JS_ToLocaleStringFree(JSContext *ctx, JSValue val) -{ - if (JS_IsUndefined(val) || JS_IsNull(val)) - return JS_ToStringFree(ctx, val); - return JS_InvokeFree(ctx, val, JS_ATOM_toLocaleString, 0, NULL); -} - -JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val) -{ - return JS_ToStringInternal(ctx, val, TRUE); -} - -static JSValue JS_ToStringCheckObject(JSContext *ctx, JSValueConst val) -{ - uint32_t tag = JS_VALUE_GET_TAG(val); - if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) - return JS_ThrowTypeError(ctx, "null or undefined are forbidden"); - return JS_ToString(ctx, val); -} - -static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1) -{ - JSValue val; - JSString *p; - int i; - uint32_t c; - StringBuffer b_s, *b = &b_s; - char buf[16]; - - val = JS_ToStringCheckObject(ctx, val1); - if (JS_IsException(val)) - return val; - p = JS_VALUE_GET_STRING(val); - - if (string_buffer_init(ctx, b, p->len + 2)) - goto fail; - - if (string_buffer_putc8(b, '\"')) - goto fail; - for(i = 0; i < p->len; ) { - c = string_getc(p, &i); - switch(c) { - case '\t': - c = 't'; - goto quote; - case '\r': - c = 'r'; - goto quote; - case '\n': - c = 'n'; - goto quote; - case '\b': - c = 'b'; - goto quote; - case '\f': - c = 'f'; - goto quote; - case '\"': - case '\\': - quote: - if (string_buffer_putc8(b, '\\')) - goto fail; - if (string_buffer_putc8(b, c)) - goto fail; - break; - default: - if (c < 32 || is_surrogate(c)) { - snprintf(buf, sizeof(buf), "\\u%04x", c); - if (string_buffer_puts8(b, buf)) - goto fail; - } else { - if (string_buffer_putc(b, c)) - goto fail; - } - break; - } - } - if (string_buffer_putc8(b, '\"')) - goto fail; - JS_FreeValue(ctx, val); - return string_buffer_end(b); - fail: - JS_FreeValue(ctx, val); - string_buffer_free(b); - return JS_EXCEPTION; -} - -#define JS_PRINT_MAX_DEPTH 8 - -typedef struct { - JSRuntime *rt; - JSContext *ctx; /* may be NULL */ - JSPrintValueOptions options; - JSPrintValueWrite *write_func; - void *write_opaque; - int level; - JSObject *print_stack[JS_PRINT_MAX_DEPTH]; /* level values */ -} JSPrintValueState; - -static void js_print_value(JSPrintValueState *s, JSValueConst val); - -static void js_putc(JSPrintValueState *s, char c) -{ - s->write_func(s->write_opaque, &c, 1); -} - -static void js_puts(JSPrintValueState *s, const char *str) -{ - s->write_func(s->write_opaque, str, strlen(str)); -} - -static void __attribute__((format(printf, 2, 3))) js_printf(JSPrintValueState *s, const char *fmt, ...) -{ - va_list ap; - char buf[256]; - - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - s->write_func(s->write_opaque, buf, strlen(buf)); -} - -static void js_print_float64(JSPrintValueState *s, double d) -{ - JSDTOATempMem dtoa_mem; - char buf[32]; - int len; - len = js_dtoa(buf, d, 10, 0, JS_DTOA_FORMAT_FREE | JS_DTOA_MINUS_ZERO, &dtoa_mem); - s->write_func(s->write_opaque, buf, len); -} - -static uint32_t js_string_get_length(JSValueConst val) -{ - if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) { - JSString *p = JS_VALUE_GET_STRING(val); - return p->len; - } else if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING_ROPE) { - JSStringRope *r = JS_VALUE_GET_PTR(val); - return r->len; - } else { - return 0; - } -} - -static void js_dump_char(JSPrintValueState *s, int c, int sep) -{ - if (c == sep || c == '\\') { - js_putc(s, '\\'); - js_putc(s, c); - } else if (c >= ' ' && c <= 126) { - js_putc(s, c); - } else if (c == '\n') { - js_putc(s, '\\'); - js_putc(s, 'n'); - } else { - js_printf(s, "\\u%04x", c); - } -} - -static void js_print_string_rec(JSPrintValueState *s, JSValueConst val, - int sep, uint32_t pos) -{ - if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) { - JSString *p = JS_VALUE_GET_STRING(val); - uint32_t i, len; - if (pos < s->options.max_string_length) { - len = min_uint32(p->len, s->options.max_string_length - pos); - for(i = 0; i < len; i++) { - js_dump_char(s, string_get(p, i), sep); - } - } - } else if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING_ROPE) { - JSStringRope *r = JS_VALUE_GET_PTR(val); - js_print_string_rec(s, r->left, sep, pos); - js_print_string_rec(s, r->right, sep, pos + js_string_get_length(r->left)); - } else { - js_printf(s, "", (int)JS_VALUE_GET_TAG(val)); - } -} - -static void js_print_string(JSPrintValueState *s, JSValueConst val) -{ - int sep; - if (s->options.raw_dump && JS_VALUE_GET_TAG(val) == JS_TAG_STRING) { - JSString *p = JS_VALUE_GET_STRING(val); - js_printf(s, "%d", p->header.ref_count); - sep = (p->header.ref_count == 1) ? '\"' : '\''; - } else { - sep = '\"'; - } - js_putc(s, sep); - js_print_string_rec(s, val, sep, 0); - js_putc(s, sep); - if (js_string_get_length(val) > s->options.max_string_length) { - uint32_t n = js_string_get_length(val) - s->options.max_string_length; - js_printf(s, "... %u more character%s", n, n > 1 ? "s" : ""); - } -} - -static void js_print_raw_string2(JSPrintValueState *s, JSValueConst val, BOOL remove_last_lf) -{ - const char *cstr; - size_t len; - cstr = JS_ToCStringLen(s->ctx, &len, val); - if (cstr) { - if (remove_last_lf && len > 0 && cstr[len - 1] == '\n') - len--; - s->write_func(s->write_opaque, cstr, len); - JS_FreeCString(s->ctx, cstr); - } -} - -static void js_print_raw_string(JSPrintValueState *s, JSValueConst val) -{ - js_print_raw_string2(s, val, FALSE); -} - -static BOOL is_ascii_ident(const JSString *p) -{ - int i, c; - - if (p->len == 0) - return FALSE; - for(i = 0; i < p->len; i++) { - c = string_get(p, i); - if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || - (c == '_' || c == '$') || (c >= '0' && c <= '9' && i > 0))) - return FALSE; - } - return TRUE; -} - -static void js_print_atom(JSPrintValueState *s, JSAtom atom) -{ - int i; - if (__JS_AtomIsTaggedInt(atom)) { - js_printf(s, "%u", __JS_AtomToUInt32(atom)); - } else if (atom == JS_ATOM_NULL) { - js_puts(s, ""); - } else { - assert(atom < s->rt->atom_size); - JSString *p; - p = s->rt->atom_array[atom]; - if (is_ascii_ident(p)) { - for(i = 0; i < p->len; i++) { - js_putc(s, string_get(p, i)); - } - } else { - js_putc(s, '"'); - for(i = 0; i < p->len; i++) { - js_dump_char(s, string_get(p, i), '\"'); - } - js_putc(s, '"'); - } - } -} - -/* return 0 if invalid length */ -static uint32_t js_print_array_get_length(JSObject *p) -{ - JSProperty *pr; - JSShapeProperty *prs; - JSValueConst val; - - prs = find_own_property(&pr, p, JS_ATOM_length); - if (!prs) - return 0; - if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL) - return 0; - val = pr->u.value; - switch(JS_VALUE_GET_NORM_TAG(val)) { - case JS_TAG_INT: - return JS_VALUE_GET_INT(val); - case JS_TAG_FLOAT64: - return (uint32_t)JS_VALUE_GET_FLOAT64(val); - default: - return 0; - } -} - -static void js_print_comma(JSPrintValueState *s, int *pcomma_state) -{ - switch(*pcomma_state) { - case 0: - break; - case 1: - js_printf(s, ", "); - break; - case 2: - js_printf(s, " { "); - break; - } - *pcomma_state = 1; -} - -static void js_print_more_items(JSPrintValueState *s, int *pcomma_state, - uint32_t n) -{ - js_print_comma(s, pcomma_state); - js_printf(s, "... %u more item%s", n, n > 1 ? "s" : ""); -} - -static void js_print_object(JSPrintValueState *s, JSObject *p) -{ - JSRuntime *rt = s->rt; - JSShape *sh; - JSShapeProperty *prs; - JSProperty *pr; - int comma_state; - BOOL is_array; - uint32_t i; - - comma_state = 0; - is_array = FALSE; - if (p->class_id == JS_CLASS_ARRAY) { - is_array = TRUE; - js_printf(s, "[ "); - /* XXX: print array like properties even if not fast array */ - if (p->fast_array) { - uint32_t len, n, len1; - len = js_print_array_get_length(p); - - len1 = min_uint32(p->u.array.count, s->options.max_item_count); - for(i = 0; i < len1; i++) { - js_print_comma(s, &comma_state); - js_print_value(s, p->u.array.u.values[i]); - } - if (len1 < p->u.array.count) - js_print_more_items(s, &comma_state, p->u.array.count - len1); - if (p->u.array.count < len) { - n = len - p->u.array.count; - js_print_comma(s, &comma_state); - js_printf(s, "<%u empty item%s>", n, n > 1 ? "s" : ""); - } - } - } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) { - uint32_t size = 1 << typed_array_size_log2(p->class_id); - uint32_t len1; - int64_t v; - - js_print_atom(s, rt->class_array[p->class_id].class_name); - js_printf(s, "(%u) [ ", p->u.array.count); - - is_array = TRUE; - len1 = min_uint32(p->u.array.count, s->options.max_item_count); - for(i = 0; i < len1; i++) { - const uint8_t *ptr = p->u.array.u.uint8_ptr + i * size; - js_print_comma(s, &comma_state); - switch(p->class_id) { - case JS_CLASS_UINT8C_ARRAY: - case JS_CLASS_UINT8_ARRAY: - v = *ptr; - goto ta_int64; - case JS_CLASS_INT8_ARRAY: - v = *(int8_t *)ptr; - goto ta_int64; - case JS_CLASS_INT16_ARRAY: - v = *(int16_t *)ptr; - goto ta_int64; - case JS_CLASS_UINT16_ARRAY: - v = *(uint16_t *)ptr; - goto ta_int64; - case JS_CLASS_INT32_ARRAY: - v = *(int32_t *)ptr; - goto ta_int64; - case JS_CLASS_UINT32_ARRAY: - v = *(uint32_t *)ptr; - goto ta_int64; - case JS_CLASS_BIG_INT64_ARRAY: - v = *(int64_t *)ptr; - ta_int64: - js_printf(s, "%" PRId64, v); - break; - case JS_CLASS_BIG_UINT64_ARRAY: - js_printf(s, "%" PRIu64, *(uint64_t *)ptr); - break; - case JS_CLASS_FLOAT16_ARRAY: - js_print_float64(s, fromfp16(*(uint16_t *)ptr)); - break; - case JS_CLASS_FLOAT32_ARRAY: - js_print_float64(s, *(float *)ptr); - break; - case JS_CLASS_FLOAT64_ARRAY: - js_print_float64(s, *(double *)ptr); - break; - } - } - if (len1 < p->u.array.count) - js_print_more_items(s, &comma_state, p->u.array.count - len1); - } else if (p->class_id == JS_CLASS_BYTECODE_FUNCTION || - (rt->class_array[p->class_id].call != NULL && - p->class_id != JS_CLASS_PROXY)) { - js_printf(s, "[Function"); - /* XXX: allow dump without ctx */ - if (!s->options.raw_dump && s->ctx) { - const char *func_name_str; - js_putc(s, ' '); - func_name_str = get_func_name(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p)); - if (!func_name_str || func_name_str[0] == '\0') - js_puts(s, "(anonymous)"); - else - js_puts(s, func_name_str); - JS_FreeCString(s->ctx, func_name_str); - } - js_printf(s, "]"); - comma_state = 2; - } else if (p->class_id == JS_CLASS_MAP || p->class_id == JS_CLASS_SET) { - JSMapState *ms = p->u.opaque; - struct list_head *el; - - if (!ms) - goto default_obj; - js_print_atom(s, rt->class_array[p->class_id].class_name); - js_printf(s, "(%u) { ", ms->record_count); - i = 0; - list_for_each(el, &ms->records) { - JSMapRecord *mr = list_entry(el, JSMapRecord, link); - js_print_comma(s, &comma_state); - if (mr->empty) - continue; - js_print_value(s, mr->key); - if (p->class_id == JS_CLASS_MAP) { - js_printf(s, " => "); - js_print_value(s, mr->value); - } - i++; - if (i >= s->options.max_item_count) - break; - } - if (i < ms->record_count) - js_print_more_items(s, &comma_state, ms->record_count - i); - } else if (p->class_id == JS_CLASS_REGEXP && s->ctx && !s->options.raw_dump) { - JSValue str = js_regexp_toString(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), 0, NULL); - if (JS_IsException(str)) - goto default_obj; - js_print_raw_string(s, str); - JS_FreeValueRT(s->rt, str); - comma_state = 2; - } else if (p->class_id == JS_CLASS_DATE && s->ctx && !s->options.raw_dump) { - JSValue str = get_date_string(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), 0, NULL, 0x23); /* toISOString() */ - if (JS_IsException(str)) - goto default_obj; - js_print_raw_string(s, str); - JS_FreeValueRT(s->rt, str); - comma_state = 2; - } else if (p->class_id == JS_CLASS_ERROR && s->ctx && !s->options.raw_dump) { - JSValue str = js_error_toString(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), 0, NULL); - if (JS_IsException(str)) - goto default_obj; - js_print_raw_string(s, str); - JS_FreeValueRT(s->rt, str); - /* dump the stack if present */ - str = JS_GetProperty(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), JS_ATOM_stack); - if (JS_IsString(str)) { - js_putc(s, '\n'); - /* XXX: should remove the last '\n' in stack as - v8. SpiderMonkey does not do it */ - js_print_raw_string2(s, str, TRUE); - } - JS_FreeValueRT(s->rt, str); - comma_state = 2; - } else { - default_obj: - if (p->class_id != JS_CLASS_OBJECT) { - js_print_atom(s, rt->class_array[p->class_id].class_name); - js_printf(s, " "); - } - js_printf(s, "{ "); - } - - sh = p->shape; /* the shape can be NULL while freeing an object */ - if (sh) { - uint32_t j; - - j = 0; - for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { - if (prs->atom != JS_ATOM_NULL) { - if (!(prs->flags & JS_PROP_ENUMERABLE) && - !s->options.show_hidden) { - continue; - } - if (j < s->options.max_item_count) { - pr = &p->prop[i]; - js_print_comma(s, &comma_state); - js_print_atom(s, prs->atom); - js_printf(s, ": "); - - /* XXX: autoinit property */ - if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { - if (s->options.raw_dump) { - js_printf(s, "[Getter %p Setter %p]", - pr->u.getset.getter, pr->u.getset.setter); - } else { - if (pr->u.getset.getter && pr->u.getset.setter) { - js_printf(s, "[Getter/Setter]"); - } else if (pr->u.getset.setter) { - js_printf(s, "[Setter]"); - } else { - js_printf(s, "[Getter]"); - } - } - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { - if (s->options.raw_dump) { - js_printf(s, "[varref %p]", (void *)pr->u.var_ref); - } else { - js_print_value(s, *pr->u.var_ref->pvalue); - } - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { - if (s->options.raw_dump) { - js_printf(s, "[autoinit %p %d %p]", - (void *)js_autoinit_get_realm(pr), - js_autoinit_get_id(pr), - (void *)pr->u.init.opaque); - } else { - /* XXX: could autoinit but need to restart - the iteration */ - js_printf(s, "[autoinit]"); - } - } else { - js_print_value(s, pr->u.value); - } - } - j++; - } - } - if (j > s->options.max_item_count) - js_print_more_items(s, &comma_state, j - s->options.max_item_count); - } - if (s->options.raw_dump && js_class_has_bytecode(p->class_id)) { - JSFunctionBytecode *b = p->u.func.function_bytecode; - if (b->closure_var_count) { - JSVarRef **var_refs; - var_refs = p->u.func.var_refs; - - js_print_comma(s, &comma_state); - js_printf(s, "[[Closure]]: ["); - for(i = 0; i < b->closure_var_count; i++) { - if (i != 0) - js_printf(s, ", "); - js_print_value(s, var_refs[i]->value); - } - js_printf(s, " ]"); - } - if (p->u.func.home_object) { - js_print_comma(s, &comma_state); - js_printf(s, "[[HomeObject]]: "); - js_print_value(s, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object)); - } - } - - if (!is_array) { - if (comma_state != 2) { - js_printf(s, " }"); - } - } else { - js_printf(s, " ]"); - } -} - -static int js_print_stack_index(JSPrintValueState *s, JSObject *p) -{ - int i; - for(i = 0; i < s->level; i++) - if (s->print_stack[i] == p) - return i; - return -1; -} - -static void js_print_value(JSPrintValueState *s, JSValueConst val) -{ - uint32_t tag = JS_VALUE_GET_NORM_TAG(val); - const char *str; - - switch(tag) { - case JS_TAG_INT: - js_printf(s, "%d", JS_VALUE_GET_INT(val)); - break; - case JS_TAG_BOOL: - if (JS_VALUE_GET_BOOL(val)) - str = "true"; - else - str = "false"; - goto print_str; - case JS_TAG_NULL: - str = "null"; - goto print_str; - case JS_TAG_EXCEPTION: - str = "exception"; - goto print_str; - case JS_TAG_UNINITIALIZED: - str = "uninitialized"; - goto print_str; - case JS_TAG_UNDEFINED: - str = "undefined"; - print_str: - js_puts(s, str); - break; - case JS_TAG_FLOAT64: - js_print_float64(s, JS_VALUE_GET_FLOAT64(val)); - break; - case JS_TAG_SHORT_BIG_INT: - js_printf(s, "%" PRId64 "n", (int64_t)JS_VALUE_GET_SHORT_BIG_INT(val)); - break; - case JS_TAG_BIG_INT: - if (!s->options.raw_dump && s->ctx) { - JSValue str = js_bigint_to_string(s->ctx, val); - if (JS_IsException(str)) - goto raw_bigint; - js_print_raw_string(s, str); - js_putc(s, 'n'); - JS_FreeValueRT(s->rt, str); - } else { - JSBigInt *p; - int sgn, i; - raw_bigint: - p = JS_VALUE_GET_PTR(val); - /* In order to avoid allocations we just dump the limbs */ - sgn = js_bigint_sign(p); - if (sgn) - js_printf(s, "BigInt.asIntN(%d,", p->len * JS_LIMB_BITS); - js_printf(s, "0x"); - for(i = p->len - 1; i >= 0; i--) { - if (i != p->len - 1) - js_putc(s, '_'); -#if JS_LIMB_BITS == 32 - js_printf(s, "%08x", p->tab[i]); -#else - js_printf(s, "%016" PRIx64, p->tab[i]); -#endif - } - js_putc(s, 'n'); - if (sgn) - js_putc(s, ')'); - } - break; - case JS_TAG_STRING: - case JS_TAG_STRING_ROPE: - if (s->options.raw_dump && tag == JS_TAG_STRING_ROPE) { - JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val); - js_printf(s, "[rope len=%d depth=%d]", r->len, r->depth); - } else { - js_print_string(s, val); - } - break; - case JS_TAG_FUNCTION_BYTECODE: - { - JSFunctionBytecode *b = JS_VALUE_GET_PTR(val); - js_puts(s, "[bytecode "); - js_print_atom(s, b->func_name); - js_putc(s, ']'); - } - break; - case JS_TAG_OBJECT: - { - JSObject *p = JS_VALUE_GET_OBJ(val); - int idx; - idx = js_print_stack_index(s, p); - if (idx >= 0) { - js_printf(s, "[circular %d]", idx); - } else if (s->level < s->options.max_depth) { - s->print_stack[s->level++] = p; - js_print_object(s, JS_VALUE_GET_OBJ(val)); - s->level--; - } else { - JSAtom atom = s->rt->class_array[p->class_id].class_name; - js_putc(s, '['); - js_print_atom(s, atom); - if (s->options.raw_dump) { - js_printf(s, " %p", (void *)p); - } - js_putc(s, ']'); - } - } - break; - case JS_TAG_SYMBOL: - { - JSAtomStruct *p = JS_VALUE_GET_PTR(val); - js_puts(s, "Symbol("); - js_print_atom(s, js_get_atom_index(s->rt, p)); - js_putc(s, ')'); - } - break; - case JS_TAG_MODULE: - js_puts(s, "[module]"); - break; - default: - js_printf(s, "[unknown tag %d]", tag); - break; - } -} - -void JS_PrintValueSetDefaultOptions(JSPrintValueOptions *options) -{ - memset(options, 0, sizeof(*options)); - options->max_depth = 2; - options->max_string_length = 1000; - options->max_item_count = 100; -} - -static void JS_PrintValueInternal(JSRuntime *rt, JSContext *ctx, - JSPrintValueWrite *write_func, void *write_opaque, - JSValueConst val, const JSPrintValueOptions *options) -{ - JSPrintValueState ss, *s = &ss; - if (options) - s->options = *options; - else - JS_PrintValueSetDefaultOptions(&s->options); - if (s->options.max_depth <= 0) - s->options.max_depth = JS_PRINT_MAX_DEPTH; - else - s->options.max_depth = min_int(s->options.max_depth, JS_PRINT_MAX_DEPTH); - if (s->options.max_string_length == 0) - s->options.max_string_length = UINT32_MAX; - if (s->options.max_item_count == 0) - s->options.max_item_count = UINT32_MAX; - s->rt = rt; - s->ctx = ctx; - s->write_func = write_func; - s->write_opaque = write_opaque; - s->level = 0; - js_print_value(s, val); -} - -void JS_PrintValueRT(JSRuntime *rt, JSPrintValueWrite *write_func, void *write_opaque, - JSValueConst val, const JSPrintValueOptions *options) -{ - JS_PrintValueInternal(rt, NULL, write_func, write_opaque, val, options); -} - -void JS_PrintValue(JSContext *ctx, JSPrintValueWrite *write_func, void *write_opaque, - JSValueConst val, const JSPrintValueOptions *options) -{ - JS_PrintValueInternal(ctx->rt, ctx, write_func, write_opaque, val, options); -} - -static void js_dump_value_write(void *opaque, const char *buf, size_t len) -{ - FILE *fo = opaque; - fwrite(buf, 1, len, fo); -} - -static __maybe_unused void print_atom(JSContext *ctx, JSAtom atom) -{ - JSPrintValueState ss, *s = &ss; - memset(s, 0, sizeof(*s)); - s->rt = ctx->rt; - s->ctx = ctx; - s->write_func = js_dump_value_write; - s->write_opaque = stdout; - js_print_atom(s, atom); -} - -static __maybe_unused void JS_DumpValue(JSContext *ctx, const char *str, JSValueConst val) -{ - printf("%s=", str); - JS_PrintValue(ctx, js_dump_value_write, stdout, val, NULL); - printf("\n"); -} - -static __maybe_unused void JS_DumpValueRT(JSRuntime *rt, const char *str, JSValueConst val) -{ - printf("%s=", str); - JS_PrintValueRT(rt, js_dump_value_write, stdout, val, NULL); - printf("\n"); -} - -static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt) -{ - printf("%14s %4s %4s %14s %s\n", - "ADDRESS", "REFS", "SHRF", "PROTO", "CONTENT"); -} - -/* for debug only: dump an object without side effect */ -static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p) -{ - JSShape *sh; - JSPrintValueOptions options; - - /* XXX: should encode atoms with special characters */ - sh = p->shape; /* the shape can be NULL while freeing an object */ - printf("%14p %4d ", - (void *)p, - p->header.ref_count); - if (sh) { - printf("%3d%c %14p ", - sh->header.ref_count, - " *"[sh->is_hashed], - (void *)sh->proto); - } else { - printf("%3s %14s ", "-", "-"); - } - - JS_PrintValueSetDefaultOptions(&options); - options.max_depth = 1; - options.show_hidden = TRUE; - options.raw_dump = TRUE; - JS_PrintValueRT(rt, js_dump_value_write, stdout, JS_MKPTR(JS_TAG_OBJECT, p), &options); - - printf("\n"); -} - -static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p) -{ - if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) { - JS_DumpObject(rt, (JSObject *)p); - } else { - printf("%14p %4d ", - (void *)p, - p->ref_count); - switch(p->gc_obj_type) { - case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: - printf("[function bytecode]"); - break; - case JS_GC_OBJ_TYPE_SHAPE: - printf("[shape]"); - break; - case JS_GC_OBJ_TYPE_VAR_REF: - printf("[var_ref]"); - break; - case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: - printf("[async_function]"); - break; - case JS_GC_OBJ_TYPE_JS_CONTEXT: - printf("[js_context]"); - break; - case JS_GC_OBJ_TYPE_MODULE: - printf("[module]"); - break; - default: - printf("[unknown %d]", p->gc_obj_type); - break; - } - printf("\n"); - } -} - -/* return -1 if exception (proxy case) or TRUE/FALSE */ -// TODO: should take flags to make proxy resolution and exceptions optional -int JS_IsArray(JSContext *ctx, JSValueConst val) -{ - if (js_resolve_proxy(ctx, &val, TRUE)) - return -1; - if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(val); - return p->class_id == JS_CLASS_ARRAY; - } else { - return FALSE; - } -} - -static double js_pow(double a, double b) -{ - if (unlikely(!isfinite(b)) && fabs(a) == 1) { - /* not compatible with IEEE 754 */ - return JS_FLOAT64_NAN; - } else { - return pow(a, b); - } -} - -JSValue JS_NewBigInt64(JSContext *ctx, int64_t v) -{ -#if JS_SHORT_BIG_INT_BITS == 64 - return __JS_NewShortBigInt(ctx, v); -#else - if (v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX) { - return __JS_NewShortBigInt(ctx, v); - } else { - JSBigInt *p; - p = js_bigint_new_si64(ctx, v); - if (!p) - return JS_EXCEPTION; - return JS_MKPTR(JS_TAG_BIG_INT, p); - } -#endif -} - -JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v) -{ - if (v <= JS_SHORT_BIG_INT_MAX) { - return __JS_NewShortBigInt(ctx, v); - } else { - JSBigInt *p; - p = js_bigint_new_ui64(ctx, v); - if (!p) - return JS_EXCEPTION; - return JS_MKPTR(JS_TAG_BIG_INT, p); - } -} - -/* return NaN if bad bigint literal */ -static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val) -{ - const char *str, *p; - size_t len; - int flags; - - str = JS_ToCStringLen(ctx, &len, val); - JS_FreeValue(ctx, val); - if (!str) - return JS_EXCEPTION; - p = str; - p += skip_spaces(p); - if ((p - str) == len) { - val = JS_NewBigInt64(ctx, 0); - } else { - flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT; - val = js_atof(ctx, p, &p, 0, flags); - p += skip_spaces(p); - if (!JS_IsException(val)) { - if ((p - str) != len) { - JS_FreeValue(ctx, val); - val = JS_NAN; - } - } - } - JS_FreeCString(ctx, str); - return val; -} - -static JSValue JS_StringToBigIntErr(JSContext *ctx, JSValue val) -{ - val = JS_StringToBigInt(ctx, val); - if (JS_VALUE_IS_NAN(val)) - return JS_ThrowSyntaxError(ctx, "invalid bigint literal"); - return val; -} - -/* JS Numbers are not allowed */ -static JSValue JS_ToBigIntFree(JSContext *ctx, JSValue val) -{ - uint32_t tag; - - redo: - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_SHORT_BIG_INT: - case JS_TAG_BIG_INT: - break; - case JS_TAG_INT: - case JS_TAG_NULL: - case JS_TAG_UNDEFINED: - case JS_TAG_FLOAT64: - goto fail; - case JS_TAG_BOOL: - val = __JS_NewShortBigInt(ctx, JS_VALUE_GET_INT(val)); - break; - case JS_TAG_STRING: - case JS_TAG_STRING_ROPE: - val = JS_StringToBigIntErr(ctx, val); - if (JS_IsException(val)) - return val; - goto redo; - case JS_TAG_OBJECT: - val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER); - if (JS_IsException(val)) - return val; - goto redo; - default: - fail: - JS_FreeValue(ctx, val); - return JS_ThrowTypeError(ctx, "cannot convert to bigint"); - } - return val; -} - -static JSValue JS_ToBigInt(JSContext *ctx, JSValueConst val) -{ - return JS_ToBigIntFree(ctx, JS_DupValue(ctx, val)); -} - -/* XXX: merge with JS_ToInt64Free with a specific flag ? */ -static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val) -{ - uint64_t res; - - val = JS_ToBigIntFree(ctx, val); - if (JS_IsException(val)) { - *pres = 0; - return -1; - } - if (JS_VALUE_GET_TAG(val) == JS_TAG_SHORT_BIG_INT) { - res = JS_VALUE_GET_SHORT_BIG_INT(val); - } else { - JSBigInt *p = JS_VALUE_GET_PTR(val); - /* return the value mod 2^64 */ - res = p->tab[0]; -#if JS_LIMB_BITS == 32 - if (p->len >= 2) - res |= (uint64_t)p->tab[1] << 32; -#endif - JS_FreeValue(ctx, val); - } - *pres = res; - return 0; -} - -int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val) -{ - return JS_ToBigInt64Free(ctx, pres, JS_DupValue(ctx, val)); -} - -static no_inline __exception int js_unary_arith_slow(JSContext *ctx, - JSValue *sp, - OPCodeEnum op) -{ - JSValue op1; - int v; - uint32_t tag; - JSBigIntBuf buf1; - JSBigInt *p1; - - op1 = sp[-1]; - /* fast path for float64 */ - if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1))) - goto handle_float64; - op1 = JS_ToNumericFree(ctx, op1); - if (JS_IsException(op1)) - goto exception; - tag = JS_VALUE_GET_TAG(op1); - switch(tag) { - case JS_TAG_INT: - { - int64_t v64; - v64 = JS_VALUE_GET_INT(op1); - switch(op) { - case OP_inc: - case OP_dec: - v = 2 * (op - OP_dec) - 1; - v64 += v; - break; - case OP_plus: - break; - case OP_neg: - if (v64 == 0) { - sp[-1] = __JS_NewFloat64(ctx, -0.0); - return 0; - } else { - v64 = -v64; - } - break; - default: - abort(); - } - sp[-1] = JS_NewInt64(ctx, v64); - } - break; - case JS_TAG_SHORT_BIG_INT: - { - int64_t v; - v = JS_VALUE_GET_SHORT_BIG_INT(op1); - switch(op) { - case OP_plus: - JS_ThrowTypeError(ctx, "bigint argument with unary +"); - goto exception; - case OP_inc: - if (v == JS_SHORT_BIG_INT_MAX) - goto bigint_slow_case; - sp[-1] = __JS_NewShortBigInt(ctx, v + 1); - break; - case OP_dec: - if (v == JS_SHORT_BIG_INT_MIN) - goto bigint_slow_case; - sp[-1] = __JS_NewShortBigInt(ctx, v - 1); - break; - case OP_neg: - v = JS_VALUE_GET_SHORT_BIG_INT(op1); - if (v == JS_SHORT_BIG_INT_MIN) { - bigint_slow_case: - p1 = js_bigint_set_short(&buf1, op1); - goto bigint_slow_case1; - } - sp[-1] = __JS_NewShortBigInt(ctx, -v); - break; - default: - abort(); - } - } - break; - case JS_TAG_BIG_INT: - { - JSBigInt *r; - p1 = JS_VALUE_GET_PTR(op1); - bigint_slow_case1: - switch(op) { - case OP_plus: - JS_ThrowTypeError(ctx, "bigint argument with unary +"); - JS_FreeValue(ctx, op1); - goto exception; - case OP_inc: - case OP_dec: - { - JSBigIntBuf buf2; - JSBigInt *p2; - p2 = js_bigint_set_si(&buf2, 2 * (op - OP_dec) - 1); - r = js_bigint_add(ctx, p1, p2, 0); - } - break; - case OP_neg: - r = js_bigint_neg(ctx, p1); - break; - case OP_not: - r = js_bigint_not(ctx, p1); - break; - default: - abort(); - } - JS_FreeValue(ctx, op1); - if (!r) - goto exception; - sp[-1] = JS_CompactBigInt(ctx, r); - } - break; - default: - handle_float64: - { - double d; - d = JS_VALUE_GET_FLOAT64(op1); - switch(op) { - case OP_inc: - case OP_dec: - v = 2 * (op - OP_dec) - 1; - d += v; - break; - case OP_plus: - break; - case OP_neg: - d = -d; - break; - default: - abort(); - } - sp[-1] = __JS_NewFloat64(ctx, d); - } - break; - } - return 0; - exception: - sp[-1] = JS_UNDEFINED; - return -1; -} - -static __exception int js_post_inc_slow(JSContext *ctx, - JSValue *sp, OPCodeEnum op) -{ - JSValue op1; - - /* XXX: allow custom operators */ - op1 = sp[-1]; - op1 = JS_ToNumericFree(ctx, op1); - if (JS_IsException(op1)) { - sp[-1] = JS_UNDEFINED; - return -1; - } - sp[-1] = op1; - sp[0] = JS_DupValue(ctx, op1); - return js_unary_arith_slow(ctx, sp + 1, op - OP_post_dec + OP_dec); -} - -static no_inline int js_not_slow(JSContext *ctx, JSValue *sp) -{ - JSValue op1; - - op1 = sp[-1]; - op1 = JS_ToNumericFree(ctx, op1); - if (JS_IsException(op1)) - goto exception; - if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT) { - sp[-1] = __JS_NewShortBigInt(ctx, ~JS_VALUE_GET_SHORT_BIG_INT(op1)); - } else if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) { - JSBigInt *r; - r = js_bigint_not(ctx, JS_VALUE_GET_PTR(op1)); - JS_FreeValue(ctx, op1); - if (!r) - goto exception; - sp[-1] = JS_CompactBigInt(ctx, r); - } else { - int32_t v1; - if (unlikely(JS_ToInt32Free(ctx, &v1, op1))) - goto exception; - sp[-1] = JS_NewInt32(ctx, ~v1); - } - return 0; - exception: - sp[-1] = JS_UNDEFINED; - return -1; -} - -static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp, - OPCodeEnum op) -{ - JSValue op1, op2; - uint32_t tag1, tag2; - double d1, d2; - - op1 = sp[-2]; - op2 = sp[-1]; - tag1 = JS_VALUE_GET_NORM_TAG(op1); - tag2 = JS_VALUE_GET_NORM_TAG(op2); - /* fast path for float operations */ - if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) { - d1 = JS_VALUE_GET_FLOAT64(op1); - d2 = JS_VALUE_GET_FLOAT64(op2); - goto handle_float64; - } - /* fast path for short big int operations */ - if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) { - js_slimb_t v1, v2; - js_sdlimb_t v; - v1 = JS_VALUE_GET_SHORT_BIG_INT(op1); - v2 = JS_VALUE_GET_SHORT_BIG_INT(op2); - switch(op) { - case OP_sub: - v = (js_sdlimb_t)v1 - (js_sdlimb_t)v2; - break; - case OP_mul: - v = (js_sdlimb_t)v1 * (js_sdlimb_t)v2; - break; - case OP_div: - if (v2 == 0 || - ((js_limb_t)v1 == (js_limb_t)1 << (JS_LIMB_BITS - 1) && - v2 == -1)) { - goto slow_big_int; - } - sp[-2] = __JS_NewShortBigInt(ctx, v1 / v2); - return 0; - case OP_mod: - if (v2 == 0 || - ((js_limb_t)v1 == (js_limb_t)1 << (JS_LIMB_BITS - 1) && - v2 == -1)) { - goto slow_big_int; - } - sp[-2] = __JS_NewShortBigInt(ctx, v1 % v2); - return 0; - case OP_pow: - goto slow_big_int; - default: - abort(); - } - if (likely(v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX)) { - sp[-2] = __JS_NewShortBigInt(ctx, v); - } else { - JSBigInt *r = js_bigint_new_di(ctx, v); - if (!r) - goto exception; - sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r); - } - return 0; - } - op1 = JS_ToNumericFree(ctx, op1); - if (JS_IsException(op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - op2 = JS_ToNumericFree(ctx, op2); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - goto exception; - } - tag1 = JS_VALUE_GET_NORM_TAG(op1); - tag2 = JS_VALUE_GET_NORM_TAG(op2); - - if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) { - int32_t v1, v2; - int64_t v; - v1 = JS_VALUE_GET_INT(op1); - v2 = JS_VALUE_GET_INT(op2); - switch(op) { - case OP_sub: - v = (int64_t)v1 - (int64_t)v2; - break; - case OP_mul: - v = (int64_t)v1 * (int64_t)v2; - if (v == 0 && (v1 | v2) < 0) { - sp[-2] = __JS_NewFloat64(ctx, -0.0); - return 0; - } - break; - case OP_div: - sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2); - return 0; - case OP_mod: - if (v1 < 0 || v2 <= 0) { - sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2)); - return 0; - } else { - v = (int64_t)v1 % (int64_t)v2; - } - break; - case OP_pow: - sp[-2] = JS_NewFloat64(ctx, js_pow(v1, v2)); - return 0; - default: - abort(); - } - sp[-2] = JS_NewInt64(ctx, v); - } else if ((tag1 == JS_TAG_SHORT_BIG_INT || tag1 == JS_TAG_BIG_INT) && - (tag2 == JS_TAG_SHORT_BIG_INT || tag2 == JS_TAG_BIG_INT)) { - JSBigInt *p1, *p2, *r; - JSBigIntBuf buf1, buf2; - slow_big_int: - /* bigint result */ - if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT) - p1 = js_bigint_set_short(&buf1, op1); - else - p1 = JS_VALUE_GET_PTR(op1); - if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT) - p2 = js_bigint_set_short(&buf2, op2); - else - p2 = JS_VALUE_GET_PTR(op2); - switch(op) { - case OP_add: - r = js_bigint_add(ctx, p1, p2, 0); - break; - case OP_sub: - r = js_bigint_add(ctx, p1, p2, 1); - break; - case OP_mul: - r = js_bigint_mul(ctx, p1, p2); - break; - case OP_div: - r = js_bigint_divrem(ctx, p1, p2, FALSE); - break; - case OP_mod: - r = js_bigint_divrem(ctx, p1, p2, TRUE); - break; - case OP_pow: - r = js_bigint_pow(ctx, p1, p2); - break; - default: - abort(); - } - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - if (!r) - goto exception; - sp[-2] = JS_CompactBigInt(ctx, r); - } else { - double dr; - /* float64 result */ - if (JS_ToFloat64Free(ctx, &d1, op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - if (JS_ToFloat64Free(ctx, &d2, op2)) - goto exception; - handle_float64: - switch(op) { - case OP_sub: - dr = d1 - d2; - break; - case OP_mul: - dr = d1 * d2; - break; - case OP_div: - dr = d1 / d2; - break; - case OP_mod: - dr = fmod(d1, d2); - break; - case OP_pow: - dr = js_pow(d1, d2); - break; - default: - abort(); - } - sp[-2] = __JS_NewFloat64(ctx, dr); - } - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -static inline BOOL tag_is_string(uint32_t tag) -{ - return tag == JS_TAG_STRING || tag == JS_TAG_STRING_ROPE; -} - -static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) -{ - JSValue op1, op2; - uint32_t tag1, tag2; - - op1 = sp[-2]; - op2 = sp[-1]; - - tag1 = JS_VALUE_GET_NORM_TAG(op1); - tag2 = JS_VALUE_GET_NORM_TAG(op2); - /* fast path for float64 */ - if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) { - double d1, d2; - d1 = JS_VALUE_GET_FLOAT64(op1); - d2 = JS_VALUE_GET_FLOAT64(op2); - sp[-2] = __JS_NewFloat64(ctx, d1 + d2); - return 0; - } - /* fast path for short bigint */ - if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) { - js_slimb_t v1, v2; - js_sdlimb_t v; - v1 = JS_VALUE_GET_SHORT_BIG_INT(op1); - v2 = JS_VALUE_GET_SHORT_BIG_INT(op2); - v = (js_sdlimb_t)v1 + (js_sdlimb_t)v2; - if (likely(v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX)) { - sp[-2] = __JS_NewShortBigInt(ctx, v); - } else { - JSBigInt *r = js_bigint_new_di(ctx, v); - if (!r) - goto exception; - sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r); - } - return 0; - } - - if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) { - op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); - if (JS_IsException(op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - - op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - goto exception; - } - tag1 = JS_VALUE_GET_NORM_TAG(op1); - tag2 = JS_VALUE_GET_NORM_TAG(op2); - } - - if (tag_is_string(tag1) || tag_is_string(tag2)) { - sp[-2] = JS_ConcatString(ctx, op1, op2); - if (JS_IsException(sp[-2])) - goto exception; - return 0; - } - - op1 = JS_ToNumericFree(ctx, op1); - if (JS_IsException(op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - op2 = JS_ToNumericFree(ctx, op2); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - goto exception; - } - tag1 = JS_VALUE_GET_NORM_TAG(op1); - tag2 = JS_VALUE_GET_NORM_TAG(op2); - - if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) { - int32_t v1, v2; - int64_t v; - v1 = JS_VALUE_GET_INT(op1); - v2 = JS_VALUE_GET_INT(op2); - v = (int64_t)v1 + (int64_t)v2; - sp[-2] = JS_NewInt64(ctx, v); - } else if ((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) && - (tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT)) { - JSBigInt *p1, *p2, *r; - JSBigIntBuf buf1, buf2; - /* bigint result */ - if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT) - p1 = js_bigint_set_short(&buf1, op1); - else - p1 = JS_VALUE_GET_PTR(op1); - if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT) - p2 = js_bigint_set_short(&buf2, op2); - else - p2 = JS_VALUE_GET_PTR(op2); - r = js_bigint_add(ctx, p1, p2, 0); - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - if (!r) - goto exception; - sp[-2] = JS_CompactBigInt(ctx, r); - } else { - double d1, d2; - /* float64 result */ - if (JS_ToFloat64Free(ctx, &d1, op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - if (JS_ToFloat64Free(ctx, &d2, op2)) - goto exception; - sp[-2] = __JS_NewFloat64(ctx, d1 + d2); - } - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -static no_inline __exception int js_binary_logic_slow(JSContext *ctx, - JSValue *sp, - OPCodeEnum op) -{ - JSValue op1, op2; - uint32_t tag1, tag2; - uint32_t v1, v2, r; - - op1 = sp[-2]; - op2 = sp[-1]; - tag1 = JS_VALUE_GET_NORM_TAG(op1); - tag2 = JS_VALUE_GET_NORM_TAG(op2); - - if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) { - js_slimb_t v1, v2, v; - js_sdlimb_t vd; - v1 = JS_VALUE_GET_SHORT_BIG_INT(op1); - v2 = JS_VALUE_GET_SHORT_BIG_INT(op2); - /* bigint fast path */ - switch(op) { - case OP_and: - v = v1 & v2; - break; - case OP_or: - v = v1 | v2; - break; - case OP_xor: - v = v1 ^ v2; - break; - case OP_sar: - if (v2 > (JS_LIMB_BITS - 1)) { - goto slow_big_int; - } else if (v2 < 0) { - if (v2 < -(JS_LIMB_BITS - 1)) - goto slow_big_int; - v2 = -v2; - goto bigint_shl; - } - bigint_sar: - v = v1 >> v2; - break; - case OP_shl: - if (v2 > (JS_LIMB_BITS - 1)) { - goto slow_big_int; - } else if (v2 < 0) { - if (v2 < -(JS_LIMB_BITS - 1)) - goto slow_big_int; - v2 = -v2; - goto bigint_sar; - } - bigint_shl: - vd = (js_dlimb_t)v1 << v2; - if (likely(vd >= JS_SHORT_BIG_INT_MIN && - vd <= JS_SHORT_BIG_INT_MAX)) { - v = vd; - } else { - JSBigInt *r = js_bigint_new_di(ctx, vd); - if (!r) - goto exception; - sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r); - return 0; - } - break; - default: - abort(); - } - sp[-2] = __JS_NewShortBigInt(ctx, v); - return 0; - } - op1 = JS_ToNumericFree(ctx, op1); - if (JS_IsException(op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - op2 = JS_ToNumericFree(ctx, op2); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - goto exception; - } - - tag1 = JS_VALUE_GET_TAG(op1); - tag2 = JS_VALUE_GET_TAG(op2); - if ((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) && - (tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT)) { - JSBigInt *p1, *p2, *r; - JSBigIntBuf buf1, buf2; - slow_big_int: - if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT) - p1 = js_bigint_set_short(&buf1, op1); - else - p1 = JS_VALUE_GET_PTR(op1); - if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT) - p2 = js_bigint_set_short(&buf2, op2); - else - p2 = JS_VALUE_GET_PTR(op2); - switch(op) { - case OP_and: - case OP_or: - case OP_xor: - r = js_bigint_logic(ctx, p1, p2, op); - break; - case OP_shl: - case OP_sar: - { - js_slimb_t shift; - shift = js_bigint_get_si_sat(p2); - if (shift > INT32_MAX) - shift = INT32_MAX; - else if (shift < -INT32_MAX) - shift = -INT32_MAX; - if (op == OP_sar) - shift = -shift; - if (shift >= 0) - r = js_bigint_shl(ctx, p1, shift); - else - r = js_bigint_shr(ctx, p1, -shift); - } - break; - default: - abort(); - } - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - if (!r) - goto exception; - sp[-2] = JS_CompactBigInt(ctx, r); - } else { - if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) { - JS_FreeValue(ctx, op2); - goto exception; - } - if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2))) - goto exception; - switch(op) { - case OP_shl: - r = v1 << (v2 & 0x1f); - break; - case OP_sar: - r = (int)v1 >> (v2 & 0x1f); - break; - case OP_and: - r = v1 & v2; - break; - case OP_or: - r = v1 | v2; - break; - case OP_xor: - r = v1 ^ v2; - break; - default: - abort(); - } - sp[-2] = JS_NewInt32(ctx, r); - } - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -/* op1 must be a bigint or int. */ -static JSBigInt *JS_ToBigIntBuf(JSContext *ctx, JSBigIntBuf *buf1, - JSValue op1) -{ - JSBigInt *p1; - - switch(JS_VALUE_GET_TAG(op1)) { - case JS_TAG_INT: - p1 = js_bigint_set_si(buf1, JS_VALUE_GET_INT(op1)); - break; - case JS_TAG_SHORT_BIG_INT: - p1 = js_bigint_set_short(buf1, op1); - break; - case JS_TAG_BIG_INT: - p1 = JS_VALUE_GET_PTR(op1); - break; - default: - abort(); - } - return p1; -} - -/* op1 and op2 must be numeric types and at least one must be a - bigint. No exception is generated. */ -static int js_compare_bigint(JSContext *ctx, OPCodeEnum op, - JSValue op1, JSValue op2) -{ - int res, val, tag1, tag2; - JSBigIntBuf buf1, buf2; - JSBigInt *p1, *p2; - - tag1 = JS_VALUE_GET_NORM_TAG(op1); - tag2 = JS_VALUE_GET_NORM_TAG(op2); - if ((tag1 == JS_TAG_SHORT_BIG_INT || tag1 == JS_TAG_INT) && - (tag2 == JS_TAG_SHORT_BIG_INT || tag2 == JS_TAG_INT)) { - /* fast path */ - js_slimb_t v1, v2; - if (tag1 == JS_TAG_INT) - v1 = JS_VALUE_GET_INT(op1); - else - v1 = JS_VALUE_GET_SHORT_BIG_INT(op1); - if (tag2 == JS_TAG_INT) - v2 = JS_VALUE_GET_INT(op2); - else - v2 = JS_VALUE_GET_SHORT_BIG_INT(op2); - val = (v1 > v2) - (v1 < v2); - } else { - if (tag1 == JS_TAG_FLOAT64) { - p2 = JS_ToBigIntBuf(ctx, &buf2, op2); - val = js_bigint_float64_cmp(ctx, p2, JS_VALUE_GET_FLOAT64(op1)); - if (val == 2) - goto unordered; - val = -val; - } else if (tag2 == JS_TAG_FLOAT64) { - p1 = JS_ToBigIntBuf(ctx, &buf1, op1); - val = js_bigint_float64_cmp(ctx, p1, JS_VALUE_GET_FLOAT64(op2)); - if (val == 2) { - unordered: - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - return FALSE; - } - } else { - p1 = JS_ToBigIntBuf(ctx, &buf1, op1); - p2 = JS_ToBigIntBuf(ctx, &buf2, op2); - val = js_bigint_cmp(ctx, p1, p2); - } - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - } - - switch(op) { - case OP_lt: - res = val < 0; - break; - case OP_lte: - res = val <= 0; - break; - case OP_gt: - res = val > 0; - break; - case OP_gte: - res = val >= 0; - break; - case OP_eq: - res = val == 0; - break; - default: - abort(); - } - return res; -} - -static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, - OPCodeEnum op) -{ - JSValue op1, op2; - int res; - uint32_t tag1, tag2; - - op1 = sp[-2]; - op2 = sp[-1]; - tag1 = JS_VALUE_GET_NORM_TAG(op1); - tag2 = JS_VALUE_GET_NORM_TAG(op2); - op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER); - if (JS_IsException(op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - goto exception; - } - tag1 = JS_VALUE_GET_NORM_TAG(op1); - tag2 = JS_VALUE_GET_NORM_TAG(op2); - - if (tag_is_string(tag1) && tag_is_string(tag2)) { - if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) { - res = js_string_compare(ctx, JS_VALUE_GET_STRING(op1), - JS_VALUE_GET_STRING(op2)); - } else { - res = js_string_rope_compare(ctx, op1, op2, FALSE); - } - switch(op) { - case OP_lt: - res = (res < 0); - break; - case OP_lte: - res = (res <= 0); - break; - case OP_gt: - res = (res > 0); - break; - default: - case OP_gte: - res = (res >= 0); - break; - } - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - } else if ((tag1 <= JS_TAG_NULL || tag1 == JS_TAG_FLOAT64) && - (tag2 <= JS_TAG_NULL || tag2 == JS_TAG_FLOAT64)) { - /* fast path for float64/int */ - goto float64_compare; - } else { - if ((((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) && - tag_is_string(tag2)) || - ((tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) && - tag_is_string(tag1)))) { - if (tag_is_string(tag1)) { - op1 = JS_StringToBigInt(ctx, op1); - if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT && - JS_VALUE_GET_TAG(op1) != JS_TAG_SHORT_BIG_INT) - goto invalid_bigint_string; - } - if (tag_is_string(tag2)) { - op2 = JS_StringToBigInt(ctx, op2); - if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT && - JS_VALUE_GET_TAG(op2) != JS_TAG_SHORT_BIG_INT) { - invalid_bigint_string: - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - res = FALSE; - goto done; - } - } - } else { - op1 = JS_ToNumericFree(ctx, op1); - if (JS_IsException(op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - op2 = JS_ToNumericFree(ctx, op2); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - goto exception; - } - } - - tag1 = JS_VALUE_GET_NORM_TAG(op1); - tag2 = JS_VALUE_GET_NORM_TAG(op2); - - if (tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT || - tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) { - res = js_compare_bigint(ctx, op, op1, op2); - } else { - double d1, d2; - - float64_compare: - /* can use floating point comparison */ - if (tag1 == JS_TAG_FLOAT64) { - d1 = JS_VALUE_GET_FLOAT64(op1); - } else { - d1 = JS_VALUE_GET_INT(op1); - } - if (tag2 == JS_TAG_FLOAT64) { - d2 = JS_VALUE_GET_FLOAT64(op2); - } else { - d2 = JS_VALUE_GET_INT(op2); - } - switch(op) { - case OP_lt: - res = (d1 < d2); /* if NaN return false */ - break; - case OP_lte: - res = (d1 <= d2); /* if NaN return false */ - break; - case OP_gt: - res = (d1 > d2); /* if NaN return false */ - break; - default: - case OP_gte: - res = (d1 >= d2); /* if NaN return false */ - break; - } - } - } - done: - sp[-2] = JS_NewBool(ctx, res); - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -static BOOL tag_is_number(uint32_t tag) -{ - return (tag == JS_TAG_INT || - tag == JS_TAG_FLOAT64 || - tag == JS_TAG_BIG_INT || tag == JS_TAG_SHORT_BIG_INT); -} - -static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, - BOOL is_neq) -{ - JSValue op1, op2; - int res; - uint32_t tag1, tag2; - - op1 = sp[-2]; - op2 = sp[-1]; - redo: - tag1 = JS_VALUE_GET_NORM_TAG(op1); - tag2 = JS_VALUE_GET_NORM_TAG(op2); - if (tag_is_number(tag1) && tag_is_number(tag2)) { - if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) { - res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2); - } else if ((tag1 == JS_TAG_FLOAT64 && - (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64)) || - (tag2 == JS_TAG_FLOAT64 && - (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64))) { - double d1, d2; - if (tag1 == JS_TAG_FLOAT64) { - d1 = JS_VALUE_GET_FLOAT64(op1); - } else { - d1 = JS_VALUE_GET_INT(op1); - } - if (tag2 == JS_TAG_FLOAT64) { - d2 = JS_VALUE_GET_FLOAT64(op2); - } else { - d2 = JS_VALUE_GET_INT(op2); - } - res = (d1 == d2); - } else { - res = js_compare_bigint(ctx, OP_eq, op1, op2); - } - } else if (tag1 == tag2) { - res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT); - } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) || - (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) { - res = TRUE; - } else if (tag_is_string(tag1) && tag_is_string(tag2)) { - /* needed when comparing strings and ropes */ - res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT); - } else if ((tag_is_string(tag1) && tag_is_number(tag2)) || - (tag_is_string(tag2) && tag_is_number(tag1))) { - - if (tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT || - tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) { - if (tag_is_string(tag1)) { - op1 = JS_StringToBigInt(ctx, op1); - if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT && - JS_VALUE_GET_TAG(op1) != JS_TAG_SHORT_BIG_INT) - goto invalid_bigint_string; - } - if (tag_is_string(tag2)) { - op2 = JS_StringToBigInt(ctx, op2); - if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT && - JS_VALUE_GET_TAG(op2) != JS_TAG_SHORT_BIG_INT ) { - invalid_bigint_string: - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - res = FALSE; - goto done; - } - } - } else { - op1 = JS_ToNumericFree(ctx, op1); - if (JS_IsException(op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - op2 = JS_ToNumericFree(ctx, op2); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - goto exception; - } - } - res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT); - } else if (tag1 == JS_TAG_BOOL) { - op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1)); - goto redo; - } else if (tag2 == JS_TAG_BOOL) { - op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2)); - goto redo; - } else if ((tag1 == JS_TAG_OBJECT && - (tag_is_number(tag2) || tag_is_string(tag2) || tag2 == JS_TAG_SYMBOL)) || - (tag2 == JS_TAG_OBJECT && - (tag_is_number(tag1) || tag_is_string(tag1) || tag1 == JS_TAG_SYMBOL))) { - op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); - if (JS_IsException(op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - goto exception; - } - goto redo; - } else { - /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */ - if ((JS_IsHTMLDDA(ctx, op1) && - (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) || - (JS_IsHTMLDDA(ctx, op2) && - (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) { - res = TRUE; - } else { - res = FALSE; - } - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - } - done: - sp[-2] = JS_NewBool(ctx, res ^ is_neq); - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp) -{ - JSValue op1, op2; - uint32_t v1, v2, r; - - op1 = sp[-2]; - op2 = sp[-1]; - op1 = JS_ToNumericFree(ctx, op1); - if (JS_IsException(op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - op2 = JS_ToNumericFree(ctx, op2); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - goto exception; - } - if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT || - JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT || - JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_INT || - JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT) { - JS_ThrowTypeError(ctx, "bigint operands are forbidden for >>>"); - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - goto exception; - } - /* cannot give an exception */ - JS_ToUint32Free(ctx, &v1, op1); - JS_ToUint32Free(ctx, &v2, op2); - r = v1 >> (v2 & 0x1f); - sp[-2] = JS_NewUint32(ctx, r); - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -/* XXX: Should take JSValueConst arguments */ -static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, - JSStrictEqModeEnum eq_mode) -{ - BOOL res; - int tag1, tag2; - double d1, d2; - - tag1 = JS_VALUE_GET_NORM_TAG(op1); - tag2 = JS_VALUE_GET_NORM_TAG(op2); - switch(tag1) { - case JS_TAG_BOOL: - if (tag1 != tag2) { - res = FALSE; - } else { - res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2); - goto done_no_free; - } - break; - case JS_TAG_NULL: - case JS_TAG_UNDEFINED: - res = (tag1 == tag2); - break; - case JS_TAG_STRING: - case JS_TAG_STRING_ROPE: - { - if (!tag_is_string(tag2)) { - res = FALSE; - } else if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) { - res = (js_string_compare(ctx, JS_VALUE_GET_STRING(op1), - JS_VALUE_GET_STRING(op2)) == 0); - } else { - res = (js_string_rope_compare(ctx, op1, op2, TRUE) == 0); - } - } - break; - case JS_TAG_SYMBOL: - { - JSAtomStruct *p1, *p2; - if (tag1 != tag2) { - res = FALSE; - } else { - p1 = JS_VALUE_GET_PTR(op1); - p2 = JS_VALUE_GET_PTR(op2); - res = (p1 == p2); - } - } - break; - case JS_TAG_OBJECT: - if (tag1 != tag2) - res = FALSE; - else - res = JS_VALUE_GET_OBJ(op1) == JS_VALUE_GET_OBJ(op2); - break; - case JS_TAG_INT: - d1 = JS_VALUE_GET_INT(op1); - if (tag2 == JS_TAG_INT) { - d2 = JS_VALUE_GET_INT(op2); - goto number_test; - } else if (tag2 == JS_TAG_FLOAT64) { - d2 = JS_VALUE_GET_FLOAT64(op2); - goto number_test; - } else { - res = FALSE; - } - break; - case JS_TAG_FLOAT64: - d1 = JS_VALUE_GET_FLOAT64(op1); - if (tag2 == JS_TAG_FLOAT64) { - d2 = JS_VALUE_GET_FLOAT64(op2); - } else if (tag2 == JS_TAG_INT) { - d2 = JS_VALUE_GET_INT(op2); - } else { - res = FALSE; - break; - } - number_test: - if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) { - JSFloat64Union u1, u2; - /* NaN is not always normalized, so this test is necessary */ - if (isnan(d1) || isnan(d2)) { - res = isnan(d1) == isnan(d2); - } else if (eq_mode == JS_EQ_SAME_VALUE_ZERO) { - res = (d1 == d2); /* +0 == -0 */ - } else { - u1.d = d1; - u2.d = d2; - res = (u1.u64 == u2.u64); /* +0 != -0 */ - } - } else { - res = (d1 == d2); /* if NaN return false and +0 == -0 */ - } - goto done_no_free; - case JS_TAG_SHORT_BIG_INT: - case JS_TAG_BIG_INT: - { - JSBigIntBuf buf1, buf2; - JSBigInt *p1, *p2; - - if (tag2 != JS_TAG_SHORT_BIG_INT && - tag2 != JS_TAG_BIG_INT) { - res = FALSE; - break; - } - - if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT) - p1 = js_bigint_set_short(&buf1, op1); - else - p1 = JS_VALUE_GET_PTR(op1); - if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT) - p2 = js_bigint_set_short(&buf2, op2); - else - p2 = JS_VALUE_GET_PTR(op2); - res = (js_bigint_cmp(ctx, p1, p2) == 0); - } - break; - default: - res = FALSE; - break; - } - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - done_no_free: - return res; -} - -static BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2) -{ - return js_strict_eq2(ctx, - JS_DupValue(ctx, op1), JS_DupValue(ctx, op2), - JS_EQ_STRICT); -} - -BOOL JS_StrictEq(JSContext *ctx, JSValueConst op1, JSValueConst op2) -{ - return js_strict_eq(ctx, op1, op2); -} - -static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2) -{ - return js_strict_eq2(ctx, - JS_DupValue(ctx, op1), JS_DupValue(ctx, op2), - JS_EQ_SAME_VALUE); -} - -BOOL JS_SameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2) -{ - return js_same_value(ctx, op1, op2); -} - -static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2) -{ - return js_strict_eq2(ctx, - JS_DupValue(ctx, op1), JS_DupValue(ctx, op2), - JS_EQ_SAME_VALUE_ZERO); -} - -BOOL JS_SameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2) -{ - return js_same_value_zero(ctx, op1, op2); -} - -static no_inline int js_strict_eq_slow(JSContext *ctx, JSValue *sp, - BOOL is_neq) -{ - BOOL res; - res = js_strict_eq2(ctx, sp[-2], sp[-1], JS_EQ_STRICT); - sp[-2] = JS_NewBool(ctx, res ^ is_neq); - return 0; -} - -static __exception int js_operator_in(JSContext *ctx, JSValue *sp) -{ - JSValue op1, op2; - JSAtom atom; - int ret; - - op1 = sp[-2]; - op2 = sp[-1]; - - if (JS_VALUE_GET_TAG(op2) != JS_TAG_OBJECT) { - JS_ThrowTypeError(ctx, "invalid 'in' operand"); - return -1; - } - atom = JS_ValueToAtom(ctx, op1); - if (unlikely(atom == JS_ATOM_NULL)) - return -1; - ret = JS_HasProperty(ctx, op2, atom); - JS_FreeAtom(ctx, atom); - if (ret < 0) - return -1; - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - sp[-2] = JS_NewBool(ctx, ret); - return 0; -} - -static __exception int js_operator_private_in(JSContext *ctx, JSValue *sp) -{ - JSValue op1, op2; - int ret; - - op1 = sp[-2]; /* object */ - op2 = sp[-1]; /* field name or method function */ - - if (JS_VALUE_GET_TAG(op1) != JS_TAG_OBJECT) { - JS_ThrowTypeError(ctx, "invalid 'in' operand"); - return -1; - } - if (JS_IsObject(op2)) { - /* method: use the brand */ - ret = JS_CheckBrand(ctx, op1, op2); - if (ret < 0) - return -1; - } else { - JSAtom atom; - JSObject *p; - JSShapeProperty *prs; - JSProperty *pr; - /* field */ - atom = JS_ValueToAtom(ctx, op2); - if (unlikely(atom == JS_ATOM_NULL)) - return -1; - p = JS_VALUE_GET_OBJ(op1); - prs = find_own_property(&pr, p, atom); - JS_FreeAtom(ctx, atom); - ret = (prs != NULL); - } - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - sp[-2] = JS_NewBool(ctx, ret); - return 0; -} - -static __exception int js_has_unscopable(JSContext *ctx, JSValueConst obj, - JSAtom atom) -{ - JSValue arr, val; - int ret; - - arr = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_unscopables); - if (JS_IsException(arr)) - return -1; - ret = 0; - if (JS_IsObject(arr)) { - val = JS_GetProperty(ctx, arr, atom); - ret = JS_ToBoolFree(ctx, val); - } - JS_FreeValue(ctx, arr); - return ret; -} - -static __exception int js_operator_instanceof(JSContext *ctx, JSValue *sp) -{ - JSValue op1, op2; - BOOL ret; - - op1 = sp[-2]; - op2 = sp[-1]; - ret = JS_IsInstanceOf(ctx, op1, op2); - if (ret < 0) - return ret; - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - sp[-2] = JS_NewBool(ctx, ret); - return 0; -} - -static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1) -{ - JSAtom atom; - uint32_t tag; - - tag = JS_VALUE_GET_NORM_TAG(op1); - switch(tag) { - case JS_TAG_SHORT_BIG_INT: - case JS_TAG_BIG_INT: - atom = JS_ATOM_bigint; - break; - case JS_TAG_INT: - case JS_TAG_FLOAT64: - atom = JS_ATOM_number; - break; - case JS_TAG_UNDEFINED: - atom = JS_ATOM_undefined; - break; - case JS_TAG_BOOL: - atom = JS_ATOM_boolean; - break; - case JS_TAG_STRING: - case JS_TAG_STRING_ROPE: - atom = JS_ATOM_string; - break; - case JS_TAG_OBJECT: - { - JSObject *p; - p = JS_VALUE_GET_OBJ(op1); - if (unlikely(p->is_HTMLDDA)) - atom = JS_ATOM_undefined; - else if (JS_IsFunction(ctx, op1)) - atom = JS_ATOM_function; - else - goto obj_type; - } - break; - case JS_TAG_NULL: - obj_type: - atom = JS_ATOM_object; - break; - case JS_TAG_SYMBOL: - atom = JS_ATOM_symbol; - break; - default: - atom = JS_ATOM_unknown; - break; - } - return atom; -} - -static __exception int js_operator_delete(JSContext *ctx, JSValue *sp) -{ - JSValue op1, op2; - JSAtom atom; - int ret; - - op1 = sp[-2]; - op2 = sp[-1]; - atom = JS_ValueToAtom(ctx, op2); - if (unlikely(atom == JS_ATOM_NULL)) - return -1; - ret = JS_DeleteProperty(ctx, op1, atom, JS_PROP_THROW_STRICT); - JS_FreeAtom(ctx, atom); - if (unlikely(ret < 0)) - return -1; - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - sp[-2] = JS_NewBool(ctx, ret); - return 0; -} - -/* XXX: not 100% compatible, but mozilla seems to use a similar - implementation to ensure that caller in non strict mode does not - throw (ES5 compatibility) */ -static JSValue js_throw_type_error(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val); - if (!b || (b->js_mode & JS_MODE_STRICT) || !b->has_prototype || argc >= 1) { - return JS_ThrowTypeError(ctx, "invalid property access"); - } - return JS_UNDEFINED; -} - -static JSValue js_function_proto_fileName(JSContext *ctx, - JSValueConst this_val) -{ - JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val); - if (b && b->has_debug) { - return JS_AtomToString(ctx, b->debug.filename); - } - return JS_UNDEFINED; -} - -static JSValue js_function_proto_lineNumber(JSContext *ctx, - JSValueConst this_val, int is_col) -{ - JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val); - if (b && b->has_debug) { - int line_num, col_num; - line_num = find_line_num(ctx, b, -1, &col_num); - if (is_col) - return JS_NewInt32(ctx, col_num); - else - return JS_NewInt32(ctx, line_num); - } - return JS_UNDEFINED; -} - -static int js_arguments_define_own_property(JSContext *ctx, - JSValueConst this_obj, - JSAtom prop, JSValueConst val, - JSValueConst getter, JSValueConst setter, int flags) -{ - JSObject *p; - uint32_t idx; - p = JS_VALUE_GET_OBJ(this_obj); - /* convert to normal array when redefining an existing numeric field */ - if (p->fast_array && JS_AtomIsArrayIndex(ctx, &idx, prop) && - idx < p->u.array.count) { - if (convert_fast_array_to_array(ctx, p)) - return -1; - } - /* run the default define own property */ - return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter, - flags | JS_PROP_NO_EXOTIC); -} - -static const JSClassExoticMethods js_arguments_exotic_methods = { - .define_own_property = js_arguments_define_own_property, -}; - -static JSValue js_build_arguments(JSContext *ctx, int argc, JSValueConst *argv) -{ - JSValue val, *tab; - JSProperty *pr; - JSObject *p; - int i; - - val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], - JS_CLASS_ARGUMENTS); - if (JS_IsException(val)) - return val; - p = JS_VALUE_GET_OBJ(val); - - /* add the length field (cannot fail) */ - pr = add_property(ctx, p, JS_ATOM_length, - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - if (unlikely(!pr)) - goto fail; - pr->u.value = JS_NewInt32(ctx, argc); - - /* initialize the fast array part */ - tab = NULL; - if (argc > 0) { - tab = js_malloc(ctx, sizeof(tab[0]) * argc); - if (!tab) - goto fail; - for(i = 0; i < argc; i++) { - tab[i] = JS_DupValue(ctx, argv[i]); - } - } - p->u.array.u.values = tab; - p->u.array.count = argc; - - JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator, - JS_DupValue(ctx, ctx->array_proto_values), - JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE); - /* add callee property to throw a TypeError in strict mode */ - JS_DefineProperty(ctx, val, JS_ATOM_callee, JS_UNDEFINED, - ctx->throw_type_error, ctx->throw_type_error, - JS_PROP_HAS_GET | JS_PROP_HAS_SET); - return val; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -#define GLOBAL_VAR_OFFSET 0x40000000 -#define ARGUMENT_VAR_OFFSET 0x20000000 - -/* legacy arguments object: add references to the function arguments */ -static JSValue js_build_mapped_arguments(JSContext *ctx, int argc, - JSValueConst *argv, - JSStackFrame *sf, int arg_count) -{ - JSValue val; - JSProperty *pr; - JSObject *p; - int i; - - val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], - JS_CLASS_MAPPED_ARGUMENTS); - if (JS_IsException(val)) - return val; - p = JS_VALUE_GET_OBJ(val); - - /* add the length field (cannot fail) */ - pr = add_property(ctx, p, JS_ATOM_length, - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - if (unlikely(!pr)) - goto fail; - pr->u.value = JS_NewInt32(ctx, argc); - - for(i = 0; i < arg_count; i++) { - JSVarRef *var_ref; - var_ref = get_var_ref(ctx, sf, i, TRUE); - if (!var_ref) - goto fail; - pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E | JS_PROP_VARREF); - if (!pr) { - free_var_ref(ctx->rt, var_ref); - goto fail; - } - pr->u.var_ref = var_ref; - } - - /* the arguments not mapped to the arguments of the function can - be normal properties */ - for(i = arg_count; i < argc; i++) { - if (JS_DefinePropertyValueUint32(ctx, val, i, - JS_DupValue(ctx, argv[i]), - JS_PROP_C_W_E) < 0) - goto fail; - } - - JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator, - JS_DupValue(ctx, ctx->array_proto_values), - JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE); - /* callee returns this function in non strict mode */ - JS_DefinePropertyValue(ctx, val, JS_ATOM_callee, - JS_DupValue(ctx, ctx->rt->current_stack_frame->cur_func), - JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE); - return val; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValueConst *argv) -{ - JSValue val; - int i, ret; - - val = JS_NewArray(ctx); - if (JS_IsException(val)) - return val; - for (i = first; i < argc; i++) { - ret = JS_DefinePropertyValueUint32(ctx, val, i - first, - JS_DupValue(ctx, argv[i]), - JS_PROP_C_W_E); - if (ret < 0) { - JS_FreeValue(ctx, val); - return JS_EXCEPTION; - } - } - return val; -} - -static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj) -{ - JSObject *p, *p1; - JSPropertyEnum *tab_atom; - int i; - JSValue enum_obj; - JSForInIterator *it; - uint32_t tag, tab_atom_count; - - tag = JS_VALUE_GET_TAG(obj); - if (tag != JS_TAG_OBJECT && tag != JS_TAG_NULL && tag != JS_TAG_UNDEFINED) { - obj = JS_ToObjectFree(ctx, obj); - } - - it = js_malloc(ctx, sizeof(*it)); - if (!it) { - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - enum_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_FOR_IN_ITERATOR); - if (JS_IsException(enum_obj)) { - js_free(ctx, it); - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - it->is_array = FALSE; - it->obj = obj; - it->idx = 0; - it->tab_atom = NULL; - it->atom_count = 0; - it->in_prototype_chain = FALSE; - p1 = JS_VALUE_GET_OBJ(enum_obj); - p1->u.for_in_iterator = it; - - if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) - return enum_obj; - - p = JS_VALUE_GET_OBJ(obj); - if (p->fast_array) { - JSShape *sh; - JSShapeProperty *prs; - /* check that there are no enumerable normal fields */ - sh = p->shape; - for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { - if (prs->flags & JS_PROP_ENUMERABLE) - goto normal_case; - } - /* for fast arrays, we only store the number of elements */ - it->is_array = TRUE; - it->atom_count = p->u.array.count; - } else { - normal_case: - if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p, - JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { - JS_FreeValue(ctx, enum_obj); - return JS_EXCEPTION; - } - it->tab_atom = tab_atom; - it->atom_count = tab_atom_count; - } - return enum_obj; -} - -/* obj -> enum_obj */ -static __exception int js_for_in_start(JSContext *ctx, JSValue *sp) -{ - sp[-1] = build_for_in_iterator(ctx, sp[-1]); - if (JS_IsException(sp[-1])) - return -1; - return 0; -} - -/* return -1 if exception, 0 if slow case, 1 if the enumeration is finished */ -static __exception int js_for_in_prepare_prototype_chain_enum(JSContext *ctx, - JSValueConst enum_obj) -{ - JSObject *p; - JSForInIterator *it; - JSPropertyEnum *tab_atom; - uint32_t tab_atom_count, i; - JSValue obj1; - - p = JS_VALUE_GET_OBJ(enum_obj); - it = p->u.for_in_iterator; - - /* check if there are enumerable properties in the prototype chain (fast path) */ - obj1 = JS_DupValue(ctx, it->obj); - for(;;) { - obj1 = JS_GetPrototypeFree(ctx, obj1); - if (JS_IsNull(obj1)) - break; - if (JS_IsException(obj1)) - goto fail; - if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, - JS_VALUE_GET_OBJ(obj1), - JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) { - JS_FreeValue(ctx, obj1); - goto fail; - } - JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count); - if (tab_atom_count != 0) { - JS_FreeValue(ctx, obj1); - goto slow_path; - } - /* must check for timeout to avoid infinite loop */ - if (js_poll_interrupts(ctx)) { - JS_FreeValue(ctx, obj1); - goto fail; - } - } - JS_FreeValue(ctx, obj1); - return 1; - - slow_path: - /* add the visited properties, even if they are not enumerable */ - if (it->is_array) { - if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, - JS_VALUE_GET_OBJ(it->obj), - JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { - goto fail; - } - it->is_array = FALSE; - it->tab_atom = tab_atom; - it->atom_count = tab_atom_count; - } - - for(i = 0; i < it->atom_count; i++) { - if (JS_DefinePropertyValue(ctx, enum_obj, it->tab_atom[i].atom, JS_NULL, JS_PROP_ENUMERABLE) < 0) - goto fail; - } - return 0; - fail: - return -1; -} - -/* enum_obj -> enum_obj value done */ -static __exception int js_for_in_next(JSContext *ctx, JSValue *sp) -{ - JSValueConst enum_obj; - JSObject *p; - JSAtom prop; - JSForInIterator *it; - JSPropertyEnum *tab_atom; - uint32_t tab_atom_count; - int ret; - - enum_obj = sp[-1]; - /* fail safe */ - if (JS_VALUE_GET_TAG(enum_obj) != JS_TAG_OBJECT) - goto done; - p = JS_VALUE_GET_OBJ(enum_obj); - if (p->class_id != JS_CLASS_FOR_IN_ITERATOR) - goto done; - it = p->u.for_in_iterator; - - for(;;) { - if (it->idx >= it->atom_count) { - if (JS_IsNull(it->obj) || JS_IsUndefined(it->obj)) - goto done; /* not an object */ - /* no more property in the current object: look in the prototype */ - if (!it->in_prototype_chain) { - ret = js_for_in_prepare_prototype_chain_enum(ctx, enum_obj); - if (ret < 0) - return -1; - if (ret) - goto done; - it->in_prototype_chain = TRUE; - } - it->obj = JS_GetPrototypeFree(ctx, it->obj); - if (JS_IsException(it->obj)) - return -1; - if (JS_IsNull(it->obj)) - goto done; /* no more prototype */ - - /* must check for timeout to avoid infinite loop */ - if (js_poll_interrupts(ctx)) - return -1; - - if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, - JS_VALUE_GET_OBJ(it->obj), - JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { - return -1; - } - JS_FreePropertyEnum(ctx, it->tab_atom, it->atom_count); - it->tab_atom = tab_atom; - it->atom_count = tab_atom_count; - it->idx = 0; - } else { - if (it->is_array) { - prop = __JS_AtomFromUInt32(it->idx); - it->idx++; - } else { - BOOL is_enumerable; - prop = it->tab_atom[it->idx].atom; - is_enumerable = it->tab_atom[it->idx].is_enumerable; - it->idx++; - if (it->in_prototype_chain) { - /* slow case: we are in the prototype chain */ - ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(enum_obj), prop); - if (ret < 0) - return ret; - if (ret) - continue; /* already visited */ - /* add to the visited property list */ - if (JS_DefinePropertyValue(ctx, enum_obj, prop, JS_NULL, - JS_PROP_ENUMERABLE) < 0) - return -1; - } - if (!is_enumerable) - continue; - } - /* check if the property was deleted */ - ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(it->obj), prop); - if (ret < 0) - return ret; - if (ret) - break; - } - } - /* return the property */ - sp[0] = JS_AtomToValue(ctx, prop); - sp[1] = JS_FALSE; - return 0; - done: - /* return the end */ - sp[0] = JS_UNDEFINED; - sp[1] = JS_TRUE; - return 0; -} - -static JSValue JS_GetIterator2(JSContext *ctx, JSValueConst obj, - JSValueConst method) -{ - JSValue enum_obj; - - enum_obj = JS_Call(ctx, method, obj, 0, NULL); - if (JS_IsException(enum_obj)) - return enum_obj; - if (!JS_IsObject(enum_obj)) { - JS_FreeValue(ctx, enum_obj); - return JS_ThrowTypeErrorNotAnObject(ctx); - } - return enum_obj; -} - -static JSValue JS_GetIterator(JSContext *ctx, JSValueConst obj, BOOL is_async) -{ - JSValue method, ret, sync_iter; - - if (is_async) { - method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_asyncIterator); - if (JS_IsException(method)) - return method; - if (JS_IsUndefined(method) || JS_IsNull(method)) { - method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator); - if (JS_IsException(method)) - return method; - sync_iter = JS_GetIterator2(ctx, obj, method); - JS_FreeValue(ctx, method); - if (JS_IsException(sync_iter)) - return sync_iter; - ret = JS_CreateAsyncFromSyncIterator(ctx, sync_iter); - JS_FreeValue(ctx, sync_iter); - return ret; - } - } else { - method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator); - if (JS_IsException(method)) - return method; - } - if (!JS_IsFunction(ctx, method)) { - JS_FreeValue(ctx, method); - return JS_ThrowTypeError(ctx, "value is not iterable"); - } - ret = JS_GetIterator2(ctx, obj, method); - JS_FreeValue(ctx, method); - return ret; -} - -/* return *pdone = 2 if the iterator object is not parsed */ -static JSValue JS_IteratorNext2(JSContext *ctx, JSValueConst enum_obj, - JSValueConst method, - int argc, JSValueConst *argv, int *pdone) -{ - JSValue obj; - - /* fast path for the built-in iterators (avoid creating the - intermediate result object) */ - if (JS_IsObject(method)) { - JSObject *p = JS_VALUE_GET_OBJ(method); - if (p->class_id == JS_CLASS_C_FUNCTION && - p->u.cfunc.cproto == JS_CFUNC_iterator_next) { - JSCFunctionType func; - JSValueConst args[1]; - - /* in case the function expects one argument */ - if (argc == 0) { - args[0] = JS_UNDEFINED; - argv = args; - } - func = p->u.cfunc.c_function; - return func.iterator_next(ctx, enum_obj, argc, argv, - pdone, p->u.cfunc.magic); - } - } - obj = JS_Call(ctx, method, enum_obj, argc, argv); - if (JS_IsException(obj)) - goto fail; - if (!JS_IsObject(obj)) { - JS_FreeValue(ctx, obj); - JS_ThrowTypeError(ctx, "iterator must return an object"); - goto fail; - } - *pdone = 2; - return obj; - fail: - *pdone = FALSE; - return JS_EXCEPTION; -} - -/* Note: always return JS_UNDEFINED when *pdone = TRUE. */ -static JSValue JS_IteratorNext(JSContext *ctx, JSValueConst enum_obj, - JSValueConst method, - int argc, JSValueConst *argv, BOOL *pdone) -{ - JSValue obj, value, done_val; - int done; - - obj = JS_IteratorNext2(ctx, enum_obj, method, argc, argv, &done); - if (JS_IsException(obj)) - goto fail; - if (likely(done == 0)) { - *pdone = FALSE; - return obj; - } else if (done != 2) { - JS_FreeValue(ctx, obj); - *pdone = TRUE; - return JS_UNDEFINED; - } else { - done_val = JS_GetProperty(ctx, obj, JS_ATOM_done); - if (JS_IsException(done_val)) - goto fail; - *pdone = JS_ToBoolFree(ctx, done_val); - value = JS_UNDEFINED; - if (!*pdone) { - value = JS_GetProperty(ctx, obj, JS_ATOM_value); - } - JS_FreeValue(ctx, obj); - return value; - } - fail: - JS_FreeValue(ctx, obj); - *pdone = FALSE; - return JS_EXCEPTION; -} - -/* return < 0 in case of exception */ -static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj, - BOOL is_exception_pending) -{ - JSValue method, ret, ex_obj; - int res; - - if (is_exception_pending) { - ex_obj = ctx->rt->current_exception; - ctx->rt->current_exception = JS_UNINITIALIZED; - res = -1; - } else { - ex_obj = JS_UNDEFINED; - res = 0; - } - method = JS_GetProperty(ctx, enum_obj, JS_ATOM_return); - if (JS_IsException(method)) { - res = -1; - goto done; - } - if (JS_IsUndefined(method) || JS_IsNull(method)) { - goto done; - } - ret = JS_CallFree(ctx, method, enum_obj, 0, NULL); - if (!is_exception_pending) { - if (JS_IsException(ret)) { - res = -1; - } else if (!JS_IsObject(ret)) { - JS_ThrowTypeErrorNotAnObject(ctx); - res = -1; - } - } - JS_FreeValue(ctx, ret); - done: - if (is_exception_pending) { - JS_Throw(ctx, ex_obj); - } - return res; -} - -/* obj -> enum_rec (3 slots) */ -static __exception int js_for_of_start(JSContext *ctx, JSValue *sp, - BOOL is_async) -{ - JSValue op1, obj, method; - op1 = sp[-1]; - obj = JS_GetIterator(ctx, op1, is_async); - if (JS_IsException(obj)) - return -1; - JS_FreeValue(ctx, op1); - sp[-1] = obj; - method = JS_GetProperty(ctx, obj, JS_ATOM_next); - if (JS_IsException(method)) - return -1; - sp[0] = method; - return 0; -} - -/* enum_rec [objs] -> enum_rec [objs] value done. There are 'offset' - objs. If 'done' is true or in case of exception, 'enum_rec' is set - to undefined. If 'done' is true, 'value' is always set to - undefined. */ -static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset) -{ - JSValue value = JS_UNDEFINED; - int done = 1; - - if (likely(!JS_IsUndefined(sp[offset]))) { - value = JS_IteratorNext(ctx, sp[offset], sp[offset + 1], 0, NULL, &done); - if (JS_IsException(value)) - done = -1; - if (done) { - /* value is JS_UNDEFINED or JS_EXCEPTION */ - /* replace the iteration object with undefined */ - JS_FreeValue(ctx, sp[offset]); - sp[offset] = JS_UNDEFINED; - if (done < 0) { - return -1; - } else { - JS_FreeValue(ctx, value); - value = JS_UNDEFINED; - } - } - } - sp[0] = value; - sp[1] = JS_NewBool(ctx, done); - return 0; -} - -static __exception int js_for_await_of_next(JSContext *ctx, JSValue *sp) -{ - JSValue obj, iter, next; - - sp[-1] = JS_UNDEFINED; /* disable the catch offset so that - exceptions do not close the iterator */ - iter = sp[-3]; - next = sp[-2]; - obj = JS_Call(ctx, next, iter, 0, NULL); - if (JS_IsException(obj)) - return -1; - sp[0] = obj; - return 0; -} - -static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValueConst obj, - BOOL *pdone) -{ - JSValue done_val, value; - BOOL done; - done_val = JS_GetProperty(ctx, obj, JS_ATOM_done); - if (JS_IsException(done_val)) - goto fail; - done = JS_ToBoolFree(ctx, done_val); - value = JS_GetProperty(ctx, obj, JS_ATOM_value); - if (JS_IsException(value)) - goto fail; - *pdone = done; - return value; - fail: - *pdone = FALSE; - return JS_EXCEPTION; -} - -static __exception int js_iterator_get_value_done(JSContext *ctx, JSValue *sp) -{ - JSValue obj, value; - BOOL done; - obj = sp[-1]; - if (!JS_IsObject(obj)) { - JS_ThrowTypeError(ctx, "iterator must return an object"); - return -1; - } - value = JS_IteratorGetCompleteValue(ctx, obj, &done); - if (JS_IsException(value)) - return -1; - JS_FreeValue(ctx, obj); - /* put again the catch offset so that exceptions close the - iterator */ - sp[-2] = JS_NewCatchOffset(ctx, 0); - sp[-1] = value; - sp[0] = JS_NewBool(ctx, done); - return 0; -} - -static JSValue js_create_iterator_result(JSContext *ctx, - JSValue val, - BOOL done) -{ - JSValue obj; - obj = JS_NewObject(ctx); - if (JS_IsException(obj)) { - JS_FreeValue(ctx, val); - return obj; - } - if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_value, - val, JS_PROP_C_W_E) < 0) { - goto fail; - } - if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_done, - JS_NewBool(ctx, done), JS_PROP_C_W_E) < 0) { - fail: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - return obj; -} - -static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - BOOL *pdone, int magic); - -static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic); - -static BOOL js_is_fast_array(JSContext *ctx, JSValueConst obj) -{ - /* Try and handle fast arrays explicitly */ - if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(obj); - if (p->class_id == JS_CLASS_ARRAY && p->fast_array) { - return TRUE; - } - } - return FALSE; -} - -/* Access an Array's internal JSValue array if available */ -static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj, - JSValue **arrpp, uint32_t *countp) -{ - /* Try and handle fast arrays explicitly */ - if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(obj); - if (p->class_id == JS_CLASS_ARRAY && p->fast_array) { - *countp = p->u.array.count; - *arrpp = p->u.array.u.values; - return TRUE; - } - } - return FALSE; -} - -static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp) -{ - JSValue iterator, enumobj, method, value; - int is_array_iterator; - JSValue *arrp; - uint32_t i, count32, pos; - - if (JS_VALUE_GET_TAG(sp[-2]) != JS_TAG_INT) { - JS_ThrowInternalError(ctx, "invalid index for append"); - return -1; - } - - pos = JS_VALUE_GET_INT(sp[-2]); - - /* XXX: further optimisations: - - use ctx->array_proto_values? - - check if array_iterator_prototype next method is built-in and - avoid constructing actual iterator object? - - build this into js_for_of_start and use in all `for (x of o)` loops - */ - iterator = JS_GetProperty(ctx, sp[-1], JS_ATOM_Symbol_iterator); - if (JS_IsException(iterator)) - return -1; - is_array_iterator = JS_IsCFunction(ctx, iterator, - (JSCFunction *)js_create_array_iterator, - JS_ITERATOR_KIND_VALUE); - JS_FreeValue(ctx, iterator); - - enumobj = JS_GetIterator(ctx, sp[-1], FALSE); - if (JS_IsException(enumobj)) - return -1; - method = JS_GetProperty(ctx, enumobj, JS_ATOM_next); - if (JS_IsException(method)) { - JS_FreeValue(ctx, enumobj); - return -1; - } - if (is_array_iterator - && JS_IsCFunction(ctx, method, (JSCFunction *)js_array_iterator_next, 0) - && js_get_fast_array(ctx, sp[-1], &arrp, &count32)) { - uint32_t len; - if (js_get_length32(ctx, &len, sp[-1])) - goto exception; - /* if len > count32, the elements >= count32 might be read in - the prototypes and might have side effects */ - if (len != count32) - goto general_case; - /* Handle fast arrays explicitly */ - for (i = 0; i < count32; i++) { - if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, - JS_DupValue(ctx, arrp[i]), JS_PROP_C_W_E) < 0) - goto exception; - } - } else { - general_case: - for (;;) { - BOOL done; - value = JS_IteratorNext(ctx, enumobj, method, 0, NULL, &done); - if (JS_IsException(value)) - goto exception; - if (done) { - /* value is JS_UNDEFINED */ - break; - } - if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, value, JS_PROP_C_W_E) < 0) - goto exception; - } - } - /* Note: could raise an error if too many elements */ - sp[-2] = JS_NewInt32(ctx, pos); - JS_FreeValue(ctx, enumobj); - JS_FreeValue(ctx, method); - return 0; - -exception: - JS_IteratorClose(ctx, enumobj, TRUE); - JS_FreeValue(ctx, enumobj); - JS_FreeValue(ctx, method); - return -1; -} - -static __exception int JS_CopyDataProperties(JSContext *ctx, - JSValueConst target, - JSValueConst source, - JSValueConst excluded, - BOOL setprop) -{ - JSPropertyEnum *tab_atom; - JSValue val; - uint32_t i, tab_atom_count; - JSObject *p; - JSObject *pexcl = NULL; - int ret, gpn_flags; - JSPropertyDescriptor desc; - BOOL is_enumerable; - - if (JS_VALUE_GET_TAG(source) != JS_TAG_OBJECT) - return 0; - - if (JS_VALUE_GET_TAG(excluded) == JS_TAG_OBJECT) - pexcl = JS_VALUE_GET_OBJ(excluded); - - p = JS_VALUE_GET_OBJ(source); - - gpn_flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK | JS_GPN_ENUM_ONLY; - if (p->is_exotic) { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - /* cannot use JS_GPN_ENUM_ONLY with e.g. proxies because it - introduces a visible change */ - if (em && em->get_own_property_names) { - gpn_flags &= ~JS_GPN_ENUM_ONLY; - } - } - if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p, - gpn_flags)) - return -1; - - for (i = 0; i < tab_atom_count; i++) { - if (pexcl) { - ret = JS_GetOwnPropertyInternal(ctx, NULL, pexcl, tab_atom[i].atom); - if (ret) { - if (ret < 0) - goto exception; - continue; - } - } - if (!(gpn_flags & JS_GPN_ENUM_ONLY)) { - /* test if the property is enumerable */ - ret = JS_GetOwnPropertyInternal(ctx, &desc, p, tab_atom[i].atom); - if (ret < 0) - goto exception; - if (!ret) - continue; - is_enumerable = (desc.flags & JS_PROP_ENUMERABLE) != 0; - js_free_desc(ctx, &desc); - if (!is_enumerable) - continue; - } - val = JS_GetProperty(ctx, source, tab_atom[i].atom); - if (JS_IsException(val)) - goto exception; - if (setprop) - ret = JS_SetProperty(ctx, target, tab_atom[i].atom, val); - else - ret = JS_DefinePropertyValue(ctx, target, tab_atom[i].atom, val, - JS_PROP_C_W_E); - if (ret < 0) - goto exception; - } - JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count); - return 0; - exception: - JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count); - return -1; -} - -/* only valid inside C functions */ -static JSValueConst JS_GetActiveFunction(JSContext *ctx) -{ - return ctx->rt->current_stack_frame->cur_func; -} - -static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, - int var_idx, BOOL is_arg) -{ - JSVarRef *var_ref; - struct list_head *el; - JSValue *pvalue; - - if (is_arg) - pvalue = &sf->arg_buf[var_idx]; - else - pvalue = &sf->var_buf[var_idx]; - - list_for_each(el, &sf->var_ref_list) { - var_ref = list_entry(el, JSVarRef, var_ref_link); - if (var_ref->pvalue == pvalue) { - var_ref->header.ref_count++; - return var_ref; - } - } - /* create a new one */ - var_ref = js_malloc(ctx, sizeof(JSVarRef)); - if (!var_ref) - return NULL; - var_ref->header.ref_count = 1; - add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF); - var_ref->is_detached = FALSE; - list_add_tail(&var_ref->var_ref_link, &sf->var_ref_list); - if (sf->js_mode & JS_MODE_ASYNC) { - /* The stack frame is detached and may be destroyed at any - time so its reference count must be increased. Calling - close_var_refs() when destroying the stack frame is not - possible because it would change the graph between the GC - objects. Another solution could be to temporarily detach - the JSVarRef of async functions during the GC. It would - have the advantage of allowing the release of unused stack - frames in a cycle. */ - var_ref->async_func = container_of(sf, JSAsyncFunctionState, frame); - var_ref->async_func->header.ref_count++; - } else { - var_ref->async_func = NULL; - } - var_ref->pvalue = pvalue; - return var_ref; -} - -static JSValue js_closure2(JSContext *ctx, JSValue func_obj, - JSFunctionBytecode *b, - JSVarRef **cur_var_refs, - JSStackFrame *sf) -{ - JSObject *p; - JSVarRef **var_refs; - int i; - - p = JS_VALUE_GET_OBJ(func_obj); - p->u.func.function_bytecode = b; - p->u.func.home_object = NULL; - p->u.func.var_refs = NULL; - if (b->closure_var_count) { - var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count); - if (!var_refs) - goto fail; - p->u.func.var_refs = var_refs; - for(i = 0; i < b->closure_var_count; i++) { - JSClosureVar *cv = &b->closure_var[i]; - JSVarRef *var_ref; - if (cv->is_local) { - /* reuse the existing variable reference if it already exists */ - var_ref = get_var_ref(ctx, sf, cv->var_idx, cv->is_arg); - if (!var_ref) - goto fail; - } else { - var_ref = cur_var_refs[cv->var_idx]; - var_ref->header.ref_count++; - } - var_refs[i] = var_ref; - } - } - return func_obj; - fail: - /* bfunc is freed when func_obj is freed */ - JS_FreeValue(ctx, func_obj); - return JS_EXCEPTION; -} - -static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque) -{ - JSValue obj, this_val; - int ret; - - this_val = JS_MKPTR(JS_TAG_OBJECT, p); - obj = JS_NewObject(ctx); - if (JS_IsException(obj)) - return JS_EXCEPTION; - set_cycle_flag(ctx, obj); - set_cycle_flag(ctx, this_val); - ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_constructor, - JS_DupValue(ctx, this_val), - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - if (ret < 0) { - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - return obj; -} - -static const uint16_t func_kind_to_class_id[] = { - [JS_FUNC_NORMAL] = JS_CLASS_BYTECODE_FUNCTION, - [JS_FUNC_GENERATOR] = JS_CLASS_GENERATOR_FUNCTION, - [JS_FUNC_ASYNC] = JS_CLASS_ASYNC_FUNCTION, - [JS_FUNC_ASYNC_GENERATOR] = JS_CLASS_ASYNC_GENERATOR_FUNCTION, -}; - -static JSValue js_closure(JSContext *ctx, JSValue bfunc, - JSVarRef **cur_var_refs, - JSStackFrame *sf) -{ - JSFunctionBytecode *b; - JSValue func_obj; - JSAtom name_atom; - - b = JS_VALUE_GET_PTR(bfunc); - func_obj = JS_NewObjectClass(ctx, func_kind_to_class_id[b->func_kind]); - if (JS_IsException(func_obj)) { - JS_FreeValue(ctx, bfunc); - return JS_EXCEPTION; - } - func_obj = js_closure2(ctx, func_obj, b, cur_var_refs, sf); - if (JS_IsException(func_obj)) { - /* bfunc has been freed */ - goto fail; - } - name_atom = b->func_name; - if (name_atom == JS_ATOM_NULL) - name_atom = JS_ATOM_empty_string; - js_function_set_properties(ctx, func_obj, name_atom, - b->defined_arg_count); - - if (b->func_kind & JS_FUNC_GENERATOR) { - JSValue proto; - int proto_class_id; - /* generators have a prototype field which is used as - prototype for the generator object */ - if (b->func_kind == JS_FUNC_ASYNC_GENERATOR) - proto_class_id = JS_CLASS_ASYNC_GENERATOR; - else - proto_class_id = JS_CLASS_GENERATOR; - proto = JS_NewObjectProto(ctx, ctx->class_proto[proto_class_id]); - if (JS_IsException(proto)) - goto fail; - JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype, proto, - JS_PROP_WRITABLE); - } else if (b->has_prototype) { - /* add the 'prototype' property: delay instantiation to avoid - creating cycles for every javascript function. The prototype - object is created on the fly when first accessed */ - JS_SetConstructorBit(ctx, func_obj, TRUE); - JS_DefineAutoInitProperty(ctx, func_obj, JS_ATOM_prototype, - JS_AUTOINIT_ID_PROTOTYPE, NULL, - JS_PROP_WRITABLE); - } - return func_obj; - fail: - /* bfunc is freed when func_obj is freed */ - JS_FreeValue(ctx, func_obj); - return JS_EXCEPTION; -} - -#define JS_DEFINE_CLASS_HAS_HERITAGE (1 << 0) - -static int js_op_define_class(JSContext *ctx, JSValue *sp, - JSAtom class_name, int class_flags, - JSVarRef **cur_var_refs, - JSStackFrame *sf, BOOL is_computed_name) -{ - JSValue bfunc, parent_class, proto = JS_UNDEFINED; - JSValue ctor = JS_UNDEFINED, parent_proto = JS_UNDEFINED; - JSFunctionBytecode *b; - - parent_class = sp[-2]; - bfunc = sp[-1]; - - if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE) { - if (JS_IsNull(parent_class)) { - parent_proto = JS_NULL; - parent_class = JS_DupValue(ctx, ctx->function_proto); - } else { - if (!JS_IsConstructor(ctx, parent_class)) { - JS_ThrowTypeError(ctx, "parent class must be constructor"); - goto fail; - } - parent_proto = JS_GetProperty(ctx, parent_class, JS_ATOM_prototype); - if (JS_IsException(parent_proto)) - goto fail; - if (!JS_IsNull(parent_proto) && !JS_IsObject(parent_proto)) { - JS_ThrowTypeError(ctx, "parent prototype must be an object or null"); - goto fail; - } - } - } else { - /* parent_class is JS_UNDEFINED in this case */ - parent_proto = JS_DupValue(ctx, ctx->class_proto[JS_CLASS_OBJECT]); - parent_class = JS_DupValue(ctx, ctx->function_proto); - } - proto = JS_NewObjectProto(ctx, parent_proto); - if (JS_IsException(proto)) - goto fail; - - b = JS_VALUE_GET_PTR(bfunc); - assert(b->func_kind == JS_FUNC_NORMAL); - ctor = JS_NewObjectProtoClass(ctx, parent_class, - JS_CLASS_BYTECODE_FUNCTION); - if (JS_IsException(ctor)) - goto fail; - ctor = js_closure2(ctx, ctor, b, cur_var_refs, sf); - bfunc = JS_UNDEFINED; - if (JS_IsException(ctor)) - goto fail; - js_method_set_home_object(ctx, ctor, proto); - JS_SetConstructorBit(ctx, ctor, TRUE); - - JS_DefinePropertyValue(ctx, ctor, JS_ATOM_length, - JS_NewInt32(ctx, b->defined_arg_count), - JS_PROP_CONFIGURABLE); - - if (is_computed_name) { - if (JS_DefineObjectNameComputed(ctx, ctor, sp[-3], - JS_PROP_CONFIGURABLE) < 0) - goto fail; - } else { - if (JS_DefineObjectName(ctx, ctor, class_name, JS_PROP_CONFIGURABLE) < 0) - goto fail; - } - - /* the constructor property must be first. It can be overriden by - computed property names */ - if (JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor, - JS_DupValue(ctx, ctor), - JS_PROP_CONFIGURABLE | - JS_PROP_WRITABLE | JS_PROP_THROW) < 0) - goto fail; - /* set the prototype property */ - if (JS_DefinePropertyValue(ctx, ctor, JS_ATOM_prototype, - JS_DupValue(ctx, proto), JS_PROP_THROW) < 0) - goto fail; - set_cycle_flag(ctx, ctor); - set_cycle_flag(ctx, proto); - - JS_FreeValue(ctx, parent_proto); - JS_FreeValue(ctx, parent_class); - - sp[-2] = ctor; - sp[-1] = proto; - return 0; - fail: - JS_FreeValue(ctx, parent_class); - JS_FreeValue(ctx, parent_proto); - JS_FreeValue(ctx, bfunc); - JS_FreeValue(ctx, proto); - JS_FreeValue(ctx, ctor); - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -static void close_var_refs(JSRuntime *rt, JSStackFrame *sf) -{ - struct list_head *el, *el1; - JSVarRef *var_ref; - - list_for_each_safe(el, el1, &sf->var_ref_list) { - var_ref = list_entry(el, JSVarRef, var_ref_link); - /* no need to unlink var_ref->var_ref_link as the list is never used afterwards */ - if (var_ref->async_func) - async_func_free(rt, var_ref->async_func); - var_ref->value = JS_DupValueRT(rt, *var_ref->pvalue); - var_ref->pvalue = &var_ref->value; - /* the reference is no longer to a local variable */ - var_ref->is_detached = TRUE; - } -} - -static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int var_idx) -{ - JSValue *pvalue; - struct list_head *el, *el1; - JSVarRef *var_ref; - - pvalue = &sf->var_buf[var_idx]; - list_for_each_safe(el, el1, &sf->var_ref_list) { - var_ref = list_entry(el, JSVarRef, var_ref_link); - if (var_ref->pvalue == pvalue) { - list_del(&var_ref->var_ref_link); - if (var_ref->async_func) - async_func_free(ctx->rt, var_ref->async_func); - var_ref->value = JS_DupValue(ctx, *var_ref->pvalue); - var_ref->pvalue = &var_ref->value; - /* the reference is no longer to a local variable */ - var_ref->is_detached = TRUE; - } - } -} - -#define JS_CALL_FLAG_COPY_ARGV (1 << 1) -#define JS_CALL_FLAG_GENERATOR (1 << 2) - -static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, int flags) -{ - JSRuntime *rt = ctx->rt; - JSCFunctionType func; - JSObject *p; - JSStackFrame sf_s, *sf = &sf_s, *prev_sf; - JSValue ret_val; - JSValueConst *arg_buf; - int arg_count, i; - JSCFunctionEnum cproto; - - p = JS_VALUE_GET_OBJ(func_obj); - cproto = p->u.cfunc.cproto; - arg_count = p->u.cfunc.length; - - /* better to always check stack overflow */ - if (js_check_stack_overflow(rt, sizeof(arg_buf[0]) * arg_count)) - return JS_ThrowStackOverflow(ctx); - - prev_sf = rt->current_stack_frame; - sf->prev_frame = prev_sf; - rt->current_stack_frame = sf; - ctx = p->u.cfunc.realm; /* change the current realm */ - sf->js_mode = 0; - sf->cur_func = (JSValue)func_obj; - sf->arg_count = argc; - arg_buf = argv; - - if (unlikely(argc < arg_count)) { - /* ensure that at least argc_count arguments are readable */ - arg_buf = alloca(sizeof(arg_buf[0]) * arg_count); - for(i = 0; i < argc; i++) - arg_buf[i] = argv[i]; - for(i = argc; i < arg_count; i++) - arg_buf[i] = JS_UNDEFINED; - sf->arg_count = arg_count; - } - sf->arg_buf = (JSValue*)arg_buf; - - func = p->u.cfunc.c_function; - switch(cproto) { - case JS_CFUNC_constructor: - case JS_CFUNC_constructor_or_func: - if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) { - if (cproto == JS_CFUNC_constructor) { - not_a_constructor: - ret_val = JS_ThrowTypeError(ctx, "must be called with new"); - break; - } else { - this_obj = JS_UNDEFINED; - } - } - /* here this_obj is new_target */ - /* fall thru */ - case JS_CFUNC_generic: - ret_val = func.generic(ctx, this_obj, argc, arg_buf); - break; - case JS_CFUNC_constructor_magic: - case JS_CFUNC_constructor_or_func_magic: - if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) { - if (cproto == JS_CFUNC_constructor_magic) { - goto not_a_constructor; - } else { - this_obj = JS_UNDEFINED; - } - } - /* fall thru */ - case JS_CFUNC_generic_magic: - ret_val = func.generic_magic(ctx, this_obj, argc, arg_buf, - p->u.cfunc.magic); - break; - case JS_CFUNC_getter: - ret_val = func.getter(ctx, this_obj); - break; - case JS_CFUNC_setter: - ret_val = func.setter(ctx, this_obj, arg_buf[0]); - break; - case JS_CFUNC_getter_magic: - ret_val = func.getter_magic(ctx, this_obj, p->u.cfunc.magic); - break; - case JS_CFUNC_setter_magic: - ret_val = func.setter_magic(ctx, this_obj, arg_buf[0], p->u.cfunc.magic); - break; - case JS_CFUNC_f_f: - { - double d1; - - if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) { - ret_val = JS_EXCEPTION; - break; - } - ret_val = JS_NewFloat64(ctx, func.f_f(d1)); - } - break; - case JS_CFUNC_f_f_f: - { - double d1, d2; - - if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) { - ret_val = JS_EXCEPTION; - break; - } - if (unlikely(JS_ToFloat64(ctx, &d2, arg_buf[1]))) { - ret_val = JS_EXCEPTION; - break; - } - ret_val = JS_NewFloat64(ctx, func.f_f_f(d1, d2)); - } - break; - case JS_CFUNC_iterator_next: - { - int done; - ret_val = func.iterator_next(ctx, this_obj, argc, arg_buf, - &done, p->u.cfunc.magic); - if (!JS_IsException(ret_val) && done != 2) { - ret_val = js_create_iterator_result(ctx, ret_val, done); - } - } - break; - default: - abort(); - } - - rt->current_stack_frame = sf->prev_frame; - return ret_val; -} - -static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, int flags) -{ - JSObject *p; - JSBoundFunction *bf; - JSValueConst *arg_buf, new_target; - int arg_count, i; - - p = JS_VALUE_GET_OBJ(func_obj); - bf = p->u.bound_function; - arg_count = bf->argc + argc; - if (js_check_stack_overflow(ctx->rt, sizeof(JSValue) * arg_count)) - return JS_ThrowStackOverflow(ctx); - arg_buf = alloca(sizeof(JSValue) * arg_count); - for(i = 0; i < bf->argc; i++) { - arg_buf[i] = bf->argv[i]; - } - for(i = 0; i < argc; i++) { - arg_buf[bf->argc + i] = argv[i]; - } - if (flags & JS_CALL_FLAG_CONSTRUCTOR) { - new_target = this_obj; - if (js_same_value(ctx, func_obj, new_target)) - new_target = bf->func_obj; - return JS_CallConstructor2(ctx, bf->func_obj, new_target, - arg_count, arg_buf); - } else { - return JS_Call(ctx, bf->func_obj, bf->this_val, - arg_count, arg_buf); - } -} - -/* argument of OP_special_object */ -typedef enum { - OP_SPECIAL_OBJECT_ARGUMENTS, - OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS, - OP_SPECIAL_OBJECT_THIS_FUNC, - OP_SPECIAL_OBJECT_NEW_TARGET, - OP_SPECIAL_OBJECT_HOME_OBJECT, - OP_SPECIAL_OBJECT_VAR_OBJECT, - OP_SPECIAL_OBJECT_IMPORT_META, -} OPSpecialObjectEnum; - -#define FUNC_RET_AWAIT 0 -#define FUNC_RET_YIELD 1 -#define FUNC_RET_YIELD_STAR 2 -#define FUNC_RET_INITIAL_YIELD 3 - -/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */ -static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, - JSValueConst this_obj, JSValueConst new_target, - int argc, JSValue *argv, int flags) -{ - JSRuntime *rt = caller_ctx->rt; - JSContext *ctx; - JSObject *p; - JSFunctionBytecode *b; - JSStackFrame sf_s, *sf = &sf_s; - const uint8_t *pc; - int opcode, arg_allocated_size, i; - JSValue *local_buf, *stack_buf, *var_buf, *arg_buf, *sp, ret_val, *pval; - JSVarRef **var_refs; - size_t alloca_size; - -#if !DIRECT_DISPATCH -#define SWITCH(pc) switch (opcode = *pc++) -#define CASE(op) case op -#define DEFAULT default -#define BREAK break -#else - static const void * const dispatch_table[256] = { -#define DEF(id, size, n_pop, n_push, f) && case_OP_ ## id, -#if SHORT_OPCODES -#define def(id, size, n_pop, n_push, f) -#else -#define def(id, size, n_pop, n_push, f) && case_default, -#endif -#include "quickjs-opcode.h" - [ OP_COUNT ... 255 ] = &&case_default - }; -#define SWITCH(pc) goto *dispatch_table[opcode = *pc++]; -#define CASE(op) case_ ## op -#define DEFAULT case_default -#define BREAK SWITCH(pc) -#endif - - if (js_poll_interrupts(caller_ctx)) - return JS_EXCEPTION; - if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)) { - if (flags & JS_CALL_FLAG_GENERATOR) { - JSAsyncFunctionState *s = JS_VALUE_GET_PTR(func_obj); - /* func_obj get contains a pointer to JSFuncAsyncState */ - /* the stack frame is already allocated */ - sf = &s->frame; - p = JS_VALUE_GET_OBJ(sf->cur_func); - b = p->u.func.function_bytecode; - ctx = b->realm; - var_refs = p->u.func.var_refs; - local_buf = arg_buf = sf->arg_buf; - var_buf = sf->var_buf; - stack_buf = sf->var_buf + b->var_count; - sp = sf->cur_sp; - sf->cur_sp = NULL; /* cur_sp is NULL if the function is running */ - pc = sf->cur_pc; - sf->prev_frame = rt->current_stack_frame; - rt->current_stack_frame = sf; - if (s->throw_flag) - goto exception; - else - goto restart; - } else { - goto not_a_function; - } - } - p = JS_VALUE_GET_OBJ(func_obj); - if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) { - JSClassCall *call_func; - call_func = rt->class_array[p->class_id].call; - if (!call_func) { - not_a_function: - return JS_ThrowTypeError(caller_ctx, "not a function"); - } - return call_func(caller_ctx, func_obj, this_obj, argc, - (JSValueConst *)argv, flags); - } - b = p->u.func.function_bytecode; - - if (unlikely(argc < b->arg_count || (flags & JS_CALL_FLAG_COPY_ARGV))) { - arg_allocated_size = b->arg_count; - } else { - arg_allocated_size = 0; - } - - alloca_size = sizeof(JSValue) * (arg_allocated_size + b->var_count + - b->stack_size); - if (js_check_stack_overflow(rt, alloca_size)) - return JS_ThrowStackOverflow(caller_ctx); - - sf->js_mode = b->js_mode; - arg_buf = argv; - sf->arg_count = argc; - sf->cur_func = (JSValue)func_obj; - init_list_head(&sf->var_ref_list); - var_refs = p->u.func.var_refs; - - local_buf = alloca(alloca_size); - if (unlikely(arg_allocated_size)) { - int n = min_int(argc, b->arg_count); - arg_buf = local_buf; - for(i = 0; i < n; i++) - arg_buf[i] = JS_DupValue(caller_ctx, argv[i]); - for(; i < b->arg_count; i++) - arg_buf[i] = JS_UNDEFINED; - sf->arg_count = b->arg_count; - } - var_buf = local_buf + arg_allocated_size; - sf->var_buf = var_buf; - sf->arg_buf = arg_buf; - - for(i = 0; i < b->var_count; i++) - var_buf[i] = JS_UNDEFINED; - - stack_buf = var_buf + b->var_count; - sp = stack_buf; - pc = b->byte_code_buf; - sf->prev_frame = rt->current_stack_frame; - rt->current_stack_frame = sf; - ctx = b->realm; /* set the current realm */ - - restart: - for(;;) { - int call_argc; - JSValue *call_argv; - - SWITCH(pc) { - CASE(OP_push_i32): - *sp++ = JS_NewInt32(ctx, get_u32(pc)); - pc += 4; - BREAK; - CASE(OP_push_bigint_i32): - *sp++ = __JS_NewShortBigInt(ctx, (int)get_u32(pc)); - pc += 4; - BREAK; - CASE(OP_push_const): - *sp++ = JS_DupValue(ctx, b->cpool[get_u32(pc)]); - pc += 4; - BREAK; -#if SHORT_OPCODES - CASE(OP_push_minus1): - CASE(OP_push_0): - CASE(OP_push_1): - CASE(OP_push_2): - CASE(OP_push_3): - CASE(OP_push_4): - CASE(OP_push_5): - CASE(OP_push_6): - CASE(OP_push_7): - *sp++ = JS_NewInt32(ctx, opcode - OP_push_0); - BREAK; - CASE(OP_push_i8): - *sp++ = JS_NewInt32(ctx, get_i8(pc)); - pc += 1; - BREAK; - CASE(OP_push_i16): - *sp++ = JS_NewInt32(ctx, get_i16(pc)); - pc += 2; - BREAK; - CASE(OP_push_const8): - *sp++ = JS_DupValue(ctx, b->cpool[*pc++]); - BREAK; - CASE(OP_fclosure8): - *sp++ = js_closure(ctx, JS_DupValue(ctx, b->cpool[*pc++]), var_refs, sf); - if (unlikely(JS_IsException(sp[-1]))) - goto exception; - BREAK; - CASE(OP_push_empty_string): - *sp++ = JS_AtomToString(ctx, JS_ATOM_empty_string); - BREAK; - CASE(OP_get_length): - { - JSValue val; - - sf->cur_pc = pc; - val = JS_GetProperty(ctx, sp[-1], JS_ATOM_length); - if (unlikely(JS_IsException(val))) - goto exception; - JS_FreeValue(ctx, sp[-1]); - sp[-1] = val; - } - BREAK; -#endif - CASE(OP_push_atom_value): - *sp++ = JS_AtomToValue(ctx, get_u32(pc)); - pc += 4; - BREAK; - CASE(OP_undefined): - *sp++ = JS_UNDEFINED; - BREAK; - CASE(OP_null): - *sp++ = JS_NULL; - BREAK; - CASE(OP_push_this): - /* OP_push_this is only called at the start of a function */ - { - JSValue val; - if (!(b->js_mode & JS_MODE_STRICT)) { - uint32_t tag = JS_VALUE_GET_TAG(this_obj); - if (likely(tag == JS_TAG_OBJECT)) - goto normal_this; - if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) { - val = JS_DupValue(ctx, ctx->global_obj); - } else { - val = JS_ToObject(ctx, this_obj); - if (JS_IsException(val)) - goto exception; - } - } else { - normal_this: - val = JS_DupValue(ctx, this_obj); - } - *sp++ = val; - } - BREAK; - CASE(OP_push_false): - *sp++ = JS_FALSE; - BREAK; - CASE(OP_push_true): - *sp++ = JS_TRUE; - BREAK; - CASE(OP_object): - *sp++ = JS_NewObject(ctx); - if (unlikely(JS_IsException(sp[-1]))) - goto exception; - BREAK; - CASE(OP_special_object): - { - int arg = *pc++; - switch(arg) { - case OP_SPECIAL_OBJECT_ARGUMENTS: - *sp++ = js_build_arguments(ctx, argc, (JSValueConst *)argv); - if (unlikely(JS_IsException(sp[-1]))) - goto exception; - break; - case OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS: - *sp++ = js_build_mapped_arguments(ctx, argc, (JSValueConst *)argv, - sf, min_int(argc, b->arg_count)); - if (unlikely(JS_IsException(sp[-1]))) - goto exception; - break; - case OP_SPECIAL_OBJECT_THIS_FUNC: - *sp++ = JS_DupValue(ctx, sf->cur_func); - break; - case OP_SPECIAL_OBJECT_NEW_TARGET: - *sp++ = JS_DupValue(ctx, new_target); - break; - case OP_SPECIAL_OBJECT_HOME_OBJECT: - { - JSObject *p1; - p1 = p->u.func.home_object; - if (unlikely(!p1)) - *sp++ = JS_UNDEFINED; - else - *sp++ = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1)); - } - break; - case OP_SPECIAL_OBJECT_VAR_OBJECT: - *sp++ = JS_NewObjectProto(ctx, JS_NULL); - if (unlikely(JS_IsException(sp[-1]))) - goto exception; - break; - case OP_SPECIAL_OBJECT_IMPORT_META: - *sp++ = js_import_meta(ctx); - if (unlikely(JS_IsException(sp[-1]))) - goto exception; - break; - default: - abort(); - } - } - BREAK; - CASE(OP_rest): - { - int first = get_u16(pc); - pc += 2; - *sp++ = js_build_rest(ctx, first, argc, (JSValueConst *)argv); - if (unlikely(JS_IsException(sp[-1]))) - goto exception; - } - BREAK; - - CASE(OP_drop): - JS_FreeValue(ctx, sp[-1]); - sp--; - BREAK; - CASE(OP_nip): - JS_FreeValue(ctx, sp[-2]); - sp[-2] = sp[-1]; - sp--; - BREAK; - CASE(OP_nip1): /* a b c -> b c */ - JS_FreeValue(ctx, sp[-3]); - sp[-3] = sp[-2]; - sp[-2] = sp[-1]; - sp--; - BREAK; - CASE(OP_dup): - sp[0] = JS_DupValue(ctx, sp[-1]); - sp++; - BREAK; - CASE(OP_dup2): /* a b -> a b a b */ - sp[0] = JS_DupValue(ctx, sp[-2]); - sp[1] = JS_DupValue(ctx, sp[-1]); - sp += 2; - BREAK; - CASE(OP_dup3): /* a b c -> a b c a b c */ - sp[0] = JS_DupValue(ctx, sp[-3]); - sp[1] = JS_DupValue(ctx, sp[-2]); - sp[2] = JS_DupValue(ctx, sp[-1]); - sp += 3; - BREAK; - CASE(OP_dup1): /* a b -> a a b */ - sp[0] = sp[-1]; - sp[-1] = JS_DupValue(ctx, sp[-2]); - sp++; - BREAK; - CASE(OP_insert2): /* obj a -> a obj a (dup_x1) */ - sp[0] = sp[-1]; - sp[-1] = sp[-2]; - sp[-2] = JS_DupValue(ctx, sp[0]); - sp++; - BREAK; - CASE(OP_insert3): /* obj prop a -> a obj prop a (dup_x2) */ - sp[0] = sp[-1]; - sp[-1] = sp[-2]; - sp[-2] = sp[-3]; - sp[-3] = JS_DupValue(ctx, sp[0]); - sp++; - BREAK; - CASE(OP_insert4): /* this obj prop a -> a this obj prop a */ - sp[0] = sp[-1]; - sp[-1] = sp[-2]; - sp[-2] = sp[-3]; - sp[-3] = sp[-4]; - sp[-4] = JS_DupValue(ctx, sp[0]); - sp++; - BREAK; - CASE(OP_perm3): /* obj a b -> a obj b (213) */ - { - JSValue tmp; - tmp = sp[-2]; - sp[-2] = sp[-3]; - sp[-3] = tmp; - } - BREAK; - CASE(OP_rot3l): /* x a b -> a b x (231) */ - { - JSValue tmp; - tmp = sp[-3]; - sp[-3] = sp[-2]; - sp[-2] = sp[-1]; - sp[-1] = tmp; - } - BREAK; - CASE(OP_rot4l): /* x a b c -> a b c x */ - { - JSValue tmp; - tmp = sp[-4]; - sp[-4] = sp[-3]; - sp[-3] = sp[-2]; - sp[-2] = sp[-1]; - sp[-1] = tmp; - } - BREAK; - CASE(OP_rot5l): /* x a b c d -> a b c d x */ - { - JSValue tmp; - tmp = sp[-5]; - sp[-5] = sp[-4]; - sp[-4] = sp[-3]; - sp[-3] = sp[-2]; - sp[-2] = sp[-1]; - sp[-1] = tmp; - } - BREAK; - CASE(OP_rot3r): /* a b x -> x a b (312) */ - { - JSValue tmp; - tmp = sp[-1]; - sp[-1] = sp[-2]; - sp[-2] = sp[-3]; - sp[-3] = tmp; - } - BREAK; - CASE(OP_perm4): /* obj prop a b -> a obj prop b */ - { - JSValue tmp; - tmp = sp[-2]; - sp[-2] = sp[-3]; - sp[-3] = sp[-4]; - sp[-4] = tmp; - } - BREAK; - CASE(OP_perm5): /* this obj prop a b -> a this obj prop b */ - { - JSValue tmp; - tmp = sp[-2]; - sp[-2] = sp[-3]; - sp[-3] = sp[-4]; - sp[-4] = sp[-5]; - sp[-5] = tmp; - } - BREAK; - CASE(OP_swap): /* a b -> b a */ - { - JSValue tmp; - tmp = sp[-2]; - sp[-2] = sp[-1]; - sp[-1] = tmp; - } - BREAK; - CASE(OP_swap2): /* a b c d -> c d a b */ - { - JSValue tmp1, tmp2; - tmp1 = sp[-4]; - tmp2 = sp[-3]; - sp[-4] = sp[-2]; - sp[-3] = sp[-1]; - sp[-2] = tmp1; - sp[-1] = tmp2; - } - BREAK; - - CASE(OP_fclosure): - { - JSValue bfunc = JS_DupValue(ctx, b->cpool[get_u32(pc)]); - pc += 4; - *sp++ = js_closure(ctx, bfunc, var_refs, sf); - if (unlikely(JS_IsException(sp[-1]))) - goto exception; - } - BREAK; -#if SHORT_OPCODES - CASE(OP_call0): - CASE(OP_call1): - CASE(OP_call2): - CASE(OP_call3): - call_argc = opcode - OP_call0; - goto has_call_argc; -#endif - CASE(OP_call): - CASE(OP_tail_call): - { - call_argc = get_u16(pc); - pc += 2; - goto has_call_argc; - has_call_argc: - call_argv = sp - call_argc; - sf->cur_pc = pc; - ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED, - JS_UNDEFINED, call_argc, call_argv, 0); - if (unlikely(JS_IsException(ret_val))) - goto exception; - if (opcode == OP_tail_call) - goto done; - for(i = -1; i < call_argc; i++) - JS_FreeValue(ctx, call_argv[i]); - sp -= call_argc + 1; - *sp++ = ret_val; - } - BREAK; - CASE(OP_call_constructor): - { - call_argc = get_u16(pc); - pc += 2; - call_argv = sp - call_argc; - sf->cur_pc = pc; - ret_val = JS_CallConstructorInternal(ctx, call_argv[-2], - call_argv[-1], - call_argc, call_argv, 0); - if (unlikely(JS_IsException(ret_val))) - goto exception; - for(i = -2; i < call_argc; i++) - JS_FreeValue(ctx, call_argv[i]); - sp -= call_argc + 2; - *sp++ = ret_val; - } - BREAK; - CASE(OP_call_method): - CASE(OP_tail_call_method): - { - call_argc = get_u16(pc); - pc += 2; - call_argv = sp - call_argc; - sf->cur_pc = pc; - ret_val = JS_CallInternal(ctx, call_argv[-1], call_argv[-2], - JS_UNDEFINED, call_argc, call_argv, 0); - if (unlikely(JS_IsException(ret_val))) - goto exception; - if (opcode == OP_tail_call_method) - goto done; - for(i = -2; i < call_argc; i++) - JS_FreeValue(ctx, call_argv[i]); - sp -= call_argc + 2; - *sp++ = ret_val; - } - BREAK; - CASE(OP_array_from): - { - int i, ret; - - call_argc = get_u16(pc); - pc += 2; - ret_val = JS_NewArray(ctx); - if (unlikely(JS_IsException(ret_val))) - goto exception; - call_argv = sp - call_argc; - for(i = 0; i < call_argc; i++) { - ret = JS_DefinePropertyValue(ctx, ret_val, __JS_AtomFromUInt32(i), call_argv[i], - JS_PROP_C_W_E | JS_PROP_THROW); - call_argv[i] = JS_UNDEFINED; - if (ret < 0) { - JS_FreeValue(ctx, ret_val); - goto exception; - } - } - sp -= call_argc; - *sp++ = ret_val; - } - BREAK; - - CASE(OP_apply): - { - int magic; - magic = get_u16(pc); - pc += 2; - sf->cur_pc = pc; - - ret_val = js_function_apply(ctx, sp[-3], 2, (JSValueConst *)&sp[-2], magic); - if (unlikely(JS_IsException(ret_val))) - goto exception; - JS_FreeValue(ctx, sp[-3]); - JS_FreeValue(ctx, sp[-2]); - JS_FreeValue(ctx, sp[-1]); - sp -= 3; - *sp++ = ret_val; - } - BREAK; - CASE(OP_return): - ret_val = *--sp; - goto done; - CASE(OP_return_undef): - ret_val = JS_UNDEFINED; - goto done; - - CASE(OP_check_ctor_return): - /* return TRUE if 'this' should be returned */ - if (!JS_IsObject(sp[-1])) { - if (!JS_IsUndefined(sp[-1])) { - JS_ThrowTypeError(caller_ctx, "derived class constructor must return an object or undefined"); - goto exception; - } - sp[0] = JS_TRUE; - } else { - sp[0] = JS_FALSE; - } - sp++; - BREAK; - CASE(OP_check_ctor): - if (JS_IsUndefined(new_target)) { - non_ctor_call: - JS_ThrowTypeError(ctx, "class constructors must be invoked with 'new'"); - goto exception; - } - BREAK; - CASE(OP_init_ctor): - { - JSValue super, ret; - sf->cur_pc = pc; - if (JS_IsUndefined(new_target)) - goto non_ctor_call; - super = JS_GetPrototype(ctx, func_obj); - if (JS_IsException(super)) - goto exception; - ret = JS_CallConstructor2(ctx, super, new_target, argc, (JSValueConst *)argv); - JS_FreeValue(ctx, super); - if (JS_IsException(ret)) - goto exception; - *sp++ = ret; - } - BREAK; - CASE(OP_check_brand): - { - int ret = JS_CheckBrand(ctx, sp[-2], sp[-1]); - if (ret < 0) - goto exception; - if (!ret) { - JS_ThrowTypeError(ctx, "invalid brand on object"); - goto exception; - } - } - BREAK; - CASE(OP_add_brand): - if (JS_AddBrand(ctx, sp[-2], sp[-1]) < 0) - goto exception; - JS_FreeValue(ctx, sp[-2]); - JS_FreeValue(ctx, sp[-1]); - sp -= 2; - BREAK; - - CASE(OP_throw): - JS_Throw(ctx, *--sp); - goto exception; - - CASE(OP_throw_error): -#define JS_THROW_VAR_RO 0 -#define JS_THROW_VAR_REDECL 1 -#define JS_THROW_VAR_UNINITIALIZED 2 -#define JS_THROW_ERROR_DELETE_SUPER 3 -#define JS_THROW_ERROR_ITERATOR_THROW 4 - { - JSAtom atom; - int type; - atom = get_u32(pc); - type = pc[4]; - pc += 5; - if (type == JS_THROW_VAR_RO) - JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, atom); - else - if (type == JS_THROW_VAR_REDECL) - JS_ThrowSyntaxErrorVarRedeclaration(ctx, atom); - else - if (type == JS_THROW_VAR_UNINITIALIZED) - JS_ThrowReferenceErrorUninitialized(ctx, atom); - else - if (type == JS_THROW_ERROR_DELETE_SUPER) - JS_ThrowReferenceError(ctx, "unsupported reference to 'super'"); - else - if (type == JS_THROW_ERROR_ITERATOR_THROW) - JS_ThrowTypeError(ctx, "iterator does not have a throw method"); - else - JS_ThrowInternalError(ctx, "invalid throw var type %d", type); - } - goto exception; - - CASE(OP_eval): - { - JSValueConst obj; - int scope_idx; - call_argc = get_u16(pc); - scope_idx = get_u16(pc + 2) + ARG_SCOPE_END; - pc += 4; - call_argv = sp - call_argc; - sf->cur_pc = pc; - if (js_same_value(ctx, call_argv[-1], ctx->eval_obj)) { - if (call_argc >= 1) - obj = call_argv[0]; - else - obj = JS_UNDEFINED; - ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj, - JS_EVAL_TYPE_DIRECT, scope_idx); - } else { - ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED, - JS_UNDEFINED, call_argc, call_argv, 0); - } - if (unlikely(JS_IsException(ret_val))) - goto exception; - for(i = -1; i < call_argc; i++) - JS_FreeValue(ctx, call_argv[i]); - sp -= call_argc + 1; - *sp++ = ret_val; - } - BREAK; - /* could merge with OP_apply */ - CASE(OP_apply_eval): - { - int scope_idx; - uint32_t len; - JSValue *tab; - JSValueConst obj; - - scope_idx = get_u16(pc) + ARG_SCOPE_END; - pc += 2; - sf->cur_pc = pc; - tab = build_arg_list(ctx, &len, sp[-1]); - if (!tab) - goto exception; - if (js_same_value(ctx, sp[-2], ctx->eval_obj)) { - if (len >= 1) - obj = tab[0]; - else - obj = JS_UNDEFINED; - ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj, - JS_EVAL_TYPE_DIRECT, scope_idx); - } else { - ret_val = JS_Call(ctx, sp[-2], JS_UNDEFINED, len, - (JSValueConst *)tab); - } - free_arg_list(ctx, tab, len); - if (unlikely(JS_IsException(ret_val))) - goto exception; - JS_FreeValue(ctx, sp[-2]); - JS_FreeValue(ctx, sp[-1]); - sp -= 2; - *sp++ = ret_val; - } - BREAK; - - CASE(OP_regexp): - { - sp[-2] = js_regexp_constructor_internal(ctx, JS_UNDEFINED, - sp[-2], sp[-1]); - sp--; - } - BREAK; - - CASE(OP_get_super): - { - JSValue proto; - sf->cur_pc = pc; - proto = JS_GetPrototype(ctx, sp[-1]); - if (JS_IsException(proto)) - goto exception; - JS_FreeValue(ctx, sp[-1]); - sp[-1] = proto; - } - BREAK; - - CASE(OP_import): - { - JSValue val; - sf->cur_pc = pc; - val = js_dynamic_import(ctx, sp[-2], sp[-1]); - if (JS_IsException(val)) - goto exception; - JS_FreeValue(ctx, sp[-2]); - JS_FreeValue(ctx, sp[-1]); - sp--; - sp[-1] = val; - } - BREAK; - - CASE(OP_check_var): - { - int ret; - JSAtom atom; - atom = get_u32(pc); - pc += 4; - sf->cur_pc = pc; - - ret = JS_CheckGlobalVar(ctx, atom); - if (ret < 0) - goto exception; - *sp++ = JS_NewBool(ctx, ret); - } - BREAK; - - CASE(OP_get_var_undef): - CASE(OP_get_var): - { - JSValue val; - JSAtom atom; - atom = get_u32(pc); - pc += 4; - sf->cur_pc = pc; - - val = JS_GetGlobalVar(ctx, atom, opcode - OP_get_var_undef); - if (unlikely(JS_IsException(val))) - goto exception; - *sp++ = val; - } - BREAK; - - CASE(OP_put_var): - CASE(OP_put_var_init): - { - int ret; - JSAtom atom; - atom = get_u32(pc); - pc += 4; - sf->cur_pc = pc; - - ret = JS_SetGlobalVar(ctx, atom, sp[-1], opcode - OP_put_var); - sp--; - if (unlikely(ret < 0)) - goto exception; - } - BREAK; - - CASE(OP_put_var_strict): - { - int ret; - JSAtom atom; - atom = get_u32(pc); - pc += 4; - sf->cur_pc = pc; - - /* sp[-2] is JS_TRUE or JS_FALSE */ - if (unlikely(!JS_VALUE_GET_INT(sp[-2]))) { - JS_ThrowReferenceErrorNotDefined(ctx, atom); - goto exception; - } - ret = JS_SetGlobalVar(ctx, atom, sp[-1], 2); - sp -= 2; - if (unlikely(ret < 0)) - goto exception; - } - BREAK; - - CASE(OP_check_define_var): - { - JSAtom atom; - int flags; - atom = get_u32(pc); - flags = pc[4]; - pc += 5; - sf->cur_pc = pc; - if (JS_CheckDefineGlobalVar(ctx, atom, flags)) - goto exception; - } - BREAK; - CASE(OP_define_var): - { - JSAtom atom; - int flags; - atom = get_u32(pc); - flags = pc[4]; - pc += 5; - sf->cur_pc = pc; - if (JS_DefineGlobalVar(ctx, atom, flags)) - goto exception; - } - BREAK; - CASE(OP_define_func): - { - JSAtom atom; - int flags; - atom = get_u32(pc); - flags = pc[4]; - pc += 5; - sf->cur_pc = pc; - if (JS_DefineGlobalFunction(ctx, atom, sp[-1], flags)) - goto exception; - JS_FreeValue(ctx, sp[-1]); - sp--; - } - BREAK; - - CASE(OP_get_loc): - { - int idx; - idx = get_u16(pc); - pc += 2; - sp[0] = JS_DupValue(ctx, var_buf[idx]); - sp++; - } - BREAK; - CASE(OP_put_loc): - { - int idx; - idx = get_u16(pc); - pc += 2; - set_value(ctx, &var_buf[idx], sp[-1]); - sp--; - } - BREAK; - CASE(OP_set_loc): - { - int idx; - idx = get_u16(pc); - pc += 2; - set_value(ctx, &var_buf[idx], JS_DupValue(ctx, sp[-1])); - } - BREAK; - CASE(OP_get_arg): - { - int idx; - idx = get_u16(pc); - pc += 2; - sp[0] = JS_DupValue(ctx, arg_buf[idx]); - sp++; - } - BREAK; - CASE(OP_put_arg): - { - int idx; - idx = get_u16(pc); - pc += 2; - set_value(ctx, &arg_buf[idx], sp[-1]); - sp--; - } - BREAK; - CASE(OP_set_arg): - { - int idx; - idx = get_u16(pc); - pc += 2; - set_value(ctx, &arg_buf[idx], JS_DupValue(ctx, sp[-1])); - } - BREAK; - -#if SHORT_OPCODES - CASE(OP_get_loc8): *sp++ = JS_DupValue(ctx, var_buf[*pc++]); BREAK; - CASE(OP_put_loc8): set_value(ctx, &var_buf[*pc++], *--sp); BREAK; - CASE(OP_set_loc8): set_value(ctx, &var_buf[*pc++], JS_DupValue(ctx, sp[-1])); BREAK; - - CASE(OP_get_loc0): *sp++ = JS_DupValue(ctx, var_buf[0]); BREAK; - CASE(OP_get_loc1): *sp++ = JS_DupValue(ctx, var_buf[1]); BREAK; - CASE(OP_get_loc2): *sp++ = JS_DupValue(ctx, var_buf[2]); BREAK; - CASE(OP_get_loc3): *sp++ = JS_DupValue(ctx, var_buf[3]); BREAK; - CASE(OP_put_loc0): set_value(ctx, &var_buf[0], *--sp); BREAK; - CASE(OP_put_loc1): set_value(ctx, &var_buf[1], *--sp); BREAK; - CASE(OP_put_loc2): set_value(ctx, &var_buf[2], *--sp); BREAK; - CASE(OP_put_loc3): set_value(ctx, &var_buf[3], *--sp); BREAK; - CASE(OP_set_loc0): set_value(ctx, &var_buf[0], JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_set_loc1): set_value(ctx, &var_buf[1], JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_set_loc2): set_value(ctx, &var_buf[2], JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_set_loc3): set_value(ctx, &var_buf[3], JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_get_arg0): *sp++ = JS_DupValue(ctx, arg_buf[0]); BREAK; - CASE(OP_get_arg1): *sp++ = JS_DupValue(ctx, arg_buf[1]); BREAK; - CASE(OP_get_arg2): *sp++ = JS_DupValue(ctx, arg_buf[2]); BREAK; - CASE(OP_get_arg3): *sp++ = JS_DupValue(ctx, arg_buf[3]); BREAK; - CASE(OP_put_arg0): set_value(ctx, &arg_buf[0], *--sp); BREAK; - CASE(OP_put_arg1): set_value(ctx, &arg_buf[1], *--sp); BREAK; - CASE(OP_put_arg2): set_value(ctx, &arg_buf[2], *--sp); BREAK; - CASE(OP_put_arg3): set_value(ctx, &arg_buf[3], *--sp); BREAK; - CASE(OP_set_arg0): set_value(ctx, &arg_buf[0], JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_set_arg1): set_value(ctx, &arg_buf[1], JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_set_arg2): set_value(ctx, &arg_buf[2], JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_set_arg3): set_value(ctx, &arg_buf[3], JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_get_var_ref0): *sp++ = JS_DupValue(ctx, *var_refs[0]->pvalue); BREAK; - CASE(OP_get_var_ref1): *sp++ = JS_DupValue(ctx, *var_refs[1]->pvalue); BREAK; - CASE(OP_get_var_ref2): *sp++ = JS_DupValue(ctx, *var_refs[2]->pvalue); BREAK; - CASE(OP_get_var_ref3): *sp++ = JS_DupValue(ctx, *var_refs[3]->pvalue); BREAK; - CASE(OP_put_var_ref0): set_value(ctx, var_refs[0]->pvalue, *--sp); BREAK; - CASE(OP_put_var_ref1): set_value(ctx, var_refs[1]->pvalue, *--sp); BREAK; - CASE(OP_put_var_ref2): set_value(ctx, var_refs[2]->pvalue, *--sp); BREAK; - CASE(OP_put_var_ref3): set_value(ctx, var_refs[3]->pvalue, *--sp); BREAK; - CASE(OP_set_var_ref0): set_value(ctx, var_refs[0]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_set_var_ref1): set_value(ctx, var_refs[1]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_set_var_ref2): set_value(ctx, var_refs[2]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK; - CASE(OP_set_var_ref3): set_value(ctx, var_refs[3]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK; -#endif - - CASE(OP_get_var_ref): - { - int idx; - JSValue val; - idx = get_u16(pc); - pc += 2; - val = *var_refs[idx]->pvalue; - sp[0] = JS_DupValue(ctx, val); - sp++; - } - BREAK; - CASE(OP_put_var_ref): - { - int idx; - idx = get_u16(pc); - pc += 2; - set_value(ctx, var_refs[idx]->pvalue, sp[-1]); - sp--; - } - BREAK; - CASE(OP_set_var_ref): - { - int idx; - idx = get_u16(pc); - pc += 2; - set_value(ctx, var_refs[idx]->pvalue, JS_DupValue(ctx, sp[-1])); - } - BREAK; - CASE(OP_get_var_ref_check): - { - int idx; - JSValue val; - idx = get_u16(pc); - pc += 2; - val = *var_refs[idx]->pvalue; - if (unlikely(JS_IsUninitialized(val))) { - JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE); - goto exception; - } - sp[0] = JS_DupValue(ctx, val); - sp++; - } - BREAK; - CASE(OP_put_var_ref_check): - { - int idx; - idx = get_u16(pc); - pc += 2; - if (unlikely(JS_IsUninitialized(*var_refs[idx]->pvalue))) { - JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE); - goto exception; - } - set_value(ctx, var_refs[idx]->pvalue, sp[-1]); - sp--; - } - BREAK; - CASE(OP_put_var_ref_check_init): - { - int idx; - idx = get_u16(pc); - pc += 2; - if (unlikely(!JS_IsUninitialized(*var_refs[idx]->pvalue))) { - JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE); - goto exception; - } - set_value(ctx, var_refs[idx]->pvalue, sp[-1]); - sp--; - } - BREAK; - CASE(OP_set_loc_uninitialized): - { - int idx; - idx = get_u16(pc); - pc += 2; - set_value(ctx, &var_buf[idx], JS_UNINITIALIZED); - } - BREAK; - CASE(OP_get_loc_check): - { - int idx; - idx = get_u16(pc); - pc += 2; - if (unlikely(JS_IsUninitialized(var_buf[idx]))) { - JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE); - goto exception; - } - sp[0] = JS_DupValue(ctx, var_buf[idx]); - sp++; - } - BREAK; - CASE(OP_get_loc_checkthis): - { - int idx; - idx = get_u16(pc); - pc += 2; - if (unlikely(JS_IsUninitialized(var_buf[idx]))) { - JS_ThrowReferenceErrorUninitialized2(caller_ctx, b, idx, FALSE); - goto exception; - } - sp[0] = JS_DupValue(ctx, var_buf[idx]); - sp++; - } - BREAK; - CASE(OP_put_loc_check): - { - int idx; - idx = get_u16(pc); - pc += 2; - if (unlikely(JS_IsUninitialized(var_buf[idx]))) { - JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE); - goto exception; - } - set_value(ctx, &var_buf[idx], sp[-1]); - sp--; - } - BREAK; - CASE(OP_put_loc_check_init): - { - int idx; - idx = get_u16(pc); - pc += 2; - if (unlikely(!JS_IsUninitialized(var_buf[idx]))) { - JS_ThrowReferenceError(ctx, "'this' can be initialized only once"); - goto exception; - } - set_value(ctx, &var_buf[idx], sp[-1]); - sp--; - } - BREAK; - CASE(OP_close_loc): - { - int idx; - idx = get_u16(pc); - pc += 2; - close_lexical_var(ctx, sf, idx); - } - BREAK; - - CASE(OP_make_loc_ref): - CASE(OP_make_arg_ref): - CASE(OP_make_var_ref_ref): - { - JSVarRef *var_ref; - JSProperty *pr; - JSAtom atom; - int idx; - atom = get_u32(pc); - idx = get_u16(pc + 4); - pc += 6; - *sp++ = JS_NewObjectProto(ctx, JS_NULL); - if (unlikely(JS_IsException(sp[-1]))) - goto exception; - if (opcode == OP_make_var_ref_ref) { - var_ref = var_refs[idx]; - var_ref->header.ref_count++; - } else { - var_ref = get_var_ref(ctx, sf, idx, opcode == OP_make_arg_ref); - if (!var_ref) - goto exception; - } - pr = add_property(ctx, JS_VALUE_GET_OBJ(sp[-1]), atom, - JS_PROP_WRITABLE | JS_PROP_VARREF); - if (!pr) { - free_var_ref(rt, var_ref); - goto exception; - } - pr->u.var_ref = var_ref; - *sp++ = JS_AtomToValue(ctx, atom); - } - BREAK; - CASE(OP_make_var_ref): - { - JSAtom atom; - atom = get_u32(pc); - pc += 4; - sf->cur_pc = pc; - - if (JS_GetGlobalVarRef(ctx, atom, sp)) - goto exception; - sp += 2; - } - BREAK; - - CASE(OP_goto): - pc += (int32_t)get_u32(pc); - if (unlikely(js_poll_interrupts(ctx))) - goto exception; - BREAK; -#if SHORT_OPCODES - CASE(OP_goto16): - pc += (int16_t)get_u16(pc); - if (unlikely(js_poll_interrupts(ctx))) - goto exception; - BREAK; - CASE(OP_goto8): - pc += (int8_t)pc[0]; - if (unlikely(js_poll_interrupts(ctx))) - goto exception; - BREAK; -#endif - CASE(OP_if_true): - { - int res; - JSValue op1; - - op1 = sp[-1]; - pc += 4; - if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) { - res = JS_VALUE_GET_INT(op1); - } else { - res = JS_ToBoolFree(ctx, op1); - } - sp--; - if (res) { - pc += (int32_t)get_u32(pc - 4) - 4; - } - if (unlikely(js_poll_interrupts(ctx))) - goto exception; - } - BREAK; - CASE(OP_if_false): - { - int res; - JSValue op1; - - op1 = sp[-1]; - pc += 4; - /* quick and dirty test for JS_TAG_INT, JS_TAG_BOOL, JS_TAG_NULL and JS_TAG_UNDEFINED */ - if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) { - res = JS_VALUE_GET_INT(op1); - } else { - res = JS_ToBoolFree(ctx, op1); - } - sp--; - if (!res) { - pc += (int32_t)get_u32(pc - 4) - 4; - } - if (unlikely(js_poll_interrupts(ctx))) - goto exception; - } - BREAK; -#if SHORT_OPCODES - CASE(OP_if_true8): - { - int res; - JSValue op1; - - op1 = sp[-1]; - pc += 1; - if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) { - res = JS_VALUE_GET_INT(op1); - } else { - res = JS_ToBoolFree(ctx, op1); - } - sp--; - if (res) { - pc += (int8_t)pc[-1] - 1; - } - if (unlikely(js_poll_interrupts(ctx))) - goto exception; - } - BREAK; - CASE(OP_if_false8): - { - int res; - JSValue op1; - - op1 = sp[-1]; - pc += 1; - if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) { - res = JS_VALUE_GET_INT(op1); - } else { - res = JS_ToBoolFree(ctx, op1); - } - sp--; - if (!res) { - pc += (int8_t)pc[-1] - 1; - } - if (unlikely(js_poll_interrupts(ctx))) - goto exception; - } - BREAK; -#endif - CASE(OP_catch): - { - int32_t diff; - diff = get_u32(pc); - sp[0] = JS_NewCatchOffset(ctx, pc + diff - b->byte_code_buf); - sp++; - pc += 4; - } - BREAK; - CASE(OP_gosub): - { - int32_t diff; - diff = get_u32(pc); - /* XXX: should have a different tag to avoid security flaw */ - sp[0] = JS_NewInt32(ctx, pc + 4 - b->byte_code_buf); - sp++; - pc += diff; - } - BREAK; - CASE(OP_ret): - { - JSValue op1; - uint32_t pos; - op1 = sp[-1]; - if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_INT)) - goto ret_fail; - pos = JS_VALUE_GET_INT(op1); - if (unlikely(pos >= b->byte_code_len)) { - ret_fail: - JS_ThrowInternalError(ctx, "invalid ret value"); - goto exception; - } - sp--; - pc = b->byte_code_buf + pos; - } - BREAK; - - CASE(OP_for_in_start): - sf->cur_pc = pc; - if (js_for_in_start(ctx, sp)) - goto exception; - BREAK; - CASE(OP_for_in_next): - sf->cur_pc = pc; - if (js_for_in_next(ctx, sp)) - goto exception; - sp += 2; - BREAK; - CASE(OP_for_of_start): - sf->cur_pc = pc; - if (js_for_of_start(ctx, sp, FALSE)) - goto exception; - sp += 1; - *sp++ = JS_NewCatchOffset(ctx, 0); - BREAK; - CASE(OP_for_of_next): - { - int offset = -3 - pc[0]; - pc += 1; - sf->cur_pc = pc; - if (js_for_of_next(ctx, sp, offset)) - goto exception; - sp += 2; - } - BREAK; - CASE(OP_for_await_of_next): - sf->cur_pc = pc; - if (js_for_await_of_next(ctx, sp)) - goto exception; - sp++; - BREAK; - CASE(OP_for_await_of_start): - sf->cur_pc = pc; - if (js_for_of_start(ctx, sp, TRUE)) - goto exception; - sp += 1; - *sp++ = JS_NewCatchOffset(ctx, 0); - BREAK; - CASE(OP_iterator_get_value_done): - sf->cur_pc = pc; - if (js_iterator_get_value_done(ctx, sp)) - goto exception; - sp += 1; - BREAK; - CASE(OP_iterator_check_object): - if (unlikely(!JS_IsObject(sp[-1]))) { - JS_ThrowTypeError(ctx, "iterator must return an object"); - goto exception; - } - BREAK; - - CASE(OP_iterator_close): - /* iter_obj next catch_offset -> */ - sp--; /* drop the catch offset to avoid getting caught by exception */ - JS_FreeValue(ctx, sp[-1]); /* drop the next method */ - sp--; - if (!JS_IsUndefined(sp[-1])) { - sf->cur_pc = pc; - if (JS_IteratorClose(ctx, sp[-1], FALSE)) - goto exception; - JS_FreeValue(ctx, sp[-1]); - } - sp--; - BREAK; - CASE(OP_nip_catch): - { - JSValue ret_val; - /* catch_offset ... ret_val -> ret_eval */ - ret_val = *--sp; - while (sp > stack_buf && - JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_CATCH_OFFSET) { - JS_FreeValue(ctx, *--sp); - } - if (unlikely(sp == stack_buf)) { - JS_ThrowInternalError(ctx, "nip_catch"); - JS_FreeValue(ctx, ret_val); - goto exception; - } - sp[-1] = ret_val; - } - BREAK; - - CASE(OP_iterator_next): - /* stack: iter_obj next catch_offset val */ - { - JSValue ret; - sf->cur_pc = pc; - ret = JS_Call(ctx, sp[-3], sp[-4], - 1, (JSValueConst *)(sp - 1)); - if (JS_IsException(ret)) - goto exception; - JS_FreeValue(ctx, sp[-1]); - sp[-1] = ret; - } - BREAK; - - CASE(OP_iterator_call): - /* stack: iter_obj next catch_offset val */ - { - JSValue method, ret; - BOOL ret_flag; - int flags; - flags = *pc++; - sf->cur_pc = pc; - method = JS_GetProperty(ctx, sp[-4], (flags & 1) ? - JS_ATOM_throw : JS_ATOM_return); - if (JS_IsException(method)) - goto exception; - if (JS_IsUndefined(method) || JS_IsNull(method)) { - ret_flag = TRUE; - } else { - if (flags & 2) { - /* no argument */ - ret = JS_CallFree(ctx, method, sp[-4], - 0, NULL); - } else { - ret = JS_CallFree(ctx, method, sp[-4], - 1, (JSValueConst *)(sp - 1)); - } - if (JS_IsException(ret)) - goto exception; - JS_FreeValue(ctx, sp[-1]); - sp[-1] = ret; - ret_flag = FALSE; - } - sp[0] = JS_NewBool(ctx, ret_flag); - sp += 1; - } - BREAK; - - CASE(OP_lnot): - { - int res; - JSValue op1; - - op1 = sp[-1]; - if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) { - res = JS_VALUE_GET_INT(op1) != 0; - } else { - res = JS_ToBoolFree(ctx, op1); - } - sp[-1] = JS_NewBool(ctx, !res); - } - BREAK; - - CASE(OP_get_field): - { - JSValue val; - JSAtom atom; - atom = get_u32(pc); - pc += 4; - - sf->cur_pc = pc; - val = JS_GetProperty(ctx, sp[-1], atom); - if (unlikely(JS_IsException(val))) - goto exception; - JS_FreeValue(ctx, sp[-1]); - sp[-1] = val; - } - BREAK; - - CASE(OP_get_field2): - { - JSValue val; - JSAtom atom; - atom = get_u32(pc); - pc += 4; - - sf->cur_pc = pc; - val = JS_GetProperty(ctx, sp[-1], atom); - if (unlikely(JS_IsException(val))) - goto exception; - *sp++ = val; - } - BREAK; - - CASE(OP_put_field): - { - int ret; - JSAtom atom; - atom = get_u32(pc); - pc += 4; - sf->cur_pc = pc; - - ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1], sp[-2], - JS_PROP_THROW_STRICT); - JS_FreeValue(ctx, sp[-2]); - sp -= 2; - if (unlikely(ret < 0)) - goto exception; - } - BREAK; - - CASE(OP_private_symbol): - { - JSAtom atom; - JSValue val; - - atom = get_u32(pc); - pc += 4; - val = JS_NewSymbolFromAtom(ctx, atom, JS_ATOM_TYPE_PRIVATE); - if (JS_IsException(val)) - goto exception; - *sp++ = val; - } - BREAK; - - CASE(OP_get_private_field): - { - JSValue val; - - val = JS_GetPrivateField(ctx, sp[-2], sp[-1]); - JS_FreeValue(ctx, sp[-1]); - JS_FreeValue(ctx, sp[-2]); - sp[-2] = val; - sp--; - if (unlikely(JS_IsException(val))) - goto exception; - } - BREAK; - - CASE(OP_put_private_field): - { - int ret; - ret = JS_SetPrivateField(ctx, sp[-3], sp[-1], sp[-2]); - JS_FreeValue(ctx, sp[-3]); - JS_FreeValue(ctx, sp[-1]); - sp -= 3; - if (unlikely(ret < 0)) - goto exception; - } - BREAK; - - CASE(OP_define_private_field): - { - int ret; - ret = JS_DefinePrivateField(ctx, sp[-3], sp[-2], sp[-1]); - JS_FreeValue(ctx, sp[-2]); - sp -= 2; - if (unlikely(ret < 0)) - goto exception; - } - BREAK; - - CASE(OP_define_field): - { - int ret; - JSAtom atom; - atom = get_u32(pc); - pc += 4; - - ret = JS_DefinePropertyValue(ctx, sp[-2], atom, sp[-1], - JS_PROP_C_W_E | JS_PROP_THROW); - sp--; - if (unlikely(ret < 0)) - goto exception; - } - BREAK; - - CASE(OP_set_name): - { - int ret; - JSAtom atom; - atom = get_u32(pc); - pc += 4; - - ret = JS_DefineObjectName(ctx, sp[-1], atom, JS_PROP_CONFIGURABLE); - if (unlikely(ret < 0)) - goto exception; - } - BREAK; - CASE(OP_set_name_computed): - { - int ret; - ret = JS_DefineObjectNameComputed(ctx, sp[-1], sp[-2], JS_PROP_CONFIGURABLE); - if (unlikely(ret < 0)) - goto exception; - } - BREAK; - CASE(OP_set_proto): - { - JSValue proto; - sf->cur_pc = pc; - proto = sp[-1]; - if (JS_IsObject(proto) || JS_IsNull(proto)) { - if (JS_SetPrototypeInternal(ctx, sp[-2], proto, TRUE) < 0) - goto exception; - } - JS_FreeValue(ctx, proto); - sp--; - } - BREAK; - CASE(OP_set_home_object): - js_method_set_home_object(ctx, sp[-1], sp[-2]); - BREAK; - CASE(OP_define_method): - CASE(OP_define_method_computed): - { - JSValue getter, setter, value; - JSValueConst obj; - JSAtom atom; - int flags, ret, op_flags; - BOOL is_computed; -#define OP_DEFINE_METHOD_METHOD 0 -#define OP_DEFINE_METHOD_GETTER 1 -#define OP_DEFINE_METHOD_SETTER 2 -#define OP_DEFINE_METHOD_ENUMERABLE 4 - - is_computed = (opcode == OP_define_method_computed); - if (is_computed) { - atom = JS_ValueToAtom(ctx, sp[-2]); - if (unlikely(atom == JS_ATOM_NULL)) - goto exception; - opcode += OP_define_method - OP_define_method_computed; - } else { - atom = get_u32(pc); - pc += 4; - } - op_flags = *pc++; - - obj = sp[-2 - is_computed]; - flags = JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE | - JS_PROP_HAS_ENUMERABLE | JS_PROP_THROW; - if (op_flags & OP_DEFINE_METHOD_ENUMERABLE) - flags |= JS_PROP_ENUMERABLE; - op_flags &= 3; - value = JS_UNDEFINED; - getter = JS_UNDEFINED; - setter = JS_UNDEFINED; - if (op_flags == OP_DEFINE_METHOD_METHOD) { - value = sp[-1]; - flags |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE; - } else if (op_flags == OP_DEFINE_METHOD_GETTER) { - getter = sp[-1]; - flags |= JS_PROP_HAS_GET; - } else { - setter = sp[-1]; - flags |= JS_PROP_HAS_SET; - } - ret = js_method_set_properties(ctx, sp[-1], atom, flags, obj); - if (ret >= 0) { - ret = JS_DefineProperty(ctx, obj, atom, value, - getter, setter, flags); - } - JS_FreeValue(ctx, sp[-1]); - if (is_computed) { - JS_FreeAtom(ctx, atom); - JS_FreeValue(ctx, sp[-2]); - } - sp -= 1 + is_computed; - if (unlikely(ret < 0)) - goto exception; - } - BREAK; - - CASE(OP_define_class): - CASE(OP_define_class_computed): - { - int class_flags; - JSAtom atom; - - atom = get_u32(pc); - class_flags = pc[4]; - pc += 5; - if (js_op_define_class(ctx, sp, atom, class_flags, - var_refs, sf, - (opcode == OP_define_class_computed)) < 0) - goto exception; - } - BREAK; - - CASE(OP_get_array_el): - { - JSValue val; - - sf->cur_pc = pc; - val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]); - JS_FreeValue(ctx, sp[-2]); - sp[-2] = val; - sp--; - if (unlikely(JS_IsException(val))) - goto exception; - } - BREAK; - - CASE(OP_get_array_el2): - { - JSValue val; - - sf->cur_pc = pc; - val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]); - sp[-1] = val; - if (unlikely(JS_IsException(val))) - goto exception; - } - BREAK; - - CASE(OP_get_array_el3): - { - JSValue val; - - switch (JS_VALUE_GET_TAG(sp[-2])) { - case JS_TAG_INT: - case JS_TAG_STRING: - case JS_TAG_SYMBOL: - /* undefined and null are tested in JS_GetPropertyValue() */ - break; - default: - /* must be tested nefore JS_ToPropertyKey */ - if (unlikely(JS_IsUndefined(sp[-2]) || JS_IsNull(sp[-2]))) { - JS_ThrowTypeError(ctx, "value has no property"); - goto exception; - } - sf->cur_pc = pc; - ret_val = JS_ToPropertyKey(ctx, sp[-1]); - if (JS_IsException(ret_val)) - goto exception; - JS_FreeValue(ctx, sp[-1]); - sp[-1] = ret_val; - break; - } - sf->cur_pc = pc; - val = JS_GetPropertyValue(ctx, sp[-2], JS_DupValue(ctx, sp[-1])); - *sp++ = val; - if (unlikely(JS_IsException(val))) - goto exception; - } - BREAK; - - CASE(OP_get_ref_value): - { - JSValue val; - JSAtom atom; - int ret; - - sf->cur_pc = pc; - atom = JS_ValueToAtom(ctx, sp[-1]); - if (atom == JS_ATOM_NULL) - goto exception; - if (unlikely(JS_IsUndefined(sp[-2]))) { - JS_ThrowReferenceErrorNotDefined(ctx, atom); - JS_FreeAtom(ctx, atom); - goto exception; - } - ret = JS_HasProperty(ctx, sp[-2], atom); - if (unlikely(ret <= 0)) { - if (ret < 0) { - JS_FreeAtom(ctx, atom); - goto exception; - } - if (is_strict_mode(ctx)) { - JS_ThrowReferenceErrorNotDefined(ctx, atom); - JS_FreeAtom(ctx, atom); - goto exception; - } - val = JS_UNDEFINED; - } else { - val = JS_GetProperty(ctx, sp[-2], atom); - } - JS_FreeAtom(ctx, atom); - if (unlikely(JS_IsException(val))) - goto exception; - sp[0] = val; - sp++; - } - BREAK; - - CASE(OP_get_super_value): - { - JSValue val; - JSAtom atom; - sf->cur_pc = pc; - atom = JS_ValueToAtom(ctx, sp[-1]); - if (unlikely(atom == JS_ATOM_NULL)) - goto exception; - val = JS_GetPropertyInternal(ctx, sp[-2], atom, sp[-3], FALSE); - JS_FreeAtom(ctx, atom); - if (unlikely(JS_IsException(val))) - goto exception; - JS_FreeValue(ctx, sp[-1]); - JS_FreeValue(ctx, sp[-2]); - JS_FreeValue(ctx, sp[-3]); - sp[-3] = val; - sp -= 2; - } - BREAK; - - CASE(OP_put_array_el): - { - int ret; - - sf->cur_pc = pc; - ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT); - JS_FreeValue(ctx, sp[-3]); - sp -= 3; - if (unlikely(ret < 0)) - goto exception; - } - BREAK; - - CASE(OP_put_ref_value): - { - int ret; - JSAtom atom; - sf->cur_pc = pc; - atom = JS_ValueToAtom(ctx, sp[-2]); - if (unlikely(atom == JS_ATOM_NULL)) - goto exception; - if (unlikely(JS_IsUndefined(sp[-3]))) { - if (is_strict_mode(ctx)) { - JS_ThrowReferenceErrorNotDefined(ctx, atom); - JS_FreeAtom(ctx, atom); - goto exception; - } else { - sp[-3] = JS_DupValue(ctx, ctx->global_obj); - } - } - ret = JS_HasProperty(ctx, sp[-3], atom); - if (unlikely(ret <= 0)) { - if (unlikely(ret < 0)) { - JS_FreeAtom(ctx, atom); - goto exception; - } - if (is_strict_mode(ctx)) { - JS_ThrowReferenceErrorNotDefined(ctx, atom); - JS_FreeAtom(ctx, atom); - goto exception; - } - } - ret = JS_SetPropertyInternal(ctx, sp[-3], atom, sp[-1], sp[-3], JS_PROP_THROW_STRICT); - JS_FreeAtom(ctx, atom); - JS_FreeValue(ctx, sp[-2]); - JS_FreeValue(ctx, sp[-3]); - sp -= 3; - if (unlikely(ret < 0)) - goto exception; - } - BREAK; - - CASE(OP_put_super_value): - { - int ret; - JSAtom atom; - sf->cur_pc = pc; - if (JS_VALUE_GET_TAG(sp[-3]) != JS_TAG_OBJECT) { - JS_ThrowTypeErrorNotAnObject(ctx); - goto exception; - } - atom = JS_ValueToAtom(ctx, sp[-2]); - if (unlikely(atom == JS_ATOM_NULL)) - goto exception; - ret = JS_SetPropertyInternal(ctx, sp[-3], atom, sp[-1], sp[-4], - JS_PROP_THROW_STRICT); - JS_FreeAtom(ctx, atom); - JS_FreeValue(ctx, sp[-4]); - JS_FreeValue(ctx, sp[-3]); - JS_FreeValue(ctx, sp[-2]); - sp -= 4; - if (ret < 0) - goto exception; - } - BREAK; - - CASE(OP_define_array_el): - { - int ret; - ret = JS_DefinePropertyValueValue(ctx, sp[-3], JS_DupValue(ctx, sp[-2]), sp[-1], - JS_PROP_C_W_E | JS_PROP_THROW); - sp -= 1; - if (unlikely(ret < 0)) - goto exception; - } - BREAK; - - CASE(OP_append): /* array pos enumobj -- array pos */ - { - sf->cur_pc = pc; - if (js_append_enumerate(ctx, sp)) - goto exception; - JS_FreeValue(ctx, *--sp); - } - BREAK; - - CASE(OP_copy_data_properties): /* target source excludeList */ - { - /* stack offsets (-1 based): - 2 bits for target, - 3 bits for source, - 2 bits for exclusionList */ - int mask; - - mask = *pc++; - sf->cur_pc = pc; - if (JS_CopyDataProperties(ctx, sp[-1 - (mask & 3)], - sp[-1 - ((mask >> 2) & 7)], - sp[-1 - ((mask >> 5) & 7)], 0)) - goto exception; - } - BREAK; - - CASE(OP_add): - { - JSValue op1, op2; - op1 = sp[-2]; - op2 = sp[-1]; - if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { - int64_t r; - r = (int64_t)JS_VALUE_GET_INT(op1) + JS_VALUE_GET_INT(op2); - if (unlikely((int)r != r)) - goto add_slow; - sp[-2] = JS_NewInt32(ctx, r); - sp--; - } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) { - sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) + - JS_VALUE_GET_FLOAT64(op2)); - sp--; - } else if (JS_IsString(op1) && JS_IsString(op2)) { - sp[-2] = JS_ConcatString(ctx, op1, op2); - sp--; - if (JS_IsException(sp[-1])) - goto exception; - } else { - add_slow: - sf->cur_pc = pc; - if (js_add_slow(ctx, sp)) - goto exception; - sp--; - } - } - BREAK; - CASE(OP_add_loc): - { - JSValue op2; - JSValue *pv; - int idx; - idx = *pc; - pc += 1; - - op2 = sp[-1]; - pv = &var_buf[idx]; - if (likely(JS_VALUE_IS_BOTH_INT(*pv, op2))) { - int64_t r; - r = (int64_t)JS_VALUE_GET_INT(*pv) + JS_VALUE_GET_INT(op2); - if (unlikely((int)r != r)) - goto add_loc_slow; - *pv = JS_NewInt32(ctx, r); - sp--; - } else if (JS_VALUE_IS_BOTH_FLOAT(*pv, op2)) { - *pv = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(*pv) + - JS_VALUE_GET_FLOAT64(op2)); - sp--; - } else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING) { - sp--; - sf->cur_pc = pc; - op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE); - if (JS_IsException(op2)) - goto exception; - if (JS_ConcatStringInPlace(ctx, JS_VALUE_GET_STRING(*pv), op2)) { - JS_FreeValue(ctx, op2); - } else { - op2 = JS_ConcatString(ctx, JS_DupValue(ctx, *pv), op2); - if (JS_IsException(op2)) - goto exception; - set_value(ctx, pv, op2); - } - } else { - JSValue ops[2]; - add_loc_slow: - /* In case of exception, js_add_slow frees ops[0] - and ops[1], so we must duplicate *pv */ - sf->cur_pc = pc; - ops[0] = JS_DupValue(ctx, *pv); - ops[1] = op2; - sp--; - if (js_add_slow(ctx, ops + 2)) - goto exception; - set_value(ctx, pv, ops[0]); - } - } - BREAK; - CASE(OP_sub): - { - JSValue op1, op2; - op1 = sp[-2]; - op2 = sp[-1]; - if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { - int64_t r; - r = (int64_t)JS_VALUE_GET_INT(op1) - JS_VALUE_GET_INT(op2); - if (unlikely((int)r != r)) - goto binary_arith_slow; - sp[-2] = JS_NewInt32(ctx, r); - sp--; - } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) { - sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) - - JS_VALUE_GET_FLOAT64(op2)); - sp--; - } else { - goto binary_arith_slow; - } - } - BREAK; - CASE(OP_mul): - { - JSValue op1, op2; - double d; - op1 = sp[-2]; - op2 = sp[-1]; - if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { - int32_t v1, v2; - int64_t r; - v1 = JS_VALUE_GET_INT(op1); - v2 = JS_VALUE_GET_INT(op2); - r = (int64_t)v1 * v2; - if (unlikely((int)r != r)) { - d = (double)r; - goto mul_fp_res; - } - /* need to test zero case for -0 result */ - if (unlikely(r == 0 && (v1 | v2) < 0)) { - d = -0.0; - goto mul_fp_res; - } - sp[-2] = JS_NewInt32(ctx, r); - sp--; - } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) { - d = JS_VALUE_GET_FLOAT64(op1) * JS_VALUE_GET_FLOAT64(op2); - mul_fp_res: - sp[-2] = __JS_NewFloat64(ctx, d); - sp--; - } else { - goto binary_arith_slow; - } - } - BREAK; - CASE(OP_div): - { - JSValue op1, op2; - op1 = sp[-2]; - op2 = sp[-1]; - if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { - int v1, v2; - v1 = JS_VALUE_GET_INT(op1); - v2 = JS_VALUE_GET_INT(op2); - sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2); - sp--; - } else { - goto binary_arith_slow; - } - } - BREAK; - CASE(OP_mod): - { - JSValue op1, op2; - op1 = sp[-2]; - op2 = sp[-1]; - if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { - int v1, v2, r; - v1 = JS_VALUE_GET_INT(op1); - v2 = JS_VALUE_GET_INT(op2); - /* We must avoid v2 = 0, v1 = INT32_MIN and v2 = - -1 and the cases where the result is -0. */ - if (unlikely(v1 < 0 || v2 <= 0)) - goto binary_arith_slow; - r = v1 % v2; - sp[-2] = JS_NewInt32(ctx, r); - sp--; - } else { - goto binary_arith_slow; - } - } - BREAK; - CASE(OP_pow): - binary_arith_slow: - sf->cur_pc = pc; - if (js_binary_arith_slow(ctx, sp, opcode)) - goto exception; - sp--; - BREAK; - - CASE(OP_plus): - { - JSValue op1; - uint32_t tag; - op1 = sp[-1]; - tag = JS_VALUE_GET_TAG(op1); - if (tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag)) { - } else { - sf->cur_pc = pc; - if (js_unary_arith_slow(ctx, sp, opcode)) - goto exception; - } - } - BREAK; - CASE(OP_neg): - { - JSValue op1; - uint32_t tag; - int val; - double d; - op1 = sp[-1]; - tag = JS_VALUE_GET_TAG(op1); - if (tag == JS_TAG_INT) { - val = JS_VALUE_GET_INT(op1); - /* Note: -0 cannot be expressed as integer */ - if (unlikely(val == 0)) { - d = -0.0; - goto neg_fp_res; - } - if (unlikely(val == INT32_MIN)) { - d = -(double)val; - goto neg_fp_res; - } - sp[-1] = JS_NewInt32(ctx, -val); - } else if (JS_TAG_IS_FLOAT64(tag)) { - d = -JS_VALUE_GET_FLOAT64(op1); - neg_fp_res: - sp[-1] = __JS_NewFloat64(ctx, d); - } else { - sf->cur_pc = pc; - if (js_unary_arith_slow(ctx, sp, opcode)) - goto exception; - } - } - BREAK; - CASE(OP_inc): - { - JSValue op1; - int val; - op1 = sp[-1]; - if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) { - val = JS_VALUE_GET_INT(op1); - if (unlikely(val == INT32_MAX)) - goto inc_slow; - sp[-1] = JS_NewInt32(ctx, val + 1); - } else { - inc_slow: - sf->cur_pc = pc; - if (js_unary_arith_slow(ctx, sp, opcode)) - goto exception; - } - } - BREAK; - CASE(OP_dec): - { - JSValue op1; - int val; - op1 = sp[-1]; - if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) { - val = JS_VALUE_GET_INT(op1); - if (unlikely(val == INT32_MIN)) - goto dec_slow; - sp[-1] = JS_NewInt32(ctx, val - 1); - } else { - dec_slow: - sf->cur_pc = pc; - if (js_unary_arith_slow(ctx, sp, opcode)) - goto exception; - } - } - BREAK; - CASE(OP_post_inc): - CASE(OP_post_dec): - sf->cur_pc = pc; - if (js_post_inc_slow(ctx, sp, opcode)) - goto exception; - sp++; - BREAK; - CASE(OP_inc_loc): - { - JSValue op1; - int val; - int idx; - idx = *pc; - pc += 1; - - op1 = var_buf[idx]; - if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) { - val = JS_VALUE_GET_INT(op1); - if (unlikely(val == INT32_MAX)) - goto inc_loc_slow; - var_buf[idx] = JS_NewInt32(ctx, val + 1); - } else { - inc_loc_slow: - sf->cur_pc = pc; - /* must duplicate otherwise the variable value may - be destroyed before JS code accesses it */ - op1 = JS_DupValue(ctx, op1); - if (js_unary_arith_slow(ctx, &op1 + 1, OP_inc)) - goto exception; - set_value(ctx, &var_buf[idx], op1); - } - } - BREAK; - CASE(OP_dec_loc): - { - JSValue op1; - int val; - int idx; - idx = *pc; - pc += 1; - - op1 = var_buf[idx]; - if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) { - val = JS_VALUE_GET_INT(op1); - if (unlikely(val == INT32_MIN)) - goto dec_loc_slow; - var_buf[idx] = JS_NewInt32(ctx, val - 1); - } else { - dec_loc_slow: - sf->cur_pc = pc; - /* must duplicate otherwise the variable value may - be destroyed before JS code accesses it */ - op1 = JS_DupValue(ctx, op1); - if (js_unary_arith_slow(ctx, &op1 + 1, OP_dec)) - goto exception; - set_value(ctx, &var_buf[idx], op1); - } - } - BREAK; - CASE(OP_not): - { - JSValue op1; - op1 = sp[-1]; - if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) { - sp[-1] = JS_NewInt32(ctx, ~JS_VALUE_GET_INT(op1)); - } else { - sf->cur_pc = pc; - if (js_not_slow(ctx, sp)) - goto exception; - } - } - BREAK; - - CASE(OP_shl): - { - JSValue op1, op2; - op1 = sp[-2]; - op2 = sp[-1]; - if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { - uint32_t v1, v2; - v1 = JS_VALUE_GET_INT(op1); - v2 = JS_VALUE_GET_INT(op2); - v2 &= 0x1f; - sp[-2] = JS_NewInt32(ctx, v1 << v2); - sp--; - } else { - sf->cur_pc = pc; - if (js_binary_logic_slow(ctx, sp, opcode)) - goto exception; - sp--; - } - } - BREAK; - CASE(OP_shr): - { - JSValue op1, op2; - op1 = sp[-2]; - op2 = sp[-1]; - if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { - uint32_t v2; - v2 = JS_VALUE_GET_INT(op2); - v2 &= 0x1f; - sp[-2] = JS_NewUint32(ctx, - (uint32_t)JS_VALUE_GET_INT(op1) >> - v2); - sp--; - } else { - sf->cur_pc = pc; - if (js_shr_slow(ctx, sp)) - goto exception; - sp--; - } - } - BREAK; - CASE(OP_sar): - { - JSValue op1, op2; - op1 = sp[-2]; - op2 = sp[-1]; - if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { - uint32_t v2; - v2 = JS_VALUE_GET_INT(op2); - v2 &= 0x1f; - sp[-2] = JS_NewInt32(ctx, - (int)JS_VALUE_GET_INT(op1) >> v2); - sp--; - } else { - sf->cur_pc = pc; - if (js_binary_logic_slow(ctx, sp, opcode)) - goto exception; - sp--; - } - } - BREAK; - CASE(OP_and): - { - JSValue op1, op2; - op1 = sp[-2]; - op2 = sp[-1]; - if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { - sp[-2] = JS_NewInt32(ctx, - JS_VALUE_GET_INT(op1) & - JS_VALUE_GET_INT(op2)); - sp--; - } else { - sf->cur_pc = pc; - if (js_binary_logic_slow(ctx, sp, opcode)) - goto exception; - sp--; - } - } - BREAK; - CASE(OP_or): - { - JSValue op1, op2; - op1 = sp[-2]; - op2 = sp[-1]; - if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { - sp[-2] = JS_NewInt32(ctx, - JS_VALUE_GET_INT(op1) | - JS_VALUE_GET_INT(op2)); - sp--; - } else { - sf->cur_pc = pc; - if (js_binary_logic_slow(ctx, sp, opcode)) - goto exception; - sp--; - } - } - BREAK; - CASE(OP_xor): - { - JSValue op1, op2; - op1 = sp[-2]; - op2 = sp[-1]; - if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { - sp[-2] = JS_NewInt32(ctx, - JS_VALUE_GET_INT(op1) ^ - JS_VALUE_GET_INT(op2)); - sp--; - } else { - sf->cur_pc = pc; - if (js_binary_logic_slow(ctx, sp, opcode)) - goto exception; - sp--; - } - } - BREAK; - - -#define OP_CMP(opcode, binary_op, slow_call) \ - CASE(opcode): \ - { \ - JSValue op1, op2; \ - op1 = sp[-2]; \ - op2 = sp[-1]; \ - if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { \ - sp[-2] = JS_NewBool(ctx, JS_VALUE_GET_INT(op1) binary_op JS_VALUE_GET_INT(op2)); \ - sp--; \ - } else { \ - sf->cur_pc = pc; \ - if (slow_call) \ - goto exception; \ - sp--; \ - } \ - } \ - BREAK - - OP_CMP(OP_lt, <, js_relational_slow(ctx, sp, opcode)); - OP_CMP(OP_lte, <=, js_relational_slow(ctx, sp, opcode)); - OP_CMP(OP_gt, >, js_relational_slow(ctx, sp, opcode)); - OP_CMP(OP_gte, >=, js_relational_slow(ctx, sp, opcode)); - OP_CMP(OP_eq, ==, js_eq_slow(ctx, sp, 0)); - OP_CMP(OP_neq, !=, js_eq_slow(ctx, sp, 1)); - OP_CMP(OP_strict_eq, ==, js_strict_eq_slow(ctx, sp, 0)); - OP_CMP(OP_strict_neq, !=, js_strict_eq_slow(ctx, sp, 1)); - - CASE(OP_in): - sf->cur_pc = pc; - if (js_operator_in(ctx, sp)) - goto exception; - sp--; - BREAK; - CASE(OP_private_in): - sf->cur_pc = pc; - if (js_operator_private_in(ctx, sp)) - goto exception; - sp--; - BREAK; - CASE(OP_instanceof): - sf->cur_pc = pc; - if (js_operator_instanceof(ctx, sp)) - goto exception; - sp--; - BREAK; - CASE(OP_typeof): - { - JSValue op1; - JSAtom atom; - - op1 = sp[-1]; - atom = js_operator_typeof(ctx, op1); - JS_FreeValue(ctx, op1); - sp[-1] = JS_AtomToString(ctx, atom); - } - BREAK; - CASE(OP_delete): - sf->cur_pc = pc; - if (js_operator_delete(ctx, sp)) - goto exception; - sp--; - BREAK; - CASE(OP_delete_var): - { - JSAtom atom; - int ret; - - atom = get_u32(pc); - pc += 4; - sf->cur_pc = pc; - - ret = JS_DeleteGlobalVar(ctx, atom); - if (unlikely(ret < 0)) - goto exception; - *sp++ = JS_NewBool(ctx, ret); - } - BREAK; - - CASE(OP_to_object): - if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_OBJECT) { - sf->cur_pc = pc; - ret_val = JS_ToObject(ctx, sp[-1]); - if (JS_IsException(ret_val)) - goto exception; - JS_FreeValue(ctx, sp[-1]); - sp[-1] = ret_val; - } - BREAK; - - CASE(OP_to_propkey): - switch (JS_VALUE_GET_TAG(sp[-1])) { - case JS_TAG_INT: - case JS_TAG_STRING: - case JS_TAG_SYMBOL: - break; - default: - sf->cur_pc = pc; - ret_val = JS_ToPropertyKey(ctx, sp[-1]); - if (JS_IsException(ret_val)) - goto exception; - JS_FreeValue(ctx, sp[-1]); - sp[-1] = ret_val; - break; - } - BREAK; - -#if 0 - CASE(OP_to_string): - if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_STRING) { - ret_val = JS_ToString(ctx, sp[-1]); - if (JS_IsException(ret_val)) - goto exception; - JS_FreeValue(ctx, sp[-1]); - sp[-1] = ret_val; - } - BREAK; -#endif - CASE(OP_with_get_var): - CASE(OP_with_put_var): - CASE(OP_with_delete_var): - CASE(OP_with_make_ref): - CASE(OP_with_get_ref): - { - JSAtom atom; - int32_t diff; - JSValue obj, val; - int ret, is_with; - atom = get_u32(pc); - diff = get_u32(pc + 4); - is_with = pc[8]; - pc += 9; - sf->cur_pc = pc; - - obj = sp[-1]; - ret = JS_HasProperty(ctx, obj, atom); - if (unlikely(ret < 0)) - goto exception; - if (ret) { - if (is_with) { - ret = js_has_unscopable(ctx, obj, atom); - if (unlikely(ret < 0)) - goto exception; - if (ret) - goto no_with; - } - switch (opcode) { - case OP_with_get_var: - /* in Object Environment Records, GetBindingValue() calls HasProperty() */ - ret = JS_HasProperty(ctx, obj, atom); - if (unlikely(ret <= 0)) { - if (ret < 0) - goto exception; - if (is_strict_mode(ctx)) { - JS_ThrowReferenceErrorNotDefined(ctx, atom); - goto exception; - } - val = JS_UNDEFINED; - } else { - val = JS_GetProperty(ctx, obj, atom); - if (unlikely(JS_IsException(val))) - goto exception; - } - set_value(ctx, &sp[-1], val); - break; - case OP_with_put_var: /* used e.g. in for in/of */ - /* in Object Environment Records, SetMutableBinding() calls HasProperty() */ - ret = JS_HasProperty(ctx, obj, atom); - if (unlikely(ret <= 0)) { - if (ret < 0) - goto exception; - if (is_strict_mode(ctx)) { - JS_ThrowReferenceErrorNotDefined(ctx, atom); - goto exception; - } - } - ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2], obj, - JS_PROP_THROW_STRICT); - JS_FreeValue(ctx, sp[-1]); - sp -= 2; - if (unlikely(ret < 0)) - goto exception; - break; - case OP_with_delete_var: - ret = JS_DeleteProperty(ctx, obj, atom, 0); - if (unlikely(ret < 0)) - goto exception; - JS_FreeValue(ctx, sp[-1]); - sp[-1] = JS_NewBool(ctx, ret); - break; - case OP_with_make_ref: - /* produce a pair object/propname on the stack */ - *sp++ = JS_AtomToValue(ctx, atom); - break; - case OP_with_get_ref: - /* produce a pair object/method on the stack */ - /* in Object Environment Records, GetBindingValue() calls HasProperty() */ - ret = JS_HasProperty(ctx, obj, atom); - if (unlikely(ret < 0)) - goto exception; - if (!ret) { - val = JS_UNDEFINED; - } else { - val = JS_GetProperty(ctx, obj, atom); - if (unlikely(JS_IsException(val))) - goto exception; - } - *sp++ = val; - break; - } - pc += diff - 5; - } else { - no_with: - /* if not jumping, drop the object argument */ - JS_FreeValue(ctx, sp[-1]); - sp--; - } - } - BREAK; - - CASE(OP_await): - ret_val = JS_NewInt32(ctx, FUNC_RET_AWAIT); - goto done_generator; - CASE(OP_yield): - ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD); - goto done_generator; - CASE(OP_yield_star): - CASE(OP_async_yield_star): - ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD_STAR); - goto done_generator; - CASE(OP_return_async): - ret_val = JS_UNDEFINED; - goto done_generator; - CASE(OP_initial_yield): - ret_val = JS_NewInt32(ctx, FUNC_RET_INITIAL_YIELD); - goto done_generator; - - CASE(OP_nop): - BREAK; - CASE(OP_is_undefined_or_null): - if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED || - JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) { - goto set_true; - } else { - goto free_and_set_false; - } -#if SHORT_OPCODES - CASE(OP_is_undefined): - if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED) { - goto set_true; - } else { - goto free_and_set_false; - } - CASE(OP_is_null): - if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) { - goto set_true; - } else { - goto free_and_set_false; - } - /* XXX: could merge to a single opcode */ - CASE(OP_typeof_is_undefined): - /* different from OP_is_undefined because of isHTMLDDA */ - if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_undefined) { - goto free_and_set_true; - } else { - goto free_and_set_false; - } - CASE(OP_typeof_is_function): - if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_function) { - goto free_and_set_true; - } else { - goto free_and_set_false; - } - free_and_set_true: - JS_FreeValue(ctx, sp[-1]); -#endif - set_true: - sp[-1] = JS_TRUE; - BREAK; - free_and_set_false: - JS_FreeValue(ctx, sp[-1]); - sp[-1] = JS_FALSE; - BREAK; - CASE(OP_invalid): - DEFAULT: - JS_ThrowInternalError(ctx, "invalid opcode: pc=%u opcode=0x%02x", - (int)(pc - b->byte_code_buf - 1), opcode); - goto exception; - } - } - exception: - if (is_backtrace_needed(ctx, rt->current_exception)) { - /* add the backtrace information now (it is not done - before if the exception happens in a bytecode - operation */ - sf->cur_pc = pc; - build_backtrace(ctx, rt->current_exception, NULL, 0, 0, 0); - } - if (!rt->current_exception_is_uncatchable) { - while (sp > stack_buf) { - JSValue val = *--sp; - JS_FreeValue(ctx, val); - if (JS_VALUE_GET_TAG(val) == JS_TAG_CATCH_OFFSET) { - int pos = JS_VALUE_GET_INT(val); - if (pos == 0) { - /* enumerator: close it with a throw */ - JS_FreeValue(ctx, sp[-1]); /* drop the next method */ - sp--; - JS_IteratorClose(ctx, sp[-1], TRUE); - } else { - *sp++ = rt->current_exception; - rt->current_exception = JS_UNINITIALIZED; - pc = b->byte_code_buf + pos; - goto restart; - } - } - } - } - ret_val = JS_EXCEPTION; - /* the local variables are freed by the caller in the generator - case. Hence the label 'done' should never be reached in a - generator function. */ - if (b->func_kind != JS_FUNC_NORMAL) { - done_generator: - sf->cur_pc = pc; - sf->cur_sp = sp; - } else { - done: - if (unlikely(!list_empty(&sf->var_ref_list))) { - /* variable references reference the stack: must close them */ - close_var_refs(rt, sf); - } - /* free the local variables and stack */ - for(pval = local_buf; pval < sp; pval++) { - JS_FreeValue(ctx, *pval); - } - } - rt->current_stack_frame = sf->prev_frame; - return ret_val; -} - -JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, - int argc, JSValueConst *argv) -{ - return JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED, - argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV); -} - -static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj, - int argc, JSValueConst *argv) -{ - JSValue res = JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED, - argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV); - JS_FreeValue(ctx, func_obj); - return res; -} - -/* warning: the refcount of the context is not incremented. Return - NULL in case of exception (case of revoked proxy only) */ -static JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj) -{ - JSObject *p; - JSContext *realm; - - if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT) - return ctx; - p = JS_VALUE_GET_OBJ(func_obj); - switch(p->class_id) { - case JS_CLASS_C_FUNCTION: - realm = p->u.cfunc.realm; - break; - case JS_CLASS_BYTECODE_FUNCTION: - case JS_CLASS_GENERATOR_FUNCTION: - case JS_CLASS_ASYNC_FUNCTION: - case JS_CLASS_ASYNC_GENERATOR_FUNCTION: - { - JSFunctionBytecode *b; - b = p->u.func.function_bytecode; - realm = b->realm; - } - break; - case JS_CLASS_PROXY: - { - JSProxyData *s = p->u.opaque; - if (!s) - return ctx; - if (s->is_revoked) { - JS_ThrowTypeErrorRevokedProxy(ctx); - return NULL; - } else { - realm = JS_GetFunctionRealm(ctx, s->target); - } - } - break; - case JS_CLASS_BOUND_FUNCTION: - { - JSBoundFunction *bf = p->u.bound_function; - realm = JS_GetFunctionRealm(ctx, bf->func_obj); - } - break; - default: - realm = ctx; - break; - } - return realm; -} - -static JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor, - int class_id) -{ - JSValue proto, obj; - JSContext *realm; - - if (JS_IsUndefined(ctor)) { - proto = JS_DupValue(ctx, ctx->class_proto[class_id]); - } else { - proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype); - if (JS_IsException(proto)) - return proto; - if (!JS_IsObject(proto)) { - JS_FreeValue(ctx, proto); - realm = JS_GetFunctionRealm(ctx, ctor); - if (!realm) - return JS_EXCEPTION; - proto = JS_DupValue(ctx, realm->class_proto[class_id]); - } - } - obj = JS_NewObjectProtoClass(ctx, proto, class_id); - JS_FreeValue(ctx, proto); - return obj; -} - -/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */ -static JSValue JS_CallConstructorInternal(JSContext *ctx, - JSValueConst func_obj, - JSValueConst new_target, - int argc, JSValue *argv, int flags) -{ - JSObject *p; - JSFunctionBytecode *b; - - if (js_poll_interrupts(ctx)) - return JS_EXCEPTION; - flags |= JS_CALL_FLAG_CONSTRUCTOR; - if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)) - goto not_a_function; - p = JS_VALUE_GET_OBJ(func_obj); - if (unlikely(!p->is_constructor)) - return JS_ThrowTypeError(ctx, "not a constructor"); - if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) { - JSClassCall *call_func; - call_func = ctx->rt->class_array[p->class_id].call; - if (!call_func) { - not_a_function: - return JS_ThrowTypeError(ctx, "not a function"); - } - return call_func(ctx, func_obj, new_target, argc, - (JSValueConst *)argv, flags); - } - - b = p->u.func.function_bytecode; - if (b->is_derived_class_constructor) { - return JS_CallInternal(ctx, func_obj, JS_UNDEFINED, new_target, argc, argv, flags); - } else { - JSValue obj, ret; - /* legacy constructor behavior */ - obj = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT); - if (JS_IsException(obj)) - return JS_EXCEPTION; - ret = JS_CallInternal(ctx, func_obj, obj, new_target, argc, argv, flags); - if (JS_VALUE_GET_TAG(ret) == JS_TAG_OBJECT || - JS_IsException(ret)) { - JS_FreeValue(ctx, obj); - return ret; - } else { - JS_FreeValue(ctx, ret); - return obj; - } - } -} - -JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj, - JSValueConst new_target, - int argc, JSValueConst *argv) -{ - return JS_CallConstructorInternal(ctx, func_obj, new_target, - argc, (JSValue *)argv, - JS_CALL_FLAG_COPY_ARGV); -} - -JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj, - int argc, JSValueConst *argv) -{ - return JS_CallConstructorInternal(ctx, func_obj, func_obj, - argc, (JSValue *)argv, - JS_CALL_FLAG_COPY_ARGV); -} - -JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom, - int argc, JSValueConst *argv) -{ - JSValue func_obj; - func_obj = JS_GetProperty(ctx, this_val, atom); - if (JS_IsException(func_obj)) - return func_obj; - return JS_CallFree(ctx, func_obj, this_val, argc, argv); -} - -static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom, - int argc, JSValueConst *argv) -{ - JSValue res = JS_Invoke(ctx, this_val, atom, argc, argv); - JS_FreeValue(ctx, this_val); - return res; -} - -/* JSAsyncFunctionState (used by generator and async functions) */ -static JSAsyncFunctionState *async_func_init(JSContext *ctx, - JSValueConst func_obj, JSValueConst this_obj, - int argc, JSValueConst *argv) -{ - JSAsyncFunctionState *s; - JSObject *p; - JSFunctionBytecode *b; - JSStackFrame *sf; - int local_count, i, arg_buf_len, n; - - s = js_mallocz(ctx, sizeof(*s)); - if (!s) - return NULL; - s->header.ref_count = 1; - add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION); - - sf = &s->frame; - init_list_head(&sf->var_ref_list); - p = JS_VALUE_GET_OBJ(func_obj); - b = p->u.func.function_bytecode; - sf->js_mode = b->js_mode | JS_MODE_ASYNC; - sf->cur_pc = b->byte_code_buf; - arg_buf_len = max_int(b->arg_count, argc); - local_count = arg_buf_len + b->var_count + b->stack_size; - sf->arg_buf = js_malloc(ctx, sizeof(JSValue) * max_int(local_count, 1)); - if (!sf->arg_buf) { - js_free(ctx, s); - return NULL; - } - sf->cur_func = JS_DupValue(ctx, func_obj); - s->this_val = JS_DupValue(ctx, this_obj); - s->argc = argc; - sf->arg_count = arg_buf_len; - sf->var_buf = sf->arg_buf + arg_buf_len; - sf->cur_sp = sf->var_buf + b->var_count; - for(i = 0; i < argc; i++) - sf->arg_buf[i] = JS_DupValue(ctx, argv[i]); - n = arg_buf_len + b->var_count; - for(i = argc; i < n; i++) - sf->arg_buf[i] = JS_UNDEFINED; - s->resolving_funcs[0] = JS_UNDEFINED; - s->resolving_funcs[1] = JS_UNDEFINED; - s->is_completed = FALSE; - return s; -} - -static void async_func_free_frame(JSRuntime *rt, JSAsyncFunctionState *s) -{ - JSStackFrame *sf = &s->frame; - JSValue *sp; - - if (sf->arg_buf) { - /* cannot free the function if it is running */ - assert(sf->cur_sp != NULL); - for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) { - JS_FreeValueRT(rt, *sp); - } - js_free_rt(rt, sf->arg_buf); - sf->arg_buf = NULL; - } - JS_FreeValueRT(rt, sf->cur_func); - JS_FreeValueRT(rt, s->this_val); -} - -static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s) -{ - JSRuntime *rt = ctx->rt; - JSStackFrame *sf = &s->frame; - JSValue func_obj, ret; - - assert(!s->is_completed); - if (js_check_stack_overflow(ctx->rt, 0)) { - ret = JS_ThrowStackOverflow(ctx); - } else { - /* the tag does not matter provided it is not an object */ - func_obj = JS_MKPTR(JS_TAG_INT, s); - ret = JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED, - s->argc, sf->arg_buf, JS_CALL_FLAG_GENERATOR); - } - if (JS_IsException(ret) || JS_IsUndefined(ret)) { - if (JS_IsUndefined(ret)) { - ret = sf->cur_sp[-1]; - sf->cur_sp[-1] = JS_UNDEFINED; - } - /* end of execution */ - s->is_completed = TRUE; - - /* close the closure variables. */ - close_var_refs(rt, sf); - - async_func_free_frame(rt, s); - } - return ret; -} - -static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) -{ - /* cannot close the closure variables here because it would - potentially modify the object graph */ - if (!s->is_completed) { - async_func_free_frame(rt, s); - } - - JS_FreeValueRT(rt, s->resolving_funcs[0]); - JS_FreeValueRT(rt, s->resolving_funcs[1]); - - remove_gc_object(&s->header); - if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && s->header.ref_count != 0) { - list_add_tail(&s->header.link, &rt->gc_zero_ref_count_list); - } else { - js_free_rt(rt, s); - } -} - -static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) -{ - if (--s->header.ref_count == 0) { - if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) { - list_del(&s->header.link); - list_add(&s->header.link, &rt->gc_zero_ref_count_list); - if (rt->gc_phase == JS_GC_PHASE_NONE) { - free_zero_refcount(rt); - } - } - } -} - -/* Generators */ - -typedef enum JSGeneratorStateEnum { - JS_GENERATOR_STATE_SUSPENDED_START, - JS_GENERATOR_STATE_SUSPENDED_YIELD, - JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR, - JS_GENERATOR_STATE_EXECUTING, - JS_GENERATOR_STATE_COMPLETED, -} JSGeneratorStateEnum; - -typedef struct JSGeneratorData { - JSGeneratorStateEnum state; - JSAsyncFunctionState *func_state; -} JSGeneratorData; - -static void free_generator_stack_rt(JSRuntime *rt, JSGeneratorData *s) -{ - if (s->state == JS_GENERATOR_STATE_COMPLETED) - return; - if (s->func_state) { - async_func_free(rt, s->func_state); - s->func_state = NULL; - } - s->state = JS_GENERATOR_STATE_COMPLETED; -} - -static void js_generator_finalizer(JSRuntime *rt, JSValue obj) -{ - JSGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_GENERATOR); - - if (s) { - free_generator_stack_rt(rt, s); - js_free_rt(rt, s); - } -} - -static void free_generator_stack(JSContext *ctx, JSGeneratorData *s) -{ - free_generator_stack_rt(ctx->rt, s); -} - -static void js_generator_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JSGeneratorData *s = p->u.generator_data; - - if (!s || !s->func_state) - return; - mark_func(rt, &s->func_state->header); -} - -/* XXX: use enum */ -#define GEN_MAGIC_NEXT 0 -#define GEN_MAGIC_RETURN 1 -#define GEN_MAGIC_THROW 2 - -static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - BOOL *pdone, int magic) -{ - JSGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_GENERATOR); - JSStackFrame *sf; - JSValue ret, func_ret; - - *pdone = TRUE; - if (!s) - return JS_ThrowTypeError(ctx, "not a generator"); - switch(s->state) { - default: - case JS_GENERATOR_STATE_SUSPENDED_START: - sf = &s->func_state->frame; - if (magic == GEN_MAGIC_NEXT) { - goto exec_no_arg; - } else { - free_generator_stack(ctx, s); - goto done; - } - break; - case JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR: - case JS_GENERATOR_STATE_SUSPENDED_YIELD: - sf = &s->func_state->frame; - /* cur_sp[-1] was set to JS_UNDEFINED in the previous call */ - ret = JS_DupValue(ctx, argv[0]); - if (magic == GEN_MAGIC_THROW && - s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) { - JS_Throw(ctx, ret); - s->func_state->throw_flag = TRUE; - } else { - sf->cur_sp[-1] = ret; - sf->cur_sp[0] = JS_NewInt32(ctx, magic); - sf->cur_sp++; - exec_no_arg: - s->func_state->throw_flag = FALSE; - } - s->state = JS_GENERATOR_STATE_EXECUTING; - func_ret = async_func_resume(ctx, s->func_state); - s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD; - if (s->func_state->is_completed) { - /* finalize the execution in case of exception or normal return */ - free_generator_stack(ctx, s); - return func_ret; - } else { - assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT); - /* get the returned yield value at the top of the stack */ - ret = sf->cur_sp[-1]; - sf->cur_sp[-1] = JS_UNDEFINED; - if (JS_VALUE_GET_INT(func_ret) == FUNC_RET_YIELD_STAR) { - s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR; - /* return (value, done) object */ - *pdone = 2; - } else { - *pdone = FALSE; - } - } - break; - case JS_GENERATOR_STATE_COMPLETED: - done: - /* execution is finished */ - switch(magic) { - default: - case GEN_MAGIC_NEXT: - ret = JS_UNDEFINED; - break; - case GEN_MAGIC_RETURN: - ret = JS_DupValue(ctx, argv[0]); - break; - case GEN_MAGIC_THROW: - ret = JS_Throw(ctx, JS_DupValue(ctx, argv[0])); - break; - } - break; - case JS_GENERATOR_STATE_EXECUTING: - ret = JS_ThrowTypeError(ctx, "cannot invoke a running generator"); - break; - } - return ret; -} - -static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, - int flags) -{ - JSValue obj, func_ret; - JSGeneratorData *s; - - s = js_mallocz(ctx, sizeof(*s)); - if (!s) - return JS_EXCEPTION; - s->state = JS_GENERATOR_STATE_SUSPENDED_START; - s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv); - if (!s->func_state) { - s->state = JS_GENERATOR_STATE_COMPLETED; - goto fail; - } - - /* execute the function up to 'OP_initial_yield' */ - func_ret = async_func_resume(ctx, s->func_state); - if (JS_IsException(func_ret)) - goto fail; - JS_FreeValue(ctx, func_ret); - - obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_GENERATOR); - if (JS_IsException(obj)) - goto fail; - JS_SetOpaque(obj, s); - return obj; - fail: - free_generator_stack_rt(ctx->rt, s); - js_free(ctx, s); - return JS_EXCEPTION; -} - -/* AsyncFunction */ - -static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JSAsyncFunctionState *s = p->u.async_function_data; - if (s) { - async_func_free(rt, s); - } -} - -static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JSAsyncFunctionState *s = p->u.async_function_data; - if (s) { - mark_func(rt, &s->header); - } -} - -static int js_async_function_resolve_create(JSContext *ctx, - JSAsyncFunctionState *s, - JSValue *resolving_funcs) -{ - int i; - JSObject *p; - - for(i = 0; i < 2; i++) { - resolving_funcs[i] = - JS_NewObjectProtoClass(ctx, ctx->function_proto, - JS_CLASS_ASYNC_FUNCTION_RESOLVE + i); - if (JS_IsException(resolving_funcs[i])) { - if (i == 1) - JS_FreeValue(ctx, resolving_funcs[0]); - return -1; - } - p = JS_VALUE_GET_OBJ(resolving_funcs[i]); - s->header.ref_count++; - p->u.async_function_data = s; - } - return 0; -} - -static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionState *s) -{ - JSValue func_ret, ret2; - - func_ret = async_func_resume(ctx, s); - if (s->is_completed) { - if (JS_IsException(func_ret)) { - JSValue error; - fail: - error = JS_GetException(ctx); - ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED, - 1, (JSValueConst *)&error); - JS_FreeValue(ctx, error); - JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */ - } else { - /* normal return */ - ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED, - 1, (JSValueConst *)&func_ret); - JS_FreeValue(ctx, func_ret); - JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */ - } - } else { - JSValue value, promise, resolving_funcs[2], resolving_funcs1[2]; - int i, res; - - value = s->frame.cur_sp[-1]; - s->frame.cur_sp[-1] = JS_UNDEFINED; - - /* await */ - JS_FreeValue(ctx, func_ret); /* not used */ - promise = js_promise_resolve(ctx, ctx->promise_ctor, - 1, (JSValueConst *)&value, 0); - JS_FreeValue(ctx, value); - if (JS_IsException(promise)) - goto fail; - if (js_async_function_resolve_create(ctx, s, resolving_funcs)) { - JS_FreeValue(ctx, promise); - goto fail; - } - - /* Note: no need to create 'thrownawayCapability' as in - the spec */ - for(i = 0; i < 2; i++) - resolving_funcs1[i] = JS_UNDEFINED; - res = perform_promise_then(ctx, promise, - (JSValueConst *)resolving_funcs, - (JSValueConst *)resolving_funcs1); - JS_FreeValue(ctx, promise); - for(i = 0; i < 2; i++) - JS_FreeValue(ctx, resolving_funcs[i]); - if (res) - goto fail; - } -} - -static JSValue js_async_function_resolve_call(JSContext *ctx, - JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, - int flags) -{ - JSObject *p = JS_VALUE_GET_OBJ(func_obj); - JSAsyncFunctionState *s = p->u.async_function_data; - BOOL is_reject = p->class_id - JS_CLASS_ASYNC_FUNCTION_RESOLVE; - JSValueConst arg; - - if (argc > 0) - arg = argv[0]; - else - arg = JS_UNDEFINED; - s->throw_flag = is_reject; - if (is_reject) { - JS_Throw(ctx, JS_DupValue(ctx, arg)); - } else { - /* return value of await */ - s->frame.cur_sp[-1] = JS_DupValue(ctx, arg); - } - js_async_function_resume(ctx, s); - return JS_UNDEFINED; -} - -static JSValue js_async_function_call(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, int flags) -{ - JSValue promise; - JSAsyncFunctionState *s; - - s = async_func_init(ctx, func_obj, this_obj, argc, argv); - if (!s) - return JS_EXCEPTION; - - promise = JS_NewPromiseCapability(ctx, s->resolving_funcs); - if (JS_IsException(promise)) { - async_func_free(ctx->rt, s); - return JS_EXCEPTION; - } - - js_async_function_resume(ctx, s); - - async_func_free(ctx->rt, s); - - return promise; -} - -/* AsyncGenerator */ - -typedef enum JSAsyncGeneratorStateEnum { - JS_ASYNC_GENERATOR_STATE_SUSPENDED_START, - JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD, - JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR, - JS_ASYNC_GENERATOR_STATE_EXECUTING, - JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN, - JS_ASYNC_GENERATOR_STATE_COMPLETED, -} JSAsyncGeneratorStateEnum; - -typedef struct JSAsyncGeneratorRequest { - struct list_head link; - /* completion */ - int completion_type; /* GEN_MAGIC_x */ - JSValue result; - /* promise capability */ - JSValue promise; - JSValue resolving_funcs[2]; -} JSAsyncGeneratorRequest; - -typedef struct JSAsyncGeneratorData { - JSObject *generator; /* back pointer to the object (const) */ - JSAsyncGeneratorStateEnum state; - /* func_state is NULL is state AWAITING_RETURN and COMPLETED */ - JSAsyncFunctionState *func_state; - struct list_head queue; /* list of JSAsyncGeneratorRequest.link */ -} JSAsyncGeneratorData; - -static void js_async_generator_free(JSRuntime *rt, - JSAsyncGeneratorData *s) -{ - struct list_head *el, *el1; - JSAsyncGeneratorRequest *req; - - list_for_each_safe(el, el1, &s->queue) { - req = list_entry(el, JSAsyncGeneratorRequest, link); - JS_FreeValueRT(rt, req->result); - JS_FreeValueRT(rt, req->promise); - JS_FreeValueRT(rt, req->resolving_funcs[0]); - JS_FreeValueRT(rt, req->resolving_funcs[1]); - js_free_rt(rt, req); - } - if (s->func_state) - async_func_free(rt, s->func_state); - js_free_rt(rt, s); -} - -static void js_async_generator_finalizer(JSRuntime *rt, JSValue obj) -{ - JSAsyncGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_ASYNC_GENERATOR); - - if (s) { - js_async_generator_free(rt, s); - } -} - -static void js_async_generator_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSAsyncGeneratorData *s = JS_GetOpaque(val, JS_CLASS_ASYNC_GENERATOR); - struct list_head *el; - JSAsyncGeneratorRequest *req; - if (s) { - list_for_each(el, &s->queue) { - req = list_entry(el, JSAsyncGeneratorRequest, link); - JS_MarkValue(rt, req->result, mark_func); - JS_MarkValue(rt, req->promise, mark_func); - JS_MarkValue(rt, req->resolving_funcs[0], mark_func); - JS_MarkValue(rt, req->resolving_funcs[1], mark_func); - } - if (s->func_state) { - mark_func(rt, &s->func_state->header); - } - } -} - -static JSValue js_async_generator_resolve_function(JSContext *ctx, - JSValueConst this_obj, - int argc, JSValueConst *argv, - int magic, JSValue *func_data); - -static int js_async_generator_resolve_function_create(JSContext *ctx, - JSValueConst generator, - JSValue *resolving_funcs, - BOOL is_resume_next) -{ - int i; - JSValue func; - - for(i = 0; i < 2; i++) { - func = JS_NewCFunctionData(ctx, js_async_generator_resolve_function, 1, - i + is_resume_next * 2, 1, &generator); - if (JS_IsException(func)) { - if (i == 1) - JS_FreeValue(ctx, resolving_funcs[0]); - return -1; - } - resolving_funcs[i] = func; - } - return 0; -} - -static int js_async_generator_await(JSContext *ctx, - JSAsyncGeneratorData *s, - JSValueConst value) -{ - JSValue promise, resolving_funcs[2], resolving_funcs1[2]; - int i, res; - - promise = js_promise_resolve(ctx, ctx->promise_ctor, - 1, &value, 0); - if (JS_IsException(promise)) - goto fail; - - if (js_async_generator_resolve_function_create(ctx, JS_MKPTR(JS_TAG_OBJECT, s->generator), - resolving_funcs, FALSE)) { - JS_FreeValue(ctx, promise); - goto fail; - } - - /* Note: no need to create 'thrownawayCapability' as in - the spec */ - for(i = 0; i < 2; i++) - resolving_funcs1[i] = JS_UNDEFINED; - res = perform_promise_then(ctx, promise, - (JSValueConst *)resolving_funcs, - (JSValueConst *)resolving_funcs1); - JS_FreeValue(ctx, promise); - for(i = 0; i < 2; i++) - JS_FreeValue(ctx, resolving_funcs[i]); - if (res) - goto fail; - return 0; - fail: - return -1; -} - -static void js_async_generator_resolve_or_reject(JSContext *ctx, - JSAsyncGeneratorData *s, - JSValueConst result, - int is_reject) -{ - JSAsyncGeneratorRequest *next; - JSValue ret; - - next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link); - list_del(&next->link); - ret = JS_Call(ctx, next->resolving_funcs[is_reject], JS_UNDEFINED, 1, - &result); - JS_FreeValue(ctx, ret); - JS_FreeValue(ctx, next->result); - JS_FreeValue(ctx, next->promise); - JS_FreeValue(ctx, next->resolving_funcs[0]); - JS_FreeValue(ctx, next->resolving_funcs[1]); - js_free(ctx, next); -} - -static void js_async_generator_resolve(JSContext *ctx, - JSAsyncGeneratorData *s, - JSValueConst value, - BOOL done) -{ - JSValue result; - result = js_create_iterator_result(ctx, JS_DupValue(ctx, value), done); - /* XXX: better exception handling ? */ - js_async_generator_resolve_or_reject(ctx, s, result, 0); - JS_FreeValue(ctx, result); - } - -static void js_async_generator_reject(JSContext *ctx, - JSAsyncGeneratorData *s, - JSValueConst exception) -{ - js_async_generator_resolve_or_reject(ctx, s, exception, 1); -} - -static void js_async_generator_complete(JSContext *ctx, - JSAsyncGeneratorData *s) -{ - if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED) { - s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED; - async_func_free(ctx->rt, s->func_state); - s->func_state = NULL; - } -} - -static int js_async_generator_completed_return(JSContext *ctx, - JSAsyncGeneratorData *s, - JSValueConst value) -{ - JSValue promise, resolving_funcs[2], resolving_funcs1[2]; - int res; - - // Can fail looking up JS_ATOM_constructor when is_reject==0. - promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, &value, - /*is_reject*/0); - // A poisoned .constructor property is observable and the resulting - // exception should be delivered to the catch handler. - if (JS_IsException(promise)) { - JSValue err = JS_GetException(ctx); - promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, (JSValueConst *)&err, - /*is_reject*/1); - JS_FreeValue(ctx, err); - if (JS_IsException(promise)) - return -1; - } - if (js_async_generator_resolve_function_create(ctx, - JS_MKPTR(JS_TAG_OBJECT, s->generator), - resolving_funcs1, - TRUE)) { - JS_FreeValue(ctx, promise); - return -1; - } - resolving_funcs[0] = JS_UNDEFINED; - resolving_funcs[1] = JS_UNDEFINED; - res = perform_promise_then(ctx, promise, - (JSValueConst *)resolving_funcs1, - (JSValueConst *)resolving_funcs); - JS_FreeValue(ctx, resolving_funcs1[0]); - JS_FreeValue(ctx, resolving_funcs1[1]); - JS_FreeValue(ctx, promise); - return res; -} - -static void js_async_generator_resume_next(JSContext *ctx, - JSAsyncGeneratorData *s) -{ - JSAsyncGeneratorRequest *next; - JSValue func_ret, value; - - for(;;) { - if (list_empty(&s->queue)) - break; - next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link); - switch(s->state) { - case JS_ASYNC_GENERATOR_STATE_EXECUTING: - /* only happens when restarting execution after await() */ - goto resume_exec; - case JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN: - goto done; - case JS_ASYNC_GENERATOR_STATE_SUSPENDED_START: - if (next->completion_type == GEN_MAGIC_NEXT) { - goto exec_no_arg; - } else { - js_async_generator_complete(ctx, s); - } - break; - case JS_ASYNC_GENERATOR_STATE_COMPLETED: - if (next->completion_type == GEN_MAGIC_NEXT) { - js_async_generator_resolve(ctx, s, JS_UNDEFINED, TRUE); - } else if (next->completion_type == GEN_MAGIC_RETURN) { - s->state = JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN; - js_async_generator_completed_return(ctx, s, next->result); - } else { - js_async_generator_reject(ctx, s, next->result); - } - goto done; - case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD: - case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR: - value = JS_DupValue(ctx, next->result); - if (next->completion_type == GEN_MAGIC_THROW && - s->state == JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD) { - JS_Throw(ctx, value); - s->func_state->throw_flag = TRUE; - } else { - /* 'yield' returns a value. 'yield *' also returns a value - in case the 'throw' method is called */ - s->func_state->frame.cur_sp[-1] = value; - s->func_state->frame.cur_sp[0] = - JS_NewInt32(ctx, next->completion_type); - s->func_state->frame.cur_sp++; - exec_no_arg: - s->func_state->throw_flag = FALSE; - } - s->state = JS_ASYNC_GENERATOR_STATE_EXECUTING; - resume_exec: - func_ret = async_func_resume(ctx, s->func_state); - if (s->func_state->is_completed) { - if (JS_IsException(func_ret)) { - value = JS_GetException(ctx); - js_async_generator_complete(ctx, s); - js_async_generator_reject(ctx, s, value); - JS_FreeValue(ctx, value); - } else { - /* end of function */ - js_async_generator_complete(ctx, s); - js_async_generator_resolve(ctx, s, func_ret, TRUE); - JS_FreeValue(ctx, func_ret); - } - } else { - int func_ret_code, ret; - assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT); - func_ret_code = JS_VALUE_GET_INT(func_ret); - value = s->func_state->frame.cur_sp[-1]; - s->func_state->frame.cur_sp[-1] = JS_UNDEFINED; - switch(func_ret_code) { - case FUNC_RET_YIELD: - case FUNC_RET_YIELD_STAR: - if (func_ret_code == FUNC_RET_YIELD_STAR) - s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR; - else - s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD; - js_async_generator_resolve(ctx, s, value, FALSE); - JS_FreeValue(ctx, value); - break; - case FUNC_RET_AWAIT: - ret = js_async_generator_await(ctx, s, value); - JS_FreeValue(ctx, value); - if (ret < 0) { - /* exception: throw it */ - s->func_state->throw_flag = TRUE; - goto resume_exec; - } - goto done; - default: - abort(); - } - } - break; - default: - abort(); - } - } - done: ; -} - -static JSValue js_async_generator_resolve_function(JSContext *ctx, - JSValueConst this_obj, - int argc, JSValueConst *argv, - int magic, JSValue *func_data) -{ - BOOL is_reject = magic & 1; - JSAsyncGeneratorData *s = JS_GetOpaque(func_data[0], JS_CLASS_ASYNC_GENERATOR); - JSValueConst arg = argv[0]; - - /* XXX: what if s == NULL */ - - if (magic >= 2) { - /* resume next case in AWAITING_RETURN state */ - assert(s->state == JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN || - s->state == JS_ASYNC_GENERATOR_STATE_COMPLETED); - s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED; - if (is_reject) { - js_async_generator_reject(ctx, s, arg); - } else { - js_async_generator_resolve(ctx, s, arg, TRUE); - } - } else { - /* restart function execution after await() */ - assert(s->state == JS_ASYNC_GENERATOR_STATE_EXECUTING); - s->func_state->throw_flag = is_reject; - if (is_reject) { - JS_Throw(ctx, JS_DupValue(ctx, arg)); - } else { - /* return value of await */ - s->func_state->frame.cur_sp[-1] = JS_DupValue(ctx, arg); - } - js_async_generator_resume_next(ctx, s); - } - return JS_UNDEFINED; -} - -/* magic = GEN_MAGIC_x */ -static JSValue js_async_generator_next(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - int magic) -{ - JSAsyncGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_GENERATOR); - JSValue promise, resolving_funcs[2]; - JSAsyncGeneratorRequest *req; - - promise = JS_NewPromiseCapability(ctx, resolving_funcs); - if (JS_IsException(promise)) - return JS_EXCEPTION; - if (!s) { - JSValue err, res2; - JS_ThrowTypeError(ctx, "not an AsyncGenerator object"); - err = JS_GetException(ctx); - res2 = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, - 1, (JSValueConst *)&err); - JS_FreeValue(ctx, err); - JS_FreeValue(ctx, res2); - JS_FreeValue(ctx, resolving_funcs[0]); - JS_FreeValue(ctx, resolving_funcs[1]); - return promise; - } - req = js_mallocz(ctx, sizeof(*req)); - if (!req) - goto fail; - req->completion_type = magic; - req->result = JS_DupValue(ctx, argv[0]); - req->promise = JS_DupValue(ctx, promise); - req->resolving_funcs[0] = resolving_funcs[0]; - req->resolving_funcs[1] = resolving_funcs[1]; - list_add_tail(&req->link, &s->queue); - if (s->state != JS_ASYNC_GENERATOR_STATE_EXECUTING) { - js_async_generator_resume_next(ctx, s); - } - return promise; - fail: - JS_FreeValue(ctx, resolving_funcs[0]); - JS_FreeValue(ctx, resolving_funcs[1]); - JS_FreeValue(ctx, promise); - return JS_EXCEPTION; -} - -static JSValue js_async_generator_function_call(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, - int flags) -{ - JSValue obj, func_ret; - JSAsyncGeneratorData *s; - - s = js_mallocz(ctx, sizeof(*s)); - if (!s) - return JS_EXCEPTION; - s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_START; - init_list_head(&s->queue); - s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv); - if (!s->func_state) - goto fail; - /* execute the function up to 'OP_initial_yield' (no yield nor - await are possible) */ - func_ret = async_func_resume(ctx, s->func_state); - if (JS_IsException(func_ret)) - goto fail; - JS_FreeValue(ctx, func_ret); - - obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_ASYNC_GENERATOR); - if (JS_IsException(obj)) - goto fail; - s->generator = JS_VALUE_GET_OBJ(obj); - JS_SetOpaque(obj, s); - return obj; - fail: - js_async_generator_free(ctx->rt, s); - return JS_EXCEPTION; -} - -/* JS parser */ - -enum { - TOK_NUMBER = -128, - TOK_STRING, - TOK_TEMPLATE, - TOK_IDENT, - TOK_REGEXP, - /* warning: order matters (see js_parse_assign_expr) */ - TOK_MUL_ASSIGN, - TOK_DIV_ASSIGN, - TOK_MOD_ASSIGN, - TOK_PLUS_ASSIGN, - TOK_MINUS_ASSIGN, - TOK_SHL_ASSIGN, - TOK_SAR_ASSIGN, - TOK_SHR_ASSIGN, - TOK_AND_ASSIGN, - TOK_XOR_ASSIGN, - TOK_OR_ASSIGN, - TOK_POW_ASSIGN, - TOK_LAND_ASSIGN, - TOK_LOR_ASSIGN, - TOK_DOUBLE_QUESTION_MARK_ASSIGN, - TOK_DEC, - TOK_INC, - TOK_SHL, - TOK_SAR, - TOK_SHR, - TOK_LT, - TOK_LTE, - TOK_GT, - TOK_GTE, - TOK_EQ, - TOK_STRICT_EQ, - TOK_NEQ, - TOK_STRICT_NEQ, - TOK_LAND, - TOK_LOR, - TOK_POW, - TOK_ARROW, - TOK_ELLIPSIS, - TOK_DOUBLE_QUESTION_MARK, - TOK_QUESTION_MARK_DOT, - TOK_ERROR, - TOK_PRIVATE_NAME, - TOK_EOF, - /* keywords: WARNING: same order as atoms */ - TOK_NULL, /* must be first */ - TOK_FALSE, - TOK_TRUE, - TOK_IF, - TOK_ELSE, - TOK_RETURN, - TOK_VAR, - TOK_THIS, - TOK_DELETE, - TOK_VOID, - TOK_TYPEOF, - TOK_NEW, - TOK_IN, - TOK_INSTANCEOF, - TOK_DO, - TOK_WHILE, - TOK_FOR, - TOK_BREAK, - TOK_CONTINUE, - TOK_SWITCH, - TOK_CASE, - TOK_DEFAULT, - TOK_THROW, - TOK_TRY, - TOK_CATCH, - TOK_FINALLY, - TOK_FUNCTION, - TOK_DEBUGGER, - TOK_WITH, - /* FutureReservedWord */ - TOK_CLASS, - TOK_CONST, - TOK_ENUM, - TOK_EXPORT, - TOK_EXTENDS, - TOK_IMPORT, - TOK_SUPER, - /* FutureReservedWords when parsing strict mode code */ - TOK_IMPLEMENTS, - TOK_INTERFACE, - TOK_LET, - TOK_PACKAGE, - TOK_PRIVATE, - TOK_PROTECTED, - TOK_PUBLIC, - TOK_STATIC, - TOK_YIELD, - TOK_AWAIT, /* must be last */ - TOK_OF, /* only used for js_parse_skip_parens_token() */ -}; - -#define TOK_FIRST_KEYWORD TOK_NULL -#define TOK_LAST_KEYWORD TOK_AWAIT - -/* unicode code points */ -#define CP_NBSP 0x00a0 -#define CP_BOM 0xfeff - -#define CP_LS 0x2028 -#define CP_PS 0x2029 - -typedef struct BlockEnv { - struct BlockEnv *prev; - JSAtom label_name; /* JS_ATOM_NULL if none */ - int label_break; /* -1 if none */ - int label_cont; /* -1 if none */ - int drop_count; /* number of stack elements to drop */ - int label_finally; /* -1 if none */ - int scope_level; - uint8_t has_iterator : 1; - uint8_t is_regular_stmt : 1; /* i.e. not a loop statement */ -} BlockEnv; - -typedef struct JSGlobalVar { - int cpool_idx; /* if >= 0, index in the constant pool for hoisted - function defintion*/ - uint8_t force_init : 1; /* force initialization to undefined */ - uint8_t is_lexical : 1; /* global let/const definition */ - uint8_t is_const : 1; /* const definition */ - int scope_level; /* scope of definition */ - JSAtom var_name; /* variable name */ -} JSGlobalVar; - -typedef struct RelocEntry { - struct RelocEntry *next; - uint32_t addr; /* address to patch */ - int size; /* address size: 1, 2 or 4 bytes */ -} RelocEntry; - -typedef struct JumpSlot { - int op; - int size; - int pos; - int label; -} JumpSlot; - -typedef struct LabelSlot { - int ref_count; - int pos; /* phase 1 address, -1 means not resolved yet */ - int pos2; /* phase 2 address, -1 means not resolved yet */ - int addr; /* phase 3 address, -1 means not resolved yet */ - RelocEntry *first_reloc; -} LabelSlot; - -typedef struct LineNumberSlot { - uint32_t pc; - uint32_t source_pos; -} LineNumberSlot; - -typedef struct { - /* last source position */ - const uint8_t *ptr; - int line_num; - int col_num; - const uint8_t *buf_start; -} GetLineColCache; - -typedef enum JSParseFunctionEnum { - JS_PARSE_FUNC_STATEMENT, - JS_PARSE_FUNC_VAR, - JS_PARSE_FUNC_EXPR, - JS_PARSE_FUNC_ARROW, - JS_PARSE_FUNC_GETTER, - JS_PARSE_FUNC_SETTER, - JS_PARSE_FUNC_METHOD, - JS_PARSE_FUNC_CLASS_STATIC_INIT, - JS_PARSE_FUNC_CLASS_CONSTRUCTOR, - JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR, -} JSParseFunctionEnum; - -typedef enum JSParseExportEnum { - JS_PARSE_EXPORT_NONE, - JS_PARSE_EXPORT_NAMED, - JS_PARSE_EXPORT_DEFAULT, -} JSParseExportEnum; - -typedef struct JSFunctionDef { - JSContext *ctx; - struct JSFunctionDef *parent; - int parent_cpool_idx; /* index in the constant pool of the parent - or -1 if none */ - int parent_scope_level; /* scope level in parent at point of definition */ - struct list_head child_list; /* list of JSFunctionDef.link */ - struct list_head link; - - BOOL is_eval; /* TRUE if eval code */ - int eval_type; /* only valid if is_eval = TRUE */ - BOOL is_global_var; /* TRUE if variables are not defined locally: - eval global, eval module or non strict eval */ - BOOL is_func_expr; /* TRUE if function expression */ - BOOL has_home_object; /* TRUE if the home object is available */ - BOOL has_prototype; /* true if a prototype field is necessary */ - BOOL has_simple_parameter_list; - BOOL has_parameter_expressions; /* if true, an argument scope is created */ - BOOL has_use_strict; /* to reject directive in special cases */ - BOOL has_eval_call; /* true if the function contains a call to eval() */ - BOOL has_arguments_binding; /* true if the 'arguments' binding is - available in the function */ - BOOL has_this_binding; /* true if the 'this' and new.target binding are - available in the function */ - BOOL new_target_allowed; /* true if the 'new.target' does not - throw a syntax error */ - BOOL super_call_allowed; /* true if super() is allowed */ - BOOL super_allowed; /* true if super. or super[] is allowed */ - BOOL arguments_allowed; /* true if the 'arguments' identifier is allowed */ - BOOL is_derived_class_constructor; - BOOL in_function_body; - JSFunctionKindEnum func_kind : 8; - JSParseFunctionEnum func_type : 8; - uint8_t js_mode; /* bitmap of JS_MODE_x */ - JSAtom func_name; /* JS_ATOM_NULL if no name */ - - JSVarDef *vars; - int var_size; /* allocated size for vars[] */ - int var_count; - JSVarDef *args; - int arg_size; /* allocated size for args[] */ - int arg_count; /* number of arguments */ - int defined_arg_count; - int var_object_idx; /* -1 if none */ - int arg_var_object_idx; /* -1 if none (var object for the argument scope) */ - int arguments_var_idx; /* -1 if none */ - int arguments_arg_idx; /* argument variable definition in argument scope, - -1 if none */ - int func_var_idx; /* variable containing the current function (-1 - if none, only used if is_func_expr is true) */ - int eval_ret_idx; /* variable containing the return value of the eval, -1 if none */ - int this_var_idx; /* variable containg the 'this' value, -1 if none */ - int new_target_var_idx; /* variable containg the 'new.target' value, -1 if none */ - int this_active_func_var_idx; /* variable containg the 'this.active_func' value, -1 if none */ - int home_object_var_idx; - BOOL need_home_object; - - int scope_level; /* index into fd->scopes if the current lexical scope */ - int scope_first; /* index into vd->vars of first lexically scoped variable */ - int scope_size; /* allocated size of fd->scopes array */ - int scope_count; /* number of entries used in the fd->scopes array */ - JSVarScope *scopes; - JSVarScope def_scope_array[4]; - int body_scope; /* scope of the body of the function or eval */ - - int global_var_count; - int global_var_size; - JSGlobalVar *global_vars; - - DynBuf byte_code; - int last_opcode_pos; /* -1 if no last opcode */ - const uint8_t *last_opcode_source_ptr; - BOOL use_short_opcodes; /* true if short opcodes are used in byte_code */ - - LabelSlot *label_slots; - int label_size; /* allocated size for label_slots[] */ - int label_count; - BlockEnv *top_break; /* break/continue label stack */ - - /* constant pool (strings, functions, numbers) */ - JSValue *cpool; - int cpool_count; - int cpool_size; - - /* list of variables in the closure */ - int closure_var_count; - int closure_var_size; - JSClosureVar *closure_var; - - JumpSlot *jump_slots; - int jump_size; - int jump_count; - - LineNumberSlot *line_number_slots; - int line_number_size; - int line_number_count; - int line_number_last; - int line_number_last_pc; - - /* pc2line table */ - BOOL strip_debug : 1; /* strip all debug info (implies strip_source = TRUE) */ - BOOL strip_source : 1; /* strip only source code */ - JSAtom filename; - uint32_t source_pos; /* pointer in the eval() source */ - GetLineColCache *get_line_col_cache; /* XXX: could remove to save memory */ - DynBuf pc2line; - - char *source; /* raw source, utf-8 encoded */ - int source_len; - - JSModuleDef *module; /* != NULL when parsing a module */ - BOOL has_await; /* TRUE if await is used (used in module eval) */ -} JSFunctionDef; - -typedef struct JSToken { - int val; - const uint8_t *ptr; /* position in the source */ - union { - struct { - JSValue str; - int sep; - } str; - struct { - JSValue val; - } num; - struct { - JSAtom atom; - BOOL has_escape; - BOOL is_reserved; - } ident; - struct { - JSValue body; - JSValue flags; - } regexp; - } u; -} JSToken; - -typedef struct JSParseState { - JSContext *ctx; - const char *filename; - JSToken token; - BOOL got_lf; /* true if got line feed before the current token */ - const uint8_t *last_ptr; - const uint8_t *buf_start; - const uint8_t *buf_ptr; - const uint8_t *buf_end; - - /* current function code */ - JSFunctionDef *cur_func; - BOOL is_module; /* parsing a module */ - BOOL allow_html_comments; - BOOL ext_json; /* true if accepting JSON superset */ - GetLineColCache get_line_col_cache; -} JSParseState; - -typedef struct JSOpCode { -#ifdef DUMP_BYTECODE - const char *name; -#endif - uint8_t size; /* in bytes */ - /* the opcodes remove n_pop items from the top of the stack, then - pushes n_push items */ - uint8_t n_pop; - uint8_t n_push; - uint8_t fmt; -} JSOpCode; - -static const JSOpCode opcode_info[OP_COUNT + (OP_TEMP_END - OP_TEMP_START)] = { -#define FMT(f) -#ifdef DUMP_BYTECODE -#define DEF(id, size, n_pop, n_push, f) { #id, size, n_pop, n_push, OP_FMT_ ## f }, -#else -#define DEF(id, size, n_pop, n_push, f) { size, n_pop, n_push, OP_FMT_ ## f }, -#endif -#include "quickjs-opcode.h" -#undef DEF -#undef FMT -}; - -#if SHORT_OPCODES -/* After the final compilation pass, short opcodes are used. Their - opcodes overlap with the temporary opcodes which cannot appear in - the final bytecode. Their description is after the temporary - opcodes in opcode_info[]. */ -#define short_opcode_info(op) \ - opcode_info[(op) >= OP_TEMP_START ? \ - (op) + (OP_TEMP_END - OP_TEMP_START) : (op)] -#else -#define short_opcode_info(op) opcode_info[op] -#endif - -static __exception int next_token(JSParseState *s); - -static void free_token(JSParseState *s, JSToken *token) -{ - switch(token->val) { - case TOK_NUMBER: - JS_FreeValue(s->ctx, token->u.num.val); - break; - case TOK_STRING: - case TOK_TEMPLATE: - JS_FreeValue(s->ctx, token->u.str.str); - break; - case TOK_REGEXP: - JS_FreeValue(s->ctx, token->u.regexp.body); - JS_FreeValue(s->ctx, token->u.regexp.flags); - break; - case TOK_IDENT: - case TOK_PRIVATE_NAME: - JS_FreeAtom(s->ctx, token->u.ident.atom); - break; - default: - if (token->val >= TOK_FIRST_KEYWORD && - token->val <= TOK_LAST_KEYWORD) { - JS_FreeAtom(s->ctx, token->u.ident.atom); - } - break; - } -} - -static void __attribute((unused)) dump_token(JSParseState *s, - const JSToken *token) -{ - switch(token->val) { - case TOK_NUMBER: - { - double d; - JS_ToFloat64(s->ctx, &d, token->u.num.val); /* no exception possible */ - printf("number: %.14g\n", d); - } - break; - case TOK_IDENT: - dump_atom: - { - char buf[ATOM_GET_STR_BUF_SIZE]; - printf("ident: '%s'\n", - JS_AtomGetStr(s->ctx, buf, sizeof(buf), token->u.ident.atom)); - } - break; - case TOK_STRING: - { - const char *str; - /* XXX: quote the string */ - str = JS_ToCString(s->ctx, token->u.str.str); - printf("string: '%s'\n", str); - JS_FreeCString(s->ctx, str); - } - break; - case TOK_TEMPLATE: - { - const char *str; - str = JS_ToCString(s->ctx, token->u.str.str); - printf("template: `%s`\n", str); - JS_FreeCString(s->ctx, str); - } - break; - case TOK_REGEXP: - { - const char *str, *str2; - str = JS_ToCString(s->ctx, token->u.regexp.body); - str2 = JS_ToCString(s->ctx, token->u.regexp.flags); - printf("regexp: '%s' '%s'\n", str, str2); - JS_FreeCString(s->ctx, str); - JS_FreeCString(s->ctx, str2); - } - break; - case TOK_EOF: - printf("eof\n"); - break; - default: - if (s->token.val >= TOK_NULL && s->token.val <= TOK_LAST_KEYWORD) { - goto dump_atom; - } else if (s->token.val >= 256) { - printf("token: %d\n", token->val); - } else { - printf("token: '%c'\n", token->val); - } - break; - } -} - -/* return the zero based line and column number in the source. */ -/* Note: we no longer support '\r' as line terminator */ -static int get_line_col(int *pcol_num, const uint8_t *buf, size_t len) -{ - int line_num, col_num, c; - size_t i; - - line_num = 0; - col_num = 0; - for(i = 0; i < len; i++) { - c = buf[i]; - if (c == '\n') { - line_num++; - col_num = 0; - } else if (c < 0x80 || c >= 0xc0) { - col_num++; - } - } - *pcol_num = col_num; - return line_num; -} - -static int get_line_col_cached(GetLineColCache *s, int *pcol_num, const uint8_t *ptr) -{ - int line_num, col_num; - if (ptr >= s->ptr) { - line_num = get_line_col(&col_num, s->ptr, ptr - s->ptr); - if (line_num == 0) { - s->col_num += col_num; - } else { - s->line_num += line_num; - s->col_num = col_num; - } - } else { - line_num = get_line_col(&col_num, ptr, s->ptr - ptr); - if (line_num == 0) { - s->col_num -= col_num; - } else { - const uint8_t *p; - s->line_num -= line_num; - /* find the absolute column position */ - col_num = 0; - for(p = ptr - 1; p >= s->buf_start; p--) { - if (*p == '\n') { - break; - } else if (*p < 0x80 || *p >= 0xc0) { - col_num++; - } - } - s->col_num = col_num; - } - } - s->ptr = ptr; - *pcol_num = s->col_num; - return s->line_num; -} - -/* 'ptr' is the position of the error in the source */ -static int js_parse_error_v(JSParseState *s, const uint8_t *ptr, const char *fmt, va_list ap) -{ - JSContext *ctx = s->ctx; - int line_num, col_num; - line_num = get_line_col(&col_num, s->buf_start, ptr - s->buf_start); - JS_ThrowError2(ctx, JS_SYNTAX_ERROR, fmt, ap, FALSE); - build_backtrace(ctx, ctx->rt->current_exception, s->filename, - line_num + 1, col_num + 1, 0); - return -1; -} - -static __attribute__((format(printf, 3, 4))) int js_parse_error_pos(JSParseState *s, const uint8_t *ptr, const char *fmt, ...) -{ - va_list ap; - int ret; - - va_start(ap, fmt); - ret = js_parse_error_v(s, ptr, fmt, ap); - va_end(ap); - return ret; -} - -static __attribute__((format(printf, 2, 3))) int js_parse_error(JSParseState *s, const char *fmt, ...) -{ - va_list ap; - int ret; - - va_start(ap, fmt); - ret = js_parse_error_v(s, s->token.ptr, fmt, ap); - va_end(ap); - return ret; -} - -static int js_parse_expect(JSParseState *s, int tok) -{ - if (s->token.val != tok) { - /* XXX: dump token correctly in all cases */ - return js_parse_error(s, "expecting '%c'", tok); - } - return next_token(s); -} - -static int js_parse_expect_semi(JSParseState *s) -{ - if (s->token.val != ';') { - /* automatic insertion of ';' */ - if (s->token.val == TOK_EOF || s->token.val == '}' || s->got_lf) { - return 0; - } - return js_parse_error(s, "expecting '%c'", ';'); - } - return next_token(s); -} - -static int js_parse_error_reserved_identifier(JSParseState *s) -{ - char buf1[ATOM_GET_STR_BUF_SIZE]; - return js_parse_error(s, "'%s' is a reserved identifier", - JS_AtomGetStr(s->ctx, buf1, sizeof(buf1), - s->token.u.ident.atom)); -} - -static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p) -{ - uint32_t c; - StringBuffer b_s, *b = &b_s; - JSValue str; - - /* p points to the first byte of the template part */ - if (string_buffer_init(s->ctx, b, 32)) - goto fail; - for(;;) { - if (p >= s->buf_end) - goto unexpected_eof; - c = *p++; - if (c == '`') { - /* template end part */ - break; - } - if (c == '$' && *p == '{') { - /* template start or middle part */ - p++; - break; - } - if (c == '\\') { - if (string_buffer_putc8(b, c)) - goto fail; - if (p >= s->buf_end) - goto unexpected_eof; - c = *p++; - } - /* newline sequences are normalized as single '\n' bytes */ - if (c == '\r') { - if (*p == '\n') - p++; - c = '\n'; - } - if (c >= 0x80) { - const uint8_t *p_next; - c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next); - if (c > 0x10FFFF) { - js_parse_error_pos(s, p - 1, "invalid UTF-8 sequence"); - goto fail; - } - p = p_next; - } - if (string_buffer_putc(b, c)) - goto fail; - } - str = string_buffer_end(b); - if (JS_IsException(str)) - return -1; - s->token.val = TOK_TEMPLATE; - s->token.u.str.sep = c; - s->token.u.str.str = str; - s->buf_ptr = p; - return 0; - - unexpected_eof: - js_parse_error(s, "unexpected end of string"); - fail: - string_buffer_free(b); - return -1; -} - -static __exception int js_parse_string(JSParseState *s, int sep, - BOOL do_throw, const uint8_t *p, - JSToken *token, const uint8_t **pp) -{ - int ret; - uint32_t c; - StringBuffer b_s, *b = &b_s; - const uint8_t *p_escape; - JSValue str; - - /* string */ - if (string_buffer_init(s->ctx, b, 32)) - goto fail; - for(;;) { - if (p >= s->buf_end) - goto invalid_char; - c = *p; - if (c < 0x20) { - if (sep == '`') { - if (c == '\r') { - if (p[1] == '\n') - p++; - c = '\n'; - } - /* do not update s->line_num */ - } else if (c == '\n' || c == '\r') - goto invalid_char; - } - p++; - if (c == sep) - break; - if (c == '$' && *p == '{' && sep == '`') { - /* template start or middle part */ - p++; - break; - } - if (c == '\\') { - p_escape = p - 1; - c = *p; - /* XXX: need a specific JSON case to avoid - accepting invalid escapes */ - switch(c) { - case '\0': - if (p >= s->buf_end) - goto invalid_char; - p++; - break; - case '\'': - case '\"': - case '\\': - p++; - break; - case '\r': /* accept DOS and MAC newline sequences */ - if (p[1] == '\n') { - p++; - } - /* fall thru */ - case '\n': - /* ignore escaped newline sequence */ - p++; - continue; - default: - if (c >= '0' && c <= '9') { - if (!(s->cur_func->js_mode & JS_MODE_STRICT) && sep != '`') - goto parse_escape; - if (c == '0' && !(p[1] >= '0' && p[1] <= '9')) { - p++; - c = '\0'; - } else { - if (c >= '8' || sep == '`') { - /* Note: according to ES2021, \8 and \9 are not - accepted in strict mode or in templates. */ - goto invalid_escape; - } else { - if (do_throw) - js_parse_error_pos(s, p_escape, "octal escape sequences are not allowed in strict mode"); - } - goto fail; - } - } else if (c >= 0x80) { - const uint8_t *p_next; - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next); - if (c > 0x10FFFF) { - goto invalid_utf8; - } - p = p_next; - /* LS or PS are skipped */ - if (c == CP_LS || c == CP_PS) - continue; - } else { - parse_escape: - ret = lre_parse_escape(&p, TRUE); - if (ret == -1) { - invalid_escape: - if (do_throw) - js_parse_error_pos(s, p_escape, "malformed escape sequence in string literal"); - goto fail; - } else if (ret < 0) { - /* ignore the '\' (could output a warning) */ - p++; - } else { - c = ret; - } - } - break; - } - } else if (c >= 0x80) { - const uint8_t *p_next; - c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next); - if (c > 0x10FFFF) - goto invalid_utf8; - p = p_next; - } - if (string_buffer_putc(b, c)) - goto fail; - } - str = string_buffer_end(b); - if (JS_IsException(str)) - return -1; - token->val = TOK_STRING; - token->u.str.sep = c; - token->u.str.str = str; - *pp = p; - return 0; - - invalid_utf8: - if (do_throw) - js_parse_error(s, "invalid UTF-8 sequence"); - goto fail; - invalid_char: - if (do_throw) - js_parse_error(s, "unexpected end of string"); - fail: - string_buffer_free(b); - return -1; -} - -static inline BOOL token_is_pseudo_keyword(JSParseState *s, JSAtom atom) { - return s->token.val == TOK_IDENT && s->token.u.ident.atom == atom && - !s->token.u.ident.has_escape; -} - -static __exception int js_parse_regexp(JSParseState *s) -{ - const uint8_t *p; - BOOL in_class; - StringBuffer b_s, *b = &b_s; - StringBuffer b2_s, *b2 = &b2_s; - uint32_t c; - JSValue body_str, flags_str; - - p = s->buf_ptr; - p++; - in_class = FALSE; - if (string_buffer_init(s->ctx, b, 32)) - return -1; - if (string_buffer_init(s->ctx, b2, 1)) - goto fail; - for(;;) { - if (p >= s->buf_end) { - eof_error: - js_parse_error(s, "unexpected end of regexp"); - goto fail; - } - c = *p++; - if (c == '\n' || c == '\r') { - goto eol_error; - } else if (c == '/') { - if (!in_class) - break; - } else if (c == '[') { - in_class = TRUE; - } else if (c == ']') { - /* XXX: incorrect as the first character in a class */ - in_class = FALSE; - } else if (c == '\\') { - if (string_buffer_putc8(b, c)) - goto fail; - c = *p++; - if (c == '\n' || c == '\r') - goto eol_error; - else if (c == '\0' && p >= s->buf_end) - goto eof_error; - else if (c >= 0x80) { - const uint8_t *p_next; - c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next); - if (c > 0x10FFFF) { - goto invalid_utf8; - } - p = p_next; - if (c == CP_LS || c == CP_PS) - goto eol_error; - } - } else if (c >= 0x80) { - const uint8_t *p_next; - c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next); - if (c > 0x10FFFF) { - invalid_utf8: - js_parse_error_pos(s, p - 1, "invalid UTF-8 sequence"); - goto fail; - } - /* LS or PS are considered as line terminator */ - if (c == CP_LS || c == CP_PS) { - eol_error: - js_parse_error_pos(s, p - 1, "unexpected line terminator in regexp"); - goto fail; - } - p = p_next; - } - if (string_buffer_putc(b, c)) - goto fail; - } - - /* flags */ - for(;;) { - const uint8_t *p_next = p; - c = *p_next++; - if (c >= 0x80) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next); - if (c > 0x10FFFF) { - p++; - goto invalid_utf8; - } - } - if (!lre_js_is_ident_next(c)) - break; - if (string_buffer_putc(b2, c)) - goto fail; - p = p_next; - } - - body_str = string_buffer_end(b); - flags_str = string_buffer_end(b2); - if (JS_IsException(body_str) || - JS_IsException(flags_str)) { - JS_FreeValue(s->ctx, body_str); - JS_FreeValue(s->ctx, flags_str); - return -1; - } - s->token.val = TOK_REGEXP; - s->token.u.regexp.body = body_str; - s->token.u.regexp.flags = flags_str; - s->buf_ptr = p; - return 0; - fail: - string_buffer_free(b); - string_buffer_free(b2); - return -1; -} - -static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize, - char *static_buf) -{ - char *buf, *new_buf; - size_t size, new_size; - - buf = *pbuf; - size = *psize; - if (size >= (SIZE_MAX / 3) * 2) - new_size = SIZE_MAX; - else - new_size = size + (size >> 1); - if (buf == static_buf) { - new_buf = js_malloc(ctx, new_size); - if (!new_buf) - return -1; - memcpy(new_buf, buf, size); - } else { - new_buf = js_realloc(ctx, buf, new_size); - if (!new_buf) - return -1; - } - *pbuf = new_buf; - *psize = new_size; - return 0; -} - -/* convert a TOK_IDENT to a keyword when needed */ -static void update_token_ident(JSParseState *s) -{ - if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD || - (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD && - (s->cur_func->js_mode & JS_MODE_STRICT)) || - (s->token.u.ident.atom == JS_ATOM_yield && - ((s->cur_func->func_kind & JS_FUNC_GENERATOR) || - (s->cur_func->func_type == JS_PARSE_FUNC_ARROW && - !s->cur_func->in_function_body && s->cur_func->parent && - (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) || - (s->token.u.ident.atom == JS_ATOM_await && - (s->is_module || - (s->cur_func->func_kind & JS_FUNC_ASYNC) || - s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT || - (s->cur_func->func_type == JS_PARSE_FUNC_ARROW && - !s->cur_func->in_function_body && s->cur_func->parent && - ((s->cur_func->parent->func_kind & JS_FUNC_ASYNC) || - s->cur_func->parent->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))))) { - if (s->token.u.ident.has_escape) { - s->token.u.ident.is_reserved = TRUE; - s->token.val = TOK_IDENT; - } else { - /* The keywords atoms are pre allocated */ - s->token.val = s->token.u.ident.atom - 1 + TOK_FIRST_KEYWORD; - } - } -} - -/* if the current token is an identifier or keyword, reparse it - according to the current function type */ -static void reparse_ident_token(JSParseState *s) -{ - if (s->token.val == TOK_IDENT || - (s->token.val >= TOK_FIRST_KEYWORD && - s->token.val <= TOK_LAST_KEYWORD)) { - s->token.val = TOK_IDENT; - s->token.u.ident.is_reserved = FALSE; - update_token_ident(s); - } -} - -/* 'c' is the first character. Return JS_ATOM_NULL in case of error */ -static JSAtom parse_ident(JSParseState *s, const uint8_t **pp, - BOOL *pident_has_escape, int c, BOOL is_private) -{ - const uint8_t *p, *p1; - char ident_buf[128], *buf; - size_t ident_size, ident_pos; - JSAtom atom; - - p = *pp; - buf = ident_buf; - ident_size = sizeof(ident_buf); - ident_pos = 0; - if (is_private) - buf[ident_pos++] = '#'; - for(;;) { - p1 = p; - - if (c < 128) { - buf[ident_pos++] = c; - } else { - ident_pos += unicode_to_utf8((uint8_t*)buf + ident_pos, c); - } - c = *p1++; - if (c == '\\' && *p1 == 'u') { - c = lre_parse_escape(&p1, TRUE); - *pident_has_escape = TRUE; - } else if (c >= 128) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1); - } - if (!lre_js_is_ident_next(c)) - break; - p = p1; - if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) { - if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) { - atom = JS_ATOM_NULL; - goto done; - } - } - } - atom = JS_NewAtomLen(s->ctx, buf, ident_pos); - done: - if (unlikely(buf != ident_buf)) - js_free(s->ctx, buf); - *pp = p; - return atom; -} - - -static __exception int next_token(JSParseState *s) -{ - const uint8_t *p; - int c; - BOOL ident_has_escape; - JSAtom atom; - - if (js_check_stack_overflow(s->ctx->rt, 0)) { - return js_parse_error(s, "stack overflow"); - } - - free_token(s, &s->token); - - p = s->last_ptr = s->buf_ptr; - s->got_lf = FALSE; - redo: - s->token.ptr = p; - c = *p; - switch(c) { - case 0: - if (p >= s->buf_end) { - s->token.val = TOK_EOF; - } else { - goto def_token; - } - break; - case '`': - if (js_parse_template_part(s, p + 1)) - goto fail; - p = s->buf_ptr; - break; - case '\'': - case '\"': - if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p)) - goto fail; - break; - case '\r': /* accept DOS and MAC newline sequences */ - if (p[1] == '\n') { - p++; - } - /* fall thru */ - case '\n': - p++; - line_terminator: - s->got_lf = TRUE; - goto redo; - case '\f': - case '\v': - case ' ': - case '\t': - p++; - goto redo; - case '/': - if (p[1] == '*') { - /* comment */ - p += 2; - for(;;) { - if (*p == '\0' && p >= s->buf_end) { - js_parse_error(s, "unexpected end of comment"); - goto fail; - } - if (p[0] == '*' && p[1] == '/') { - p += 2; - break; - } - if (*p == '\n' || *p == '\r') { - s->got_lf = TRUE; /* considered as LF for ASI */ - p++; - } else if (*p >= 0x80) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); - if (c == CP_LS || c == CP_PS) { - s->got_lf = TRUE; /* considered as LF for ASI */ - } else if (c == -1) { - p++; /* skip invalid UTF-8 */ - } - } else { - p++; - } - } - goto redo; - } else if (p[1] == '/') { - /* line comment */ - p += 2; - skip_line_comment: - for(;;) { - if (*p == '\0' && p >= s->buf_end) - break; - if (*p == '\r' || *p == '\n') - break; - if (*p >= 0x80) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); - /* LS or PS are considered as line terminator */ - if (c == CP_LS || c == CP_PS) { - break; - } else if (c == -1) { - p++; /* skip invalid UTF-8 */ - } - } else { - p++; - } - } - goto redo; - } else if (p[1] == '=') { - p += 2; - s->token.val = TOK_DIV_ASSIGN; - } else { - p++; - s->token.val = c; - } - break; - case '\\': - if (p[1] == 'u') { - const uint8_t *p1 = p + 1; - int c1 = lre_parse_escape(&p1, TRUE); - if (c1 >= 0 && lre_js_is_ident_first(c1)) { - c = c1; - p = p1; - ident_has_escape = TRUE; - goto has_ident; - } else { - /* XXX: syntax error? */ - } - } - goto def_token; - case 'a': case 'b': case 'c': case 'd': - case 'e': case 'f': case 'g': case 'h': - case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': - case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - case 'A': case 'B': case 'C': case 'D': - case 'E': case 'F': case 'G': case 'H': - case 'I': case 'J': case 'K': case 'L': - case 'M': case 'N': case 'O': case 'P': - case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - case '_': - case '$': - /* identifier */ - p++; - ident_has_escape = FALSE; - has_ident: - atom = parse_ident(s, &p, &ident_has_escape, c, FALSE); - if (atom == JS_ATOM_NULL) - goto fail; - s->token.u.ident.atom = atom; - s->token.u.ident.has_escape = ident_has_escape; - s->token.u.ident.is_reserved = FALSE; - s->token.val = TOK_IDENT; - update_token_ident(s); - break; - case '#': - /* private name */ - { - const uint8_t *p1; - p++; - p1 = p; - c = *p1++; - if (c == '\\' && *p1 == 'u') { - c = lre_parse_escape(&p1, TRUE); - } else if (c >= 128) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1); - } - if (!lre_js_is_ident_first(c)) { - js_parse_error(s, "invalid first character of private name"); - goto fail; - } - p = p1; - ident_has_escape = FALSE; /* not used */ - atom = parse_ident(s, &p, &ident_has_escape, c, TRUE); - if (atom == JS_ATOM_NULL) - goto fail; - s->token.u.ident.atom = atom; - s->token.val = TOK_PRIVATE_NAME; - } - break; - case '.': - if (p[1] == '.' && p[2] == '.') { - p += 3; - s->token.val = TOK_ELLIPSIS; - break; - } - if (p[1] >= '0' && p[1] <= '9') { - goto parse_number; - } else { - goto def_token; - } - break; - case '0': - /* in strict mode, octal literals are not accepted */ - if (is_digit(p[1]) && (s->cur_func->js_mode & JS_MODE_STRICT)) { - js_parse_error(s, "octal literals are deprecated in strict mode"); - goto fail; - } - goto parse_number; - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': - case '9': - /* number */ - parse_number: - { - JSValue ret; - const uint8_t *p1; - int flags; - flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL | - ATOD_ACCEPT_UNDERSCORES | ATOD_ACCEPT_SUFFIX; - ret = js_atof(s->ctx, (const char *)p, (const char **)&p, 0, - flags); - if (JS_IsException(ret)) - goto fail; - /* reject `10instanceof Number` */ - if (JS_VALUE_IS_NAN(ret) || - lre_js_is_ident_next(unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1))) { - JS_FreeValue(s->ctx, ret); - js_parse_error(s, "invalid number literal"); - goto fail; - } - s->token.val = TOK_NUMBER; - s->token.u.num.val = ret; - } - break; - case '*': - if (p[1] == '=') { - p += 2; - s->token.val = TOK_MUL_ASSIGN; - } else if (p[1] == '*') { - if (p[2] == '=') { - p += 3; - s->token.val = TOK_POW_ASSIGN; - } else { - p += 2; - s->token.val = TOK_POW; - } - } else { - goto def_token; - } - break; - case '%': - if (p[1] == '=') { - p += 2; - s->token.val = TOK_MOD_ASSIGN; - } else { - goto def_token; - } - break; - case '+': - if (p[1] == '=') { - p += 2; - s->token.val = TOK_PLUS_ASSIGN; - } else if (p[1] == '+') { - p += 2; - s->token.val = TOK_INC; - } else { - goto def_token; - } - break; - case '-': - if (p[1] == '=') { - p += 2; - s->token.val = TOK_MINUS_ASSIGN; - } else if (p[1] == '-') { - if (s->allow_html_comments && p[2] == '>' && - (s->got_lf || s->last_ptr == s->buf_start)) { - /* Annex B: `-->` at beginning of line is an html comment end. - It extends to the end of the line. - */ - goto skip_line_comment; - } - p += 2; - s->token.val = TOK_DEC; - } else { - goto def_token; - } - break; - case '<': - if (p[1] == '=') { - p += 2; - s->token.val = TOK_LTE; - } else if (p[1] == '<') { - if (p[2] == '=') { - p += 3; - s->token.val = TOK_SHL_ASSIGN; - } else { - p += 2; - s->token.val = TOK_SHL; - } - } else if (s->allow_html_comments && - p[1] == '!' && p[2] == '-' && p[3] == '-') { - /* Annex B: handle ` 0;) { - } - return n; -} - -function empty_do_loop(n) { - var j = n; - do { } while (--j > 0); - return n; -} - -function date_now(n) { - var j; - for(j = 0; j < n; j++) { - Date.now(); - } - return n; -} - -function date_parse(n) { - var x0 = 0, dx = 0; - var j; - for(j = 0; j < n; j++) { - var x1 = x0 - x0 % 1000; - var x2 = -x0; - var x3 = -x1; - var d0 = new Date(x0); - var d1 = new Date(x1); - var d2 = new Date(x2); - var d3 = new Date(x3); - if (Date.parse(d0.toISOString()) != x0 - || Date.parse(d1.toGMTString()) != x1 - || Date.parse(d1.toString()) != x1 - || Date.parse(d2.toISOString()) != x2 - || Date.parse(d3.toGMTString()) != x3 - || Date.parse(d3.toString()) != x3) { - console.log("Date.parse error for " + x0); - return -1; - } - dx = (dx * 1.1 + 1) >> 0; - x0 = (x0 + dx) % 8.64e15; - } - return n * 6; -} - -function prop_read(n) -{ - var obj, sum, j; - obj = {a: 1, b: 2, c:3, d:4 }; - sum = 0; - for(j = 0; j < n; j++) { - sum += obj.a; - sum += obj.b; - sum += obj.c; - sum += obj.d; - } - global_res = sum; - return n * 4; -} - -function prop_write(n) -{ - var obj, j; - obj = {a: 1, b: 2, c:3, d:4 }; - for(j = 0; j < n; j++) { - obj.a = j; - obj.b = j; - obj.c = j; - obj.d = j; - } - return n * 4; -} - -function prop_update(n) -{ - var obj, j; - obj = {a: 1, b: 2, c:3, d:4 }; - for(j = 0; j < n; j++) { - obj.a += j; - obj.b += j; - obj.c += j; - obj.d += j; - } - return n * 4; -} - -function prop_create(n) -{ - var obj, i, j; - for(j = 0; j < n; j++) { - obj = {}; - obj.a = 1; - obj.b = 2; - obj.c = 3; - obj.d = 4; - obj.e = 5; - obj.f = 6; - obj.g = 7; - obj.h = 8; - obj.i = 9; - obj.j = 10; - for(i = 0; i < 10; i++) { - obj[i] = i; - } - } - return n * 20; -} - -function prop_clone(n) -{ - var ref, obj, j, k; - ref = { a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10 }; - for(k = 0; k < 10; k++) { - ref[k] = k; - } - for (j = 0; j < n; j++) { - global_res = { ...ref }; - } - return n * 20; -} - -function prop_delete(n) -{ - var ref, obj, j, k; - ref = { a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10 }; - for(k = 0; k < 10; k++) { - ref[k] = k; - } - for (j = 0; j < n; j++) { - obj = { ...ref }; - delete obj.a; - delete obj.b; - delete obj.c; - delete obj.d; - delete obj.e; - delete obj.f; - delete obj.g; - delete obj.h; - delete obj.i; - delete obj.j; - for(k = 0; k < 10; k++) { - delete obj[k]; - } - } - return n * 20; -} - -function array_read(n) -{ - var tab, len, sum, i, j; - tab = []; - len = 10; - for(i = 0; i < len; i++) - tab[i] = i; - sum = 0; - for(j = 0; j < n; j++) { - sum += tab[0]; - sum += tab[1]; - sum += tab[2]; - sum += tab[3]; - sum += tab[4]; - sum += tab[5]; - sum += tab[6]; - sum += tab[7]; - sum += tab[8]; - sum += tab[9]; - } - global_res = sum; - return len * n; -} - -function array_write(n) -{ - var tab, len, i, j; - tab = []; - len = 10; - for(i = 0; i < len; i++) - tab[i] = i; - for(j = 0; j < n; j++) { - tab[0] = j; - tab[1] = j; - tab[2] = j; - tab[3] = j; - tab[4] = j; - tab[5] = j; - tab[6] = j; - tab[7] = j; - tab[8] = j; - tab[9] = j; - } - return len * n; -} - -function array_prop_create(n) -{ - var tab, i, j, len; - len = 1000; - for(j = 0; j < n; j++) { - tab = []; - for(i = 0; i < len; i++) - tab[i] = i; - } - return len * n; -} - -function array_slice(n) -{ - var ref, a, i, j, len; - len = 1000; - ref = []; - for(i = 0; i < len; i++) - ref[i] = i; - for(j = 0; j < n; j++) { - ref[0] = j; - a = ref.slice(); - a[0] = 0; - global_res = a; - } - return len * n; -} - -function array_length_decr(n) -{ - var tab, ref, i, j, len; - len = 1000; - ref = []; - for(i = 0; i < len; i++) - ref[i] = i; - for(j = 0; j < n; j++) { - tab = ref.slice(); - for(i = len; i --> 0;) - tab.length = i; - } - return len * n; -} - -function array_hole_length_decr(n) -{ - var tab, ref, i, j, len; - len = 1000; - ref = []; - for(i = 0; i < len; i++) { - if (i % 10 == 9) - ref[i] = i; - } - for(j = 0; j < n; j++) { - tab = ref.slice(); - for(i = len; i --> 0;) - tab.length = i; - } - return len * n; -} - -function array_push(n) -{ - var tab, i, j, len; - len = 500; - for(j = 0; j < n; j++) { - tab = []; - for(i = 0; i < len; i++) - tab.push(i); - } - return len * n; -} - -function array_pop(n) -{ - var tab, ref, i, j, len, sum; - len = 500; - ref = []; - for(i = 0; i < len; i++) - ref[i] = i; - for(j = 0; j < n; j++) { - tab = ref.slice(); - sum = 0; - for(i = 0; i < len; i++) - sum += tab.pop(); - global_res = sum; - } - return len * n; -} - -function typed_array_read(n) -{ - var tab, len, sum, i, j; - len = 10; - tab = new Int32Array(len); - for(i = 0; i < len; i++) - tab[i] = i; - sum = 0; - for(j = 0; j < n; j++) { - sum += tab[0]; - sum += tab[1]; - sum += tab[2]; - sum += tab[3]; - sum += tab[4]; - sum += tab[5]; - sum += tab[6]; - sum += tab[7]; - sum += tab[8]; - sum += tab[9]; - } - global_res = sum; - return len * n; -} - -function typed_array_write(n) -{ - var tab, len, i, j; - len = 10; - tab = new Int32Array(len); - for(i = 0; i < len; i++) - tab[i] = i; - for(j = 0; j < n; j++) { - tab[0] = j; - tab[1] = j; - tab[2] = j; - tab[3] = j; - tab[4] = j; - tab[5] = j; - tab[6] = j; - tab[7] = j; - tab[8] = j; - tab[9] = j; - } - return len * n; -} - -var global_var0; - -function global_read(n) -{ - var sum, j; - global_var0 = 0; - sum = 0; - for(j = 0; j < n; j++) { - sum += global_var0; - sum += global_var0; - sum += global_var0; - sum += global_var0; - } - global_res = sum; - return n * 4; -} - -// non strict version -var global_write = - (1, eval)(`(function global_write(n) - { - var j; - for(j = 0; j < n; j++) { - global_var0 = j; - global_var0 = j; - global_var0 = j; - global_var0 = j; - } - return n * 4; - })`); - -function global_write_strict(n) -{ - var j; - for(j = 0; j < n; j++) { - global_var0 = j; - global_var0 = j; - global_var0 = j; - global_var0 = j; - } - return n * 4; -} - -function local_destruct(n) -{ - var j, v1, v2, v3, v4; - var array = [ 1, 2, 3, 4, 5]; - var o = { a:1, b:2, c:3, d:4 }; - var a, b, c, d; - for(j = 0; j < n; j++) { - [ v1, v2,, v3, ...v4] = array; - ({ a, b, c, d } = o); - ({ a: a, b: b, c: c, d: d } = o); - } - return n * 12; -} - -var global_v1, global_v2, global_v3, global_v4; -var global_a, global_b, global_c, global_d; - -// non strict version -var global_destruct = - (1, eval)(`(function global_destruct(n) - { - var j, v1, v2, v3, v4; - var array = [ 1, 2, 3, 4, 5 ]; - var o = { a:1, b:2, c:3, d:4 }; - var a, b, c, d; - for(j = 0; j < n; j++) { - [ global_v1, global_v2,, global_v3, ...global_v4] = array; - ({ a: global_a, b: global_b, c: global_c, d: global_d } = o); - } - return n * 8; - })`); - -function global_destruct_strict(n) -{ - var j, v1, v2, v3, v4; - var array = [ 1, 2, 3, 4, 5 ]; - var o = { a:1, b:2, c:3, d:4 }; - var a, b, c, d; - for(j = 0; j < n; j++) { - [ global_v1, global_v2,, global_v3, ...global_v4] = array; - ({ a: global_a, b: global_b, c: global_c, d: global_d } = o); - } - return n * 8; -} - -function g(a) -{ - return 1; -} - -function global_func_call(n) -{ - var j, sum; - sum = 0; - for(j = 0; j < n; j++) { - sum += g(j); - sum += g(j); - sum += g(j); - sum += g(j); - } - global_res = sum; - return n * 4; -} - -function func_call(n) -{ - function f(a) - { - return 1; - } - - var j, sum; - sum = 0; - for(j = 0; j < n; j++) { - sum += f(j); - sum += f(j); - sum += f(j); - sum += f(j); - } - global_res = sum; - return n * 4; -} - -function func_closure_call(n) -{ - function f(a) - { - sum++; - } - - var j, sum; - sum = 0; - for(j = 0; j < n; j++) { - f(j); - f(j); - f(j); - f(j); - } - global_res = sum; - return n * 4; -} - -function int_arith(n) -{ - var i, j, sum; - global_res = 0; - for(j = 0; j < n; j++) { - sum = 0; - for(i = 0; i < 1000; i++) { - sum += i * i; - } - global_res += sum; - } - return n * 1000; -} - -function float_arith(n) -{ - var i, j, sum, a, incr, a0; - global_res = 0; - a0 = 0.1; - incr = 1.1; - for(j = 0; j < n; j++) { - sum = 0; - a = a0; - for(i = 0; i < 1000; i++) { - sum += a * a; - a += incr; - } - global_res += sum; - } - return n * 1000; -} - -function bigint_arith(n, bits) -{ - var i, j, sum, a, incr, a0, sum0; - sum0 = global_res = BigInt(0); - a0 = BigInt(1) << BigInt(Math.floor((bits - 10) * 0.5)); - incr = BigInt(1); - for(j = 0; j < n; j++) { - sum = sum0; - a = a0; - for(i = 0; i < 1000; i++) { - sum += a * a; - a += incr; - } - global_res += sum; - } - return n * 1000; -} - -function bigint32_arith(n) -{ - return bigint_arith(n, 32); -} - -function bigint64_arith(n) -{ - return bigint_arith(n, 64); -} - -function bigint256_arith(n) -{ - return bigint_arith(n, 256); -} - -function map_set_string(n) -{ - var s, i, j, len = 1000; - for(j = 0; j < n; j++) { - s = new Map(); - for(i = 0; i < len; i++) { - s.set(String(i), i); - } - for(i = 0; i < len; i++) { - if (!s.has(String(i))) - throw Error("bug in Map"); - } - } - return n * len; -} - -function map_set_int(n) -{ - var s, i, j, len = 1000; - for(j = 0; j < n; j++) { - s = new Map(); - for(i = 0; i < len; i++) { - s.set(i, i); - } - for(i = 0; i < len; i++) { - if (!s.has(i)) - throw Error("bug in Map"); - } - } - return n * len; -} - -function map_set_bigint(n) -{ - var s, i, j, len = 1000; - for(j = 0; j < n; j++) { - s = new Map(); - for(i = 0; i < len; i++) { - s.set(BigInt(i), i); - } - for(i = 0; i < len; i++) { - if (!s.has(BigInt(i))) - throw Error("bug in Map"); - } - } - return n * len; -} - -function map_delete(n) -{ - var a, i, j; - - len = 1000; - for(j = 0; j < n; j++) { - a = new Map(); - for(i = 0; i < len; i++) { - a.set(String(i), i); - } - for(i = 0; i < len; i++) { - a.delete(String(i)); - } - } - return len * n; -} - -function weak_map_set(n) -{ - var a, i, j, tab; - - len = 1000; - tab = []; - for(i = 0; i < len; i++) { - tab.push({ key: i }); - } - for(j = 0; j < n; j++) { - a = new WeakMap(); - for(i = 0; i < len; i++) { - a.set(tab[i], i); - } - } - return len * n; -} - -function weak_map_delete(n) -{ - var a, i, j, tab; - - len = 1000; - for(j = 0; j < n; j++) { - tab = []; - for(i = 0; i < len; i++) { - tab.push({ key: i }); - } - a = new WeakMap(); - for(i = 0; i < len; i++) { - a.set(tab[i], i); - } - for(i = 0; i < len; i++) { - tab[i] = null; - } - } - return len * n; -} - - -function array_for(n) -{ - var r, i, j, sum, len = 100; - r = []; - for(i = 0; i < len; i++) - r[i] = i; - for(j = 0; j < n; j++) { - sum = 0; - for(i = 0; i < len; i++) { - sum += r[i]; - } - global_res = sum; - } - return n * len; -} - -function array_for_in(n) -{ - var r, i, j, sum, len = 100; - r = []; - for(i = 0; i < len; i++) - r[i] = i; - for(j = 0; j < n; j++) { - sum = 0; - for(i in r) { - sum += r[i]; - } - global_res = sum; - } - return n * len; -} - -function array_for_of(n) -{ - var r, i, j, sum, len = 100; - r = []; - for(i = 0; i < len; i++) - r[i] = i; - for(j = 0; j < n; j++) { - sum = 0; - for(i of r) { - sum += i; - } - global_res = sum; - } - return n * len; -} - -function math_min(n) -{ - var i, j, r; - r = 0; - for(j = 0; j < n; j++) { - for(i = 0; i < 1000; i++) - r = Math.min(i, 500); - global_res = r; - } - return n * 1000; -} - -function regexp_ascii(n) -{ - var i, j, r, s; - s = "the quick brown fox jumped over the lazy dog" - for(j = 0; j < n; j++) { - for(i = 0; i < 1000; i++) - r = /the quick brown fox/.exec(s) - global_res = r; - } - return n * 1000; -} - -function regexp_utf16(n) -{ - var i, j, r, s; - s = "the quick brown ᶠᵒˣ jumped over the lazy ᵈᵒᵍ" - for(j = 0; j < n; j++) { - for(i = 0; i < 1000; i++) - r = /the quick brown ᶠᵒˣ/.exec(s) - global_res = r; - } - return n * 1000; -} - -/* incremental string contruction as local var */ -function string_build1(n) -{ - var i, j, r; - for(j = 0; j < n; j++) { - r = ""; - for(i = 0; i < 1000; i++) - r += "x"; - global_res = r; - } - return n * 1000; -} - -/* incremental string contruction using + */ -function string_build1x(n) -{ - var i, j, r; - for(j = 0; j < n; j++) { - r = ""; - for(i = 0; i < 1000; i++) - r = r + "x"; - global_res = r; - } - return n * 1000; -} - -/* incremental string contruction using +2c */ -function string_build2c(n) -{ - var i, j; - for(j = 0; j < n; j++) { - var r = ""; - for(i = 0; i < 1000; i++) - r += "xy"; - global_res = r; - } - return n * 1000; -} - -/* incremental string contruction as arg */ -function string_build2(n, r) -{ - var i, j; - for(j = 0; j < n; j++) { - r = ""; - for(i = 0; i < 1000; i++) - r += "x"; - global_res = r; - } - return n * 1000; -} - -/* incremental string contruction by prepending */ -function string_build3(n) -{ - var i, j, r; - for(j = 0; j < n; j++) { - r = ""; - for(i = 0; i < 1000; i++) - r = "x" + r; - global_res = r; - } - return n * 1000; -} - -/* incremental string contruction with multiple reference */ -function string_build4(n) -{ - var i, j, r, s; - for(j = 0; j < n; j++) { - r = ""; - for(i = 0; i < 1000; i++) { - s = r; - r += "x"; - } - global_res = r; - } - return n * 1000; -} - -/* append */ -function string_build_large1(n) -{ - var i, j, r, len = 20000; - for(j = 0; j < n; j++) { - r = ""; - for(i = 0; i < len; i++) - r += "abcdef"; - global_res = r; - } - return n * len; -} - -/* prepend */ -function string_build_large2(n) -{ - var i, j, r, len = 20000; - for(j = 0; j < n; j++) { - r = ""; - for(i = 0; i < len; i++) - r = "abcdef" + r; - global_res = r; - } - return n * len; -} - -/* sort bench */ - -function sort_bench(text) { - function random(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[(Math.random() * n) >> 0]; - } - function random8(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[(Math.random() * 256) >> 0]; - } - function random1(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[(Math.random() * 2) >> 0]; - } - function hill(arr, n, def) { - var mid = n >> 1; - for (var i = 0; i < mid; i++) - arr[i] = def[i]; - for (var i = mid; i < n; i++) - arr[i] = def[n - i]; - } - function comb(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[(i & 1) * i]; - } - function crisscross(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[(i & 1) ? n - i : i]; - } - function zero(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[0]; - } - function increasing(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[i]; - } - function decreasing(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[n - 1 - i]; - } - function alternate(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[i ^ 1]; - } - function jigsaw(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[i % (n >> 4)]; - } - function incbutone(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[i]; - if (n > 0) - arr[n >> 2] = def[n]; - } - function incbutfirst(arr, n, def) { - if (n > 0) - arr[0] = def[n]; - for (var i = 1; i < n; i++) - arr[i] = def[i]; - } - function incbutlast(arr, n, def) { - for (var i = 0; i < n - 1; i++) - arr[i] = def[i + 1]; - if (n > 0) - arr[n - 1] = def[0]; - } - - var sort_cases = [ random, random8, random1, jigsaw, hill, comb, - crisscross, zero, increasing, decreasing, alternate, - incbutone, incbutlast, incbutfirst ]; - - var n = sort_bench.array_size || 10000; - var array_type = sort_bench.array_type || Array; - var def, arr; - var i, j, x, y; - var total = 0; - - var save_total_score = total_score; - var save_total_scale = total_scale; - - // initialize default sorted array (n + 1 elements) - def = new array_type(n + 1); - if (array_type == Array) { - for (i = 0; i <= n; i++) { - def[i] = i + ""; - } - } else { - for (i = 0; i <= n; i++) { - def[i] = i; - } - } - def.sort(); - for (var f of sort_cases) { - var ti = 0, tx = 0; - for (j = 0; j < 100; j++) { - arr = new array_type(n); - f(arr, n, def); - var t1 = get_clock(); - arr.sort(); - t1 = get_clock() - t1; - tx += t1; - if (!ti || ti > t1) - ti = t1; - if (tx >= clocks_per_sec) - break; - } - total += ti; - - i = 0; - x = arr[0]; - if (x !== void 0) { - for (i = 1; i < n; i++) { - y = arr[i]; - if (y === void 0) - break; - if (x > y) - break; - x = y; - } - } - while (i < n && arr[i] === void 0) - i++; - if (i < n) { - console.log("sort_bench: out of order error for " + f.name + - " at offset " + (i - 1) + - ": " + arr[i - 1] + " > " + arr[i]); - } - if (sort_bench.verbose) - log_one("sort_" + f.name, 1, ti / 100); - } - total_score = save_total_score; - total_scale = save_total_scale; - return total / n / 100; -} -sort_bench.bench = true; -sort_bench.verbose = false; - -function int_to_string(n) -{ - var s, j; - for(j = 0; j < n; j++) { - s = (j % 1000).toString(); - s = (1234000 + j % 1000).toString(); - } - global_res = s; - return n * 2; -} - -function int_to_string(n) -{ - var s, r, j; - r = 0; - for(j = 0; j < n; j++) { - s = (j % 10) + ''; - s = (j % 100) + ''; - s = (j) + ''; - } - return n * 3; -} - -function int_toString(n) -{ - var s, r, j; - r = 0; - for(j = 0; j < n; j++) { - s = (j % 10).toString(); - s = (j % 100).toString(); - s = (j).toString(); - } - return n * 3; -} - -function float_to_string(n) -{ - var s, r, j; - r = 0; - for(j = 0; j < n; j++) { - s = (j % 10 + 0.1) + ''; - s = (j + 0.1) + ''; - s = (j * 12345678 + 0.1) + ''; - } - return n * 3; -} - -function float_toString(n) -{ - var s, r, j; - r = 0; - for(j = 0; j < n; j++) { - s = (j % 10 + 0.1).toString(); - s = (j + 0.1).toString(); - s = (j * 12345678 + 0.1).toString(); - } - return n * 3; -} - -function float_toFixed(n) -{ - var s, r, j; - r = 0; - for(j = 0; j < n; j++) { - s = (j % 10 + 0.1).toFixed(j % 16); - s = (j + 0.1).toFixed(j % 16); - s = (j * 12345678 + 0.1).toFixed(j % 16); - } - return n * 3; -} - -function float_toPrecision(n) -{ - var s, r, j; - r = 0; - for(j = 0; j < n; j++) { - s = (j % 10 + 0.1).toPrecision(j % 16 + 1); - s = (j + 0.1).toPrecision(j % 16 + 1); - s = (j * 12345678 + 0.1).toPrecision(j % 16 + 1); - } - return n * 3; -} - -function float_toExponential(n) -{ - var s, r, j; - r = 0; - for(j = 0; j < n; j++) { - s = (j % 10 + 0.1).toExponential(j % 16); - s = (j + 0.1).toExponential(j % 16); - s = (j * 12345678 + 0.1).toExponential(j % 16); - } - return n * 3; -} - -function string_to_int(n) -{ - var s, r, j; - r = 0; - s = "12345"; - for(j = 0; j < n; j++) { - r += (s | 0); - } - global_res = r; - return n; -} - -function string_to_float(n) -{ - var s, r, j; - r = 0; - s = "12345.6"; - for(j = 0; j < n; j++) { - r -= s; - } - global_res = r; - return n; -} - -function load_result(filename) -{ - var has_filename = filename; - var has_error = false; - var str, res; - - if (!filename) - filename = "microbench.txt"; - - if (typeof fs !== "undefined") { - // read the file in Node.js - try { - str = fs.readFileSync(filename, { encoding: "utf8" }); - } catch { - has_error = true; - } - } else - if (typeof std !== "undefined") { - // read the file in QuickJS - var f = std.open(filename, "r"); - if (f) { - str = f.readAsString(); - f.close(); - } else { - has_error = true; - } - } else { - return null; - } - if (has_error) { - if (has_filename) { - // Should throw exception? - console.log("cannot load " + filename); - } - return null; - } - res = JSON.parse(str); - return res; -} - -function save_result(filename, obj) -{ - var str = JSON.stringify(obj, null, 2) + "\n"; - var has_error = false; - - if (typeof fs !== "undefined") { - // save the file in Node.js - try { - str = fs.writeFileSync(filename, str, { encoding: "utf8" }); - } catch { - has_error = true; - } - } else - if (typeof std !== "undefined") { - // save the file in QuickJS - var f = std.open(filename, "w"); - if (f) { - f.puts(str); - f.close(); - } else { - has_error = 'true'; - } - } else { - return; - } - if (has_error) - console.log("cannot save " + filename); -} - -function main(argc, argv, g) -{ - var test_list = [ - empty_loop, - empty_down_loop, - empty_down_loop2, - empty_do_loop, - date_now, - date_parse, - prop_read, - prop_write, - prop_update, - prop_create, - prop_clone, - prop_delete, - array_read, - array_write, - array_prop_create, - array_slice, - array_length_decr, - array_hole_length_decr, - array_push, - array_pop, - typed_array_read, - typed_array_write, - global_read, - global_write, - global_write_strict, - local_destruct, - global_destruct, - global_destruct_strict, - global_func_call, - func_call, - func_closure_call, - int_arith, - float_arith, - map_set_string, - map_set_int, - map_set_bigint, - map_delete, - weak_map_set, - weak_map_delete, - array_for, - array_for_in, - array_for_of, - math_min, - regexp_ascii, - regexp_utf16, - string_build1, - string_build1x, - string_build2c, - string_build2, - string_build3, - string_build4, - string_build_large1, - string_build_large2, - int_to_string, - int_toString, - float_to_string, - float_toString, - float_toFixed, - float_toPrecision, - float_toExponential, - string_to_int, - string_to_float, - ]; - var tests = []; - var i, j, n, f, name, found; - var ref_file, new_ref_file = "microbench-new.txt"; - - if (typeof BigInt === "function") { - /* BigInt test */ - test_list.push(bigint32_arith); - test_list.push(bigint64_arith); - test_list.push(bigint256_arith); - } - test_list.push(sort_bench); - - for (i = 1; i < argc;) { - name = argv[i++]; - if (name == "-a") { - sort_bench.verbose = true; - continue; - } - if (name == "-t") { - name = argv[i++]; - sort_bench.array_type = g[name]; - if (typeof sort_bench.array_type !== "function") { - console.log("unknown array type: " + name); - return 1; - } - continue; - } - if (name == "-n") { - sort_bench.array_size = +argv[i++]; - continue; - } - if (name == "-r") { - ref_file = argv[i++]; - continue; - } - if (name == "-s") { - new_ref_file = argv[i++]; - continue; - } - for (j = 0, found = false; j < test_list.length; j++) { - f = test_list[j]; - if (f.name.startsWith(name)) { - tests.push(f); - found = true; - } - } - if (!found) { - console.log("unknown benchmark: " + name); - return 1; - } - } - if (tests.length == 0) - tests = test_list; - - ref_data = load_result(ref_file); - log_data = {}; - log_line.apply(null, heads); - n = 0; - - for(i = 0; i < tests.length; i++) { - f = tests[i]; - bench(f, f.name, ref_data, log_data); - if (ref_data && ref_data[f.name]) - n++; - } - if (ref_data) - log_line("total", "", total[2], total[3], Math.round(total_scale * 1000 / total_score)); - else - log_line("total", "", total[2]); - - if (tests == test_list && new_ref_file) - save_result(new_ref_file, log_data); -} - -if (typeof scriptArgs === "undefined") { - scriptArgs = []; - if (typeof process.argv === "object") - scriptArgs = process.argv.slice(1); -} -main(scriptArgs.length, scriptArgs, this); diff --git a/packages/javascript/javascript_android/cxx/quickjs/tests/test262.patch b/packages/javascript/javascript_android/cxx/quickjs/tests/test262.patch deleted file mode 100644 index 6956d15..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/tests/test262.patch +++ /dev/null @@ -1,135 +0,0 @@ -diff --git a/harness/atomicsHelper.js b/harness/atomicsHelper.js -index 9828b15..4a5919d 100644 ---- a/harness/atomicsHelper.js -+++ b/harness/atomicsHelper.js -@@ -272,10 +272,14 @@ $262.agent.waitUntil = function(typedArray, index, expected) { - * } - */ - $262.agent.timeouts = { -- yield: 100, -- small: 200, -- long: 1000, -- huge: 10000, -+// yield: 100, -+// small: 200, -+// long: 1000, -+// huge: 10000, -+ yield: 20, -+ small: 20, -+ long: 100, -+ huge: 1000, - }; - - /** -diff --git a/harness/regExpUtils.js b/harness/regExpUtils.js -index b397be0..c197ddc 100644 ---- a/harness/regExpUtils.js -+++ b/harness/regExpUtils.js -@@ -6,27 +6,30 @@ description: | - defines: [buildString, testPropertyEscapes, testPropertyOfStrings, testExtendedCharacterClass, matchValidator] - ---*/ - -+if ($262 && typeof $262.codePointRange === "function") { -+ /* use C function to build the codePointRange (much faster with -+ slow JS engines) */ -+ codePointRange = $262.codePointRange; -+} else { -+ codePointRange = function codePointRange(start, end) { -+ const codePoints = []; -+ let length = 0; -+ for (codePoint = start; codePoint < end; codePoint++) { -+ codePoints[length++] = codePoint; -+ } -+ return String.fromCodePoint.apply(null, codePoints); -+ } -+} -+ - function buildString(args) { - // Use member expressions rather than destructuring `args` for improved - // compatibility with engines that only implement assignment patterns - // partially or not at all. - const loneCodePoints = args.loneCodePoints; - const ranges = args.ranges; -- const CHUNK_SIZE = 10000; - let result = String.fromCodePoint.apply(null, loneCodePoints); -- for (let i = 0; i < ranges.length; i++) { -- let range = ranges[i]; -- let start = range[0]; -- let end = range[1]; -- let codePoints = []; -- for (let length = 0, codePoint = start; codePoint <= end; codePoint++) { -- codePoints[length++] = codePoint; -- if (length === CHUNK_SIZE) { -- result += String.fromCodePoint.apply(null, codePoints); -- codePoints.length = length = 0; -- } -- } -- result += String.fromCodePoint.apply(null, codePoints); -+ for (const [start, end] of ranges) { -+ result += codePointRange(start, end + 1); - } - return result; - } -diff --git a/harness/sm/non262.js b/harness/sm/non262.js -index 89df923..79ded15 100644 ---- a/harness/sm/non262.js -+++ b/harness/sm/non262.js -@@ -34,8 +34,6 @@ globalThis.createNewGlobal = function() { - return $262.createRealm().global - } - --function print(...args) { --} - function assertEq(...args) { - assert.sameValue(...args) - } -diff --git a/test/staging/sm/extensions/regress-469625-01.js b/test/staging/sm/extensions/regress-469625-01.js -index 81f84fc..4652002 100644 ---- a/test/staging/sm/extensions/regress-469625-01.js -+++ b/test/staging/sm/extensions/regress-469625-01.js -@@ -14,8 +14,7 @@ esid: pending - //----------------------------------------------------------------------------- - var BUGNUMBER = 469625; - var summary = 'TM: Array prototype and expression closures'; --var actual = ''; --var expect = ''; -+var actual = null; - - - //----------------------------------------------------------------------------- -@@ -24,9 +23,6 @@ test(); - - function test() - { -- expect = 'TypeError: [].__proto__ is not a function'; -- -- - Array.prototype.__proto__ = function () { return 3; }; - - try -@@ -35,8 +31,10 @@ function test() - } - catch(ex) - { -- print(actual = ex + ''); -+ print(ex + ''); -+ actual = ex; - } - -- assert.sameValue(expect, actual, summary); -+ assert.sameValue(actual instanceof TypeError, true); -+ assert.sameValue(actual.message.includes("not a function"), true); - } -diff --git a/test/staging/sm/misc/new-with-non-constructor.js b/test/staging/sm/misc/new-with-non-constructor.js -index 18c2f0c..f9aa209 100644 ---- a/test/staging/sm/misc/new-with-non-constructor.js -+++ b/test/staging/sm/misc/new-with-non-constructor.js -@@ -16,7 +16,7 @@ function checkConstruct(thing) { - new thing(); - assert.sameValue(0, 1, "not reached " + thing); - } catch (e) { -- assert.sameValue(e.message.includes(" is not a constructor") || -+ assert.sameValue(e.message.includes("not a constructor") || - e.message === "Function.prototype.toString called on incompatible object", true); - } - } diff --git a/packages/javascript/javascript_android/cxx/quickjs/tests/test_bigint.js b/packages/javascript/javascript_android/cxx/quickjs/tests/test_bigint.js deleted file mode 100644 index a0d028c..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/tests/test_bigint.js +++ /dev/null @@ -1,249 +0,0 @@ -"use strict"; - -function assert(actual, expected, message) { - if (arguments.length == 1) - expected = true; - - if (actual === expected) - return; - - if (actual !== null && expected !== null - && typeof actual == 'object' && typeof expected == 'object' - && actual.toString() === expected.toString()) - return; - - throw Error("assertion failed: got |" + actual + "|" + - ", expected |" + expected + "|" + - (message ? " (" + message + ")" : "")); -} - -function assertThrows(err, func) -{ - var ex; - ex = false; - try { - func(); - } catch(e) { - ex = true; - assert(e instanceof err); - } - assert(ex, true, "exception expected"); -} - -// load more elaborate version of assert if available -try { __loadScript("test_assert.js"); } catch(e) {} - -/*----------------*/ - -function bigint_pow(a, n) -{ - var r, i; - r = 1n; - for(i = 0n; i < n; i++) - r *= a; - return r; -} - -/* a must be < b */ -function test_less(a, b) -{ - assert(a < b); - assert(!(b < a)); - assert(a <= b); - assert(!(b <= a)); - assert(b > a); - assert(!(a > b)); - assert(b >= a); - assert(!(a >= b)); - assert(a != b); - assert(!(a == b)); -} - -/* a must be numerically equal to b */ -function test_eq(a, b) -{ - assert(a == b); - assert(b == a); - assert(!(a != b)); - assert(!(b != a)); - assert(a <= b); - assert(b <= a); - assert(!(a < b)); - assert(a >= b); - assert(b >= a); - assert(!(a > b)); -} - -function test_bigint1() -{ - var a, r; - - test_less(2n, 3n); - test_eq(3n, 3n); - - test_less(2, 3n); - test_eq(3, 3n); - - test_less(2.1, 3n); - test_eq(Math.sqrt(4), 2n); - - a = bigint_pow(3n, 100n); - assert((a - 1n) != a); - assert(a == 515377520732011331036461129765621272702107522001n); - assert(a == 0x5a4653ca673768565b41f775d6947d55cf3813d1n); - - r = 1n << 31n; - assert(r, 2147483648n, "1 << 31n === 2147483648n"); - - r = 1n << 32n; - assert(r, 4294967296n, "1 << 32n === 4294967296n"); -} - -function test_bigint2() -{ - assert(BigInt(""), 0n); - assert(BigInt(" 123"), 123n); - assert(BigInt(" 123 "), 123n); - assertThrows(SyntaxError, () => { BigInt("+") } ); - assertThrows(SyntaxError, () => { BigInt("-") } ); - assertThrows(SyntaxError, () => { BigInt("\x00a") } ); - assertThrows(SyntaxError, () => { BigInt(" 123 r") } ); -} - -function test_bigint3() -{ - assert(Number(0xffffffffffffffffn), 18446744073709552000); - assert(Number(-0xffffffffffffffffn), -18446744073709552000); - assert(100000000000000000000n == 1e20, true); - assert(100000000000000000001n == 1e20, false); - assert((1n << 100n).toString(10), "1267650600228229401496703205376"); - assert((-1n << 100n).toString(36), "-3ewfdnca0n6ld1ggvfgg"); - assert((1n << 100n).toString(8), "2000000000000000000000000000000000"); - - assert(0x5a4653ca673768565b41f775n << 78n, 8443945299673273647701379149826607537748959488376832n); - assert(-0x5a4653ca673768565b41f775n << 78n, -8443945299673273647701379149826607537748959488376832n); - assert(0x5a4653ca673768565b41f775n >> 78n, 92441n); - assert(-0x5a4653ca673768565b41f775n >> 78n, -92442n); - - assert(~0x5a653ca6n, -1516584103n); - assert(0x5a463ca6n | 0x67376856n, 2138537206n); - assert(0x5a463ca6n & 0x67376856n, 1107699718n); - assert(0x5a463ca6n ^ 0x67376856n, 1030837488n); - - assert(3213213213213213432453243n / 123434343439n, 26031760073331n); - assert(-3213213213213213432453243n / 123434343439n, -26031760073331n); - assert(-3213213213213213432453243n % -123434343439n, -26953727934n); - assert(3213213213213213432453243n % 123434343439n, 26953727934n); - - assert((-2n) ** 127n, -170141183460469231731687303715884105728n); - assert((2n) ** 127n, 170141183460469231731687303715884105728n); - assert((-256n) ** 11n, -309485009821345068724781056n); - assert((7n) ** 20n, 79792266297612001n); -} - -/* pi computation */ - -/* return floor(log2(a)) for a > 0 and 0 for a = 0 */ -function floor_log2(a) -{ - var k_max, a1, k, i; - k_max = 0n; - while ((a >> (2n ** k_max)) != 0n) { - k_max++; - } - k = 0n; - a1 = a; - for(i = k_max - 1n; i >= 0n; i--) { - a1 = a >> (2n ** i); - if (a1 != 0n) { - a = a1; - k |= (1n << i); - } - } - return k; -} - -/* return ceil(log2(a)) for a > 0 */ -function ceil_log2(a) -{ - return floor_log2(a - 1n) + 1n; -} - -/* return floor(sqrt(a)) (not efficient but simple) */ -function int_sqrt(a) -{ - var l, u, s; - if (a == 0n) - return a; - l = ceil_log2(a); - u = 1n << ((l + 1n) / 2n); - /* u >= floor(sqrt(a)) */ - for(;;) { - s = u; - u = ((a / s) + s) / 2n; - if (u >= s) - break; - } - return s; -} - -/* return pi * 2**prec */ -function calc_pi(prec) { - const CHUD_A = 13591409n; - const CHUD_B = 545140134n; - const CHUD_C = 640320n; - const CHUD_C3 = 10939058860032000n; /* C^3/24 */ - const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */ - - /* return [P, Q, G] */ - function chud_bs(a, b, need_G) { - var c, P, Q, G, P1, Q1, G1, P2, Q2, G2; - if (a == (b - 1n)) { - G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n); - P = G * (CHUD_B * b + CHUD_A); - if (b & 1n) - P = -P; - Q = b * b * b * CHUD_C3; - } else { - c = (a + b) >> 1n; - [P1, Q1, G1] = chud_bs(a, c, true); - [P2, Q2, G2] = chud_bs(c, b, need_G); - P = P1 * Q2 + P2 * G1; - Q = Q1 * Q2; - if (need_G) - G = G1 * G2; - else - G = 0n; - } - return [P, Q, G]; - } - - var n, P, Q, G; - /* number of serie terms */ - n = BigInt(Math.ceil(Number(prec) / CHUD_BITS_PER_TERM)) + 10n; - [P, Q, G] = chud_bs(0n, n, false); - Q = (CHUD_C / 12n) * (Q << prec) / (P + Q * CHUD_A); - G = int_sqrt(CHUD_C << (2n * prec)); - return (Q * G) >> prec; -} - -function compute_pi(n_digits) { - var r, n_digits, n_bits, out; - /* we add more bits to reduce the probability of bad rounding for - the last digits */ - n_bits = BigInt(Math.ceil(n_digits * Math.log2(10))) + 32n; - r = calc_pi(n_bits); - r = ((10n ** BigInt(n_digits)) * r) >> n_bits; - out = r.toString(); - return out[0] + "." + out.slice(1); -} - -function test_pi() -{ - assert(compute_pi(2000), "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912983367336244065664308602139494639522473719070217986094370277053921717629317675238467481846766940513200056812714526356082778577134275778960917363717872146844090122495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349042875546873115956286388235378759375195778185778053217122680661300192787661119590921642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151557485724245415069595082953311686172785588907509838175463746493931925506040092770167113900984882401285836160356370766010471018194295559619894676783744944825537977472684710404753464620804668425906949129331367702898915210475216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992458631503028618297455570674983850549458858692699569092721079750930295532116534498720275596023648066549911988183479775356636980742654252786255181841757467289097777279380008164706001614524919217321721477235014144197356854816136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179049460165346680498862723279178608578438382796797668145410095388378636095068006422512520511739298489608412848862694560424196528502221066118630674427862203919494504712371378696095636437191728746776465757396241389086583264599581339047802759009"); -} - -test_bigint1(); -test_bigint2(); -test_bigint3(); -test_pi(); diff --git a/packages/javascript/javascript_android/cxx/quickjs/tests/test_bjson.js b/packages/javascript/javascript_android/cxx/quickjs/tests/test_bjson.js deleted file mode 100644 index a90bfe1..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/tests/test_bjson.js +++ /dev/null @@ -1,177 +0,0 @@ -import * as bjson from "./bjson.so"; - -function assert(actual, expected, message) { - if (arguments.length == 1) - expected = true; - - if (actual === expected) - return; - - if (actual !== null && expected !== null - && typeof actual == 'object' && typeof expected == 'object' - && actual.toString() === expected.toString()) - return; - - throw Error("assertion failed: got |" + actual + "|" + - ", expected |" + expected + "|" + - (message ? " (" + message + ")" : "")); -} - -function toHex(a) -{ - var i, s = "", tab, v; - tab = new Uint8Array(a); - for(i = 0; i < tab.length; i++) { - v = tab[i].toString(16); - if (v.length < 2) - v = "0" + v; - if (i !== 0) - s += " "; - s += v; - } - return s; -} - -function isArrayLike(a) -{ - return Array.isArray(a) || - (a instanceof Uint8ClampedArray) || - (a instanceof Uint8Array) || - (a instanceof Uint16Array) || - (a instanceof Uint32Array) || - (a instanceof Int8Array) || - (a instanceof Int16Array) || - (a instanceof Int32Array) || - (a instanceof Float16Array) || - (a instanceof Float32Array) || - (a instanceof Float64Array); -} - -function toStr(a) -{ - var s, i, props, prop; - - switch(typeof(a)) { - case "object": - if (a === null) - return "null"; - if (a instanceof Date) { - s = "Date(" + toStr(a.valueOf()) + ")"; - } else if (a instanceof Number) { - s = "Number(" + toStr(a.valueOf()) + ")"; - } else if (a instanceof String) { - s = "String(" + toStr(a.valueOf()) + ")"; - } else if (a instanceof Boolean) { - s = "Boolean(" + toStr(a.valueOf()) + ")"; - } else if (isArrayLike(a)) { - s = "["; - for(i = 0; i < a.length; i++) { - if (i != 0) - s += ","; - s += toStr(a[i]); - } - s += "]"; - } else { - props = Object.keys(a); - s = "{"; - for(i = 0; i < props.length; i++) { - if (i != 0) - s += ","; - prop = props[i]; - s += prop + ":" + toStr(a[prop]); - } - s += "}"; - } - return s; - case "undefined": - return "undefined"; - case "string": - return a.__quote(); - case "number": - if (a == 0 && 1 / a < 0) - return "-0"; - else - return a.toString(); - break; - default: - return a.toString(); - } -} - -function bjson_test(a) -{ - var buf, r, a_str, r_str; - a_str = toStr(a); - buf = bjson.write(a); - if (0) { - print(a_str, "->", toHex(buf)); - } - r = bjson.read(buf, 0, buf.byteLength); - r_str = toStr(r); - if (a_str != r_str) { - print(a_str); - print(r_str); - assert(false); - } -} - -/* test multiple references to an object including circular - references */ -function bjson_test_reference() -{ - var array, buf, i, n, array_buffer; - n = 16; - array = []; - for(i = 0; i < n; i++) - array[i] = {}; - array_buffer = new ArrayBuffer(n); - for(i = 0; i < n; i++) { - array[i].next = array[(i + 1) % n]; - array[i].idx = i; - array[i].typed_array = new Uint8Array(array_buffer, i, 1); - } - buf = bjson.write(array, true); - - array = bjson.read(buf, 0, buf.byteLength, true); - - /* check the result */ - for(i = 0; i < n; i++) { - assert(array[i].next, array[(i + 1) % n]); - assert(array[i].idx, i); - assert(array[i].typed_array.buffer, array_buffer); - assert(array[i].typed_array.length, 1); - assert(array[i].typed_array.byteOffset, i); - } -} - -function bjson_test_all() -{ - var obj; - - bjson_test({x:1, y:2, if:3}); - bjson_test([1, 2, 3]); - bjson_test([1.0, "aa", true, false, undefined, null, NaN, -Infinity, -0.0]); - if (typeof BigInt !== "undefined") { - bjson_test([BigInt("1"), -BigInt("0x123456789"), - BigInt("0x123456789abcdef123456789abcdef")]); - } - bjson_test([new Date(1234), new String("abc"), new Number(-12.1), new Boolean(true)]); - - bjson_test(new Int32Array([123123, 222111, -32222])); - bjson_test(new Float16Array([1024, 1024.5])); - bjson_test(new Float64Array([123123, 222111.5])); - - /* tested with a circular reference */ - obj = {}; - obj.x = obj; - try { - bjson.write(obj); - assert(false); - } catch(e) { - assert(e instanceof TypeError); - } - - bjson_test_reference(); -} - -bjson_test_all(); diff --git a/packages/javascript/javascript_android/cxx/quickjs/tests/test_builtin.js b/packages/javascript/javascript_android/cxx/quickjs/tests/test_builtin.js deleted file mode 100644 index a541c19..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/tests/test_builtin.js +++ /dev/null @@ -1,1167 +0,0 @@ -"use strict"; - -var status = 0; -var throw_errors = true; - -function throw_error(msg) { - if (throw_errors) - throw Error(msg); - console.log(msg); - status = 1; -} - -function assert(actual, expected, message) { - function get_full_type(o) { - var type = typeof(o); - if (type === 'object') { - if (o === null) - return 'null'; - if (o.constructor && o.constructor.name) - return o.constructor.name; - } - return type; - } - - if (arguments.length == 1) - expected = true; - - if (typeof actual === typeof expected) { - if (actual === expected) { - if (actual !== 0 || (1 / actual) === (1 / expected)) - return; - } - if (typeof actual === 'number') { - if (isNaN(actual) && isNaN(expected)) - return true; - } - if (typeof actual === 'object') { - if (actual !== null && expected !== null - && actual.constructor === expected.constructor - && actual.toString() === expected.toString()) - return; - } - } - // Should output the source file and line number and extract - // the expression from the assert call - throw_error("assertion failed: got " + - get_full_type(actual) + ":|" + actual + "|, expected " + - get_full_type(expected) + ":|" + expected + "|" + - (message ? " (" + message + ")" : "")); -} - -function assert_throws(expected_error, func) -{ - var err = false; - try { - func(); - } catch(e) { - err = true; - if (!(e instanceof expected_error)) { - // Should output the source file and line number and extract - // the expression from the assert_throws() call - throw_error("unexpected exception type"); - return; - } - } - if (!err) { - // Should output the source file and line number and extract - // the expression from the assert_throws() call - throw_error("expected exception"); - } -} - -// load more elaborate version of assert if available -try { __loadScript("test_assert.js"); } catch(e) {} - -/*----------------*/ - -function my_func(a, b) -{ - return a + b; -} - -function test_function() -{ - function f(a, b) { - var i, tab = []; - tab.push(this); - for(i = 0; i < arguments.length; i++) - tab.push(arguments[i]); - return tab; - } - function constructor1(a) { - this.x = a; - } - - var r, g; - - r = my_func.call(null, 1, 2); - assert(r, 3, "call"); - - r = my_func.apply(null, [1, 2]); - assert(r, 3, "apply"); - - r = (function () { return 1; }).apply(null, undefined); - assert(r, 1); - - assert_throws(TypeError, (function() { - Reflect.apply((function () { return 1; }), null, undefined); - })); - - r = new Function("a", "b", "return a + b;"); - assert(r(2,3), 5, "function"); - - g = f.bind(1, 2); - assert(g.length, 1); - assert(g.name, "bound f"); - assert(g(3), [1,2,3]); - - g = constructor1.bind(null, 1); - r = new g(); - assert(r.x, 1); -} - -function test() -{ - var r, a, b, c, err; - - r = Error("hello"); - assert(r.message, "hello", "Error"); - - a = new Object(); - a.x = 1; - assert(a.x, 1, "Object"); - - assert(Object.getPrototypeOf(a), Object.prototype, "getPrototypeOf"); - Object.defineProperty(a, "y", { value: 3, writable: true, configurable: true, enumerable: true }); - assert(a.y, 3, "defineProperty"); - - Object.defineProperty(a, "z", { get: function () { return 4; }, set: function(val) { this.z_val = val; }, configurable: true, enumerable: true }); - assert(a.z, 4, "get"); - a.z = 5; - assert(a.z_val, 5, "set"); - - a = { get z() { return 4; }, set z(val) { this.z_val = val; } }; - assert(a.z, 4, "get"); - a.z = 5; - assert(a.z_val, 5, "set"); - - b = Object.create(a); - assert(Object.getPrototypeOf(b), a, "create"); - c = {u:2}; - /* XXX: refcount bug in 'b' instead of 'a' */ - Object.setPrototypeOf(a, c); - assert(Object.getPrototypeOf(a), c, "setPrototypeOf"); - - a = {}; - assert(a.toString(), "[object Object]", "toString"); - - a = {x:1}; - assert(Object.isExtensible(a), true, "extensible"); - Object.preventExtensions(a); - - err = false; - try { - a.y = 2; - } catch(e) { - err = true; - } - assert(Object.isExtensible(a), false, "extensible"); - assert(typeof a.y, "undefined", "extensible"); - assert(err, true, "extensible"); -} - -function test_enum() -{ - var a, tab; - a = {x:1, - "18014398509481984": 1, - "9007199254740992": 1, - "9007199254740991": 1, - "4294967296": 1, - "4294967295": 1, - y:1, - "4294967294": 1, - "1": 2}; - tab = Object.keys(a); -// console.log("tab=" + tab.toString()); - assert(tab, ["1","4294967294","x","18014398509481984","9007199254740992","9007199254740991","4294967296","4294967295","y"], "keys"); -} - -function test_array() -{ - var a, err; - - a = [1, 2, 3]; - assert(a.length, 3, "array"); - assert(a[2], 3, "array1"); - - a = new Array(10); - assert(a.length, 10, "array2"); - - a = new Array(1, 2); - assert(a.length === 2 && a[0] === 1 && a[1] === 2, true, "array3"); - - a = [1, 2, 3]; - a.length = 2; - assert(a.length === 2 && a[0] === 1 && a[1] === 2, true, "array4"); - - a = []; - a[1] = 10; - a[4] = 3; - assert(a.length, 5); - - a = [1,2]; - a.length = 5; - a[4] = 1; - a.length = 4; - assert(a[4] !== 1, true, "array5"); - - a = [1,2]; - a.push(3,4); - assert(a.join(), "1,2,3,4", "join"); - - a = [1,2,3,4,5]; - Object.defineProperty(a, "3", { configurable: false }); - err = false; - try { - a.length = 2; - } catch(e) { - err = true; - } - assert(err && a.toString() === "1,2,3,4"); -} - -function test_string() -{ - var a; - a = String("abc"); - assert(a.length, 3, "string"); - assert(a[1], "b", "string"); - assert(a.charCodeAt(1), 0x62, "string"); - assert(String.fromCharCode(65), "A", "string"); - assert(String.fromCharCode.apply(null, [65, 66, 67]), "ABC", "string"); - assert(a.charAt(1), "b"); - assert(a.charAt(-1), ""); - assert(a.charAt(3), ""); - - a = "abcd"; - assert(a.substring(1, 3), "bc", "substring"); - a = String.fromCharCode(0x20ac); - assert(a.charCodeAt(0), 0x20ac, "unicode"); - assert(a, "€", "unicode"); - assert(a, "\u20ac", "unicode"); - assert(a, "\u{20ac}", "unicode"); - assert("a", "\x61", "unicode"); - - a = "\u{10ffff}"; - assert(a.length, 2, "unicode"); - assert(a, "\u{dbff}\u{dfff}", "unicode"); - assert(a.codePointAt(0), 0x10ffff); - assert(String.fromCodePoint(0x10ffff), a); - - assert("a".concat("b", "c"), "abc"); - - assert("abcabc".indexOf("cab"), 2); - assert("abcabc".indexOf("cab2"), -1); - assert("abc".indexOf("c"), 2); - - assert("aaa".indexOf("a"), 0); - assert("aaa".indexOf("a", NaN), 0); - assert("aaa".indexOf("a", -Infinity), 0); - assert("aaa".indexOf("a", -1), 0); - assert("aaa".indexOf("a", -0), 0); - assert("aaa".indexOf("a", 0), 0); - assert("aaa".indexOf("a", 1), 1); - assert("aaa".indexOf("a", 2), 2); - assert("aaa".indexOf("a", 3), -1); - assert("aaa".indexOf("a", 4), -1); - assert("aaa".indexOf("a", Infinity), -1); - - assert("aaa".indexOf(""), 0); - assert("aaa".indexOf("", NaN), 0); - assert("aaa".indexOf("", -Infinity), 0); - assert("aaa".indexOf("", -1), 0); - assert("aaa".indexOf("", -0), 0); - assert("aaa".indexOf("", 0), 0); - assert("aaa".indexOf("", 1), 1); - assert("aaa".indexOf("", 2), 2); - assert("aaa".indexOf("", 3), 3); - assert("aaa".indexOf("", 4), 3); - assert("aaa".indexOf("", Infinity), 3); - - assert("aaa".lastIndexOf("a"), 2); - assert("aaa".lastIndexOf("a", NaN), 2); - assert("aaa".lastIndexOf("a", -Infinity), 0); - assert("aaa".lastIndexOf("a", -1), 0); - assert("aaa".lastIndexOf("a", -0), 0); - assert("aaa".lastIndexOf("a", 0), 0); - assert("aaa".lastIndexOf("a", 1), 1); - assert("aaa".lastIndexOf("a", 2), 2); - assert("aaa".lastIndexOf("a", 3), 2); - assert("aaa".lastIndexOf("a", 4), 2); - assert("aaa".lastIndexOf("a", Infinity), 2); - - assert("aaa".lastIndexOf(""), 3); - assert("aaa".lastIndexOf("", NaN), 3); - assert("aaa".lastIndexOf("", -Infinity), 0); - assert("aaa".lastIndexOf("", -1), 0); - assert("aaa".lastIndexOf("", -0), 0); - assert("aaa".lastIndexOf("", 0), 0); - assert("aaa".lastIndexOf("", 1), 1); - assert("aaa".lastIndexOf("", 2), 2); - assert("aaa".lastIndexOf("", 3), 3); - assert("aaa".lastIndexOf("", 4), 3); - assert("aaa".lastIndexOf("", Infinity), 3); - - assert("a,b,c".split(","), ["a","b","c"]); - assert(",b,c".split(","), ["","b","c"]); - assert("a,b,".split(","), ["a","b",""]); - - assert("aaaa".split(), [ "aaaa" ]); - assert("aaaa".split(undefined, 0), [ ]); - assert("aaaa".split(""), [ "a", "a", "a", "a" ]); - assert("aaaa".split("", 0), [ ]); - assert("aaaa".split("", 1), [ "a" ]); - assert("aaaa".split("", 2), [ "a", "a" ]); - assert("aaaa".split("a"), [ "", "", "", "", "" ]); - assert("aaaa".split("a", 2), [ "", "" ]); - assert("aaaa".split("aa"), [ "", "", "" ]); - assert("aaaa".split("aa", 0), [ ]); - assert("aaaa".split("aa", 1), [ "" ]); - assert("aaaa".split("aa", 2), [ "", "" ]); - assert("aaaa".split("aaa"), [ "", "a" ]); - assert("aaaa".split("aaaa"), [ "", "" ]); - assert("aaaa".split("aaaaa"), [ "aaaa" ]); - assert("aaaa".split("aaaaa", 0), [ ]); - assert("aaaa".split("aaaaa", 1), [ "aaaa" ]); - - assert(eval('"\0"'), "\0"); - - assert("abc".padStart(Infinity, ""), "abc"); -} - -function test_math() -{ - var a; - a = 1.4; - assert(Math.floor(a), 1); - assert(Math.ceil(a), 2); - assert(Math.imul(0x12345678, 123), -1088058456); - assert(Math.imul(0xB505, 0xB504), 2147441940); - assert(Math.imul(0xB505, 0xB505), -2147479015); - assert(Math.imul((-2)**31, (-2)**31), 0); - assert(Math.imul(2**31-1, 2**31-1), 1); - assert(Math.fround(0.1), 0.10000000149011612); - assert(Math.hypot(), 0); - assert(Math.hypot(-2), 2); - assert(Math.hypot(3, 4), 5); - assert(Math.abs(Math.hypot(3, 4, 5) - 7.0710678118654755) <= 1e-15); -} - -function test_number() -{ - assert(parseInt("123"), 123); - assert(parseInt(" 123r"), 123); - assert(parseInt("0x123"), 0x123); - assert(parseInt("0o123"), 0); - assert(+" 123 ", 123); - assert(+"0b111", 7); - assert(+"0o123", 83); - assert(parseFloat("2147483647"), 2147483647); - assert(parseFloat("2147483648"), 2147483648); - assert(parseFloat("-2147483647"), -2147483647); - assert(parseFloat("-2147483648"), -2147483648); - assert(parseFloat("0x1234"), 0); - assert(parseFloat("Infinity"), Infinity); - assert(parseFloat("-Infinity"), -Infinity); - assert(parseFloat("123.2"), 123.2); - assert(parseFloat("123.2e3"), 123200); - assert(Number.isNaN(Number("+"))); - assert(Number.isNaN(Number("-"))); - assert(Number.isNaN(Number("\x00a"))); - - assert((1-2**-53).toString(12), "0.bbbbbbbbbbbbbba"); - assert((1000000000000000128).toString(), "1000000000000000100"); - assert((1000000000000000128).toFixed(0), "1000000000000000128"); - assert((25).toExponential(0), "3e+1"); - assert((-25).toExponential(0), "-3e+1"); - assert((2.5).toPrecision(1), "3"); - assert((-2.5).toPrecision(1), "-3"); - assert((25).toPrecision(1) === "3e+1"); - assert((1.125).toFixed(2), "1.13"); - assert((-1.125).toFixed(2), "-1.13"); - assert((0.5).toFixed(0), "1"); - assert((-0.5).toFixed(0), "-1"); - assert((-1e-10).toFixed(0), "-0"); - - assert((1.3).toString(7), "1.2046204620462046205"); - assert((1.3).toString(35), "1.ahhhhhhhhhm"); -} - -function test_eval2() -{ - var g_call_count = 0; - /* force non strict mode for f1 and f2 */ - var f1 = new Function("eval", "eval(1, 2)"); - var f2 = new Function("eval", "eval(...[1, 2])"); - function g(a, b) { - assert(a, 1); - assert(b, 2); - g_call_count++; - } - f1(g); - f2(g); - assert(g_call_count, 2); -} - -function test_eval() -{ - function f(b) { - var x = 1; - return eval(b); - } - var r, a; - - r = eval("1+1;"); - assert(r, 2, "eval"); - - r = eval("var my_var=2; my_var;"); - assert(r, 2, "eval"); - assert(typeof my_var, "undefined"); - - assert(eval("if (1) 2; else 3;"), 2); - assert(eval("if (0) 2; else 3;"), 3); - - assert(f.call(1, "this"), 1); - - a = 2; - assert(eval("a"), 2); - - eval("a = 3"); - assert(a, 3); - - assert(f("arguments.length", 1), 2); - assert(f("arguments[1]", 1), 1); - - a = 4; - assert(f("a"), 4); - f("a=3"); - assert(a, 3); - - test_eval2(); -} - -function test_typed_array() -{ - var buffer, a, i, str; - - a = new Uint8Array(4); - assert(a.length, 4); - for(i = 0; i < a.length; i++) - a[i] = i; - assert(a.join(","), "0,1,2,3"); - a[0] = -1; - assert(a[0], 255); - - a = new Int8Array(3); - a[0] = 255; - assert(a[0], -1); - - a = new Int32Array(3); - a[0] = Math.pow(2, 32) - 1; - assert(a[0], -1); - assert(a.BYTES_PER_ELEMENT, 4); - - a = new Uint8ClampedArray(4); - a[0] = -100; - a[1] = 1.5; - a[2] = 0.5; - a[3] = 1233.5; - assert(a.toString(), "0,2,0,255"); - - buffer = new ArrayBuffer(16); - assert(buffer.byteLength, 16); - a = new Uint32Array(buffer, 12, 1); - assert(a.length, 1); - a[0] = -1; - - a = new Uint16Array(buffer, 2); - a[0] = -1; - - a = new Float16Array(buffer, 8, 1); - a[0] = 1; - - a = new Float32Array(buffer, 8, 1); - a[0] = 1; - - a = new Uint8Array(buffer); - - str = a.toString(); - /* test little and big endian cases */ - if (str !== "0,0,255,255,0,0,0,0,0,0,128,63,255,255,255,255" && - str !== "0,0,255,255,0,0,0,0,63,128,0,0,255,255,255,255") { - assert(false); - } - - assert(a.buffer, buffer); - - a = new Uint8Array([1, 2, 3, 4]); - assert(a.toString(), "1,2,3,4"); - a.set([10, 11], 2); - assert(a.toString(), "1,2,10,11"); -} - -/* return [s, line_num, col_num] where line_num and col_num are the - position of the '@' character in 'str'. 's' is str without the '@' - character */ -function get_string_pos(str) -{ - var p, line_num, col_num, s, q, r; - p = str.indexOf('@'); - assert(p >= 0, true); - q = 0; - line_num = 1; - for(;;) { - r = str.indexOf('\n', q); - if (r < 0 || r >= p) - break; - q = r + 1; - line_num++; - } - col_num = p - q + 1; - s = str.slice(0, p) + str.slice(p + 1); - return [s, line_num, col_num]; -} - -function check_error_pos(e, expected_error, line_num, col_num, level) -{ - var expected_pos, tab, line; - level |= 0; - expected_pos = ":" + line_num + ":" + col_num; - tab = e.stack.split("\n"); - line = tab[level]; - if (line.slice(-1) == ')') - line = line.slice(0, -1); - if (line.indexOf(expected_pos) < 0) { - throw_error("unexpected line or column number. error=" + e.message + - ".got |" + line + "|, expected |" + expected_pos + "|"); - } -} - -function assert_json_error(str, line_num, col_num) -{ - var err = false; - var expected_pos, tab; - - tab = get_string_pos(str); - - try { - JSON.parse(tab[0]); - } catch(e) { - err = true; - if (!(e instanceof SyntaxError)) { - throw_error("unexpected exception type"); - return; - } - /* XXX: the way quickjs returns JSON errors is not similar to Node or spiderMonkey */ - check_error_pos(e, SyntaxError, tab[1], tab[2]); - } - if (!err) { - throw_error("expected exception"); - } -} - -function test_json() -{ - var a, s; - s = '{"x":1,"y":true,"z":null,"a":[1,2,3],"s":"str"}'; - a = JSON.parse(s); - assert(a.x, 1); - assert(a.y, true); - assert(a.z, null); - assert(JSON.stringify(a), s); - - /* indentation test */ - assert(JSON.stringify([[{x:1,y:{},z:[]},2,3]],undefined,1), -`[ - [ - { - "x": 1, - "y": {}, - "z": [] - }, - 2, - 3 - ] -]`); - - assert_json_error('\n" \\@x"'); - assert_json_error('\n{ "a": @x }"'); -} - -function test_date() -{ - // Date Time String format is YYYY-MM-DDTHH:mm:ss.sssZ - // accepted date formats are: YYYY, YYYY-MM and YYYY-MM-DD - // accepted time formats are: THH:mm, THH:mm:ss, THH:mm:ss.sss - // expanded years are represented with 6 digits prefixed by + or - - // -000000 is invalid. - // A string containing out-of-bounds or nonconforming elements - // is not a valid instance of this format. - // Hence the fractional part after . should have 3 digits and how - // a different number of digits is handled is implementation defined. - assert(Date.parse(""), NaN); - assert(Date.parse("2000"), 946684800000); - assert(Date.parse("2000-01"), 946684800000); - assert(Date.parse("2000-01-01"), 946684800000); - //assert(Date.parse("2000-01-01T"), NaN); - //assert(Date.parse("2000-01-01T00Z"), NaN); - assert(Date.parse("2000-01-01T00:00Z"), 946684800000); - assert(Date.parse("2000-01-01T00:00:00Z"), 946684800000); - assert(Date.parse("2000-01-01T00:00:00.1Z"), 946684800100); - assert(Date.parse("2000-01-01T00:00:00.10Z"), 946684800100); - assert(Date.parse("2000-01-01T00:00:00.100Z"), 946684800100); - assert(Date.parse("2000-01-01T00:00:00.1000Z"), 946684800100); - assert(Date.parse("2000-01-01T00:00:00+00:00"), 946684800000); - //assert(Date.parse("2000-01-01T00:00:00+00:30"), 946686600000); - var d = new Date("2000T00:00"); // Jan 1st 2000, 0:00:00 local time - assert(typeof d === 'object' && d.toString() != 'Invalid Date'); - assert((new Date('Jan 1 2000')).toISOString(), - d.toISOString()); - assert((new Date('Jan 1 2000 00:00')).toISOString(), - d.toISOString()); - assert((new Date('Jan 1 2000 00:00:00')).toISOString(), - d.toISOString()); - assert((new Date('Jan 1 2000 00:00:00 GMT+0100')).toISOString(), - '1999-12-31T23:00:00.000Z'); - assert((new Date('Jan 1 2000 00:00:00 GMT+0200')).toISOString(), - '1999-12-31T22:00:00.000Z'); - assert((new Date('Sat Jan 1 2000')).toISOString(), - d.toISOString()); - assert((new Date('Sat Jan 1 2000 00:00')).toISOString(), - d.toISOString()); - assert((new Date('Sat Jan 1 2000 00:00:00')).toISOString(), - d.toISOString()); - assert((new Date('Sat Jan 1 2000 00:00:00 GMT+0100')).toISOString(), - '1999-12-31T23:00:00.000Z'); - assert((new Date('Sat Jan 1 2000 00:00:00 GMT+0200')).toISOString(), - '1999-12-31T22:00:00.000Z'); - - var d = new Date(1506098258091); - assert(d.toISOString(), "2017-09-22T16:37:38.091Z"); - d.setUTCHours(18, 10, 11); - assert(d.toISOString(), "2017-09-22T18:10:11.091Z"); - var a = Date.parse(d.toISOString()); - assert((new Date(a)).toISOString(), d.toISOString()); - - assert((new Date("2020-01-01T01:01:01.123Z")).toISOString(), - "2020-01-01T01:01:01.123Z"); - /* implementation defined behavior */ - assert((new Date("2020-01-01T01:01:01.1Z")).toISOString(), - "2020-01-01T01:01:01.100Z"); - assert((new Date("2020-01-01T01:01:01.12Z")).toISOString(), - "2020-01-01T01:01:01.120Z"); - assert((new Date("2020-01-01T01:01:01.1234Z")).toISOString(), - "2020-01-01T01:01:01.123Z"); - assert((new Date("2020-01-01T01:01:01.12345Z")).toISOString(), - "2020-01-01T01:01:01.123Z"); - assert((new Date("2020-01-01T01:01:01.1235Z")).toISOString(), - "2020-01-01T01:01:01.123Z"); - assert((new Date("2020-01-01T01:01:01.9999Z")).toISOString(), - "2020-01-01T01:01:01.999Z"); - - assert(Date.UTC(2017), 1483228800000); - assert(Date.UTC(2017, 9), 1506816000000); - assert(Date.UTC(2017, 9, 22), 1508630400000); - assert(Date.UTC(2017, 9, 22, 18), 1508695200000); - assert(Date.UTC(2017, 9, 22, 18, 10), 1508695800000); - assert(Date.UTC(2017, 9, 22, 18, 10, 11), 1508695811000); - assert(Date.UTC(2017, 9, 22, 18, 10, 11, 91), 1508695811091); - - assert(Date.UTC(NaN), NaN); - assert(Date.UTC(2017, NaN), NaN); - assert(Date.UTC(2017, 9, NaN), NaN); - assert(Date.UTC(2017, 9, 22, NaN), NaN); - assert(Date.UTC(2017, 9, 22, 18, NaN), NaN); - assert(Date.UTC(2017, 9, 22, 18, 10, NaN), NaN); - assert(Date.UTC(2017, 9, 22, 18, 10, 11, NaN), NaN); - assert(Date.UTC(2017, 9, 22, 18, 10, 11, 91, NaN), 1508695811091); - - // TODO: Fix rounding errors on Windows/Cygwin. - if (!(typeof os !== 'undefined' && ['win32', 'cygwin'].includes(os.platform))) { - // from test262/test/built-ins/Date/UTC/fp-evaluation-order.js - assert(Date.UTC(1970, 0, 1, 80063993375, 29, 1, -288230376151711740), 29312, - 'order of operations / precision in MakeTime'); - assert(Date.UTC(1970, 0, 213503982336, 0, 0, 0, -18446744073709552000), 34447360, - 'precision in MakeDate'); - } - //assert(Date.UTC(2017 - 1e9, 9 + 12e9), 1506816000000); // node fails this - assert(Date.UTC(2017, 9, 22 - 1e10, 18 + 24e10), 1508695200000); - assert(Date.UTC(2017, 9, 22, 18 - 1e10, 10 + 60e10), 1508695800000); - assert(Date.UTC(2017, 9, 22, 18, 10 - 1e10, 11 + 60e10), 1508695811000); - assert(Date.UTC(2017, 9, 22, 18, 10, 11 - 1e12, 91 + 1000e12), 1508695811091); -} - -function test_regexp() -{ - var a, str; - str = "abbbbbc"; - a = /(b+)c/.exec(str); - assert(a[0], "bbbbbc"); - assert(a[1], "bbbbb"); - assert(a.index, 1); - assert(a.input, str); - a = /(b+)c/.test(str); - assert(a, true); - assert(/\x61/.exec("a")[0], "a"); - assert(/\u0061/.exec("a")[0], "a"); - assert(/\ca/.exec("\x01")[0], "\x01"); - assert(/\\a/.exec("\\a")[0], "\\a"); - assert(/\c0/.exec("\\c0")[0], "\\c0"); - - a = /(\.(?=com|org)|\/)/.exec("ah.com"); - assert(a.index === 2 && a[0] === "."); - - a = /(\.(?!com|org)|\/)/.exec("ah.com"); - assert(a, null); - - a = /(?=(a+))/.exec("baaabac"); - assert(a.index === 1 && a[0] === "" && a[1] === "aaa"); - - a = /(z)((a+)?(b+)?(c))*/.exec("zaacbbbcac"); - assert(a, ["zaacbbbcac","z","ac","a",,"c"]); - - a = eval("/\0a/"); - assert(a.toString(), "/\0a/"); - assert(a.exec("\0a")[0], "\0a"); - - assert(/{1a}/.toString(), "/{1a}/"); - a = /a{1+/.exec("a{11"); - assert(a, ["a{11"]); - - /* test zero length matches */ - a = /(?:(?=(abc)))a/.exec("abc"); - assert(a, ["a", "abc"]); - a = /(?:(?=(abc)))?a/.exec("abc"); - assert(a, ["a", undefined]); - a = /(?:(?=(abc))){0,2}a/.exec("abc"); - assert(a, ["a", undefined]); - a = /(?:|[\w])+([0-9])/.exec("123a23"); - assert(a, ["123a23", "3"]); - a = /()*?a/.exec(","); - assert(a, null); - - /* test \b escape */ - assert(/[\q{a\b}]/.test("a\b"), true); - assert(/[\b]/.test("\b"), true); - - /* test case insensitive matching (test262 hardly tests it) */ - assert("aAbBcC#4".replace(/\p{Lower}/gu,"X"), "XAXBXC#4"); - - assert("aAbBcC#4".replace(/\p{Lower}/gui,"X"), "XXXXXX#4"); - assert("aAbBcC#4".replace(/\p{Upper}/gui,"X"), "XXXXXX#4"); - assert("aAbBcC#4".replace(/\P{Lower}/gui,"X"), "XXXXXXXX"); - assert("aAbBcC#4".replace(/\P{Upper}/gui,"X"), "XXXXXXXX"); - assert("aAbBcC".replace(/[^b]/gui, "X"), "XXbBXX"); - assert("aAbBcC".replace(/[^A-B]/gui, "X"), "aAbBXX"); - - assert("aAbBcC#4".replace(/\p{Lower}/gvi,"X"), "XXXXXX#4"); - assert("aAbBcC#4".replace(/\P{Lower}/gvi,"X"), "aAbBcCXX"); - assert("aAbBcC#4".replace(/[^\P{Lower}]/gvi,"X"), "XXXXXX#4"); - assert("aAbBcC#4".replace(/\P{Upper}/gvi,"X"), "aAbBcCXX"); - assert("aAbBcC".replace(/[^b]/gvi, "X"), "XXbBXX"); - assert("aAbBcC".replace(/[^A-B]/gvi, "X"), "aAbBXX"); - assert("aAbBcC".replace(/[[a-c]&&B]/gvi, "X"), "aAXXcC"); - assert("aAbBcC".replace(/[[a-c]--B]/gvi, "X"), "XXbBXX"); - - assert("abcAbC".replace(/[\q{AbC}]/gvi,"X"), "XX"); - /* Note: SpiderMonkey and v8 may not be correct */ - assert("abcAbC".replace(/[\q{BC|A}]/gvi,"X"), "XXXX"); - assert("abcAbC".replace(/[\q{BC|A}--a]/gvi,"X"), "aXAX"); -} - -function test_symbol() -{ - var a, b, obj, c; - a = Symbol("abc"); - obj = {}; - obj[a] = 2; - assert(obj[a], 2); - assert(typeof obj["abc"], "undefined"); - assert(String(a), "Symbol(abc)"); - b = Symbol("abc"); - assert(a == a); - assert(a === a); - assert(a != b); - assert(a !== b); - - b = Symbol.for("abc"); - c = Symbol.for("abc"); - assert(b === c); - assert(b !== a); - - assert(Symbol.keyFor(b), "abc"); - assert(Symbol.keyFor(a), undefined); - - a = Symbol("aaa"); - assert(a.valueOf(), a); - assert(a.toString(), "Symbol(aaa)"); - - b = Object(a); - assert(b.valueOf(), a); - assert(b.toString(), "Symbol(aaa)"); -} - -function test_map1(key_type, n) -{ - var a, i, tab, o, v; - a = new Map(); - tab = []; - for(i = 0; i < n; i++) { - v = { }; - switch(key_type) { - case "small_bigint": - o = BigInt(i); - break; - case "bigint": - o = BigInt(i) + (1n << 128n); - break; - case "object": - o = { id: i }; - break; - default: - assert(false); - } - tab[i] = [o, v]; - a.set(o, v); - } - - assert(a.size, n); - for(i = 0; i < n; i++) { - assert(a.get(tab[i][0]), tab[i][1]); - } - - i = 0; - a.forEach(function (v, o) { - assert(o, tab[i++][0]); - assert(a.has(o)); - assert(a.delete(o)); - assert(!a.has(o)); - }); - - assert(a.size, 0); -} - -function test_map() -{ - var a, i, n, tab, o, v; - n = 1000; - - a = new Map(); - for (var i = 0; i < n; i++) { - a.set(i, i); - } - a.set(-2147483648, 1); - assert(a.get(-2147483648), 1); - assert(a.get(-2147483647 - 1), 1); - assert(a.get(-2147483647.5 - 0.5), 1); - - a.set(1n, 1n); - assert(a.get(1n), 1n); - assert(a.get(2n**1000n - (2n**1000n - 1n)), 1n); - - test_map1("object", n); - test_map1("small_bigint", n); - test_map1("bigint", n); -} - -function test_weak_map() -{ - var a, i, n, tab, o, v, n2; - a = new WeakMap(); - n = 10; - tab = []; - for(i = 0; i < n; i++) { - v = { }; - if (i & 1) - o = Symbol("x" + i); - else - o = { id: i }; - tab[i] = [o, v]; - a.set(o, v); - } - o = null; - - n2 = 5; - for(i = 0; i < n2; i++) { - a.delete(tab[i][0]); - } - for(i = n2; i < n; i++) { - tab[i][0] = null; /* should remove the object from the WeakMap too */ - } - std.gc(); - /* the WeakMap should be empty here */ -} - -function test_weak_map_cycles() -{ - const weak1 = new WeakMap(); - const weak2 = new WeakMap(); - function createCyclicKey() { - const parent = {}; - const child = {parent}; - parent.child = child; - return child; - } - function testWeakMap() { - const cyclicKey = createCyclicKey(); - const valueOfCyclicKey = {}; - weak1.set(cyclicKey, valueOfCyclicKey); - weak2.set(valueOfCyclicKey, 1); - } - testWeakMap(); - // Force to free cyclicKey. - std.gc(); - // Here will cause sigsegv because [cyclicKey] and [valueOfCyclicKey] in [weak1] was free, - // but weak2's map record was not removed, and it's key refers [valueOfCyclicKey] which is free. - weak2.get({}); - std.gc(); -} - -function test_weak_ref() -{ - var w1, w2, o, i; - - for(i = 0; i < 2; i++) { - if (i == 0) - o = { }; - else - o = Symbol("x"); - w1 = new WeakRef(o); - assert(w1.deref(), o); - w2 = new WeakRef(o); - assert(w2.deref(), o); - - o = null; - assert(w1.deref(), undefined); - assert(w2.deref(), undefined); - std.gc(); - assert(w1.deref(), undefined); - assert(w2.deref(), undefined); - } -} - -function test_finalization_registry() -{ - { - let expected = {}; - let actual; - let finrec = new FinalizationRegistry(v => { actual = v }); - finrec.register({}, expected); - os.setTimeout(() => { - assert(actual, expected); - }, 0); - } - { - let expected = 42; - let actual; - let finrec = new FinalizationRegistry(v => { actual = v }); - finrec.register({}, expected); - os.setTimeout(() => { - assert(actual, expected); - }, 0); - } - std.gc(); -} - -function test_generator() -{ - function *f() { - var ret; - yield 1; - ret = yield 2; - assert(ret, "next_arg"); - return 3; - } - function *f2() { - yield 1; - yield 2; - return "ret_val"; - } - function *f1() { - var ret = yield *f2(); - assert(ret, "ret_val"); - return 3; - } - function *f3() { - var ret; - /* test stack consistency with nip_n to handle yield return + - * finally clause */ - try { - ret = 2 + (yield 1); - } catch(e) { - } finally { - ret++; - } - return ret; - } - var g, v; - g = f(); - v = g.next(); - assert(v.value === 1 && v.done === false); - v = g.next(); - assert(v.value === 2 && v.done === false); - v = g.next("next_arg"); - assert(v.value === 3 && v.done === true); - v = g.next(); - assert(v.value === undefined && v.done === true); - - g = f1(); - v = g.next(); - assert(v.value === 1 && v.done === false); - v = g.next(); - assert(v.value === 2 && v.done === false); - v = g.next(); - assert(v.value === 3 && v.done === true); - v = g.next(); - assert(v.value === undefined && v.done === true); - - g = f3(); - v = g.next(); - assert(v.value === 1 && v.done === false); - v = g.next(3); - assert(v.value === 6 && v.done === true); -} - -function rope_concat(n, dir) -{ - var i, s; - s = ""; - if (dir > 0) { - for(i = 0; i < n; i++) - s += String.fromCharCode(i & 0xffff); - } else { - for(i = n - 1; i >= 0; i--) - s = String.fromCharCode(i & 0xffff) + s; - } - - for(i = 0; i < n; i++) { - /* test before the assert to go faster */ - if (s.charCodeAt(i) != (i & 0xffff)) { - assert(s.charCodeAt(i), i & 0xffff); - } - } -} - -function test_rope() -{ - rope_concat(100000, 1); - rope_concat(100000, -1); -} - -function eval_error(eval_str, expected_error, level) -{ - var err = false; - var expected_pos, tab; - - tab = get_string_pos(eval_str); - - try { - eval(tab[0]); - } catch(e) { - err = true; - if (!(e instanceof expected_error)) { - throw_error("unexpected exception type"); - return; - } - check_error_pos(e, expected_error, tab[1], tab[2], level); - } - if (!err) { - throw_error("expected exception"); - } -} - -var poisoned_number = { - valueOf: function() { throw Error("poisoned number") }, -}; - -function test_line_column_numbers() -{ - var f, e, tab; - - /* The '@' character provides the expected position of the - error. It is removed before evaluating the string. */ - - /* parsing */ - eval_error("\n 123 @a ", SyntaxError); - eval_error("\n @/* ", SyntaxError); - eval_error("function f @a", SyntaxError); - /* currently regexp syntax errors point to the start of the regexp */ - eval_error("\n @/aaa]/u", SyntaxError); - - /* function definitions */ - - tab = get_string_pos("\n @function f() { }; f;"); - e = eval(tab[0]); - assert(e.lineNumber, tab[1]); - assert(e.columnNumber, tab[2]); - - /* errors */ - tab = get_string_pos('\n Error@("hello");'); - e = eval(tab[0]); - check_error_pos(e, Error, tab[1], tab[2]); - - eval_error('\n throw Error@("hello");', Error); - - /* operators */ - eval_error('\n 1 + 2 @* poisoned_number;', Error, 1); - eval_error('\n 1 + "café" @* poisoned_number;', Error, 1); - eval_error('\n 1 + 2 @** poisoned_number;', Error, 1); - eval_error('\n 2 * @+ poisoned_number;', Error, 1); - eval_error('\n 2 * @- poisoned_number;', Error, 1); - eval_error('\n 2 * @~ poisoned_number;', Error, 1); - eval_error('\n 2 * @++ poisoned_number;', Error, 1); - eval_error('\n 2 * @-- poisoned_number;', Error, 1); - eval_error('\n 2 * poisoned_number @++;', Error, 1); - eval_error('\n 2 * poisoned_number @--;', Error, 1); - - /* accessors */ - eval_error('\n 1 + null@[0];', TypeError); - eval_error('\n 1 + null @. abcd;', TypeError); - eval_error('\n 1 + null @( 1234 );', TypeError); - eval_error('var obj = { get a() { throw Error("test"); } }\n 1 + obj @. a;', - Error, 1); - eval_error('var obj = { set a(b) { throw Error("test"); } }\n obj @. a = 1;', - Error, 1); - - /* variables reference */ - eval_error('\n 1 + @not_def', ReferenceError, 0); - - /* assignments */ - eval_error('1 + (@not_def = 1)', ReferenceError, 0); - eval_error('1 + (@not_def += 2)', ReferenceError, 0); - eval_error('var a;\n 1 + (a @+= poisoned_number);', Error, 1); -} - -test(); -test_function(); -test_enum(); -test_array(); -test_string(); -test_math(); -test_number(); -test_eval(); -test_typed_array(); -test_json(); -test_date(); -test_regexp(); -test_symbol(); -test_map(); -test_weak_map(); -test_weak_map_cycles(); -test_weak_ref(); -test_finalization_registry(); -test_generator(); -test_rope(); -test_line_column_numbers(); diff --git a/packages/javascript/javascript_android/cxx/quickjs/tests/test_closure.js b/packages/javascript/javascript_android/cxx/quickjs/tests/test_closure.js deleted file mode 100644 index f5d4160..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/tests/test_closure.js +++ /dev/null @@ -1,221 +0,0 @@ -function assert(actual, expected, message) { - if (arguments.length == 1) - expected = true; - - if (actual === expected) - return; - - if (actual !== null && expected !== null - && typeof actual == 'object' && typeof expected == 'object' - && actual.toString() === expected.toString()) - return; - - throw Error("assertion failed: got |" + actual + "|" + - ", expected |" + expected + "|" + - (message ? " (" + message + ")" : "")); -} - -// load more elaborate version of assert if available -try { __loadScript("test_assert.js"); } catch(e) {} - -/*----------------*/ - -var log_str = ""; - -function log(str) -{ - log_str += str + ","; -} - -function f(a, b, c) -{ - var x = 10; - log("a="+a); - function g(d) { - function h() { - log("d=" + d); - log("x=" + x); - } - log("b=" + b); - log("c=" + c); - h(); - } - g(4); - return g; -} - -var g1 = f(1, 2, 3); -g1(5); - -assert(log_str, "a=1,b=2,c=3,d=4,x=10,b=2,c=3,d=5,x=10,", "closure1"); - -function test_closure1() -{ - function f2() - { - var val = 1; - - function set(a) { - val = a; - } - function get(a) { - return val; - } - return { "set": set, "get": get }; - } - - var obj = f2(); - obj.set(10); - var r; - r = obj.get(); - assert(r, 10, "closure2"); -} - -function test_closure2() -{ - var expr_func = function myfunc1(n) { - function myfunc2(n) { - return myfunc1(n - 1); - } - if (n == 0) - return 0; - else - return myfunc2(n); - }; - var r; - r = expr_func(1); - assert(r, 0, "expr_func"); -} - -function test_closure3() -{ - function fib(n) - { - if (n <= 0) - return 0; - else if (n == 1) - return 1; - else - return fib(n - 1) + fib(n - 2); - } - - var fib_func = function fib1(n) - { - if (n <= 0) - return 0; - else if (n == 1) - return 1; - else - return fib1(n - 1) + fib1(n - 2); - }; - - assert(fib(6), 8, "fib"); - assert(fib_func(6), 8, "fib_func"); -} - -function test_arrow_function() -{ - "use strict"; - - function f1() { - return (() => arguments)(); - } - function f2() { - return (() => this)(); - } - function f3() { - return (() => eval("this"))(); - } - function f4() { - return (() => eval("new.target"))(); - } - var a; - - a = f1(1, 2); - assert(a.length, 2); - assert(a[0] === 1 && a[1] === 2); - - assert(f2.call("this_val") === "this_val"); - assert(f3.call("this_val") === "this_val"); - assert(new f4() === f4); - - var o1 = { f() { return this; } }; - var o2 = { f() { - return (() => eval("super.f()"))(); - } }; - o2.__proto__ = o1; - - assert(o2.f() === o2); -} - -function test_with() -{ - var o1 = { x: "o1", y: "o1" }; - var x = "local"; - eval('var z="var_obj";'); - assert(z === "var_obj"); - with (o1) { - assert(x === "o1"); - assert(eval("x") === "o1"); - var f = function () { - o2 = { x: "o2" }; - with (o2) { - assert(x === "o2"); - assert(y === "o1"); - assert(z === "var_obj"); - assert(eval("x") === "o2"); - assert(eval("y") === "o1"); - assert(eval("z") === "var_obj"); - assert(eval('eval("x")') === "o2"); - } - }; - f(); - } -} - -function test_eval_closure() -{ - var tab; - - tab = []; - for(let i = 0; i < 3; i++) { - eval("tab.push(function g1() { return i; })"); - } - for(let i = 0; i < 3; i++) { - assert(tab[i]() === i); - } - - tab = []; - for(let i = 0; i < 3; i++) { - let f = function f() { - eval("tab.push(function g2() { return i; })"); - }; - f(); - } - for(let i = 0; i < 3; i++) { - assert(tab[i]() === i); - } -} - -function test_eval_const() -{ - const a = 1; - var success = false; - var f = function () { - eval("a = 1"); - }; - try { - f(); - } catch(e) { - success = (e instanceof TypeError); - } - assert(success); -} - -test_closure1(); -test_closure2(); -test_closure3(); -test_arrow_function(); -test_with(); -test_eval_closure(); -test_eval_const(); diff --git a/packages/javascript/javascript_android/cxx/quickjs/tests/test_cyclic_import.js b/packages/javascript/javascript_android/cxx/quickjs/tests/test_cyclic_import.js deleted file mode 100644 index bf51d9b..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/tests/test_cyclic_import.js +++ /dev/null @@ -1,12 +0,0 @@ -/*--- -negative: - phase: resolution - type: SyntaxError ----*/ -// FIXME(bnoordhuis) shouldn't throw SyntaxError but that's still better -// than segfaulting, see https://github.com/quickjs-ng/quickjs/issues/567 -import {assert} from "./assert.js" -import {f} from "./fixture_cyclic_import.js" -export {f} -export function g(x) { return x + 1 } -assert(f(1), 4) diff --git a/packages/javascript/javascript_android/cxx/quickjs/tests/test_language.js b/packages/javascript/javascript_android/cxx/quickjs/tests/test_language.js deleted file mode 100644 index 4fa16c8..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/tests/test_language.js +++ /dev/null @@ -1,654 +0,0 @@ -function assert(actual, expected, message) { - if (arguments.length == 1) - expected = true; - - if (Object.is(actual, expected)) - return; - - if (actual !== null && expected !== null - && typeof actual == 'object' && typeof expected == 'object' - && actual.toString() === expected.toString()) - return; - - throw Error("assertion failed: got |" + actual + "|" + - ", expected |" + expected + "|" + - (message ? " (" + message + ")" : "")); -} - -function assert_throws(expected_error, func) -{ - var err = false; - try { - func(); - } catch(e) { - err = true; - if (!(e instanceof expected_error)) { - throw Error("unexpected exception type"); - } - } - if (!err) { - throw Error("expected exception"); - } -} - -// load more elaborate version of assert if available -try { __loadScript("test_assert.js"); } catch(e) {} - -/*----------------*/ - -function test_op1() -{ - var r, a; - r = 1 + 2; - assert(r, 3, "1 + 2 === 3"); - - r = 1 - 2; - assert(r, -1, "1 - 2 === -1"); - - r = -1; - assert(r, -1, "-1 === -1"); - - r = +2; - assert(r, 2, "+2 === 2"); - - r = 2 * 3; - assert(r, 6, "2 * 3 === 6"); - - r = 4 / 2; - assert(r, 2, "4 / 2 === 2"); - - r = 4 % 3; - assert(r, 1, "4 % 3 === 3"); - - r = 4 << 2; - assert(r, 16, "4 << 2 === 16"); - - r = 1 << 0; - assert(r, 1, "1 << 0 === 1"); - - r = 1 << 31; - assert(r, -2147483648, "1 << 31 === -2147483648"); - - r = 1 << 32; - assert(r, 1, "1 << 32 === 1"); - - r = (1 << 31) < 0; - assert(r, true, "(1 << 31) < 0 === true"); - - r = -4 >> 1; - assert(r, -2, "-4 >> 1 === -2"); - - r = -4 >>> 1; - assert(r, 0x7ffffffe, "-4 >>> 1 === 0x7ffffffe"); - - r = 1 & 1; - assert(r, 1, "1 & 1 === 1"); - - r = 0 | 1; - assert(r, 1, "0 | 1 === 1"); - - r = 1 ^ 1; - assert(r, 0, "1 ^ 1 === 0"); - - r = ~1; - assert(r, -2, "~1 === -2"); - - r = !1; - assert(r, false, "!1 === false"); - - assert((1 < 2), true, "(1 < 2) === true"); - - assert((2 > 1), true, "(2 > 1) === true"); - - assert(('b' > 'a'), true, "('b' > 'a') === true"); - - assert(2 ** 8, 256, "2 ** 8 === 256"); -} - -function test_cvt() -{ - assert((NaN | 0) === 0); - assert((Infinity | 0) === 0); - assert(((-Infinity) | 0) === 0); - assert(("12345" | 0) === 12345); - assert(("0x12345" | 0) === 0x12345); - assert(((4294967296 * 3 - 4) | 0) === -4); - - assert(("12345" >>> 0) === 12345); - assert(("0x12345" >>> 0) === 0x12345); - assert((NaN >>> 0) === 0); - assert((Infinity >>> 0) === 0); - assert(((-Infinity) >>> 0) === 0); - assert(((4294967296 * 3 - 4) >>> 0) === (4294967296 - 4)); - assert((19686109595169230000).toString() === "19686109595169230000"); -} - -function test_eq() -{ - assert(null == undefined); - assert(undefined == null); - assert(true == 1); - assert(0 == false); - assert("" == 0); - assert("123" == 123); - assert("122" != 123); - assert((new Number(1)) == 1); - assert(2 == (new Number(2))); - assert((new String("abc")) == "abc"); - assert({} != "abc"); -} - -function test_inc_dec() -{ - var a, r; - - a = 1; - r = a++; - assert(r === 1 && a === 2, true, "++"); - - a = 1; - r = ++a; - assert(r === 2 && a === 2, true, "++"); - - a = 1; - r = a--; - assert(r === 1 && a === 0, true, "--"); - - a = 1; - r = --a; - assert(r === 0 && a === 0, true, "--"); - - a = {x:true}; - a.x++; - assert(a.x, 2, "++"); - - a = {x:true}; - a.x--; - assert(a.x, 0, "--"); - - a = [true]; - a[0]++; - assert(a[0], 2, "++"); - - a = {x:true}; - r = a.x++; - assert(r === 1 && a.x === 2, true, "++"); - - a = {x:true}; - r = a.x--; - assert(r === 1 && a.x === 0, true, "--"); - - a = [true]; - r = a[0]++; - assert(r === 1 && a[0] === 2, true, "++"); - - a = [true]; - r = a[0]--; - assert(r === 1 && a[0] === 0, true, "--"); -} - -function F(x) -{ - this.x = x; -} - -function test_op2() -{ - var a, b; - a = new Object; - a.x = 1; - assert(a.x, 1, "new"); - b = new F(2); - assert(b.x, 2, "new"); - - a = {x : 2}; - assert(("x" in a), true, "in"); - assert(("y" in a), false, "in"); - - a = {}; - assert((a instanceof Object), true, "instanceof"); - assert((a instanceof String), false, "instanceof"); - - assert((typeof 1), "number", "typeof"); - assert((typeof Object), "function", "typeof"); - assert((typeof null), "object", "typeof"); - assert((typeof unknown_var), "undefined", "typeof"); - - a = {x: 1, if: 2, async: 3}; - assert(a.if === 2); - assert(a.async === 3); -} - -function test_delete() -{ - var a, err; - - a = {x: 1, y: 1}; - assert((delete a.x), true, "delete"); - assert(("x" in a), false, "delete"); - - /* the following are not tested by test262 */ - assert(delete "abc"[100], true); - - err = false; - try { - delete null.a; - } catch(e) { - err = (e instanceof TypeError); - } - assert(err, true, "delete"); - - err = false; - try { - a = { f() { delete super.a; } }; - a.f(); - } catch(e) { - err = (e instanceof ReferenceError); - } - assert(err, true, "delete"); -} - -function test_prototype() -{ - var f = function f() { }; - assert(f.prototype.constructor, f, "prototype"); - - var g = function g() { }; - /* QuickJS bug */ - Object.defineProperty(g, "prototype", { writable: false }); - assert(g.prototype.constructor, g, "prototype"); -} - -function test_arguments() -{ - function f2() { - assert(arguments.length, 2, "arguments"); - assert(arguments[0], 1, "arguments"); - assert(arguments[1], 3, "arguments"); - } - f2(1, 3); -} - -function test_class() -{ - var o; - class C { - constructor() { - this.x = 10; - } - f() { - return 1; - } - static F() { - return -1; - } - get y() { - return 12; - } - }; - class D extends C { - constructor() { - super(); - this.z = 20; - } - g() { - return 2; - } - static G() { - return -2; - } - h() { - return super.f(); - } - static H() { - return super["F"](); - } - } - - assert(C.F() === -1); - assert(Object.getOwnPropertyDescriptor(C.prototype, "y").get.name === "get y"); - - o = new C(); - assert(o.f() === 1); - assert(o.x === 10); - - assert(D.F() === -1); - assert(D.G() === -2); - assert(D.H() === -1); - - o = new D(); - assert(o.f() === 1); - assert(o.g() === 2); - assert(o.x === 10); - assert(o.z === 20); - assert(o.h() === 1); - - /* test class name scope */ - var E1 = class E { static F() { return E; } }; - assert(E1 === E1.F()); - - class S { - static x = 42; - static y = S.x; - static z = this.x; - } - assert(S.x === 42); - assert(S.y === 42); - assert(S.z === 42); - - class P { - get = () => "123"; - static() { return 42; } - } - assert(new P().get() === "123"); - assert(new P().static() === 42); -}; - -function test_template() -{ - var a, b; - b = 123; - a = `abc${b}d`; - assert(a, "abc123d"); - - a = String.raw `abc${b}d`; - assert(a, "abc123d"); - - a = "aaa"; - b = "bbb"; - assert(`aaa${a, b}ccc`, "aaabbbccc"); -} - -function test_template_skip() -{ - var a = "Bar"; - var { b = `${a + `a${a}` }baz` } = {}; - assert(b, "BaraBarbaz"); -} - -function test_object_literal() -{ - var x = 0, get = 1, set = 2; async = 3; - a = { get: 2, set: 3, async: 4, get a(){ return this.get} }; - assert(JSON.stringify(a), '{"get":2,"set":3,"async":4,"a":2}'); - assert(a.a === 2); - - a = { x, get, set, async }; - assert(JSON.stringify(a), '{"x":0,"get":1,"set":2,"async":3}'); -} - -function test_regexp_skip() -{ - var a, b; - [a, b = /abc\(/] = [1]; - assert(a === 1); - - [a, b =/abc\(/] = [2]; - assert(a === 2); -} - -function test_labels() -{ - do x: { break x; } while(0); - if (1) - x: { break x; } - else - x: { break x; } - with ({}) x: { break x; }; - while (0) x: { break x; }; -} - -function test_labels2() -{ - while (1) label: break - var i = 0 - while (i < 3) label: { - if (i > 0) - break - i++ - } - assert(i, 1) - for (;;) label: break - for (i = 0; i < 3; i++) label: { - if (i > 0) - break - } - assert(i, 1) -} - -function test_destructuring() -{ - function * g () { return 0; }; - var [x] = g(); - assert(x, void 0); -} - -function test_spread() -{ - var x; - x = [1, 2, ...[3, 4]]; - assert(x.toString(), "1,2,3,4"); - - x = [ ...[ , ] ]; - assert(Object.getOwnPropertyNames(x).toString(), "0,length"); -} - -function test_function_length() -{ - assert( ((a, b = 1, c) => {}).length, 1); - assert( (([a,b]) => {}).length, 1); - assert( (({a,b}) => {}).length, 1); - assert( ((c, [a,b] = 1, d) => {}).length, 1); -} - -function test_argument_scope() -{ - var f; - var c = "global"; - - (function() { - "use strict"; - // XXX: node only throws in strict mode - f = function(a = eval("var arguments")) {}; - assert_throws(SyntaxError, f); - })(); - - f = function(a = eval("1"), b = arguments[0]) { return b; }; - assert(f(12), 12); - - f = function(a, b = arguments[0]) { return b; }; - assert(f(12), 12); - - f = function(a, b = () => arguments) { return b; }; - assert(f(12)()[0], 12); - - f = function(a = eval("1"), b = () => arguments) { return b; }; - assert(f(12)()[0], 12); - - (function() { - "use strict"; - f = function(a = this) { return a; }; - assert(f.call(123), 123); - - f = function f(a = f) { return a; }; - assert(f(), f); - - f = function f(a = eval("f")) { return a; }; - assert(f(), f); - })(); - - f = (a = eval("var c = 1"), probe = () => c) => { - var c = 2; - assert(c, 2); - assert(probe(), 1); - } - f(); - - f = (a = eval("var arguments = 1"), probe = () => arguments) => { - var arguments = 2; - assert(arguments, 2); - assert(probe(), 1); - } - f(); - - f = function f(a = eval("var c = 1"), b = c, probe = () => c) { - assert(b, 1); - assert(c, 1); - assert(probe(), 1) - } - f(); - - assert(c, "global"); - f = function f(a, b = c, probe = () => c) { - eval("var c = 1"); - assert(c, 1); - assert(b, "global"); - assert(probe(), "global") - } - f(); - assert(c, "global"); - - f = function f(a = eval("var c = 1"), probe = (d = eval("c")) => d) { - assert(probe(), 1) - } - f(); -} - -function test_function_expr_name() -{ - var f; - - /* non strict mode test : assignment to the function name silently - fails */ - - f = function myfunc() { - myfunc = 1; - return myfunc; - }; - assert(f(), f); - - f = function myfunc() { - myfunc = 1; - (() => { - myfunc = 1; - })(); - return myfunc; - }; - assert(f(), f); - - f = function myfunc() { - eval("myfunc = 1"); - return myfunc; - }; - assert(f(), f); - - /* strict mode test : assignment to the function name raises a - TypeError exception */ - - f = function myfunc() { - "use strict"; - myfunc = 1; - }; - assert_throws(TypeError, f); - - f = function myfunc() { - "use strict"; - (() => { - myfunc = 1; - })(); - }; - assert_throws(TypeError, f); - - f = function myfunc() { - "use strict"; - eval("myfunc = 1"); - }; - assert_throws(TypeError, f); -} - -function test_parse_semicolon() -{ - /* 'yield' or 'await' may not be considered as a token if the - previous ';' is missing */ - function *f() - { - function func() { - } - yield 1; - var h = x => x + 1 - yield 2; - } - async function g() - { - function func() { - } - await 1; - var h = x => x + 1 - await 2; - } -} - -function test_parse_arrow_function() -{ - assert(typeof eval("() => {}\n() => {}"), "function"); - assert(eval("() => {}\n+1"), 1); - assert(typeof eval("x => {}\n() => {}"), "function"); - assert(typeof eval("async () => {}\n() => {}"), "function"); - assert(typeof eval("async x => {}\n() => {}"), "function"); -} - -/* optional chaining tests not present in test262 */ -function test_optional_chaining() -{ - var a, z; - z = null; - a = { b: { c: 2 } }; - assert(delete z?.b.c, true); - assert(delete a?.b.c, true); - assert(JSON.stringify(a), '{"b":{}}', "optional chaining delete"); - - a = { b: { c: 2 } }; - assert(delete z?.b["c"], true); - assert(delete a?.b["c"], true); - assert(JSON.stringify(a), '{"b":{}}'); - - a = { - b() { return this._b; }, - _b: { c: 42 } - }; - - assert((a?.b)().c, 42); - - assert((a?.["b"])().c, 42); -} - -function test_unicode_ident() -{ - var õ = 3; - assert(typeof õ, "undefined"); -} - -test_op1(); -test_cvt(); -test_eq(); -test_inc_dec(); -test_op2(); -test_delete(); -test_prototype(); -test_arguments(); -test_class(); -test_template(); -test_template_skip(); -test_object_literal(); -test_regexp_skip(); -test_labels(); -test_labels2(); -test_destructuring(); -test_spread(); -test_function_length(); -test_argument_scope(); -test_function_expr_name(); -test_parse_semicolon(); -test_optional_chaining(); -test_parse_arrow_function(); -test_unicode_ident(); diff --git a/packages/javascript/javascript_android/cxx/quickjs/tests/test_loop.js b/packages/javascript/javascript_android/cxx/quickjs/tests/test_loop.js deleted file mode 100644 index 8f1934d..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/tests/test_loop.js +++ /dev/null @@ -1,402 +0,0 @@ -function assert(actual, expected, message) { - if (arguments.length == 1) - expected = true; - - if (actual === expected) - return; - - if (actual !== null && expected !== null - && typeof actual == 'object' && typeof expected == 'object' - && actual.toString() === expected.toString()) - return; - - throw Error("assertion failed: got |" + actual + "|" + - ", expected |" + expected + "|" + - (message ? " (" + message + ")" : "")); -} - -// load more elaborate version of assert if available -try { __loadScript("test_assert.js"); } catch(e) {} - -/*----------------*/ - -function test_while() -{ - var i, c; - i = 0; - c = 0; - while (i < 3) { - c++; - i++; - } - assert(c === 3); -} - -function test_while_break() -{ - var i, c; - i = 0; - c = 0; - while (i < 3) { - c++; - if (i == 1) - break; - i++; - } - assert(c === 2 && i === 1); -} - -function test_do_while() -{ - var i, c; - i = 0; - c = 0; - do { - c++; - i++; - } while (i < 3); - assert(c === 3 && i === 3); -} - -function test_for() -{ - var i, c; - c = 0; - for(i = 0; i < 3; i++) { - c++; - } - assert(c === 3 && i === 3); - - c = 0; - for(var j = 0; j < 3; j++) { - c++; - } - assert(c === 3 && j === 3); -} - -function test_for_in() -{ - var i, tab, a, b; - - tab = []; - for(i in {x:1, y: 2}) { - tab.push(i); - } - assert(tab.toString(), "x,y", "for_in"); - - /* prototype chain test */ - a = {x:2, y: 2, "1": 3}; - b = {"4" : 3 }; - Object.setPrototypeOf(a, b); - tab = []; - for(i in a) { - tab.push(i); - } - assert(tab.toString(), "1,x,y,4", "for_in"); - - /* non enumerable properties hide enumerables ones in the - prototype chain */ - a = {y: 2, "1": 3}; - Object.defineProperty(a, "x", { value: 1 }); - b = {"x" : 3 }; - Object.setPrototypeOf(a, b); - tab = []; - for(i in a) { - tab.push(i); - } - assert(tab.toString(), "1,y", "for_in"); - - /* array optimization */ - a = []; - for(i = 0; i < 10; i++) - a.push(i); - tab = []; - for(i in a) { - tab.push(i); - } - assert(tab.toString(), "0,1,2,3,4,5,6,7,8,9", "for_in"); - - /* iterate with a field */ - a={x:0}; - tab = []; - for(a.x in {x:1, y: 2}) { - tab.push(a.x); - } - assert(tab.toString(), "x,y", "for_in"); - - /* iterate with a variable field */ - a=[0]; - tab = []; - for(a[0] in {x:1, y: 2}) { - tab.push(a[0]); - } - assert(tab.toString(), "x,y", "for_in"); - - /* variable definition in the for in */ - tab = []; - for(var j in {x:1, y: 2}) { - tab.push(j); - } - assert(tab.toString(), "x,y", "for_in"); - - /* variable assigment in the for in */ - tab = []; - for(var k = 2 in {x:1, y: 2}) { - tab.push(k); - } - assert(tab.toString(), "x,y", "for_in"); -} - -function test_for_in2() -{ - var i, tab; - tab = []; - for(i in {x:1, y: 2, z:3}) { - if (i === "y") - continue; - tab.push(i); - } - assert(tab.toString() == "x,z"); - - tab = []; - for(i in {x:1, y: 2, z:3}) { - if (i === "z") - break; - tab.push(i); - } - assert(tab.toString() == "x,y"); -} - -function test_for_in_proxy() { - let removed_key = ""; - let target = {} - let proxy = new Proxy(target, { - ownKeys: function() { - return ["a", "b", "c"]; - }, - getOwnPropertyDescriptor: function(target, key) { - if (removed_key != "" && key == removed_key) - return undefined; - else - return { enumerable: true, configurable: true, value: this[key] }; - } - }); - let str = ""; - for(let o in proxy) { - str += " " + o; - if (o == "a") - removed_key = "b"; - } - assert(str == " a c"); -} - -function test_for_break() -{ - var i, c; - c = 0; - L1: for(i = 0; i < 3; i++) { - c++; - if (i == 0) - continue; - while (1) { - break L1; - } - } - assert(c === 2 && i === 1); -} - -function test_switch1() -{ - var i, a, s; - s = ""; - for(i = 0; i < 3; i++) { - a = "?"; - switch(i) { - case 0: - a = "a"; - break; - case 1: - a = "b"; - break; - default: - a = "c"; - break; - } - s += a; - } - assert(s === "abc" && i === 3); -} - -function test_switch2() -{ - var i, a, s; - s = ""; - for(i = 0; i < 4; i++) { - a = "?"; - switch(i) { - case 0: - a = "a"; - break; - case 1: - a = "b"; - break; - case 2: - continue; - default: - a = "" + i; - break; - } - s += a; - } - assert(s === "ab3" && i === 4); -} - -function test_try_catch1() -{ - try { - throw "hello"; - } catch (e) { - assert(e, "hello", "catch"); - return; - } - assert(false, "catch"); -} - -function test_try_catch2() -{ - var a; - try { - a = 1; - } catch (e) { - a = 2; - } - assert(a, 1, "catch"); -} - -function test_try_catch3() -{ - var s; - s = ""; - try { - s += "t"; - } catch (e) { - s += "c"; - } finally { - s += "f"; - } - assert(s, "tf", "catch"); -} - -function test_try_catch4() -{ - var s; - s = ""; - try { - s += "t"; - throw "c"; - } catch (e) { - s += e; - } finally { - s += "f"; - } - assert(s, "tcf", "catch"); -} - -function test_try_catch5() -{ - var s; - s = ""; - for(;;) { - try { - s += "t"; - break; - s += "b"; - } finally { - s += "f"; - } - } - assert(s, "tf", "catch"); -} - -function test_try_catch6() -{ - function f() { - try { - s += 't'; - return 1; - } finally { - s += "f"; - } - } - var s = ""; - assert(f() === 1); - assert(s, "tf", "catch6"); -} - -function test_try_catch7() -{ - var s; - s = ""; - - try { - try { - s += "t"; - throw "a"; - } finally { - s += "f"; - } - } catch(e) { - s += e; - } finally { - s += "g"; - } - assert(s, "tfag", "catch"); -} - -function test_try_catch8() -{ - var i, s; - - s = ""; - for(var i in {x:1, y:2}) { - try { - s += i; - throw "a"; - } catch (e) { - s += e; - } finally { - s += "f"; - } - } - assert(s === "xafyaf"); -} - -function test_cyclic_labels() -{ - /* just check that it compiles without a crash */ - for (;;) { - l: break l; - l: break l; - l: break l; - } -} - -test_while(); -test_while_break(); -test_do_while(); -test_for(); -test_for_break(); -test_switch1(); -test_switch2(); -test_for_in(); -test_for_in2(); -test_for_in_proxy(); - -test_try_catch1(); -test_try_catch2(); -test_try_catch3(); -test_try_catch4(); -test_try_catch5(); -test_try_catch6(); -test_try_catch7(); -test_try_catch8(); diff --git a/packages/javascript/javascript_android/cxx/quickjs/tests/test_std.js b/packages/javascript/javascript_android/cxx/quickjs/tests/test_std.js deleted file mode 100644 index 3debe40..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/tests/test_std.js +++ /dev/null @@ -1,336 +0,0 @@ -#! (shebang test) -import * as std from "std"; -import * as os from "os"; - -function assert(actual, expected, message) { - if (arguments.length == 1) - expected = true; - - if (Object.is(actual, expected)) - return; - - if (actual !== null && expected !== null - && typeof actual == 'object' && typeof expected == 'object' - && actual.toString() === expected.toString()) - return; - - throw Error("assertion failed: got |" + actual + "|" + - ", expected |" + expected + "|" + - (message ? " (" + message + ")" : "")); -} - -// load more elaborate version of assert if available -try { std.loadScript("test_assert.js"); } catch(e) {} - -/*----------------*/ - -function test_printf() -{ - assert(std.sprintf("a=%d s=%s", 123, "abc"), "a=123 s=abc"); - assert(std.sprintf("%010d", 123), "0000000123"); - assert(std.sprintf("%x", -2), "fffffffe"); - assert(std.sprintf("%lx", -2), "fffffffffffffffe"); - assert(std.sprintf("%10.1f", 2.1), " 2.1"); - assert(std.sprintf("%*.*f", 10, 2, -2.13), " -2.13"); - assert(std.sprintf("%#lx", 0x7fffffffffffffffn), "0x7fffffffffffffff"); -} - -function test_file1() -{ - var f, len, str, size, buf, ret, i, str1; - - f = std.tmpfile(); - str = "hello world\n"; - f.puts(str); - - f.seek(0, std.SEEK_SET); - str1 = f.readAsString(); - assert(str1 === str); - - f.seek(0, std.SEEK_END); - size = f.tell(); - assert(size === str.length); - - f.seek(0, std.SEEK_SET); - - buf = new Uint8Array(size); - ret = f.read(buf.buffer, 0, size); - assert(ret === size); - for(i = 0; i < size; i++) - assert(buf[i] === str.charCodeAt(i)); - - f.close(); -} - -function test_file2() -{ - var f, str, i, size; - f = std.tmpfile(); - str = "hello world\n"; - size = str.length; - for(i = 0; i < size; i++) - f.putByte(str.charCodeAt(i)); - f.seek(0, std.SEEK_SET); - for(i = 0; i < size; i++) { - assert(str.charCodeAt(i) === f.getByte()); - } - assert(f.getByte() === -1); - f.close(); -} - -function test_getline() -{ - var f, line, line_count, lines, i; - - lines = ["hello world", "line 1", "line 2" ]; - f = std.tmpfile(); - for(i = 0; i < lines.length; i++) { - f.puts(lines[i], "\n"); - } - - f.seek(0, std.SEEK_SET); - assert(!f.eof()); - line_count = 0; - for(;;) { - line = f.getline(); - if (line === null) - break; - assert(line == lines[line_count]); - line_count++; - } - assert(f.eof()); - assert(line_count === lines.length); - - f.close(); -} - -function test_popen() -{ - var str, f, fname = "tmp_file.txt"; - var content = "hello world"; - - f = std.open(fname, "w"); - f.puts(content); - f.close(); - - /* test loadFile */ - assert(std.loadFile(fname), content); - - /* execute the 'cat' shell command */ - f = std.popen("cat " + fname, "r"); - str = f.readAsString(); - f.close(); - - assert(str, content); - - os.remove(fname); -} - -function test_ext_json() -{ - var expected, input, obj; - expected = '{"x":false,"y":true,"z2":null,"a":[1,8,160],"b":"abc\\u000bd","s":"str"}'; - input = `{ "x":false, /*comments are allowed */ - "y":true, // also a comment - z2:null, // unquoted property names - "a":[+1,0o10,0xa0,], // plus prefix, octal, hexadecimal - "b": "ab\ -c\\vd", // multi-line strings, '\v' escape - "s":'str',} // trailing comma in objects and arrays, single quoted string - `; - obj = std.parseExtJSON(input); - assert(JSON.stringify(obj), expected); - - obj = std.parseExtJSON('[Infinity, +Infinity, -Infinity, NaN, +NaN, -NaN, .1, -.2]'); - assert(obj[0], Infinity); - assert(obj[1], Infinity); - assert(obj[2], -Infinity); - assert(obj[3], NaN); - assert(obj[4], NaN); - assert(obj[5], NaN); - assert(obj[6], 0.1); - assert(obj[7], -0.2); -} - -function test_os() -{ - var fd, fpath, fname, fdir, buf, buf2, i, files, err, fdate, st, link_path; - - const stdinIsTTY = !os.exec(["/bin/sh", "-c", "test -t 0"], { usePath: false }); - - assert(os.isatty(0), stdinIsTTY, `isatty(STDIN)`); - - fdir = "test_tmp_dir"; - fname = "tmp_file.txt"; - fpath = fdir + "/" + fname; - link_path = fdir + "/test_link"; - - os.remove(link_path); - os.remove(fpath); - os.remove(fdir); - - err = os.mkdir(fdir, 0o755); - assert(err === 0); - - fd = os.open(fpath, os.O_RDWR | os.O_CREAT | os.O_TRUNC); - assert(fd >= 0); - - buf = new Uint8Array(10); - for(i = 0; i < buf.length; i++) - buf[i] = i; - assert(os.write(fd, buf.buffer, 0, buf.length) === buf.length); - - assert(os.seek(fd, 0, std.SEEK_SET) === 0); - buf2 = new Uint8Array(buf.length); - assert(os.read(fd, buf2.buffer, 0, buf2.length) === buf2.length); - - for(i = 0; i < buf.length; i++) - assert(buf[i] == buf2[i]); - - if (typeof BigInt !== "undefined") { - assert(os.seek(fd, BigInt(6), std.SEEK_SET), BigInt(6)); - assert(os.read(fd, buf2.buffer, 0, 1) === 1); - assert(buf[6] == buf2[0]); - } - - assert(os.close(fd) === 0); - - [files, err] = os.readdir(fdir); - assert(err, 0); - assert(files.indexOf(fname) >= 0); - - fdate = 10000; - - err = os.utimes(fpath, fdate, fdate); - assert(err, 0); - - [st, err] = os.stat(fpath); - assert(err, 0); - assert(st.mode & os.S_IFMT, os.S_IFREG); - assert(st.mtime, fdate); - - err = os.symlink(fname, link_path); - assert(err === 0); - - [st, err] = os.lstat(link_path); - assert(err, 0); - assert(st.mode & os.S_IFMT, os.S_IFLNK); - - [buf, err] = os.readlink(link_path); - assert(err, 0); - assert(buf, fname); - - assert(os.remove(link_path) === 0); - - [buf, err] = os.getcwd(); - assert(err, 0); - - [buf2, err] = os.realpath("."); - assert(err, 0); - - assert(buf, buf2); - - assert(os.remove(fpath) === 0); - - fd = os.open(fpath, os.O_RDONLY); - assert(fd < 0); - - assert(os.remove(fdir) === 0); -} - -function test_os_exec() -{ - var ret, fds, pid, f, status; - - ret = os.exec(["true"]); - assert(ret, 0); - - ret = os.exec(["/bin/sh", "-c", "exit 1"], { usePath: false }); - assert(ret, 1); - - fds = os.pipe(); - pid = os.exec(["sh", "-c", "echo $FOO"], { - stdout: fds[1], - block: false, - env: { FOO: "hello" }, - } ); - assert(pid >= 0); - os.close(fds[1]); /* close the write end (as it is only in the child) */ - f = std.fdopen(fds[0], "r"); - assert(f.getline(), "hello"); - assert(f.getline(), null); - f.close(); - [ret, status] = os.waitpid(pid, 0); - assert(ret, pid); - assert(status & 0x7f, 0); /* exited */ - assert(status >> 8, 0); /* exit code */ - - pid = os.exec(["cat"], { block: false } ); - assert(pid >= 0); - os.kill(pid, os.SIGTERM); - [ret, status] = os.waitpid(pid, 0); - assert(ret, pid); - assert(status !== 0, true, `expect nonzero exit code (got ${status})`); - assert(status & 0x7f, os.SIGTERM); -} - -function test_timer() -{ - var th, i; - - /* just test that a timer can be inserted and removed */ - th = []; - for(i = 0; i < 3; i++) - th[i] = os.setTimeout(function () { }, 1000); - for(i = 0; i < 3; i++) - os.clearTimeout(th[i]); -} - -/* test closure variable handling when freeing asynchronous - function */ -function test_async_gc() -{ - (async function run () { - let obj = {} - - let done = () => { - obj - std.gc(); - } - - Promise.resolve().then(done) - - const p = new Promise(() => {}) - - await p - })(); -} - -/* check that the promise async rejection handler is not invoked when - the rejection is handled not too late after the promise - rejection. */ -function test_async_promise_rejection() -{ - var counter = 0; - var p1, p2, p3; - p1 = Promise.reject(); - p2 = Promise.reject(); - p3 = Promise.resolve(); - p1.catch(() => counter++); - p2.catch(() => counter++); - p3.then(() => counter++) - os.setTimeout(() => { assert(counter, 3) }, 10); -} - -test_printf(); -test_file1(); -test_file2(); -test_getline(); -test_popen(); -test_os(); -test_os_exec(); -test_timer(); -test_ext_json(); -test_async_gc(); -test_async_promise_rejection(); - diff --git a/packages/javascript/javascript_android/cxx/quickjs/tests/test_worker.js b/packages/javascript/javascript_android/cxx/quickjs/tests/test_worker.js deleted file mode 100644 index 4b52bf8..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/tests/test_worker.js +++ /dev/null @@ -1,62 +0,0 @@ -/* os.Worker API test */ -import * as std from "std"; -import * as os from "os"; - -function assert(actual, expected, message) { - if (arguments.length == 1) - expected = true; - - if (actual === expected) - return; - - if (actual !== null && expected !== null - && typeof actual == 'object' && typeof expected == 'object' - && actual.toString() === expected.toString()) - return; - - throw Error("assertion failed: got |" + actual + "|" + - ", expected |" + expected + "|" + - (message ? " (" + message + ")" : "")); -} - -var worker; - -function test_worker() -{ - var counter; - - worker = new os.Worker("./test_worker_module.js"); - - counter = 0; - worker.onmessage = function (e) { - var ev = e.data; -// print("recv", JSON.stringify(ev)); - switch(ev.type) { - case "num": - assert(ev.num, counter); - counter++; - if (counter == 10) { - /* test SharedArrayBuffer modification */ - let sab = new SharedArrayBuffer(10); - let buf = new Uint8Array(sab); - worker.postMessage({ type: "sab", buf: buf }); - } - break; - case "sab_done": - { - let buf = ev.buf; - /* check that the SharedArrayBuffer was modified */ - assert(buf[2], 10); - worker.postMessage({ type: "abort" }); - } - break; - case "done": - /* terminate */ - worker.onmessage = null; - break; - } - }; -} - - -test_worker(); diff --git a/packages/javascript/javascript_android/cxx/quickjs/tests/test_worker_module.js b/packages/javascript/javascript_android/cxx/quickjs/tests/test_worker_module.js deleted file mode 100644 index ddf8e40..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/tests/test_worker_module.js +++ /dev/null @@ -1,32 +0,0 @@ -/* Worker code for test_worker.js */ -import * as std from "std"; -import * as os from "os"; - -var parent = os.Worker.parent; - -function handle_msg(e) { - var ev = e.data; - // print("child_recv", JSON.stringify(ev)); - switch(ev.type) { - case "abort": - parent.postMessage({ type: "done" }); - parent.onmessage = null; /* terminate the worker */ - break; - case "sab": - /* modify the SharedArrayBuffer */ - ev.buf[2] = 10; - parent.postMessage({ type: "sab_done", buf: ev.buf }); - break; - } -} - -function worker_main() { - var i; - - parent.onmessage = handle_msg; - for(i = 0; i < 10; i++) { - parent.postMessage({ type: "num", num: i }); - } -} - -worker_main(); diff --git a/packages/javascript/javascript_android/cxx/quickjs/unicode_download.sh b/packages/javascript/javascript_android/cxx/quickjs/unicode_download.sh deleted file mode 100755 index ef8b30d..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/unicode_download.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh -set -e - -version="16.0.0" -emoji_version="16.0" -url="ftp://ftp.unicode.org/Public" - -files="CaseFolding.txt DerivedNormalizationProps.txt PropList.txt \ -SpecialCasing.txt CompositionExclusions.txt ScriptExtensions.txt \ -UnicodeData.txt DerivedCoreProperties.txt NormalizationTest.txt Scripts.txt \ -PropertyValueAliases.txt" - -mkdir -p unicode - -for f in $files; do - g="${url}/${version}/ucd/${f}" - wget $g -O unicode/$f -done - -wget "${url}/${version}/ucd/emoji/emoji-data.txt" -O unicode/emoji-data.txt - -wget "${url}/emoji/${emoji_version}/emoji-sequences.txt" -O unicode/emoji-sequences.txt -wget "${url}/emoji/${emoji_version}/emoji-zwj-sequences.txt" -O unicode/emoji-zwj-sequences.txt diff --git a/packages/javascript/javascript_android/cxx/quickjs/unicode_gen.c b/packages/javascript/javascript_android/cxx/quickjs/unicode_gen.c deleted file mode 100644 index c793ba1..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/unicode_gen.c +++ /dev/null @@ -1,3779 +0,0 @@ -/* - * Generation of Unicode tables - * - * Copyright (c) 2017-2018 Fabrice Bellard - * Copyright (c) 2017-2018 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cutils.h" - -uint32_t total_tables; -uint32_t total_table_bytes; -uint32_t total_index; -uint32_t total_index_bytes; - -/* define it to be able to test unicode.c */ -//#define USE_TEST -/* profile tests */ -//#define PROFILE - -//#define DUMP_CASE_CONV_TABLE -//#define DUMP_TABLE_SIZE -//#define DUMP_CC_TABLE -//#define DUMP_DECOMP_TABLE -//#define DUMP_CASE_FOLDING_SPECIAL_CASES - -/* Ideas: - - Generalize run length encoding + index for all tables - - remove redundant tables for ID_start, ID_continue, Case_Ignorable, Cased - - Case conversion: - - use a single entry for consecutive U/LF runs - - allow EXT runs of length > 1 - - Decomposition: - - Greek lower case (+1f10/1f10) ? - - allow holes in B runs - - suppress more upper / lower case redundancy -*/ - -#ifdef USE_TEST -#include "libunicode.c" -#endif - -#define CHARCODE_MAX 0x10ffff -#define CC_LEN_MAX 3 - -void *mallocz(size_t size) -{ - void *ptr; - ptr = malloc(size); - memset(ptr, 0, size); - return ptr; -} - -const char *get_field(const char *p, int n) -{ - int i; - for(i = 0; i < n; i++) { - while (*p != ';' && *p != '\0') - p++; - if (*p == '\0') - return NULL; - p++; - } - return p; -} - -const char *get_field_buf(char *buf, size_t buf_size, const char *p, int n) -{ - char *q; - p = get_field(p, n); - q = buf; - while (*p != ';' && *p != '\0') { - if ((q - buf) < buf_size - 1) - *q++ = *p; - p++; - } - *q = '\0'; - return buf; -} - -void add_char(int **pbuf, int *psize, int *plen, int c) -{ - int len, size, *buf; - buf = *pbuf; - size = *psize; - len = *plen; - if (len >= size) { - size = *psize; - size = max_int(len + 1, size * 3 / 2); - buf = realloc(buf, sizeof(buf[0]) * size); - *pbuf = buf; - *psize = size; - } - buf[len++] = c; - *plen = len; -} - -int *get_field_str(int *plen, const char *str, int n) -{ - const char *p; - int *buf, len, size; - p = get_field(str, n); - if (!p) { - *plen = 0; - return NULL; - } - len = 0; - size = 0; - buf = NULL; - for(;;) { - while (isspace(*p)) - p++; - if (!isxdigit(*p)) - break; - add_char(&buf, &size, &len, strtoul(p, (char **)&p, 16)); - } - *plen = len; - return buf; -} - -char *get_line(char *buf, int buf_size, FILE *f) -{ - int len; - if (!fgets(buf, buf_size, f)) - return NULL; - len = strlen(buf); - if (len > 0 && buf[len - 1] == '\n') - buf[len - 1] = '\0'; - return buf; -} - -typedef struct REString { - struct REString *next; - uint32_t hash; - uint32_t len; - uint32_t flags; - uint32_t buf[]; -} REString; - -typedef struct { - uint32_t n_strings; - uint32_t hash_size; - int hash_bits; - REString **hash_table; -} REStringList; - -static uint32_t re_string_hash(int len, const uint32_t *buf) -{ - int i; - uint32_t h; - h = 1; - for(i = 0; i < len; i++) - h = h * 263 + buf[i]; - return h * 0x61C88647; -} - -static void re_string_list_init(REStringList *s) -{ - s->n_strings = 0; - s->hash_size = 0; - s->hash_bits = 0; - s->hash_table = NULL; -} - -static __maybe_unused void re_string_list_free(REStringList *s) -{ - REString *p, *p_next; - int i; - for(i = 0; i < s->hash_size; i++) { - for(p = s->hash_table[i]; p != NULL; p = p_next) { - p_next = p->next; - free(p); - } - } - free(s->hash_table); -} - -static void lre_print_char(int c, BOOL is_range) -{ - if (c == '\'' || c == '\\' || - (is_range && (c == '-' || c == ']'))) { - printf("\\%c", c); - } else if (c >= ' ' && c <= 126) { - printf("%c", c); - } else { - printf("\\u{%04x}", c); - } -} - -static __maybe_unused void re_string_list_dump(const char *str, const REStringList *s) -{ - REString *p; - int i, j, k; - - printf("%s:\n", str); - - j = 0; - for(i = 0; i < s->hash_size; i++) { - for(p = s->hash_table[i]; p != NULL; p = p->next) { - printf(" %d/%d: '", j, s->n_strings); - for(k = 0; k < p->len; k++) { - lre_print_char(p->buf[k], FALSE); - } - printf("'\n"); - j++; - } - } -} - -static REString *re_string_find2(REStringList *s, int len, const uint32_t *buf, - uint32_t h0, BOOL add_flag) -{ - uint32_t h = 0; /* avoid warning */ - REString *p; - if (s->n_strings != 0) { - h = h0 >> (32 - s->hash_bits); - for(p = s->hash_table[h]; p != NULL; p = p->next) { - if (p->hash == h0 && p->len == len && - !memcmp(p->buf, buf, len * sizeof(buf[0]))) { - return p; - } - } - } - /* not found */ - if (!add_flag) - return NULL; - /* increase the size of the hash table if needed */ - if (unlikely((s->n_strings + 1) > s->hash_size)) { - REString **new_hash_table, *p_next; - int new_hash_bits, i; - uint32_t new_hash_size; - new_hash_bits = max_int(s->hash_bits + 1, 4); - new_hash_size = 1 << new_hash_bits; - new_hash_table = malloc(sizeof(new_hash_table[0]) * new_hash_size); - if (!new_hash_table) - return NULL; - memset(new_hash_table, 0, sizeof(new_hash_table[0]) * new_hash_size); - for(i = 0; i < s->hash_size; i++) { - for(p = s->hash_table[i]; p != NULL; p = p_next) { - p_next = p->next; - h = p->hash >> (32 - new_hash_bits); - p->next = new_hash_table[h]; - new_hash_table[h] = p; - } - } - free(s->hash_table); - s->hash_bits = new_hash_bits; - s->hash_size = new_hash_size; - s->hash_table = new_hash_table; - h = h0 >> (32 - s->hash_bits); - } - - p = malloc(sizeof(REString) + len * sizeof(buf[0])); - if (!p) - return NULL; - p->next = s->hash_table[h]; - s->hash_table[h] = p; - s->n_strings++; - p->hash = h0; - p->len = len; - p->flags = 0; - memcpy(p->buf, buf, sizeof(buf[0]) * len); - return p; -} - -static REString *re_string_find(REStringList *s, int len, const uint32_t *buf, - BOOL add_flag) -{ - uint32_t h0; - h0 = re_string_hash(len, buf); - return re_string_find2(s, len, buf, h0, add_flag); -} - -static void re_string_add(REStringList *s, int len, const uint32_t *buf) -{ - re_string_find(s, len, buf, TRUE); -} - -#define UNICODE_GENERAL_CATEGORY - -typedef enum { -#define DEF(id, str) GCAT_ ## id, -#include "unicode_gen_def.h" -#undef DEF - GCAT_COUNT, -} UnicodeGCEnum1; - -static const char *unicode_gc_name[] = { -#define DEF(id, str) #id, -#include "unicode_gen_def.h" -#undef DEF -}; - -static const char *unicode_gc_short_name[] = { -#define DEF(id, str) str, -#include "unicode_gen_def.h" -#undef DEF -}; - -#undef UNICODE_GENERAL_CATEGORY - -#define UNICODE_SCRIPT - -typedef enum { -#define DEF(id, str) SCRIPT_ ## id, -#include "unicode_gen_def.h" -#undef DEF - SCRIPT_COUNT, -} UnicodeScriptEnum1; - -static const char *unicode_script_name[] = { -#define DEF(id, str) #id, -#include "unicode_gen_def.h" -#undef DEF -}; - -const char *unicode_script_short_name[] = { -#define DEF(id, str) str, -#include "unicode_gen_def.h" -#undef DEF -}; - -#undef UNICODE_SCRIPT - -#define UNICODE_PROP_LIST - -typedef enum { -#define DEF(id, str) PROP_ ## id, -#include "unicode_gen_def.h" -#undef DEF - PROP_COUNT, -} UnicodePropEnum1; - -static const char *unicode_prop_name[] = { -#define DEF(id, str) #id, -#include "unicode_gen_def.h" -#undef DEF -}; - -static const char *unicode_prop_short_name[] = { -#define DEF(id, str) str, -#include "unicode_gen_def.h" -#undef DEF -}; - -#undef UNICODE_PROP_LIST - -#define UNICODE_SEQUENCE_PROP_LIST - -typedef enum { -#define DEF(id) SEQUENCE_PROP_ ## id, -#include "unicode_gen_def.h" -#undef DEF - SEQUENCE_PROP_COUNT, -} UnicodeSequencePropEnum1; - -static const char *unicode_sequence_prop_name[] = { -#define DEF(id) #id, -#include "unicode_gen_def.h" -#undef DEF -}; - -#undef UNICODE_SEQUENCE_PROP_LIST - -typedef struct { - /* case conv */ - uint8_t u_len; - uint8_t l_len; - uint8_t f_len; - int u_data[CC_LEN_MAX]; /* to upper case */ - int l_data[CC_LEN_MAX]; /* to lower case */ - int f_data[CC_LEN_MAX]; /* to case folding */ - - uint8_t combining_class; - uint8_t is_compat:1; - uint8_t is_excluded:1; - uint8_t general_category; - uint8_t script; - uint8_t script_ext_len; - uint8_t *script_ext; - uint32_t prop_bitmap_tab[3]; - /* decomposition */ - int decomp_len; - int *decomp_data; -} CCInfo; - -typedef struct { - int count; - int size; - int *tab; -} UnicodeSequenceProperties; - -CCInfo *unicode_db; -REStringList rgi_emoji_zwj_sequence; -DynBuf rgi_emoji_tag_sequence; - -int find_name(const char **tab, int tab_len, const char *name) -{ - int i, len, name_len; - const char *p, *r; - - name_len = strlen(name); - for(i = 0; i < tab_len; i++) { - p = tab[i]; - for(;;) { - r = strchr(p, ','); - if (!r) - len = strlen(p); - else - len = r - p; - if (len == name_len && memcmp(p, name, len) == 0) - return i; - if (!r) - break; - p = r + 1; - } - } - return -1; -} - -static BOOL get_prop(uint32_t c, int prop_idx) -{ - return (unicode_db[c].prop_bitmap_tab[prop_idx >> 5] >> (prop_idx & 0x1f)) & 1; -} - -static void set_prop(uint32_t c, int prop_idx, int val) -{ - uint32_t mask; - mask = 1U << (prop_idx & 0x1f); - if (val) - unicode_db[c].prop_bitmap_tab[prop_idx >> 5] |= mask; - else - unicode_db[c].prop_bitmap_tab[prop_idx >> 5] &= ~mask; -} - -void parse_unicode_data(const char *filename) -{ - FILE *f; - char line[1024]; - char buf1[256]; - const char *p; - int code, lc, uc, last_code; - CCInfo *ci, *tab = unicode_db; - - f = fopen(filename, "rb"); - if (!f) { - perror(filename); - exit(1); - } - - last_code = 0; - for(;;) { - if (!get_line(line, sizeof(line), f)) - break; - p = line; - while (isspace(*p)) - p++; - if (*p == '#') - continue; - - p = get_field(line, 0); - if (!p) - continue; - code = strtoul(p, NULL, 16); - lc = 0; - uc = 0; - - p = get_field(line, 12); - if (p && *p != ';') { - uc = strtoul(p, NULL, 16); - } - - p = get_field(line, 13); - if (p && *p != ';') { - lc = strtoul(p, NULL, 16); - } - ci = &tab[code]; - if (uc > 0 || lc > 0) { - assert(code <= CHARCODE_MAX); - if (uc > 0) { - assert(ci->u_len == 0); - ci->u_len = 1; - ci->u_data[0] = uc; - } - if (lc > 0) { - assert(ci->l_len == 0); - ci->l_len = 1; - ci->l_data[0] = lc; - } - } - - { - int i; - get_field_buf(buf1, sizeof(buf1), line, 2); - i = find_name(unicode_gc_name, countof(unicode_gc_name), buf1); - if (i < 0) { - fprintf(stderr, "General category '%s' not found\n", - buf1); - exit(1); - } - ci->general_category = i; - } - - p = get_field(line, 3); - if (p && *p != ';' && *p != '\0') { - int cc; - cc = strtoul(p, NULL, 0); - if (cc != 0) { - assert(code <= CHARCODE_MAX); - ci->combining_class = cc; - // printf("%05x: %d\n", code, ci->combining_class); - } - } - - p = get_field(line, 5); - if (p && *p != ';' && *p != '\0') { - int size; - assert(code <= CHARCODE_MAX); - ci->is_compat = 0; - if (*p == '<') { - while (*p != '\0' && *p != '>') - p++; - if (*p == '>') - p++; - ci->is_compat = 1; - } - size = 0; - for(;;) { - while (isspace(*p)) - p++; - if (!isxdigit(*p)) - break; - add_char(&ci->decomp_data, &size, &ci->decomp_len, strtoul(p, (char **)&p, 16)); - } -#if 0 - { - int i; - static int count, d_count; - - printf("%05x: %c", code, ci->is_compat ? 'C': ' '); - for(i = 0; i < ci->decomp_len; i++) - printf(" %05x", ci->decomp_data[i]); - printf("\n"); - count++; - d_count += ci->decomp_len; - // printf("%d %d\n", count, d_count); - } -#endif - } - - p = get_field(line, 9); - if (p && *p == 'Y') { - set_prop(code, PROP_Bidi_Mirrored, 1); - } - - /* handle ranges */ - get_field_buf(buf1, sizeof(buf1), line, 1); - if (strstr(buf1, " Last>")) { - int i; - // printf("range: 0x%x-%0x\n", last_code, code); - assert(ci->decomp_len == 0); - assert(ci->script_ext_len == 0); - for(i = last_code + 1; i < code; i++) { - unicode_db[i] = *ci; - } - } - last_code = code; - } - - fclose(f); -} - -void parse_special_casing(CCInfo *tab, const char *filename) -{ - FILE *f; - char line[1024]; - const char *p; - int code; - CCInfo *ci; - - f = fopen(filename, "rb"); - if (!f) { - perror(filename); - exit(1); - } - - for(;;) { - if (!get_line(line, sizeof(line), f)) - break; - p = line; - while (isspace(*p)) - p++; - if (*p == '#') - continue; - - p = get_field(line, 0); - if (!p) - continue; - code = strtoul(p, NULL, 16); - assert(code <= CHARCODE_MAX); - ci = &tab[code]; - - p = get_field(line, 4); - if (p) { - /* locale dependent casing */ - while (isspace(*p)) - p++; - if (*p != '#' && *p != '\0') - continue; - } - - - p = get_field(line, 1); - if (p && *p != ';') { - ci->l_len = 0; - for(;;) { - while (isspace(*p)) - p++; - if (*p == ';') - break; - assert(ci->l_len < CC_LEN_MAX); - ci->l_data[ci->l_len++] = strtoul(p, (char **)&p, 16); - } - - if (ci->l_len == 1 && ci->l_data[0] == code) - ci->l_len = 0; - } - - p = get_field(line, 3); - if (p && *p != ';') { - ci->u_len = 0; - for(;;) { - while (isspace(*p)) - p++; - if (*p == ';') - break; - assert(ci->u_len < CC_LEN_MAX); - ci->u_data[ci->u_len++] = strtoul(p, (char **)&p, 16); - } - - if (ci->u_len == 1 && ci->u_data[0] == code) - ci->u_len = 0; - } - } - - fclose(f); -} - -void parse_case_folding(CCInfo *tab, const char *filename) -{ - FILE *f; - char line[1024]; - const char *p; - int code, status; - CCInfo *ci; - - f = fopen(filename, "rb"); - if (!f) { - perror(filename); - exit(1); - } - - for(;;) { - if (!get_line(line, sizeof(line), f)) - break; - p = line; - while (isspace(*p)) - p++; - if (*p == '#') - continue; - - p = get_field(line, 0); - if (!p) - continue; - code = strtoul(p, NULL, 16); - assert(code <= CHARCODE_MAX); - ci = &tab[code]; - - p = get_field(line, 1); - if (!p) - continue; - /* locale dependent casing */ - while (isspace(*p)) - p++; - status = *p; - if (status != 'C' && status != 'S' && status != 'F') - continue; - - p = get_field(line, 2); - assert(p != NULL); - if (status == 'S') { - /* we always select the simple case folding and assume it - * comes after the full case folding case */ - assert(ci->f_len >= 2); - ci->f_len = 0; - } else { - assert(ci->f_len == 0); - } - for(;;) { - while (isspace(*p)) - p++; - if (*p == ';') - break; - assert(ci->l_len < CC_LEN_MAX); - ci->f_data[ci->f_len++] = strtoul(p, (char **)&p, 16); - } - } - - fclose(f); -} - -void parse_composition_exclusions(const char *filename) -{ - FILE *f; - char line[4096], *p; - uint32_t c0; - - f = fopen(filename, "rb"); - if (!f) { - perror(filename); - exit(1); - } - - for(;;) { - if (!get_line(line, sizeof(line), f)) - break; - p = line; - while (isspace(*p)) - p++; - if (*p == '#' || *p == '@' || *p == '\0') - continue; - c0 = strtoul(p, (char **)&p, 16); - assert(c0 > 0 && c0 <= CHARCODE_MAX); - unicode_db[c0].is_excluded = TRUE; - } - fclose(f); -} - -void parse_derived_core_properties(const char *filename) -{ - FILE *f; - char line[4096], *p, buf[256], *q; - uint32_t c0, c1, c; - int i; - - f = fopen(filename, "rb"); - if (!f) { - perror(filename); - exit(1); - } - - for(;;) { - if (!get_line(line, sizeof(line), f)) - break; - p = line; - while (isspace(*p)) - p++; - if (*p == '#' || *p == '@' || *p == '\0') - continue; - c0 = strtoul(p, (char **)&p, 16); - if (*p == '.' && p[1] == '.') { - p += 2; - c1 = strtoul(p, (char **)&p, 16); - } else { - c1 = c0; - } - assert(c1 <= CHARCODE_MAX); - p += strspn(p, " \t"); - if (*p == ';') { - p++; - p += strspn(p, " \t"); - q = buf; - while (*p != '\0' && *p != ' ' && *p != '#' && *p != '\t' && *p != ';') { - if ((q - buf) < sizeof(buf) - 1) - *q++ = *p; - p++; - } - *q = '\0'; - i = find_name(unicode_prop_name, - countof(unicode_prop_name), buf); - if (i < 0) { - if (!strcmp(buf, "Grapheme_Link")) - goto next; - fprintf(stderr, "Property not found: %s\n", buf); - exit(1); - } - for(c = c0; c <= c1; c++) { - set_prop(c, i, 1); - } -next: ; - } - } - fclose(f); -} - -void parse_derived_norm_properties(const char *filename) -{ - FILE *f; - char line[4096], *p, buf[256], *q; - uint32_t c0, c1, c; - - f = fopen(filename, "rb"); - if (!f) { - perror(filename); - exit(1); - } - - for(;;) { - if (!get_line(line, sizeof(line), f)) - break; - p = line; - while (isspace(*p)) - p++; - if (*p == '#' || *p == '@' || *p == '\0') - continue; - c0 = strtoul(p, (char **)&p, 16); - if (*p == '.' && p[1] == '.') { - p += 2; - c1 = strtoul(p, (char **)&p, 16); - } else { - c1 = c0; - } - assert(c1 <= CHARCODE_MAX); - p += strspn(p, " \t"); - if (*p == ';') { - p++; - p += strspn(p, " \t"); - q = buf; - while (*p != '\0' && *p != ' ' && *p != '#' && *p != '\t') { - if ((q - buf) < sizeof(buf) - 1) - *q++ = *p; - p++; - } - *q = '\0'; - if (!strcmp(buf, "Changes_When_NFKC_Casefolded")) { - for(c = c0; c <= c1; c++) { - set_prop(c, PROP_Changes_When_NFKC_Casefolded, 1); - } - } - } - } - fclose(f); -} - -void parse_prop_list(const char *filename) -{ - FILE *f; - char line[4096], *p, buf[256], *q; - uint32_t c0, c1, c; - int i; - - f = fopen(filename, "rb"); - if (!f) { - perror(filename); - exit(1); - } - - for(;;) { - if (!get_line(line, sizeof(line), f)) - break; - p = line; - while (isspace(*p)) - p++; - if (*p == '#' || *p == '@' || *p == '\0') - continue; - c0 = strtoul(p, (char **)&p, 16); - if (*p == '.' && p[1] == '.') { - p += 2; - c1 = strtoul(p, (char **)&p, 16); - } else { - c1 = c0; - } - assert(c1 <= CHARCODE_MAX); - p += strspn(p, " \t"); - if (*p == ';') { - p++; - p += strspn(p, " \t"); - q = buf; - while (*p != '\0' && *p != ' ' && *p != '#' && *p != '\t') { - if ((q - buf) < sizeof(buf) - 1) - *q++ = *p; - p++; - } - *q = '\0'; - i = find_name(unicode_prop_name, - countof(unicode_prop_name), buf); - if (i < 0) { - fprintf(stderr, "Property not found: %s\n", buf); - exit(1); - } - for(c = c0; c <= c1; c++) { - set_prop(c, i, 1); - } - } - } - fclose(f); -} - -#define SEQ_MAX_LEN 16 - -static BOOL is_emoji_modifier(uint32_t c) -{ - return (c >= 0x1f3fb && c <= 0x1f3ff); -} - -static void add_sequence_prop(int idx, int seq_len, int *seq) -{ - int i; - - assert(idx < SEQUENCE_PROP_COUNT); - switch(idx) { - case SEQUENCE_PROP_Basic_Emoji: - /* convert to 2 properties lists */ - if (seq_len == 1) { - set_prop(seq[0], PROP_Basic_Emoji1, 1); - } else if (seq_len == 2 && seq[1] == 0xfe0f) { - set_prop(seq[0], PROP_Basic_Emoji2, 1); - } else { - abort(); - } - break; - case SEQUENCE_PROP_RGI_Emoji_Modifier_Sequence: - assert(seq_len == 2); - assert(is_emoji_modifier(seq[1])); - assert(get_prop(seq[0], PROP_Emoji_Modifier_Base)); - set_prop(seq[0], PROP_RGI_Emoji_Modifier_Sequence, 1); - break; - case SEQUENCE_PROP_RGI_Emoji_Flag_Sequence: - { - int code; - assert(seq_len == 2); - assert(seq[0] >= 0x1F1E6 && seq[0] <= 0x1F1FF); - assert(seq[1] >= 0x1F1E6 && seq[1] <= 0x1F1FF); - code = (seq[0] - 0x1F1E6) * 26 + (seq[1] - 0x1F1E6); - /* XXX: would be more compact with a simple bitmap -> 676 bits */ - set_prop(code, PROP_RGI_Emoji_Flag_Sequence, 1); - } - break; - case SEQUENCE_PROP_RGI_Emoji_ZWJ_Sequence: - re_string_add(&rgi_emoji_zwj_sequence, seq_len, (uint32_t *)seq); - break; - case SEQUENCE_PROP_RGI_Emoji_Tag_Sequence: - { - assert(seq_len >= 3); - assert(seq[0] == 0x1F3F4); - assert(seq[seq_len - 1] == 0xE007F); - for(i = 1; i < seq_len - 1; i++) { - assert(seq[i] >= 0xe0001 && seq[i] <= 0xe007e); - dbuf_putc(&rgi_emoji_tag_sequence, seq[i] - 0xe0000); - } - dbuf_putc(&rgi_emoji_tag_sequence, 0); - } - break; - case SEQUENCE_PROP_Emoji_Keycap_Sequence: - assert(seq_len == 3); - assert(seq[1] == 0xfe0f); - assert(seq[2] == 0x20e3); - set_prop(seq[0], PROP_Emoji_Keycap_Sequence, 1); - break; - default: - assert(0); - } -} - -void parse_sequence_prop_list(const char *filename) -{ - FILE *f; - char line[4096], *p, buf[256], *q, *p_start; - uint32_t c0, c1, c; - int idx, seq_len; - int seq[SEQ_MAX_LEN]; - - f = fopen(filename, "rb"); - if (!f) { - perror(filename); - exit(1); - } - - for(;;) { - if (!get_line(line, sizeof(line), f)) - break; - p = line; - while (isspace(*p)) - p++; - if (*p == '#' || *p == '@' || *p == '\0') - continue; - p_start = p; - - /* find the sequence property name */ - p = strchr(p, ';'); - if (!p) - continue; - p++; - p += strspn(p, " \t"); - q = buf; - while (*p != '\0' && *p != ' ' && *p != '#' && *p != '\t' && *p != ';') { - if ((q - buf) < sizeof(buf) - 1) - *q++ = *p; - p++; - } - *q = '\0'; - idx = find_name(unicode_sequence_prop_name, - countof(unicode_sequence_prop_name), buf); - if (idx < 0) { - fprintf(stderr, "Property not found: %s\n", buf); - exit(1); - } - - p = p_start; - c0 = strtoul(p, (char **)&p, 16); - assert(c0 <= CHARCODE_MAX); - - if (*p == '.' && p[1] == '.') { - p += 2; - c1 = strtoul(p, (char **)&p, 16); - assert(c1 <= CHARCODE_MAX); - for(c = c0; c <= c1; c++) { - seq[0] = c; - add_sequence_prop(idx, 1, seq); - } - } else { - seq_len = 0; - seq[seq_len++] = c0; - for(;;) { - while (isspace(*p)) - p++; - if (*p == ';' || *p == '\0') - break; - c0 = strtoul(p, (char **)&p, 16); - assert(c0 <= CHARCODE_MAX); - assert(seq_len < countof(seq)); - seq[seq_len++] = c0; - } - add_sequence_prop(idx, seq_len, seq); - } - } - fclose(f); -} - -void parse_scripts(const char *filename) -{ - FILE *f; - char line[4096], *p, buf[256], *q; - uint32_t c0, c1, c; - int i; - - f = fopen(filename, "rb"); - if (!f) { - perror(filename); - exit(1); - } - - for(;;) { - if (!get_line(line, sizeof(line), f)) - break; - p = line; - while (isspace(*p)) - p++; - if (*p == '#' || *p == '@' || *p == '\0') - continue; - c0 = strtoul(p, (char **)&p, 16); - if (*p == '.' && p[1] == '.') { - p += 2; - c1 = strtoul(p, (char **)&p, 16); - } else { - c1 = c0; - } - assert(c1 <= CHARCODE_MAX); - p += strspn(p, " \t"); - if (*p == ';') { - p++; - p += strspn(p, " \t"); - q = buf; - while (*p != '\0' && *p != ' ' && *p != '#' && *p != '\t') { - if ((q - buf) < sizeof(buf) - 1) - *q++ = *p; - p++; - } - *q = '\0'; - i = find_name(unicode_script_name, - countof(unicode_script_name), buf); - if (i < 0) { - fprintf(stderr, "Unknown script: '%s'\n", buf); - exit(1); - } - for(c = c0; c <= c1; c++) - unicode_db[c].script = i; - } - } - fclose(f); -} - -void parse_script_extensions(const char *filename) -{ - FILE *f; - char line[4096], *p, buf[256], *q; - uint32_t c0, c1, c; - int i; - uint8_t script_ext[255]; - int script_ext_len; - - f = fopen(filename, "rb"); - if (!f) { - perror(filename); - exit(1); - } - - for(;;) { - if (!get_line(line, sizeof(line), f)) - break; - p = line; - while (isspace(*p)) - p++; - if (*p == '#' || *p == '@' || *p == '\0') - continue; - c0 = strtoul(p, (char **)&p, 16); - if (*p == '.' && p[1] == '.') { - p += 2; - c1 = strtoul(p, (char **)&p, 16); - } else { - c1 = c0; - } - assert(c1 <= CHARCODE_MAX); - p += strspn(p, " \t"); - script_ext_len = 0; - if (*p == ';') { - p++; - for(;;) { - p += strspn(p, " \t"); - q = buf; - while (*p != '\0' && *p != ' ' && *p != '#' && *p != '\t') { - if ((q - buf) < sizeof(buf) - 1) - *q++ = *p; - p++; - } - *q = '\0'; - if (buf[0] == '\0') - break; - i = find_name(unicode_script_short_name, - countof(unicode_script_short_name), buf); - if (i < 0) { - fprintf(stderr, "Script not found: %s\n", buf); - exit(1); - } - assert(script_ext_len < sizeof(script_ext)); - script_ext[script_ext_len++] = i; - } - for(c = c0; c <= c1; c++) { - CCInfo *ci = &unicode_db[c]; - ci->script_ext_len = script_ext_len; - ci->script_ext = malloc(sizeof(ci->script_ext[0]) * script_ext_len); - for(i = 0; i < script_ext_len; i++) - ci->script_ext[i] = script_ext[i]; - } - } - } - fclose(f); -} - -void dump_cc_info(CCInfo *ci, int i) -{ - int j; - printf("%05x:", i); - if (ci->u_len != 0) { - printf(" U:"); - for(j = 0; j < ci->u_len; j++) - printf(" %05x", ci->u_data[j]); - } - if (ci->l_len != 0) { - printf(" L:"); - for(j = 0; j < ci->l_len; j++) - printf(" %05x", ci->l_data[j]); - } - if (ci->f_len != 0) { - printf(" F:"); - for(j = 0; j < ci->f_len; j++) - printf(" %05x", ci->f_data[j]); - } - printf("\n"); -} - -void dump_unicode_data(CCInfo *tab) -{ - int i; - CCInfo *ci; - for(i = 0; i <= CHARCODE_MAX; i++) { - ci = &tab[i]; - if (ci->u_len != 0 || ci->l_len != 0 || ci->f_len != 0) { - dump_cc_info(ci, i); - } - } -} - -BOOL is_complicated_case(const CCInfo *ci) -{ - return (ci->u_len > 1 || ci->l_len > 1 || - (ci->u_len > 0 && ci->l_len > 0) || - (ci->f_len != ci->l_len) || - (memcmp(ci->f_data, ci->l_data, ci->f_len * sizeof(ci->f_data[0])) != 0)); -} - -#ifndef USE_TEST -enum { - RUN_TYPE_U, - RUN_TYPE_L, - RUN_TYPE_UF, - RUN_TYPE_LF, - RUN_TYPE_UL, - RUN_TYPE_LSU, - RUN_TYPE_U2L_399_EXT2, - RUN_TYPE_UF_D20, - RUN_TYPE_UF_D1_EXT, - RUN_TYPE_U_EXT, - RUN_TYPE_LF_EXT, - RUN_TYPE_UF_EXT2, - RUN_TYPE_LF_EXT2, - RUN_TYPE_UF_EXT3, -}; -#endif - -const char *run_type_str[] = { - "U", - "L", - "UF", - "LF", - "UL", - "LSU", - "U2L_399_EXT2", - "UF_D20", - "UF_D1_EXT", - "U_EXT", - "LF_EXT", - "UF_EXT2", - "LF_EXT2", - "UF_EXT3", -}; - -typedef struct { - int code; - int len; - int type; - int data; - int ext_len; - int ext_data[3]; - int data_index; /* 'data' coming from the table */ -} TableEntry; - -static int simple_to_lower(CCInfo *tab, int c) -{ - if (tab[c].l_len != 1) - return c; - return tab[c].l_data[0]; -} - -/* code (17), len (7), type (4) */ - -void find_run_type(TableEntry *te, CCInfo *tab, int code) -{ - int is_lower, len; - CCInfo *ci, *ci1, *ci2; - - ci = &tab[code]; - ci1 = &tab[code + 1]; - ci2 = &tab[code + 2]; - te->code = code; - - if (ci->l_len == 1 && ci->l_data[0] == code + 2 && - ci->f_len == 1 && ci->f_data[0] == ci->l_data[0] && - ci->u_len == 0 && - - ci1->l_len == 1 && ci1->l_data[0] == code + 2 && - ci1->f_len == 1 && ci1->f_data[0] == ci1->l_data[0] && - ci1->u_len == 1 && ci1->u_data[0] == code && - - ci2->l_len == 0 && - ci2->f_len == 0 && - ci2->u_len == 1 && ci2->u_data[0] == code) { - te->len = 3; - te->data = 0; - te->type = RUN_TYPE_LSU; - return; - } - - if (is_complicated_case(ci)) { - len = 1; - while (code + len <= CHARCODE_MAX) { - ci1 = &tab[code + len]; - if (ci1->u_len != 1 || - ci1->u_data[0] != ci->u_data[0] + len || - ci1->l_len != 0 || - ci1->f_len != 1 || ci1->f_data[0] != ci1->u_data[0]) - break; - len++; - } - if (len > 1) { - te->len = len; - te->type = RUN_TYPE_UF; - te->data = ci->u_data[0]; - return; - } - - if (ci->l_len == 0 && - ci->u_len == 2 && ci->u_data[1] == 0x399 && - ci->f_len == 2 && ci->f_data[1] == 0x3B9 && - ci->f_data[0] == simple_to_lower(tab, ci->u_data[0])) { - len = 1; - while (code + len <= CHARCODE_MAX) { - ci1 = &tab[code + len]; - if (!(ci1->u_len == 2 && - ci1->u_data[1] == ci->u_data[1] && - ci1->u_data[0] == ci->u_data[0] + len && - ci1->f_len == 2 && - ci1->f_data[1] == ci->f_data[1] && - ci1->f_data[0] == ci->f_data[0] + len && - ci1->l_len == 0)) - break; - len++; - } - te->len = len; - te->type = RUN_TYPE_UF_EXT2; - te->ext_data[0] = ci->u_data[0]; - te->ext_data[1] = ci->u_data[1]; - te->ext_len = 2; - return; - } - - if (ci->u_len == 2 && ci->u_data[1] == 0x399 && - ci->l_len == 1 && - ci->f_len == 1 && ci->f_data[0] == ci->l_data[0]) { - len = 1; - while (code + len <= CHARCODE_MAX) { - ci1 = &tab[code + len]; - if (!(ci1->u_len == 2 && - ci1->u_data[1] == 0x399 && - ci1->u_data[0] == ci->u_data[0] + len && - ci1->l_len == 1 && - ci1->l_data[0] == ci->l_data[0] + len && - ci1->f_len == 1 && ci1->f_data[0] == ci1->l_data[0])) - break; - len++; - } - te->len = len; - te->type = RUN_TYPE_U2L_399_EXT2; - te->ext_data[0] = ci->u_data[0]; - te->ext_data[1] = ci->l_data[0]; - te->ext_len = 2; - return; - } - - if (ci->l_len == 1 && ci->u_len == 0 && ci->f_len == 0) { - len = 1; - while (code + len <= CHARCODE_MAX) { - ci1 = &tab[code + len]; - if (!(ci1->l_len == 1 && - ci1->l_data[0] == ci->l_data[0] + len && - ci1->u_len == 0 && ci1->f_len == 0)) - break; - len++; - } - te->len = len; - te->type = RUN_TYPE_L; - te->data = ci->l_data[0]; - return; - } - - if (ci->l_len == 0 && - ci->u_len == 1 && - ci->u_data[0] < 0x1000 && - ci->f_len == 1 && ci->f_data[0] == ci->u_data[0] + 0x20) { - te->len = 1; - te->type = RUN_TYPE_UF_D20; - te->data = ci->u_data[0]; - } else if (ci->l_len == 0 && - ci->u_len == 1 && - ci->f_len == 1 && ci->f_data[0] == ci->u_data[0] + 1) { - te->len = 1; - te->type = RUN_TYPE_UF_D1_EXT; - te->ext_data[0] = ci->u_data[0]; - te->ext_len = 1; - } else if (ci->l_len == 2 && ci->u_len == 0 && ci->f_len == 2 && - ci->l_data[0] == ci->f_data[0] && - ci->l_data[1] == ci->f_data[1]) { - te->len = 1; - te->type = RUN_TYPE_LF_EXT2; - te->ext_data[0] = ci->l_data[0]; - te->ext_data[1] = ci->l_data[1]; - te->ext_len = 2; - } else if (ci->u_len == 2 && ci->l_len == 0 && ci->f_len == 2 && - ci->f_data[0] == simple_to_lower(tab, ci->u_data[0]) && - ci->f_data[1] == simple_to_lower(tab, ci->u_data[1])) { - te->len = 1; - te->type = RUN_TYPE_UF_EXT2; - te->ext_data[0] = ci->u_data[0]; - te->ext_data[1] = ci->u_data[1]; - te->ext_len = 2; - } else if (ci->u_len == 3 && ci->l_len == 0 && ci->f_len == 3 && - ci->f_data[0] == simple_to_lower(tab, ci->u_data[0]) && - ci->f_data[1] == simple_to_lower(tab, ci->u_data[1]) && - ci->f_data[2] == simple_to_lower(tab, ci->u_data[2])) { - te->len = 1; - te->type = RUN_TYPE_UF_EXT3; - te->ext_data[0] = ci->u_data[0]; - te->ext_data[1] = ci->u_data[1]; - te->ext_data[2] = ci->u_data[2]; - te->ext_len = 3; - } else if (ci->u_len == 2 && ci->l_len == 0 && ci->f_len == 1) { - // U+FB05 LATIN SMALL LIGATURE LONG S T - assert(code == 0xFB05); - te->len = 1; - te->type = RUN_TYPE_UF_EXT2; - te->ext_data[0] = ci->u_data[0]; - te->ext_data[1] = ci->u_data[1]; - te->ext_len = 2; - } else if (ci->u_len == 3 && ci->l_len == 0 && ci->f_len == 1) { - // U+1FD3 GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA or - // U+1FE3 GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA - assert(code == 0x1FD3 || code == 0x1FE3); - te->len = 1; - te->type = RUN_TYPE_UF_EXT3; - te->ext_data[0] = ci->u_data[0]; - te->ext_data[1] = ci->u_data[1]; - te->ext_data[2] = ci->u_data[2]; - te->ext_len = 3; - } else { - printf("unsupported encoding case:\n"); - dump_cc_info(ci, code); - abort(); - } - } else { - /* look for a run of identical conversions */ - len = 0; - for(;;) { - if (code >= CHARCODE_MAX || len >= 126) - break; - ci = &tab[code + len]; - ci1 = &tab[code + len + 1]; - if (is_complicated_case(ci) || is_complicated_case(ci1)) { - break; - } - if (ci->l_len != 1 || ci->l_data[0] != code + len + 1) - break; - if (ci1->u_len != 1 || ci1->u_data[0] != code + len) - break; - len += 2; - } - if (len > 0) { - te->len = len; - te->type = RUN_TYPE_UL; - te->data = 0; - return; - } - - ci = &tab[code]; - is_lower = ci->l_len > 0; - len = 1; - while (code + len <= CHARCODE_MAX) { - ci1 = &tab[code + len]; - if (is_complicated_case(ci1)) - break; - if (is_lower) { - if (ci1->l_len != 1 || - ci1->l_data[0] != ci->l_data[0] + len) - break; - } else { - if (ci1->u_len != 1 || - ci1->u_data[0] != ci->u_data[0] + len) - break; - } - len++; - } - te->len = len; - if (is_lower) { - te->type = RUN_TYPE_LF; - te->data = ci->l_data[0]; - } else { - te->type = RUN_TYPE_U; - te->data = ci->u_data[0]; - } - } -} - -TableEntry conv_table[1000]; -int conv_table_len; -int ext_data[1000]; -int ext_data_len; - -void dump_case_conv_table1(void) -{ - int i, j; - const TableEntry *te; - - for(i = 0; i < conv_table_len; i++) { - te = &conv_table[i]; - printf("%05x %02x %-10s %05x", - te->code, te->len, run_type_str[te->type], te->data); - for(j = 0; j < te->ext_len; j++) { - printf(" %05x", te->ext_data[j]); - } - printf("\n"); - } - printf("table_len=%d ext_len=%d\n", conv_table_len, ext_data_len); -} - -int find_data_index(const TableEntry *conv_table, int len, int data) -{ - int i; - const TableEntry *te; - for(i = 0; i < len; i++) { - te = &conv_table[i]; - if (te->code == data) - return i; - } - return -1; -} - -int find_ext_data_index(int data) -{ - int i; - for(i = 0; i < ext_data_len; i++) { - if (ext_data[i] == data) - return i; - } - assert(ext_data_len < countof(ext_data)); - ext_data[ext_data_len++] = data; - return ext_data_len - 1; -} - -void build_conv_table(CCInfo *tab) -{ - int code, i, j; - CCInfo *ci; - TableEntry *te; - - te = conv_table; - for(code = 0; code <= CHARCODE_MAX; code++) { - ci = &tab[code]; - if (ci->u_len == 0 && ci->l_len == 0 && ci->f_len == 0) - continue; - assert(te - conv_table < countof(conv_table)); - find_run_type(te, tab, code); -#if 0 - if (te->type == RUN_TYPE_TODO) { - printf("TODO: "); - dump_cc_info(ci, code); - } -#endif - assert(te->len <= 127); - code += te->len - 1; - te++; - } - conv_table_len = te - conv_table; - - /* find the data index */ - for(i = 0; i < conv_table_len; i++) { - int data_index; - te = &conv_table[i]; - - switch(te->type) { - case RUN_TYPE_U: - case RUN_TYPE_L: - case RUN_TYPE_UF: - case RUN_TYPE_LF: - data_index = find_data_index(conv_table, conv_table_len, te->data); - if (data_index < 0) { - switch(te->type) { - case RUN_TYPE_U: - te->type = RUN_TYPE_U_EXT; - te->ext_len = 1; - te->ext_data[0] = te->data; - break; - case RUN_TYPE_LF: - te->type = RUN_TYPE_LF_EXT; - te->ext_len = 1; - te->ext_data[0] = te->data; - break; - default: - printf("%05x: index not found\n", te->code); - exit(1); - } - } else { - te->data_index = data_index; - } - break; - case RUN_TYPE_UF_D20: - te->data_index = te->data; - break; - } - } - - /* find the data index for ext_data */ - for(i = 0; i < conv_table_len; i++) { - te = &conv_table[i]; - if (te->type == RUN_TYPE_UF_EXT3) { - int p, v; - v = 0; - for(j = 0; j < 3; j++) { - p = find_ext_data_index(te->ext_data[j]); - assert(p < 16); - v = (v << 4) | p; - } - te->data_index = v; - } - } - - for(i = 0; i < conv_table_len; i++) { - te = &conv_table[i]; - if (te->type == RUN_TYPE_LF_EXT2 || - te->type == RUN_TYPE_UF_EXT2 || - te->type == RUN_TYPE_U2L_399_EXT2) { - int p, v; - v = 0; - for(j = 0; j < 2; j++) { - p = find_ext_data_index(te->ext_data[j]); - assert(p < 64); - v = (v << 6) | p; - } - te->data_index = v; - } - } - - for(i = 0; i < conv_table_len; i++) { - te = &conv_table[i]; - if (te->type == RUN_TYPE_UF_D1_EXT || - te->type == RUN_TYPE_U_EXT || - te->type == RUN_TYPE_LF_EXT) { - te->data_index = find_ext_data_index(te->ext_data[0]); - } - } -#ifdef DUMP_CASE_CONV_TABLE - dump_case_conv_table1(); -#endif -} - -void dump_case_conv_table(FILE *f) -{ - int i; - uint32_t v; - const TableEntry *te; - - total_tables++; - total_table_bytes += conv_table_len * sizeof(uint32_t); - fprintf(f, "static const uint32_t case_conv_table1[%d] = {", conv_table_len); - for(i = 0; i < conv_table_len; i++) { - if (i % 4 == 0) - fprintf(f, "\n "); - te = &conv_table[i]; - v = te->code << (32 - 17); - v |= te->len << (32 - 17 - 7); - v |= te->type << (32 - 17 - 7 - 4); - v |= te->data_index >> 8; - fprintf(f, " 0x%08x,", v); - } - fprintf(f, "\n};\n\n"); - - total_tables++; - total_table_bytes += conv_table_len; - fprintf(f, "static const uint8_t case_conv_table2[%d] = {", conv_table_len); - for(i = 0; i < conv_table_len; i++) { - if (i % 8 == 0) - fprintf(f, "\n "); - te = &conv_table[i]; - fprintf(f, " 0x%02x,", te->data_index & 0xff); - } - fprintf(f, "\n};\n\n"); - - total_tables++; - total_table_bytes += ext_data_len * sizeof(uint16_t); - fprintf(f, "static const uint16_t case_conv_ext[%d] = {", ext_data_len); - for(i = 0; i < ext_data_len; i++) { - if (i % 8 == 0) - fprintf(f, "\n "); - fprintf(f, " 0x%04x,", ext_data[i]); - } - fprintf(f, "\n};\n\n"); -} - - -static CCInfo *global_tab; - -static int sp_cc_cmp(const void *p1, const void *p2) -{ - CCInfo *c1 = &global_tab[*(const int *)p1]; - CCInfo *c2 = &global_tab[*(const int *)p2]; - if (c1->f_len < c2->f_len) { - return -1; - } else if (c2->f_len < c1->f_len) { - return 1; - } else { - return memcmp(c1->f_data, c2->f_data, sizeof(c1->f_data[0]) * c1->f_len); - } -} - -/* dump the case special cases (multi character results which are - identical and need specific handling in lre_canonicalize() */ -void dump_case_folding_special_cases(CCInfo *tab) -{ - int i, len, j; - int *perm; - - perm = malloc(sizeof(perm[0]) * (CHARCODE_MAX + 1)); - for(i = 0; i <= CHARCODE_MAX; i++) - perm[i] = i; - global_tab = tab; - qsort(perm, CHARCODE_MAX + 1, sizeof(perm[0]), sp_cc_cmp); - for(i = 0; i <= CHARCODE_MAX;) { - if (tab[perm[i]].f_len <= 1) { - i++; - } else { - len = 1; - while ((i + len) <= CHARCODE_MAX && !sp_cc_cmp(&perm[i], &perm[i + len])) - len++; - - if (len > 1) { - for(j = i; j < i + len; j++) - dump_cc_info(&tab[perm[j]], perm[j]); - } - i += len; - } - } - free(perm); - global_tab = NULL; -} - - -int tabcmp(const int *tab1, const int *tab2, int n) -{ - int i; - for(i = 0; i < n; i++) { - if (tab1[i] != tab2[i]) - return -1; - } - return 0; -} - -void dump_str(const char *str, const int *buf, int len) -{ - int i; - printf("%s=", str); - for(i = 0; i < len; i++) - printf(" %05x", buf[i]); - printf("\n"); -} - -void compute_internal_props(void) -{ - int i; - BOOL has_ul; - - for(i = 0; i <= CHARCODE_MAX; i++) { - CCInfo *ci = &unicode_db[i]; - has_ul = (ci->u_len != 0 || ci->l_len != 0 || ci->f_len != 0); - if (has_ul) { - assert(get_prop(i, PROP_Cased)); - } else { - set_prop(i, PROP_Cased1, get_prop(i, PROP_Cased)); - } - set_prop(i, PROP_ID_Continue1, - get_prop(i, PROP_ID_Continue) & (get_prop(i, PROP_ID_Start) ^ 1)); - set_prop(i, PROP_XID_Start1, - get_prop(i, PROP_ID_Start) ^ get_prop(i, PROP_XID_Start)); - set_prop(i, PROP_XID_Continue1, - get_prop(i, PROP_ID_Continue) ^ get_prop(i, PROP_XID_Continue)); - set_prop(i, PROP_Changes_When_Titlecased1, - get_prop(i, PROP_Changes_When_Titlecased) ^ (ci->u_len != 0)); - set_prop(i, PROP_Changes_When_Casefolded1, - get_prop(i, PROP_Changes_When_Casefolded) ^ (ci->f_len != 0)); - /* XXX: reduce table size (438 bytes) */ - set_prop(i, PROP_Changes_When_NFKC_Casefolded1, - get_prop(i, PROP_Changes_When_NFKC_Casefolded) ^ (ci->f_len != 0)); -#if 0 - /* TEST */ -#define M(x) (1U << GCAT_ ## x) - { - int b; - b = ((M(Mn) | M(Cf) | M(Lm) | M(Sk)) >> - unicode_db[i].general_category) & 1; - set_prop(i, PROP_Cased1, - get_prop(i, PROP_Case_Ignorable) ^ b); - } -#undef M -#endif - } -} - -void dump_byte_table(FILE *f, const char *cname, const uint8_t *tab, int len) -{ - int i; - - total_tables++; - total_table_bytes += len; - fprintf(f, "static const uint8_t %s[%d] = {", cname, len); - for(i = 0; i < len; i++) { - if (i % 8 == 0) - fprintf(f, "\n "); - fprintf(f, " 0x%02x,", tab[i]); - } - fprintf(f, "\n};\n\n"); -} - -void dump_index_table(FILE *f, const char *cname, const uint8_t *tab, int len) -{ - int i, code, offset; - - total_index++; - total_index_bytes += len; - fprintf(f, "static const uint8_t %s[%d] = {\n", cname, len); - for(i = 0; i < len; i += 3) { - code = tab[i] + (tab[i+1] << 8) + ((tab[i+2] & 0x1f) << 16); - offset = ((i / 3) + 1) * 32 + (tab[i+2] >> 5); - fprintf(f, " 0x%02x, 0x%02x, 0x%02x,", tab[i], tab[i+1], tab[i+2]); - fprintf(f, " // %6.5X at %d%s\n", code, offset, - i == len - 3 ? " (upper bound)" : ""); - } - fprintf(f, "};\n\n"); -} - -#define PROP_BLOCK_LEN 32 - -void build_prop_table(FILE *f, const char *name, int prop_index, BOOL add_index) -{ - int i, j, n, v, offset, code; - DynBuf dbuf_s, *dbuf = &dbuf_s; - DynBuf dbuf1_s, *dbuf1 = &dbuf1_s; - DynBuf dbuf2_s, *dbuf2 = &dbuf2_s; - const uint32_t *buf; - int buf_len, block_end_pos, bit; - char cname[128]; - - dbuf_init(dbuf1); - - for(i = 0; i <= CHARCODE_MAX;) { - v = get_prop(i, prop_index); - j = i + 1; - while (j <= CHARCODE_MAX && get_prop(j, prop_index) == v) { - j++; - } - n = j - i; - if (j == (CHARCODE_MAX + 1) && v == 0) - break; /* no need to encode last zero run */ - //printf("%05x: %d %d\n", i, n, v); - dbuf_put_u32(dbuf1, n - 1); - i += n; - } - - dbuf_init(dbuf); - dbuf_init(dbuf2); - buf = (uint32_t *)dbuf1->buf; - buf_len = dbuf1->size / sizeof(buf[0]); - - /* the first value is assumed to be 0 */ - assert(get_prop(0, prop_index) == 0); - - block_end_pos = PROP_BLOCK_LEN; - i = 0; - code = 0; - bit = 0; - while (i < buf_len) { - if (add_index && dbuf->size >= block_end_pos && bit == 0) { - offset = (dbuf->size - block_end_pos); - /* XXX: offset could be larger in case of runs of small - lengths. Could add code to change the encoding to - prevent it at the expense of one byte loss */ - assert(offset <= 7); - v = code | (offset << 21); - dbuf_putc(dbuf2, v); - dbuf_putc(dbuf2, v >> 8); - dbuf_putc(dbuf2, v >> 16); - block_end_pos += PROP_BLOCK_LEN; - } - - /* Compressed byte encoding: - 00..3F: 2 packed lengths: 3-bit + 3-bit - 40..5F: 5-bits plus extra byte for length - 60..7F: 5-bits plus 2 extra bytes for length - 80..FF: 7-bit length - lengths must be incremented to get character count - Ranges alternate between false and true return value. - */ - v = buf[i]; - code += v + 1; - bit ^= 1; - if (v < 8 && (i + 1) < buf_len && buf[i + 1] < 8) { - code += buf[i + 1] + 1; - bit ^= 1; - dbuf_putc(dbuf, (v << 3) | buf[i + 1]); - i += 2; - } else if (v < 128) { - dbuf_putc(dbuf, 0x80 + v); - i++; - } else if (v < (1 << 13)) { - dbuf_putc(dbuf, 0x40 + (v >> 8)); - dbuf_putc(dbuf, v); - i++; - } else { - assert(v < (1 << 21)); - dbuf_putc(dbuf, 0x60 + (v >> 16)); - dbuf_putc(dbuf, v >> 8); - dbuf_putc(dbuf, v); - i++; - } - } - - if (add_index) { - /* last index entry */ - v = code; - dbuf_putc(dbuf2, v); - dbuf_putc(dbuf2, v >> 8); - dbuf_putc(dbuf2, v >> 16); - } - -#ifdef DUMP_TABLE_SIZE - printf("prop %s: length=%d bytes\n", unicode_prop_name[prop_index], - (int)(dbuf->size + dbuf2->size)); -#endif - snprintf(cname, sizeof(cname), "unicode_prop_%s_table", unicode_prop_name[prop_index]); - dump_byte_table(f, cname, dbuf->buf, dbuf->size); - if (add_index) { - snprintf(cname, sizeof(cname), "unicode_prop_%s_index", unicode_prop_name[prop_index]); - dump_index_table(f, cname, dbuf2->buf, dbuf2->size); - } - - dbuf_free(dbuf); - dbuf_free(dbuf1); - dbuf_free(dbuf2); -} - -void build_flags_tables(FILE *f) -{ - build_prop_table(f, "Cased1", PROP_Cased1, TRUE); - build_prop_table(f, "Case_Ignorable", PROP_Case_Ignorable, TRUE); - build_prop_table(f, "ID_Start", PROP_ID_Start, TRUE); - build_prop_table(f, "ID_Continue1", PROP_ID_Continue1, TRUE); -} - -void dump_name_table(FILE *f, const char *cname, const char **tab_name, int len, - const char **tab_short_name) -{ - int i, w, maxw; - - maxw = 0; - for(i = 0; i < len; i++) { - w = strlen(tab_name[i]); - if (tab_short_name && tab_short_name[i][0] != '\0') { - w += 1 + strlen(tab_short_name[i]); - } - if (maxw < w) - maxw = w; - } - - /* generate a sequence of strings terminated by an empty string */ - fprintf(f, "static const char %s[] =\n", cname); - for(i = 0; i < len; i++) { - fprintf(f, " \""); - w = fprintf(f, "%s", tab_name[i]); - if (tab_short_name && tab_short_name[i][0] != '\0') { - w += fprintf(f, ",%s", tab_short_name[i]); - } - fprintf(f, "\"%*s\"\\0\"\n", 1 + maxw - w, ""); - } - fprintf(f, ";\n\n"); -} - -void build_general_category_table(FILE *f) -{ - int i, v, j, n, n1; - DynBuf dbuf_s, *dbuf = &dbuf_s; -#ifdef DUMP_TABLE_SIZE - int cw_count, cw_len_count[4], cw_start; -#endif - - fprintf(f, "typedef enum {\n"); - for(i = 0; i < GCAT_COUNT; i++) - fprintf(f, " UNICODE_GC_%s,\n", unicode_gc_name[i]); - fprintf(f, " UNICODE_GC_COUNT,\n"); - fprintf(f, "} UnicodeGCEnum;\n\n"); - - dump_name_table(f, "unicode_gc_name_table", - unicode_gc_name, GCAT_COUNT, - unicode_gc_short_name); - - - dbuf_init(dbuf); -#ifdef DUMP_TABLE_SIZE - cw_count = 0; - for(i = 0; i < 4; i++) - cw_len_count[i] = 0; -#endif - for(i = 0; i <= CHARCODE_MAX;) { - v = unicode_db[i].general_category; - j = i + 1; - while (j <= CHARCODE_MAX && unicode_db[j].general_category == v) - j++; - n = j - i; - /* compress Lu/Ll runs */ - if (v == GCAT_Lu) { - n1 = 1; - while ((i + n1) <= CHARCODE_MAX && unicode_db[i + n1].general_category == (v + (n1 & 1))) { - n1++; - } - if (n1 > n) { - v = 31; - n = n1; - } - } - // printf("%05x %05x %d\n", i, n, v); - n--; -#ifdef DUMP_TABLE_SIZE - cw_count++; - cw_start = dbuf->size; -#endif - if (n < 7) { - dbuf_putc(dbuf, (n << 5) | v); - } else if (n < 7 + 128) { - n1 = n - 7; - assert(n1 < 128); - dbuf_putc(dbuf, (0xf << 5) | v); - dbuf_putc(dbuf, n1); - } else if (n < 7 + 128 + (1 << 14)) { - n1 = n - (7 + 128); - assert(n1 < (1 << 14)); - dbuf_putc(dbuf, (0xf << 5) | v); - dbuf_putc(dbuf, (n1 >> 8) + 128); - dbuf_putc(dbuf, n1); - } else { - n1 = n - (7 + 128 + (1 << 14)); - assert(n1 < (1 << 22)); - dbuf_putc(dbuf, (0xf << 5) | v); - dbuf_putc(dbuf, (n1 >> 16) + 128 + 64); - dbuf_putc(dbuf, n1 >> 8); - dbuf_putc(dbuf, n1); - } -#ifdef DUMP_TABLE_SIZE - cw_len_count[dbuf->size - cw_start - 1]++; -#endif - i += n + 1; - } -#ifdef DUMP_TABLE_SIZE - printf("general category: %d entries [", cw_count); - for(i = 0; i < 4; i++) - printf(" %d", cw_len_count[i]); - printf(" ], length=%d bytes\n", (int)dbuf->size); -#endif - - dump_byte_table(f, "unicode_gc_table", dbuf->buf, dbuf->size); - - dbuf_free(dbuf); -} - -void build_script_table(FILE *f) -{ - int i, v, j, n, n1, type; - DynBuf dbuf_s, *dbuf = &dbuf_s; -#ifdef DUMP_TABLE_SIZE - int cw_count, cw_len_count[4], cw_start; -#endif - - fprintf(f, "typedef enum {\n"); - for(i = 0; i < SCRIPT_COUNT; i++) - fprintf(f, " UNICODE_SCRIPT_%s,\n", unicode_script_name[i]); - fprintf(f, " UNICODE_SCRIPT_COUNT,\n"); - fprintf(f, "} UnicodeScriptEnum;\n\n"); - - dump_name_table(f, "unicode_script_name_table", - unicode_script_name, SCRIPT_COUNT, - unicode_script_short_name); - - dbuf_init(dbuf); -#ifdef DUMP_TABLE_SIZE - cw_count = 0; - for(i = 0; i < 4; i++) - cw_len_count[i] = 0; -#endif - for(i = 0; i <= CHARCODE_MAX;) { - v = unicode_db[i].script; - j = i + 1; - while (j <= CHARCODE_MAX && unicode_db[j].script == v) - j++; - n = j - i; - if (v == 0 && j == (CHARCODE_MAX + 1)) - break; - // printf("%05x %05x %d\n", i, n, v); - n--; -#ifdef DUMP_TABLE_SIZE - cw_count++; - cw_start = dbuf->size; -#endif - if (v == 0) - type = 0; - else - type = 1; - if (n < 96) { - dbuf_putc(dbuf, n | (type << 7)); - } else if (n < 96 + (1 << 12)) { - n1 = n - 96; - assert(n1 < (1 << 12)); - dbuf_putc(dbuf, ((n1 >> 8) + 96) | (type << 7)); - dbuf_putc(dbuf, n1); - } else { - n1 = n - (96 + (1 << 12)); - assert(n1 < (1 << 20)); - dbuf_putc(dbuf, ((n1 >> 16) + 112) | (type << 7)); - dbuf_putc(dbuf, n1 >> 8); - dbuf_putc(dbuf, n1); - } - if (type != 0) - dbuf_putc(dbuf, v); - -#ifdef DUMP_TABLE_SIZE - cw_len_count[dbuf->size - cw_start - 1]++; -#endif - i += n + 1; - } -#ifdef DUMP_TABLE_SIZE - printf("script: %d entries [", cw_count); - for(i = 0; i < 4; i++) - printf(" %d", cw_len_count[i]); - printf(" ], length=%d bytes\n", (int)dbuf->size); -#endif - - dump_byte_table(f, "unicode_script_table", dbuf->buf, dbuf->size); - - dbuf_free(dbuf); -} - -void build_script_ext_table(FILE *f) -{ - int i, j, n, n1, script_ext_len; - DynBuf dbuf_s, *dbuf = &dbuf_s; -#if defined(DUMP_TABLE_SIZE) - int cw_count = 0; -#endif - - dbuf_init(dbuf); - for(i = 0; i <= CHARCODE_MAX;) { - script_ext_len = unicode_db[i].script_ext_len; - j = i + 1; - while (j <= CHARCODE_MAX && - unicode_db[j].script_ext_len == script_ext_len && - !memcmp(unicode_db[j].script_ext, unicode_db[i].script_ext, - script_ext_len)) { - j++; - } - n = j - i; -#if defined(DUMP_TABLE_SIZE) - cw_count++; -#endif - n--; - if (n < 128) { - dbuf_putc(dbuf, n); - } else if (n < 128 + (1 << 14)) { - n1 = n - 128; - assert(n1 < (1 << 14)); - dbuf_putc(dbuf, (n1 >> 8) + 128); - dbuf_putc(dbuf, n1); - } else { - n1 = n - (128 + (1 << 14)); - assert(n1 < (1 << 22)); - dbuf_putc(dbuf, (n1 >> 16) + 128 + 64); - dbuf_putc(dbuf, n1 >> 8); - dbuf_putc(dbuf, n1); - } - dbuf_putc(dbuf, script_ext_len); - for(j = 0; j < script_ext_len; j++) - dbuf_putc(dbuf, unicode_db[i].script_ext[j]); - i += n + 1; - } -#ifdef DUMP_TABLE_SIZE - printf("script_ext: %d entries", cw_count); - printf(", length=%d bytes\n", (int)dbuf->size); -#endif - - dump_byte_table(f, "unicode_script_ext_table", dbuf->buf, dbuf->size); - - dbuf_free(dbuf); -} - -/* the following properties are synthetized so no table is necessary */ -#define PROP_TABLE_COUNT PROP_ASCII - -void build_prop_list_table(FILE *f) -{ - int i; - - for(i = 0; i < PROP_TABLE_COUNT; i++) { - if (i == PROP_ID_Start || - i == PROP_Case_Ignorable || - i == PROP_ID_Continue1) { - /* already generated */ - } else { - build_prop_table(f, unicode_prop_name[i], i, FALSE); - } - } - - fprintf(f, "typedef enum {\n"); - for(i = 0; i < PROP_COUNT; i++) - fprintf(f, " UNICODE_PROP_%s,\n", unicode_prop_name[i]); - fprintf(f, " UNICODE_PROP_COUNT,\n"); - fprintf(f, "} UnicodePropertyEnum;\n\n"); - - i = PROP_ASCII_Hex_Digit; - dump_name_table(f, "unicode_prop_name_table", - unicode_prop_name + i, PROP_XID_Start - i + 1, - unicode_prop_short_name + i); - - fprintf(f, "static const uint8_t * const unicode_prop_table[] = {\n"); - for(i = 0; i < PROP_TABLE_COUNT; i++) { - fprintf(f, " unicode_prop_%s_table,\n", unicode_prop_name[i]); - } - fprintf(f, "};\n\n"); - - fprintf(f, "static const uint16_t unicode_prop_len_table[] = {\n"); - for(i = 0; i < PROP_TABLE_COUNT; i++) { - fprintf(f, " countof(unicode_prop_%s_table),\n", unicode_prop_name[i]); - } - fprintf(f, "};\n\n"); -} - -static BOOL is_emoji_hair_color(uint32_t c) -{ - return (c >= 0x1F9B0 && c <= 0x1F9B3); -} - -#define EMOJI_MOD_NONE 0 -#define EMOJI_MOD_TYPE1 1 -#define EMOJI_MOD_TYPE2 2 -#define EMOJI_MOD_TYPE2D 3 - -static BOOL mark_zwj_string(REStringList *sl, uint32_t *buf, int len, int mod_type, int *mod_pos, - int hc_pos, BOOL mark_flag) -{ - REString *p; - int i, n_mod, i0, i1, hc_count, j; - -#if 0 - if (mark_flag) - printf("mod_type=%d\n", mod_type); -#endif - - switch(mod_type) { - case EMOJI_MOD_NONE: - n_mod = 1; - break; - case EMOJI_MOD_TYPE1: - n_mod = 5; - break; - case EMOJI_MOD_TYPE2: - n_mod = 25; - break; - case EMOJI_MOD_TYPE2D: - n_mod = 20; - break; - default: - assert(0); - } - if (hc_pos >= 0) - hc_count = 4; - else - hc_count = 1; - /* check that all the related strings are present */ - for(j = 0; j < hc_count; j++) { - for(i = 0; i < n_mod; i++) { - switch(mod_type) { - case EMOJI_MOD_NONE: - break; - case EMOJI_MOD_TYPE1: - buf[mod_pos[0]] = 0x1f3fb + i; - break; - case EMOJI_MOD_TYPE2: - case EMOJI_MOD_TYPE2D: - i0 = i / 5; - i1 = i % 5; - /* avoid identical values */ - if (mod_type == EMOJI_MOD_TYPE2D && i0 >= i1) - i0++; - buf[mod_pos[0]] = 0x1f3fb + i0; - buf[mod_pos[1]] = 0x1f3fb + i1; - break; - default: - assert(0); - } - - if (hc_pos >= 0) - buf[hc_pos] = 0x1F9B0 + j; - - p = re_string_find(sl, len, buf, FALSE); - if (!p) - return FALSE; - if (mark_flag) - p->flags |= 1; - } - } - return TRUE; -} - -static void zwj_encode_string(DynBuf *dbuf, const uint32_t *buf, int len, int mod_type, int *mod_pos, - int hc_pos) -{ - int i, j; - int c, code; - uint32_t buf1[SEQ_MAX_LEN]; - - j = 0; - for(i = 0; i < len;) { - c = buf[i++]; - if (c >= 0x2000 && c <= 0x2fff) { - code = c - 0x2000; - } else if (c >= 0x1f000 && c <= 0x1ffff) { - code = c - 0x1f000 + 0x1000; - } else { - assert(0); - } - if (i < len && is_emoji_modifier(buf[i])) { - /* modifier */ - code |= (mod_type << 13); - i++; - } - if (i < len && buf[i] == 0xfe0f) { - /* presentation selector present */ - code |= 0x8000; - i++; - } - if (i < len) { - /* zero width join */ - assert(buf[i] == 0x200d); - i++; - } - buf1[j++] = code; - } - dbuf_putc(dbuf, j); - for(i = 0; i < j; i++) { - dbuf_putc(dbuf, buf1[i]); - dbuf_putc(dbuf, buf1[i] >> 8); - } -} - -static void build_rgi_emoji_zwj_sequence(FILE *f, REStringList *sl) -{ - int mod_pos[2], mod_count, hair_color_pos, j, h; - REString *p; - uint32_t buf[SEQ_MAX_LEN]; - DynBuf dbuf; - -#if 0 - { - for(h = 0; h < sl->hash_size; h++) { - for(p = sl->hash_table[h]; p != NULL; p = p->next) { - for(j = 0; j < p->len; j++) - printf(" %04x", p->buf[j]); - printf("\n"); - } - } - exit(0); - } -#endif - // printf("rgi_emoji_zwj_sequence: n=%d\n", sl->n_strings); - - dbuf_init(&dbuf); - - /* avoid duplicating strings with emoji modifiers or hair colors */ - for(h = 0; h < sl->hash_size; h++) { - for(p = sl->hash_table[h]; p != NULL; p = p->next) { - if (p->flags) /* already examined */ - continue; - mod_count = 0; - hair_color_pos = -1; - for(j = 0; j < p->len; j++) { - if (is_emoji_modifier(p->buf[j])) { - assert(mod_count < 2); - mod_pos[mod_count++] = j; - } else if (is_emoji_hair_color(p->buf[j])) { - hair_color_pos = j; - } - buf[j] = p->buf[j]; - } - - if (mod_count != 0 || hair_color_pos >= 0) { - int mod_type; - if (mod_count == 0) - mod_type = EMOJI_MOD_NONE; - else if (mod_count == 1) - mod_type = EMOJI_MOD_TYPE1; - else - mod_type = EMOJI_MOD_TYPE2; - - if (mark_zwj_string(sl, buf, p->len, mod_type, mod_pos, hair_color_pos, FALSE)) { - mark_zwj_string(sl, buf, p->len, mod_type, mod_pos, hair_color_pos, TRUE); - } else if (mod_type == EMOJI_MOD_TYPE2) { - mod_type = EMOJI_MOD_TYPE2D; - if (mark_zwj_string(sl, buf, p->len, mod_type, mod_pos, hair_color_pos, FALSE)) { - mark_zwj_string(sl, buf, p->len, mod_type, mod_pos, hair_color_pos, TRUE); - } else { - dump_str("not_found", (int *)p->buf, p->len); - goto keep; - } - } - if (hair_color_pos >= 0) - buf[hair_color_pos] = 0x1f9b0; - /* encode the string */ - zwj_encode_string(&dbuf, buf, p->len, mod_type, mod_pos, hair_color_pos); - } else { - keep: - zwj_encode_string(&dbuf, buf, p->len, EMOJI_MOD_NONE, NULL, -1); - } - } - } - - /* Encode */ - dump_byte_table(f, "unicode_rgi_emoji_zwj_sequence", dbuf.buf, dbuf.size); - - dbuf_free(&dbuf); -} - -void build_sequence_prop_list_table(FILE *f) -{ - int i; - fprintf(f, "typedef enum {\n"); - for(i = 0; i < SEQUENCE_PROP_COUNT; i++) - fprintf(f, " UNICODE_SEQUENCE_PROP_%s,\n", unicode_sequence_prop_name[i]); - fprintf(f, " UNICODE_SEQUENCE_PROP_COUNT,\n"); - fprintf(f, "} UnicodeSequencePropertyEnum;\n\n"); - - dump_name_table(f, "unicode_sequence_prop_name_table", - unicode_sequence_prop_name, SEQUENCE_PROP_COUNT, NULL); - - dump_byte_table(f, "unicode_rgi_emoji_tag_sequence", rgi_emoji_tag_sequence.buf, rgi_emoji_tag_sequence.size); - - build_rgi_emoji_zwj_sequence(f, &rgi_emoji_zwj_sequence); -} - -#ifdef USE_TEST -int check_conv(uint32_t *res, uint32_t c, int conv_type) -{ - return lre_case_conv(res, c, conv_type); -} - -void check_case_conv(void) -{ - CCInfo *tab = unicode_db; - uint32_t res[3]; - int l, error; - CCInfo ci_s, *ci1, *ci = &ci_s; - int code; - - for(code = 0; code <= CHARCODE_MAX; code++) { - ci1 = &tab[code]; - *ci = *ci1; - if (ci->l_len == 0) { - ci->l_len = 1; - ci->l_data[0] = code; - } - if (ci->u_len == 0) { - ci->u_len = 1; - ci->u_data[0] = code; - } - if (ci->f_len == 0) { - ci->f_len = 1; - ci->f_data[0] = code; - } - - error = 0; - l = check_conv(res, code, 0); - if (l != ci->u_len || tabcmp((int *)res, ci->u_data, l)) { - printf("ERROR: L\n"); - error++; - } - l = check_conv(res, code, 1); - if (l != ci->l_len || tabcmp((int *)res, ci->l_data, l)) { - printf("ERROR: U\n"); - error++; - } - l = check_conv(res, code, 2); - if (l != ci->f_len || tabcmp((int *)res, ci->f_data, l)) { - printf("ERROR: F\n"); - error++; - } - if (error) { - dump_cc_info(ci, code); - exit(1); - } - } -} - -#ifdef PROFILE -static int64_t get_time_ns(void) -{ - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (int64_t)ts.tv_sec * 1000000000 + ts.tv_nsec; -} -#endif - - -void check_flags(void) -{ - int c; - BOOL flag_ref, flag; - for(c = 0; c <= CHARCODE_MAX; c++) { - flag_ref = get_prop(c, PROP_Cased); - flag = !!lre_is_cased(c); - if (flag != flag_ref) { - printf("ERROR: c=%05x cased=%d ref=%d\n", - c, flag, flag_ref); - exit(1); - } - - flag_ref = get_prop(c, PROP_Case_Ignorable); - flag = !!lre_is_case_ignorable(c); - if (flag != flag_ref) { - printf("ERROR: c=%05x case_ignorable=%d ref=%d\n", - c, flag, flag_ref); - exit(1); - } - - flag_ref = get_prop(c, PROP_ID_Start); - flag = !!lre_is_id_start(c); - if (flag != flag_ref) { - printf("ERROR: c=%05x id_start=%d ref=%d\n", - c, flag, flag_ref); - exit(1); - } - - flag_ref = get_prop(c, PROP_ID_Continue); - flag = !!lre_is_id_continue(c); - if (flag != flag_ref) { - printf("ERROR: c=%05x id_cont=%d ref=%d\n", - c, flag, flag_ref); - exit(1); - } - } -#ifdef PROFILE - { - int64_t ti, count; - ti = get_time_ns(); - count = 0; - for(c = 0x20; c <= 0xffff; c++) { - flag_ref = get_prop(c, PROP_ID_Start); - flag = !!lre_is_id_start(c); - assert(flag == flag_ref); - count++; - } - ti = get_time_ns() - ti; - printf("flags time=%0.1f ns/char\n", - (double)ti / count); - } -#endif -} - -#endif - -#define CC_BLOCK_LEN 32 - -void build_cc_table(FILE *f) -{ - // Compress combining class table - // see: https://www.unicode.org/reports/tr44/#Canonical_Combining_Class_Values - int i, cc, n, type, n1, block_end_pos; - DynBuf dbuf_s, *dbuf = &dbuf_s; - DynBuf dbuf1_s, *dbuf1 = &dbuf1_s; -#if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE) - int cw_len_tab[3], cw_start, cc_table_len; -#endif - uint32_t v; - - dbuf_init(dbuf); - dbuf_init(dbuf1); -#if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE) - cc_table_len = 0; - for(i = 0; i < countof(cw_len_tab); i++) - cw_len_tab[i] = 0; -#endif - block_end_pos = CC_BLOCK_LEN; - for(i = 0; i <= CHARCODE_MAX;) { - cc = unicode_db[i].combining_class; - assert(cc <= 255); - /* check increasing values */ - n = 1; - while ((i + n) <= CHARCODE_MAX && - unicode_db[i + n].combining_class == (cc + n)) - n++; - if (n >= 2) { - type = 1; - } else { - type = 0; - n = 1; - while ((i + n) <= CHARCODE_MAX && - unicode_db[i + n].combining_class == cc) - n++; - } - /* no need to encode the last run */ - if (cc == 0 && (i + n - 1) == CHARCODE_MAX) - break; -#ifdef DUMP_CC_TABLE - printf("%05x %6d %d %d\n", i, n, type, cc); -#endif - if (type == 0) { - if (cc == 0) - type = 2; - else if (cc == 230) - type = 3; - } - n1 = n - 1; - - /* add an entry to the index if necessary */ - if (dbuf->size >= block_end_pos) { - v = i | ((dbuf->size - block_end_pos) << 21); - dbuf_putc(dbuf1, v); - dbuf_putc(dbuf1, v >> 8); - dbuf_putc(dbuf1, v >> 16); - block_end_pos += CC_BLOCK_LEN; - } -#if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE) - cw_start = dbuf->size; -#endif - /* Compressed run length encoding: - - 2 high order bits are combining class type - - 0:0, 1:230, 2:extra byte linear progression, 3:extra byte - - 00..2F: range length (add 1) - - 30..37: 3-bit range-length + 1 extra byte - - 38..3F: 3-bit range-length + 2 extra byte - */ - if (n1 < 48) { - dbuf_putc(dbuf, n1 | (type << 6)); - } else if (n1 < 48 + (1 << 11)) { - n1 -= 48; - dbuf_putc(dbuf, ((n1 >> 8) + 48) | (type << 6)); - dbuf_putc(dbuf, n1); - } else { - n1 -= 48 + (1 << 11); - assert(n1 < (1 << 20)); - dbuf_putc(dbuf, ((n1 >> 16) + 56) | (type << 6)); - dbuf_putc(dbuf, n1 >> 8); - dbuf_putc(dbuf, n1); - } -#if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE) - cw_len_tab[dbuf->size - cw_start - 1]++; - cc_table_len++; -#endif - if (type == 0 || type == 1) - dbuf_putc(dbuf, cc); - i += n; - } - - /* last index entry */ - v = i; - dbuf_putc(dbuf1, v); - dbuf_putc(dbuf1, v >> 8); - dbuf_putc(dbuf1, v >> 16); - - dump_byte_table(f, "unicode_cc_table", dbuf->buf, dbuf->size); - dump_index_table(f, "unicode_cc_index", dbuf1->buf, dbuf1->size); - -#if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE) - printf("CC table: size=%d (%d entries) [", - (int)(dbuf->size + dbuf1->size), - cc_table_len); - for(i = 0; i < countof(cw_len_tab); i++) - printf(" %d", cw_len_tab[i]); - printf(" ]\n"); -#endif - dbuf_free(dbuf); - dbuf_free(dbuf1); -} - -/* maximum length of decomposition: 18 chars (1), then 8 */ -#ifndef USE_TEST -typedef enum { - DECOMP_TYPE_C1, /* 16 bit char */ - DECOMP_TYPE_L1, /* 16 bit char table */ - DECOMP_TYPE_L2, - DECOMP_TYPE_L3, - DECOMP_TYPE_L4, - DECOMP_TYPE_L5, /* XXX: not used */ - DECOMP_TYPE_L6, /* XXX: could remove */ - DECOMP_TYPE_L7, /* XXX: could remove */ - DECOMP_TYPE_LL1, /* 18 bit char table */ - DECOMP_TYPE_LL2, - DECOMP_TYPE_S1, /* 8 bit char table */ - DECOMP_TYPE_S2, - DECOMP_TYPE_S3, - DECOMP_TYPE_S4, - DECOMP_TYPE_S5, - DECOMP_TYPE_I1, /* increment 16 bit char value */ - DECOMP_TYPE_I2_0, - DECOMP_TYPE_I2_1, - DECOMP_TYPE_I3_1, - DECOMP_TYPE_I3_2, - DECOMP_TYPE_I4_1, - DECOMP_TYPE_I4_2, - DECOMP_TYPE_B1, /* 16 bit base + 8 bit offset */ - DECOMP_TYPE_B2, - DECOMP_TYPE_B3, - DECOMP_TYPE_B4, - DECOMP_TYPE_B5, - DECOMP_TYPE_B6, - DECOMP_TYPE_B7, - DECOMP_TYPE_B8, - DECOMP_TYPE_B18, - DECOMP_TYPE_LS2, - DECOMP_TYPE_PAT3, - DECOMP_TYPE_S2_UL, - DECOMP_TYPE_LS2_UL, -} DecompTypeEnum; -#endif - -const char *decomp_type_str[] = { - "C1", - "L1", - "L2", - "L3", - "L4", - "L5", - "L6", - "L7", - "LL1", - "LL2", - "S1", - "S2", - "S3", - "S4", - "S5", - "I1", - "I2_0", - "I2_1", - "I3_1", - "I3_2", - "I4_1", - "I4_2", - "B1", - "B2", - "B3", - "B4", - "B5", - "B6", - "B7", - "B8", - "B18", - "LS2", - "PAT3", - "S2_UL", - "LS2_UL", -}; - -const int decomp_incr_tab[4][4] = { - { DECOMP_TYPE_I1, 0, -1 }, - { DECOMP_TYPE_I2_0, 0, 1, -1 }, - { DECOMP_TYPE_I3_1, 1, 2, -1 }, - { DECOMP_TYPE_I4_1, 1, 2, -1 }, -}; - -/* - entry size: - type bits - code 18 - len 7 - compat 1 - type 5 - index 16 - total 47 -*/ - -typedef struct { - int code; - uint8_t len; - uint8_t type; - uint8_t c_len; - uint16_t c_min; - uint16_t data_index; - int cost; /* size in bytes from this entry to the end */ -} DecompEntry; - -int get_decomp_run_size(const DecompEntry *de) -{ - int s; - s = 6; - if (de->type <= DECOMP_TYPE_C1) { - /* nothing more */ - } else if (de->type <= DECOMP_TYPE_L7) { - s += de->len * de->c_len * 2; - } else if (de->type <= DECOMP_TYPE_LL2) { - /* 18 bits per char */ - s += (de->len * de->c_len * 18 + 7) / 8; - } else if (de->type <= DECOMP_TYPE_S5) { - s += de->len * de->c_len; - } else if (de->type <= DECOMP_TYPE_I4_2) { - s += de->c_len * 2; - } else if (de->type <= DECOMP_TYPE_B18) { - s += 2 + de->len * de->c_len; - } else if (de->type <= DECOMP_TYPE_LS2) { - s += de->len * 3; - } else if (de->type <= DECOMP_TYPE_PAT3) { - s += 4 + de->len * 2; - } else if (de->type <= DECOMP_TYPE_S2_UL) { - s += de->len; - } else if (de->type <= DECOMP_TYPE_LS2_UL) { - s += (de->len / 2) * 3; - } else { - abort(); - } - return s; -} - -static const uint16_t unicode_short_table[2] = { 0x2044, 0x2215 }; - -/* return -1 if not found */ -int get_short_code(int c) -{ - int i; - if (c < 0x80) { - return c; - } else if (c >= 0x300 && c < 0x350) { - return c - 0x300 + 0x80; - } else { - for(i = 0; i < countof(unicode_short_table); i++) { - if (c == unicode_short_table[i]) - return i + 0x80 + 0x50; - } - return -1; - } -} - -static BOOL is_short(int code) -{ - return get_short_code(code) >= 0; -} - -static BOOL is_short_tab(const int *tab, int len) -{ - int i; - for(i = 0; i < len; i++) { - if (!is_short(tab[i])) - return FALSE; - } - return TRUE; -} - -static BOOL is_16bit(const int *tab, int len) -{ - int i; - for(i = 0; i < len; i++) { - if (tab[i] > 0xffff) - return FALSE; - } - return TRUE; -} - -static uint32_t to_lower_simple(uint32_t c) -{ - /* Latin1 and Cyrillic */ - if (c < 0x100 || (c >= 0x410 && c <= 0x42f)) - c += 0x20; - else - c++; - return c; -} - -/* select best encoding with dynamic programming */ -void find_decomp_run(DecompEntry *tab_de, int i) -{ - DecompEntry de_s, *de = &de_s; - CCInfo *ci, *ci1, *ci2; - int l, j, n, len_max; - - ci = &unicode_db[i]; - l = ci->decomp_len; - if (l == 0) { - tab_de[i].cost = tab_de[i + 1].cost; - return; - } - - /* the offset for the compose table has only 6 bits, so we must - limit if it can be used by the compose table */ - if (!ci->is_compat && !ci->is_excluded && l == 2) - len_max = 64; - else - len_max = 127; - - tab_de[i].cost = 0x7fffffff; - - if (!is_16bit(ci->decomp_data, l)) { - assert(l <= 2); - - n = 1; - for(;;) { - de->code = i; - de->len = n; - de->type = DECOMP_TYPE_LL1 + l - 1; - de->c_len = l; - de->cost = get_decomp_run_size(de) + tab_de[i + n].cost; - if (de->cost < tab_de[i].cost) { - tab_de[i] = *de; - } - if (!((i + n) <= CHARCODE_MAX && n < len_max)) - break; - ci1 = &unicode_db[i + n]; - /* Note: we accept a hole */ - if (!(ci1->decomp_len == 0 || - (ci1->decomp_len == l && - ci1->is_compat == ci->is_compat))) - break; - n++; - } - return; - } - - if (l <= 7) { - n = 1; - for(;;) { - de->code = i; - de->len = n; - if (l == 1 && n == 1) { - de->type = DECOMP_TYPE_C1; - } else { - assert(l <= 8); - de->type = DECOMP_TYPE_L1 + l - 1; - } - de->c_len = l; - de->cost = get_decomp_run_size(de) + tab_de[i + n].cost; - if (de->cost < tab_de[i].cost) { - tab_de[i] = *de; - } - - if (!((i + n) <= CHARCODE_MAX && n < len_max)) - break; - ci1 = &unicode_db[i + n]; - /* Note: we accept a hole */ - if (!(ci1->decomp_len == 0 || - (ci1->decomp_len == l && - ci1->is_compat == ci->is_compat && - is_16bit(ci1->decomp_data, l)))) - break; - n++; - } - } - - if (l <= 8 || l == 18) { - int c_min, c_max, c; - c_min = c_max = -1; - n = 1; - for(;;) { - ci1 = &unicode_db[i + n - 1]; - for(j = 0; j < l; j++) { - c = ci1->decomp_data[j]; - if (c == 0x20) { - /* we accept space for Arabic */ - } else if (c_min == -1) { - c_min = c_max = c; - } else { - c_min = min_int(c_min, c); - c_max = max_int(c_max, c); - } - } - if ((c_max - c_min) > 254) - break; - de->code = i; - de->len = n; - if (l == 18) - de->type = DECOMP_TYPE_B18; - else - de->type = DECOMP_TYPE_B1 + l - 1; - de->c_len = l; - de->c_min = c_min; - de->cost = get_decomp_run_size(de) + tab_de[i + n].cost; - if (de->cost < tab_de[i].cost) { - tab_de[i] = *de; - } - if (!((i + n) <= CHARCODE_MAX && n < len_max)) - break; - ci1 = &unicode_db[i + n]; - if (!(ci1->decomp_len == l && - ci1->is_compat == ci->is_compat)) - break; - n++; - } - } - - /* find an ascii run */ - if (l <= 5 && is_short_tab(ci->decomp_data, l)) { - n = 1; - for(;;) { - de->code = i; - de->len = n; - de->type = DECOMP_TYPE_S1 + l - 1; - de->c_len = l; - de->cost = get_decomp_run_size(de) + tab_de[i + n].cost; - if (de->cost < tab_de[i].cost) { - tab_de[i] = *de; - } - - if (!((i + n) <= CHARCODE_MAX && n < len_max)) - break; - ci1 = &unicode_db[i + n]; - /* Note: we accept a hole */ - if (!(ci1->decomp_len == 0 || - (ci1->decomp_len == l && - ci1->is_compat == ci->is_compat && - is_short_tab(ci1->decomp_data, l)))) - break; - n++; - } - } - - /* check if a single char is increasing */ - if (l <= 4) { - int idx1, idx; - - for(idx1 = 1; (idx = decomp_incr_tab[l - 1][idx1]) >= 0; idx1++) { - n = 1; - for(;;) { - de->code = i; - de->len = n; - de->type = decomp_incr_tab[l - 1][0] + idx1 - 1; - de->c_len = l; - de->cost = get_decomp_run_size(de) + tab_de[i + n].cost; - if (de->cost < tab_de[i].cost) { - tab_de[i] = *de; - } - - if (!((i + n) <= CHARCODE_MAX && n < len_max)) - break; - ci1 = &unicode_db[i + n]; - if (!(ci1->decomp_len == l && - ci1->is_compat == ci->is_compat)) - goto next1; - for(j = 0; j < l; j++) { - if (j == idx) { - if (ci1->decomp_data[j] != ci->decomp_data[j] + n) - goto next1; - } else { - if (ci1->decomp_data[j] != ci->decomp_data[j]) - goto next1; - } - } - n++; - } - next1: ; - } - } - - if (l == 3) { - n = 1; - for(;;) { - de->code = i; - de->len = n; - de->type = DECOMP_TYPE_PAT3; - de->c_len = l; - de->cost = get_decomp_run_size(de) + tab_de[i + n].cost; - if (de->cost < tab_de[i].cost) { - tab_de[i] = *de; - } - if (!((i + n) <= CHARCODE_MAX && n < len_max)) - break; - ci1 = &unicode_db[i + n]; - if (!(ci1->decomp_len == l && - ci1->is_compat == ci->is_compat && - ci1->decomp_data[1] <= 0xffff && - ci1->decomp_data[0] == ci->decomp_data[0] && - ci1->decomp_data[l - 1] == ci->decomp_data[l - 1])) - break; - n++; - } - } - - if (l == 2 && is_short(ci->decomp_data[1])) { - n = 1; - for(;;) { - de->code = i; - de->len = n; - de->type = DECOMP_TYPE_LS2; - de->c_len = l; - de->cost = get_decomp_run_size(de) + tab_de[i + n].cost; - if (de->cost < tab_de[i].cost) { - tab_de[i] = *de; - } - if (!((i + n) <= CHARCODE_MAX && n < len_max)) - break; - ci1 = &unicode_db[i + n]; - if (!(ci1->decomp_len == 0 || - (ci1->decomp_len == l && - ci1->is_compat == ci->is_compat && - ci1->decomp_data[0] <= 0xffff && - is_short(ci1->decomp_data[1])))) - break; - n++; - } - } - - if (l == 2) { - BOOL is_16bit; - - n = 0; - is_16bit = FALSE; - for(;;) { - if (!((i + n + 1) <= CHARCODE_MAX && n + 2 <= len_max)) - break; - ci1 = &unicode_db[i + n]; - if (!(ci1->decomp_len == l && - ci1->is_compat == ci->is_compat && - is_short(ci1->decomp_data[1]))) - break; - if (!is_16bit && !is_short(ci1->decomp_data[0])) - is_16bit = TRUE; - ci2 = &unicode_db[i + n + 1]; - if (!(ci2->decomp_len == l && - ci2->is_compat == ci->is_compat && - ci2->decomp_data[0] == to_lower_simple(ci1->decomp_data[0]) && - ci2->decomp_data[1] == ci1->decomp_data[1])) - break; - n += 2; - de->code = i; - de->len = n; - de->type = DECOMP_TYPE_S2_UL + is_16bit; - de->c_len = l; - de->cost = get_decomp_run_size(de) + tab_de[i + n].cost; - if (de->cost < tab_de[i].cost) { - tab_de[i] = *de; - } - } - } -} - -void put16(uint8_t *data_buf, int *pidx, uint16_t c) -{ - int idx; - idx = *pidx; - data_buf[idx++] = c; - data_buf[idx++] = c >> 8; - *pidx = idx; -} - -void add_decomp_data(uint8_t *data_buf, int *pidx, DecompEntry *de) -{ - int i, j, idx, c; - CCInfo *ci; - - idx = *pidx; - de->data_index = idx; - if (de->type <= DECOMP_TYPE_C1) { - ci = &unicode_db[de->code]; - assert(ci->decomp_len == 1); - de->data_index = ci->decomp_data[0]; - } else if (de->type <= DECOMP_TYPE_L7) { - for(i = 0; i < de->len; i++) { - ci = &unicode_db[de->code + i]; - for(j = 0; j < de->c_len; j++) { - if (ci->decomp_len == 0) - c = 0; - else - c = ci->decomp_data[j]; - put16(data_buf, &idx, c); - } - } - } else if (de->type <= DECOMP_TYPE_LL2) { - int n, p, k; - n = (de->len * de->c_len * 18 + 7) / 8; - p = de->len * de->c_len * 2; - memset(data_buf + idx, 0, n); - k = 0; - for(i = 0; i < de->len; i++) { - ci = &unicode_db[de->code + i]; - for(j = 0; j < de->c_len; j++) { - if (ci->decomp_len == 0) - c = 0; - else - c = ci->decomp_data[j]; - data_buf[idx + k * 2] = c; - data_buf[idx + k * 2 + 1] = c >> 8; - data_buf[idx + p + (k / 4)] |= (c >> 16) << ((k % 4) * 2); - k++; - } - } - idx += n; - } else if (de->type <= DECOMP_TYPE_S5) { - for(i = 0; i < de->len; i++) { - ci = &unicode_db[de->code + i]; - for(j = 0; j < de->c_len; j++) { - if (ci->decomp_len == 0) - c = 0; - else - c = ci->decomp_data[j]; - c = get_short_code(c); - assert(c >= 0); - data_buf[idx++] = c; - } - } - } else if (de->type <= DECOMP_TYPE_I4_2) { - ci = &unicode_db[de->code]; - assert(ci->decomp_len == de->c_len); - for(j = 0; j < de->c_len; j++) - put16(data_buf, &idx, ci->decomp_data[j]); - } else if (de->type <= DECOMP_TYPE_B18) { - c = de->c_min; - data_buf[idx++] = c; - data_buf[idx++] = c >> 8; - for(i = 0; i < de->len; i++) { - ci = &unicode_db[de->code + i]; - for(j = 0; j < de->c_len; j++) { - assert(ci->decomp_len == de->c_len); - c = ci->decomp_data[j]; - if (c == 0x20) { - c = 0xff; - } else { - c -= de->c_min; - assert((uint32_t)c <= 254); - } - data_buf[idx++] = c; - } - } - } else if (de->type <= DECOMP_TYPE_LS2) { - assert(de->c_len == 2); - for(i = 0; i < de->len; i++) { - ci = &unicode_db[de->code + i]; - if (ci->decomp_len == 0) - c = 0; - else - c = ci->decomp_data[0]; - put16(data_buf, &idx, c); - - if (ci->decomp_len == 0) - c = 0; - else - c = ci->decomp_data[1]; - c = get_short_code(c); - assert(c >= 0); - data_buf[idx++] = c; - } - } else if (de->type <= DECOMP_TYPE_PAT3) { - ci = &unicode_db[de->code]; - assert(ci->decomp_len == 3); - put16(data_buf, &idx, ci->decomp_data[0]); - put16(data_buf, &idx, ci->decomp_data[2]); - for(i = 0; i < de->len; i++) { - ci = &unicode_db[de->code + i]; - assert(ci->decomp_len == 3); - put16(data_buf, &idx, ci->decomp_data[1]); - } - } else if (de->type <= DECOMP_TYPE_S2_UL) { - for(i = 0; i < de->len; i += 2) { - ci = &unicode_db[de->code + i]; - c = ci->decomp_data[0]; - c = get_short_code(c); - assert(c >= 0); - data_buf[idx++] = c; - c = ci->decomp_data[1]; - c = get_short_code(c); - assert(c >= 0); - data_buf[idx++] = c; - } - } else if (de->type <= DECOMP_TYPE_LS2_UL) { - for(i = 0; i < de->len; i += 2) { - ci = &unicode_db[de->code + i]; - c = ci->decomp_data[0]; - put16(data_buf, &idx, c); - c = ci->decomp_data[1]; - c = get_short_code(c); - assert(c >= 0); - data_buf[idx++] = c; - } - } else { - abort(); - } - *pidx = idx; -} - -#if 0 -void dump_large_char(void) -{ - int i, j; - for(i = 0; i <= CHARCODE_MAX; i++) { - CCInfo *ci = &unicode_db[i]; - for(j = 0; j < ci->decomp_len; j++) { - if (ci->decomp_data[j] > 0xffff) - printf("%05x\n", ci->decomp_data[j]); - } - } -} -#endif - -void build_compose_table(FILE *f, const DecompEntry *tab_de); - -void build_decompose_table(FILE *f) -{ - int i, array_len, code_max, data_len, count; - DecompEntry *tab_de, de_s, *de = &de_s; - uint8_t *data_buf; - - code_max = CHARCODE_MAX; - - tab_de = mallocz((code_max + 2) * sizeof(*tab_de)); - - for(i = code_max; i >= 0; i--) { - find_decomp_run(tab_de, i); - } - - /* build the data buffer */ - data_buf = malloc(100000); - data_len = 0; - array_len = 0; - for(i = 0; i <= code_max; i++) { - de = &tab_de[i]; - if (de->len != 0) { - add_decomp_data(data_buf, &data_len, de); - i += de->len - 1; - array_len++; - } - } - -#ifdef DUMP_DECOMP_TABLE - /* dump */ - { - int size, size1; - - printf("START LEN TYPE L C SIZE\n"); - size = 0; - for(i = 0; i <= code_max; i++) { - de = &tab_de[i]; - if (de->len != 0) { - size1 = get_decomp_run_size(de); - printf("%05x %3d %6s %2d %1d %4d\n", i, de->len, - decomp_type_str[de->type], de->c_len, - unicode_db[i].is_compat, size1); - i += de->len - 1; - size += size1; - } - } - - printf("array_len=%d estimated size=%d bytes actual=%d bytes\n", - array_len, size, array_len * 6 + data_len); - } -#endif - - total_tables++; - total_table_bytes += array_len * sizeof(uint32_t); - fprintf(f, "static const uint32_t unicode_decomp_table1[%d] = {", array_len); - count = 0; - for(i = 0; i <= code_max; i++) { - de = &tab_de[i]; - if (de->len != 0) { - uint32_t v; - if (count++ % 4 == 0) - fprintf(f, "\n "); - v = (de->code << (32 - 18)) | - (de->len << (32 - 18 - 7)) | - (de->type << (32 - 18 - 7 - 6)) | - unicode_db[de->code].is_compat; - fprintf(f, " 0x%08x,", v); - i += de->len - 1; - } - } - fprintf(f, "\n};\n\n"); - - total_tables++; - total_table_bytes += array_len * sizeof(uint16_t); - fprintf(f, "static const uint16_t unicode_decomp_table2[%d] = {", array_len); - count = 0; - for(i = 0; i <= code_max; i++) { - de = &tab_de[i]; - if (de->len != 0) { - if (count++ % 8 == 0) - fprintf(f, "\n "); - fprintf(f, " 0x%04x,", de->data_index); - i += de->len - 1; - } - } - fprintf(f, "\n};\n\n"); - - total_tables++; - total_table_bytes += data_len; - fprintf(f, "static const uint8_t unicode_decomp_data[%d] = {", data_len); - for(i = 0; i < data_len; i++) { - if (i % 8 == 0) - fprintf(f, "\n "); - fprintf(f, " 0x%02x,", data_buf[i]); - } - fprintf(f, "\n};\n\n"); - - build_compose_table(f, tab_de); - - free(data_buf); - - free(tab_de); -} - -typedef struct { - uint32_t c[2]; - uint32_t p; -} ComposeEntry; - -#define COMPOSE_LEN_MAX 10000 - -static int ce_cmp(const void *p1, const void *p2) -{ - const ComposeEntry *ce1 = p1; - const ComposeEntry *ce2 = p2; - int i; - - for(i = 0; i < 2; i++) { - if (ce1->c[i] < ce2->c[i]) - return -1; - else if (ce1->c[i] > ce2->c[i]) - return 1; - } - return 0; -} - - -static int get_decomp_pos(const DecompEntry *tab_de, int c) -{ - int i, v, k; - const DecompEntry *de; - - k = 0; - for(i = 0; i <= CHARCODE_MAX; i++) { - de = &tab_de[i]; - if (de->len != 0) { - if (c >= de->code && c < de->code + de->len) { - v = c - de->code; - assert(v < 64); - v |= k << 6; - assert(v < 65536); - return v; - } - i += de->len - 1; - k++; - } - } - return -1; -} - -void build_compose_table(FILE *f, const DecompEntry *tab_de) -{ - int i, v, tab_ce_len; - ComposeEntry *ce, *tab_ce; - - tab_ce = malloc(sizeof(*tab_ce) * COMPOSE_LEN_MAX); - tab_ce_len = 0; - for(i = 0; i <= CHARCODE_MAX; i++) { - CCInfo *ci = &unicode_db[i]; - if (ci->decomp_len == 2 && !ci->is_compat && - !ci->is_excluded) { - assert(tab_ce_len < COMPOSE_LEN_MAX); - ce = &tab_ce[tab_ce_len++]; - ce->c[0] = ci->decomp_data[0]; - ce->c[1] = ci->decomp_data[1]; - ce->p = i; - } - } - qsort(tab_ce, tab_ce_len, sizeof(*tab_ce), ce_cmp); - -#if 0 - { - printf("tab_ce_len=%d\n", tab_ce_len); - for(i = 0; i < tab_ce_len; i++) { - ce = &tab_ce[i]; - printf("%05x %05x %05x\n", ce->c[0], ce->c[1], ce->p); - } - } -#endif - - total_tables++; - total_table_bytes += tab_ce_len * sizeof(uint16_t); - fprintf(f, "static const uint16_t unicode_comp_table[%u] = {", tab_ce_len); - for(i = 0; i < tab_ce_len; i++) { - if (i % 8 == 0) - fprintf(f, "\n "); - v = get_decomp_pos(tab_de, tab_ce[i].p); - if (v < 0) { - printf("ERROR: entry for c=%04x not found\n", - tab_ce[i].p); - exit(1); - } - fprintf(f, " 0x%04x,", v); - } - fprintf(f, "\n};\n\n"); - - free(tab_ce); -} - -#ifdef USE_TEST -void check_decompose_table(void) -{ - int c; - CCInfo *ci; - int res[UNICODE_DECOMP_LEN_MAX], *ref; - int len, ref_len, is_compat; - - for(is_compat = 0; is_compat <= 1; is_compat++) { - for(c = 0; c < CHARCODE_MAX; c++) { - ci = &unicode_db[c]; - ref_len = ci->decomp_len; - ref = ci->decomp_data; - if (!is_compat && ci->is_compat) { - ref_len = 0; - } - len = unicode_decomp_char((uint32_t *)res, c, is_compat); - if (len != ref_len || - tabcmp(res, ref, ref_len) != 0) { - printf("ERROR c=%05x compat=%d\n", c, is_compat); - dump_str("res", res, len); - dump_str("ref", ref, ref_len); - exit(1); - } - } - } -} - -void check_compose_table(void) -{ - int i, p; - /* XXX: we don't test all the cases */ - - for(i = 0; i <= CHARCODE_MAX; i++) { - CCInfo *ci = &unicode_db[i]; - if (ci->decomp_len == 2 && !ci->is_compat && - !ci->is_excluded) { - p = unicode_compose_pair(ci->decomp_data[0], ci->decomp_data[1]); - if (p != i) { - printf("ERROR compose: c=%05x %05x -> %05x ref=%05x\n", - ci->decomp_data[0], ci->decomp_data[1], p, i); - exit(1); - } - } - } - - - -} - -#endif - - - -#ifdef USE_TEST - -void check_str(const char *msg, int num, const int *in_buf, int in_len, - const int *buf1, int len1, - const int *buf2, int len2) -{ - if (len1 != len2 || tabcmp(buf1, buf2, len1) != 0) { - printf("%d: ERROR %s:\n", num, msg); - dump_str(" in", in_buf, in_len); - dump_str("res", buf1, len1); - dump_str("ref", buf2, len2); - exit(1); - } -} - -void check_cc_table(void) -{ - int cc, cc_ref, c; - - for(c = 0; c <= CHARCODE_MAX; c++) { - cc_ref = unicode_db[c].combining_class; - cc = unicode_get_cc(c); - if (cc != cc_ref) { - printf("ERROR: c=%04x cc=%d cc_ref=%d\n", - c, cc, cc_ref); - exit(1); - } - } -#ifdef PROFILE - { - int64_t ti, count; - - ti = get_time_ns(); - count = 0; - /* only do it on meaningful chars */ - for(c = 0x20; c <= 0xffff; c++) { - cc_ref = unicode_db[c].combining_class; - cc = unicode_get_cc(c); - count++; - } - ti = get_time_ns() - ti; - printf("cc time=%0.1f ns/char\n", - (double)ti / count); - } -#endif -} - -void normalization_test(const char *filename) -{ - FILE *f; - char line[4096], *p; - int *in_str, *nfc_str, *nfd_str, *nfkc_str, *nfkd_str; - int in_len, nfc_len, nfd_len, nfkc_len, nfkd_len; - int *buf, buf_len, pos; - - f = fopen(filename, "rb"); - if (!f) { - perror(filename); - exit(1); - } - pos = 0; - for(;;) { - if (!get_line(line, sizeof(line), f)) - break; - pos++; - p = line; - while (isspace(*p)) - p++; - if (*p == '#' || *p == '@') - continue; - in_str = get_field_str(&in_len, p, 0); - nfc_str = get_field_str(&nfc_len, p, 1); - nfd_str = get_field_str(&nfd_len, p, 2); - nfkc_str = get_field_str(&nfkc_len, p, 3); - nfkd_str = get_field_str(&nfkd_len, p, 4); - - // dump_str("in", in_str, in_len); - - buf_len = unicode_normalize((uint32_t **)&buf, (uint32_t *)in_str, in_len, UNICODE_NFD, NULL, NULL); - check_str("nfd", pos, in_str, in_len, buf, buf_len, nfd_str, nfd_len); - free(buf); - - buf_len = unicode_normalize((uint32_t **)&buf, (uint32_t *)in_str, in_len, UNICODE_NFKD, NULL, NULL); - check_str("nfkd", pos, in_str, in_len, buf, buf_len, nfkd_str, nfkd_len); - free(buf); - - buf_len = unicode_normalize((uint32_t **)&buf, (uint32_t *)in_str, in_len, UNICODE_NFC, NULL, NULL); - check_str("nfc", pos, in_str, in_len, buf, buf_len, nfc_str, nfc_len); - free(buf); - - buf_len = unicode_normalize((uint32_t **)&buf, (uint32_t *)in_str, in_len, UNICODE_NFKC, NULL, NULL); - check_str("nfkc", pos, in_str, in_len, buf, buf_len, nfkc_str, nfkc_len); - free(buf); - - free(in_str); - free(nfc_str); - free(nfd_str); - free(nfkc_str); - free(nfkd_str); - } - fclose(f); -} -#endif - -int main(int argc, char *argv[]) -{ - const char *unicode_db_path, *outfilename; - char filename[1024]; - int arg = 1; - - if (arg >= argc || (!strcmp(argv[arg], "-h") || !strcmp(argv[arg], "--help"))) { - printf("usage: %s PATH [OUTPUT]\n" - " PATH path to the Unicode database directory\n" - " OUTPUT name of the output file. If omitted, a self test is performed\n" - " using the files from the Unicode library\n" - , argv[0]); - return 1; - } - unicode_db_path = argv[arg++]; - outfilename = NULL; - if (arg < argc) - outfilename = argv[arg++]; - - unicode_db = mallocz(sizeof(unicode_db[0]) * (CHARCODE_MAX + 1)); - re_string_list_init(&rgi_emoji_zwj_sequence); - dbuf_init(&rgi_emoji_tag_sequence); - - snprintf(filename, sizeof(filename), "%s/UnicodeData.txt", unicode_db_path); - - parse_unicode_data(filename); - - snprintf(filename, sizeof(filename), "%s/SpecialCasing.txt", unicode_db_path); - parse_special_casing(unicode_db, filename); - - snprintf(filename, sizeof(filename), "%s/CaseFolding.txt", unicode_db_path); - parse_case_folding(unicode_db, filename); - - snprintf(filename, sizeof(filename), "%s/CompositionExclusions.txt", unicode_db_path); - parse_composition_exclusions(filename); - - snprintf(filename, sizeof(filename), "%s/DerivedCoreProperties.txt", unicode_db_path); - parse_derived_core_properties(filename); - - snprintf(filename, sizeof(filename), "%s/DerivedNormalizationProps.txt", unicode_db_path); - parse_derived_norm_properties(filename); - - snprintf(filename, sizeof(filename), "%s/PropList.txt", unicode_db_path); - parse_prop_list(filename); - - snprintf(filename, sizeof(filename), "%s/Scripts.txt", unicode_db_path); - parse_scripts(filename); - - snprintf(filename, sizeof(filename), "%s/ScriptExtensions.txt", - unicode_db_path); - parse_script_extensions(filename); - - snprintf(filename, sizeof(filename), "%s/emoji-data.txt", - unicode_db_path); - parse_prop_list(filename); - - snprintf(filename, sizeof(filename), "%s/emoji-sequences.txt", - unicode_db_path); - parse_sequence_prop_list(filename); - - snprintf(filename, sizeof(filename), "%s/emoji-zwj-sequences.txt", - unicode_db_path); - parse_sequence_prop_list(filename); - - // dump_unicode_data(unicode_db); - build_conv_table(unicode_db); - -#ifdef DUMP_CASE_FOLDING_SPECIAL_CASES - dump_case_folding_special_cases(unicode_db); -#endif - - if (!outfilename) { -#ifdef USE_TEST - check_case_conv(); - check_flags(); - check_decompose_table(); - check_compose_table(); - check_cc_table(); - snprintf(filename, sizeof(filename), "%s/NormalizationTest.txt", unicode_db_path); - normalization_test(filename); -#else - fprintf(stderr, "Tests are not compiled\n"); - exit(1); -#endif - } else - { - FILE *fo = fopen(outfilename, "wb"); - - if (!fo) { - perror(outfilename); - exit(1); - } - fprintf(fo, - "/* Compressed unicode tables */\n" - "/* Automatically generated file - do not edit */\n" - "\n" - "#include \n" - "\n"); - dump_case_conv_table(fo); - compute_internal_props(); - build_flags_tables(fo); - fprintf(fo, "#ifdef CONFIG_ALL_UNICODE\n\n"); - build_cc_table(fo); - build_decompose_table(fo); - build_general_category_table(fo); - build_script_table(fo); - build_script_ext_table(fo); - build_prop_list_table(fo); - build_sequence_prop_list_table(fo); - fprintf(fo, "#endif /* CONFIG_ALL_UNICODE */\n"); - fprintf(fo, "/* %u tables / %u bytes, %u index / %u bytes */\n", - total_tables, total_table_bytes, total_index, total_index_bytes); - fclose(fo); - } - re_string_list_free(&rgi_emoji_zwj_sequence); - return 0; -} diff --git a/packages/javascript/javascript_android/cxx/quickjs/unicode_gen_def.h b/packages/javascript/javascript_android/cxx/quickjs/unicode_gen_def.h deleted file mode 100644 index 95c369f..0000000 --- a/packages/javascript/javascript_android/cxx/quickjs/unicode_gen_def.h +++ /dev/null @@ -1,318 +0,0 @@ -#ifdef UNICODE_GENERAL_CATEGORY -DEF(Cn, "Unassigned") /* must be zero */ -DEF(Lu, "Uppercase_Letter") -DEF(Ll, "Lowercase_Letter") -DEF(Lt, "Titlecase_Letter") -DEF(Lm, "Modifier_Letter") -DEF(Lo, "Other_Letter") -DEF(Mn, "Nonspacing_Mark") -DEF(Mc, "Spacing_Mark") -DEF(Me, "Enclosing_Mark") -DEF(Nd, "Decimal_Number,digit") -DEF(Nl, "Letter_Number") -DEF(No, "Other_Number") -DEF(Sm, "Math_Symbol") -DEF(Sc, "Currency_Symbol") -DEF(Sk, "Modifier_Symbol") -DEF(So, "Other_Symbol") -DEF(Pc, "Connector_Punctuation") -DEF(Pd, "Dash_Punctuation") -DEF(Ps, "Open_Punctuation") -DEF(Pe, "Close_Punctuation") -DEF(Pi, "Initial_Punctuation") -DEF(Pf, "Final_Punctuation") -DEF(Po, "Other_Punctuation") -DEF(Zs, "Space_Separator") -DEF(Zl, "Line_Separator") -DEF(Zp, "Paragraph_Separator") -DEF(Cc, "Control,cntrl") -DEF(Cf, "Format") -DEF(Cs, "Surrogate") -DEF(Co, "Private_Use") -/* synthetic properties */ -DEF(LC, "Cased_Letter") -DEF(L, "Letter") -DEF(M, "Mark,Combining_Mark") -DEF(N, "Number") -DEF(S, "Symbol") -DEF(P, "Punctuation,punct") -DEF(Z, "Separator") -DEF(C, "Other") -#endif - -#ifdef UNICODE_SCRIPT -/* scripts aliases names in PropertyValueAliases.txt */ -DEF(Unknown, "Zzzz") -DEF(Adlam, "Adlm") -DEF(Ahom, "Ahom") -DEF(Anatolian_Hieroglyphs, "Hluw") -DEF(Arabic, "Arab") -DEF(Armenian, "Armn") -DEF(Avestan, "Avst") -DEF(Balinese, "Bali") -DEF(Bamum, "Bamu") -DEF(Bassa_Vah, "Bass") -DEF(Batak, "Batk") -DEF(Bengali, "Beng") -DEF(Bhaiksuki, "Bhks") -DEF(Bopomofo, "Bopo") -DEF(Brahmi, "Brah") -DEF(Braille, "Brai") -DEF(Buginese, "Bugi") -DEF(Buhid, "Buhd") -DEF(Canadian_Aboriginal, "Cans") -DEF(Carian, "Cari") -DEF(Caucasian_Albanian, "Aghb") -DEF(Chakma, "Cakm") -DEF(Cham, "Cham") -DEF(Cherokee, "Cher") -DEF(Chorasmian, "Chrs") -DEF(Common, "Zyyy") -DEF(Coptic, "Copt,Qaac") -DEF(Cuneiform, "Xsux") -DEF(Cypriot, "Cprt") -DEF(Cyrillic, "Cyrl") -DEF(Cypro_Minoan, "Cpmn") -DEF(Deseret, "Dsrt") -DEF(Devanagari, "Deva") -DEF(Dives_Akuru, "Diak") -DEF(Dogra, "Dogr") -DEF(Duployan, "Dupl") -DEF(Egyptian_Hieroglyphs, "Egyp") -DEF(Elbasan, "Elba") -DEF(Elymaic, "Elym") -DEF(Ethiopic, "Ethi") -DEF(Garay, "Gara") -DEF(Georgian, "Geor") -DEF(Glagolitic, "Glag") -DEF(Gothic, "Goth") -DEF(Grantha, "Gran") -DEF(Greek, "Grek") -DEF(Gujarati, "Gujr") -DEF(Gunjala_Gondi, "Gong") -DEF(Gurmukhi, "Guru") -DEF(Gurung_Khema, "Gukh") -DEF(Han, "Hani") -DEF(Hangul, "Hang") -DEF(Hanifi_Rohingya, "Rohg") -DEF(Hanunoo, "Hano") -DEF(Hatran, "Hatr") -DEF(Hebrew, "Hebr") -DEF(Hiragana, "Hira") -DEF(Imperial_Aramaic, "Armi") -DEF(Inherited, "Zinh,Qaai") -DEF(Inscriptional_Pahlavi, "Phli") -DEF(Inscriptional_Parthian, "Prti") -DEF(Javanese, "Java") -DEF(Kaithi, "Kthi") -DEF(Kannada, "Knda") -DEF(Katakana, "Kana") -DEF(Kawi, "Kawi") -DEF(Kayah_Li, "Kali") -DEF(Kharoshthi, "Khar") -DEF(Khmer, "Khmr") -DEF(Khojki, "Khoj") -DEF(Khitan_Small_Script, "Kits") -DEF(Khudawadi, "Sind") -DEF(Kirat_Rai, "Krai") -DEF(Lao, "Laoo") -DEF(Latin, "Latn") -DEF(Lepcha, "Lepc") -DEF(Limbu, "Limb") -DEF(Linear_A, "Lina") -DEF(Linear_B, "Linb") -DEF(Lisu, "Lisu") -DEF(Lycian, "Lyci") -DEF(Lydian, "Lydi") -DEF(Makasar, "Maka") -DEF(Mahajani, "Mahj") -DEF(Malayalam, "Mlym") -DEF(Mandaic, "Mand") -DEF(Manichaean, "Mani") -DEF(Marchen, "Marc") -DEF(Masaram_Gondi, "Gonm") -DEF(Medefaidrin, "Medf") -DEF(Meetei_Mayek, "Mtei") -DEF(Mende_Kikakui, "Mend") -DEF(Meroitic_Cursive, "Merc") -DEF(Meroitic_Hieroglyphs, "Mero") -DEF(Miao, "Plrd") -DEF(Modi, "Modi") -DEF(Mongolian, "Mong") -DEF(Mro, "Mroo") -DEF(Multani, "Mult") -DEF(Myanmar, "Mymr") -DEF(Nabataean, "Nbat") -DEF(Nag_Mundari, "Nagm") -DEF(Nandinagari, "Nand") -DEF(New_Tai_Lue, "Talu") -DEF(Newa, "Newa") -DEF(Nko, "Nkoo") -DEF(Nushu, "Nshu") -DEF(Nyiakeng_Puachue_Hmong, "Hmnp") -DEF(Ogham, "Ogam") -DEF(Ol_Chiki, "Olck") -DEF(Ol_Onal, "Onao") -DEF(Old_Hungarian, "Hung") -DEF(Old_Italic, "Ital") -DEF(Old_North_Arabian, "Narb") -DEF(Old_Permic, "Perm") -DEF(Old_Persian, "Xpeo") -DEF(Old_Sogdian, "Sogo") -DEF(Old_South_Arabian, "Sarb") -DEF(Old_Turkic, "Orkh") -DEF(Old_Uyghur, "Ougr") -DEF(Oriya, "Orya") -DEF(Osage, "Osge") -DEF(Osmanya, "Osma") -DEF(Pahawh_Hmong, "Hmng") -DEF(Palmyrene, "Palm") -DEF(Pau_Cin_Hau, "Pauc") -DEF(Phags_Pa, "Phag") -DEF(Phoenician, "Phnx") -DEF(Psalter_Pahlavi, "Phlp") -DEF(Rejang, "Rjng") -DEF(Runic, "Runr") -DEF(Samaritan, "Samr") -DEF(Saurashtra, "Saur") -DEF(Sharada, "Shrd") -DEF(Shavian, "Shaw") -DEF(Siddham, "Sidd") -DEF(SignWriting, "Sgnw") -DEF(Sinhala, "Sinh") -DEF(Sogdian, "Sogd") -DEF(Sora_Sompeng, "Sora") -DEF(Soyombo, "Soyo") -DEF(Sundanese, "Sund") -DEF(Sunuwar, "Sunu") -DEF(Syloti_Nagri, "Sylo") -DEF(Syriac, "Syrc") -DEF(Tagalog, "Tglg") -DEF(Tagbanwa, "Tagb") -DEF(Tai_Le, "Tale") -DEF(Tai_Tham, "Lana") -DEF(Tai_Viet, "Tavt") -DEF(Takri, "Takr") -DEF(Tamil, "Taml") -DEF(Tangut, "Tang") -DEF(Telugu, "Telu") -DEF(Thaana, "Thaa") -DEF(Thai, "Thai") -DEF(Tibetan, "Tibt") -DEF(Tifinagh, "Tfng") -DEF(Tirhuta, "Tirh") -DEF(Tangsa, "Tnsa") -DEF(Todhri, "Todr") -DEF(Toto, "Toto") -DEF(Tulu_Tigalari, "Tutg") -DEF(Ugaritic, "Ugar") -DEF(Vai, "Vaii") -DEF(Vithkuqi, "Vith") -DEF(Wancho, "Wcho") -DEF(Warang_Citi, "Wara") -DEF(Yezidi, "Yezi") -DEF(Yi, "Yiii") -DEF(Zanabazar_Square, "Zanb") -#endif - -#ifdef UNICODE_PROP_LIST -/* Prop list not exported to regexp */ -DEF(Hyphen, "") -DEF(Other_Math, "") -DEF(Other_Alphabetic, "") -DEF(Other_Lowercase, "") -DEF(Other_Uppercase, "") -DEF(Other_Grapheme_Extend, "") -DEF(Other_Default_Ignorable_Code_Point, "") -DEF(Other_ID_Start, "") -DEF(Other_ID_Continue, "") -DEF(Prepended_Concatenation_Mark, "") -/* additional computed properties for smaller tables */ -DEF(ID_Continue1, "") -DEF(XID_Start1, "") -DEF(XID_Continue1, "") -DEF(Changes_When_Titlecased1, "") -DEF(Changes_When_Casefolded1, "") -DEF(Changes_When_NFKC_Casefolded1, "") -DEF(Basic_Emoji1, "") -DEF(Basic_Emoji2, "") -DEF(RGI_Emoji_Modifier_Sequence, "") -DEF(RGI_Emoji_Flag_Sequence, "") -DEF(Emoji_Keycap_Sequence, "") - -/* Prop list exported to JS */ -DEF(ASCII_Hex_Digit, "AHex") -DEF(Bidi_Control, "Bidi_C") -DEF(Dash, "") -DEF(Deprecated, "Dep") -DEF(Diacritic, "Dia") -DEF(Extender, "Ext") -DEF(Hex_Digit, "Hex") -DEF(IDS_Unary_Operator, "IDSU") -DEF(IDS_Binary_Operator, "IDSB") -DEF(IDS_Trinary_Operator, "IDST") -DEF(Ideographic, "Ideo") -DEF(Join_Control, "Join_C") -DEF(Logical_Order_Exception, "LOE") -DEF(Modifier_Combining_Mark, "MCM") -DEF(Noncharacter_Code_Point, "NChar") -DEF(Pattern_Syntax, "Pat_Syn") -DEF(Pattern_White_Space, "Pat_WS") -DEF(Quotation_Mark, "QMark") -DEF(Radical, "") -DEF(Regional_Indicator, "RI") -DEF(Sentence_Terminal, "STerm") -DEF(Soft_Dotted, "SD") -DEF(Terminal_Punctuation, "Term") -DEF(Unified_Ideograph, "UIdeo") -DEF(Variation_Selector, "VS") -DEF(White_Space, "space") -DEF(Bidi_Mirrored, "Bidi_M") -DEF(Emoji, "") -DEF(Emoji_Component, "EComp") -DEF(Emoji_Modifier, "EMod") -DEF(Emoji_Modifier_Base, "EBase") -DEF(Emoji_Presentation, "EPres") -DEF(Extended_Pictographic, "ExtPict") -DEF(Default_Ignorable_Code_Point, "DI") -DEF(ID_Start, "IDS") -DEF(Case_Ignorable, "CI") - -/* other binary properties */ -DEF(ASCII,"") -DEF(Alphabetic, "Alpha") -DEF(Any, "") -DEF(Assigned,"") -DEF(Cased, "") -DEF(Changes_When_Casefolded, "CWCF") -DEF(Changes_When_Casemapped, "CWCM") -DEF(Changes_When_Lowercased, "CWL") -DEF(Changes_When_NFKC_Casefolded, "CWKCF") -DEF(Changes_When_Titlecased, "CWT") -DEF(Changes_When_Uppercased, "CWU") -DEF(Grapheme_Base, "Gr_Base") -DEF(Grapheme_Extend, "Gr_Ext") -DEF(ID_Continue, "IDC") -DEF(ID_Compat_Math_Start, "") -DEF(ID_Compat_Math_Continue, "") -DEF(InCB, "") -DEF(Lowercase, "Lower") -DEF(Math, "") -DEF(Uppercase, "Upper") -DEF(XID_Continue, "XIDC") -DEF(XID_Start, "XIDS") - -/* internal tables with index */ -DEF(Cased1, "") - -#endif - -#ifdef UNICODE_SEQUENCE_PROP_LIST -DEF(Basic_Emoji) -DEF(Emoji_Keycap_Sequence) -DEF(RGI_Emoji_Modifier_Sequence) -DEF(RGI_Emoji_Flag_Sequence) -DEF(RGI_Emoji_Tag_Sequence) -DEF(RGI_Emoji_ZWJ_Sequence) -DEF(RGI_Emoji) -#endif diff --git a/packages/javascript/javascript_android/cxx/revision b/packages/javascript/javascript_android/cxx/revision deleted file mode 100644 index 93045d1..0000000 --- a/packages/javascript/javascript_android/cxx/revision +++ /dev/null @@ -1 +0,0 @@ -1fdc768fdc8571300755cdd3e4654ce99c0255ce diff --git a/packages/javascript/javascript_android/cxx/update.sh b/packages/javascript/javascript_android/cxx/update.sh deleted file mode 100755 index 9d28371..0000000 --- a/packages/javascript/javascript_android/cxx/update.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -# change current directory to script's directory -cd "$(dirname "$0")" - -rm -rf quickjs; -git clone https://github.com/bellard/quickjs; -cd quickjs; -git rev-parse HEAD > ../revision; -rm -rf .git; diff --git a/packages/javascript/javascript_android/lib/javascript_android.dart b/packages/javascript/javascript_android/lib/javascript_android.dart index dd2f6be..c5253be 100644 --- a/packages/javascript/javascript_android/lib/javascript_android.dart +++ b/packages/javascript/javascript_android/lib/javascript_android.dart @@ -1,70 +1,85 @@ +import 'package:flutter/foundation.dart'; +import 'package:javascript_android/src/user_scripts.dart'; import 'package:javascript_platform_interface/javascript_platform_interface.dart'; -import 'package:javascript_android/src/third_party/flutter_qjs/lib/flutter_qjs.dart'; +import 'src/engine_context.dart'; +import 'src/pigeons/messages.pigeon.dart'; +import 'src/scripts/messaging.dart'; /// The Android implementation of [JavaScriptPlatform]. class JavaScriptAndroid extends JavaScriptPlatform { + /// The method channel used to interact with the native platform. + @visibleForTesting + final pigeonPlatformApi = JavaScriptAndroidPlatformApi(); + /// Registers this class as the default instance of [JavaScriptPlatform] static void registerWith() { JavaScriptPlatform.instance = JavaScriptAndroid(); } - final _enabledChannels = {}; + final _activeEngines = {}; + + EngineHostState _requireEngineState(String javascriptEngineId) { + if (!_activeEngines.containsKey(javascriptEngineId)) { + throw Exception('Engine by id "$javascriptEngineId" is not found'); + } + return _activeEngines[javascriptEngineId]!; + } + + @override + Future startJavaScriptEngine(String javascriptEngineId) async { + await pigeonPlatformApi.startJavaScriptEngine(javascriptEngineId); + _activeEngines[javascriptEngineId] = EngineHostState(); + for (final script in getEngineStartupScripts()) { + await runJavaScriptReturningResult(javascriptEngineId, script); + } + } @override Future addJavaScriptChannel( String javascriptEngineId, JavaScriptChannelParams javaScriptChannelParams, - ) async {} - - @override - Future dispose(String javascriptEngineId) { - final runtime = requireRuntime(javascriptEngineId); - _activeRuntimes.remove(javascriptEngineId); - return runtime.close(); + ) async { + final engineState = _requireEngineState(javascriptEngineId); + engineState.addChannel( + javaScriptChannelParams.name, + javaScriptChannelParams, + ); } @override Future removeJavaScriptChannel( String javascriptEngineId, String javaScriptChannelName, - ) async {} + ) async { + final engineState = _requireEngineState(javascriptEngineId); + engineState.removeChannel(javaScriptChannelName); + } @override - Future runJavaScriptReturningResult( - String javascriptEngineId, - String javaScript, - ) { - final runtime = requireRuntime(javascriptEngineId); - return runtime.evaluate(javaScript); + Future dispose(String javascriptEngineId) { + final engineState = _requireEngineState(javascriptEngineId); + engineState.dispose(); + _activeEngines.remove(javascriptEngineId); + return pigeonPlatformApi.dispose(javascriptEngineId); } @override - Future setIsInspectable( + Future runJavaScriptReturningResult( String javascriptEngineId, - bool isInspectable, - ) async { - // no op + String javaScript, + ) { + return pigeonPlatformApi.runJavaScriptReturningResult( + javascriptEngineId, + javaScript, + ); } - final _activeRuntimes = {}; - @override - Future startJavaScriptEngine(String javascriptEngineId) { - final runtime = FlutterQjs(); - _activeRuntimes[javascriptEngineId] = runtime; - return Future.value(); - } - - FlutterQjs requireRuntime(String javascriptEngineId) { - final runtime = _activeRuntimes[javascriptEngineId]; - if (runtime == null) { - throw ArgumentError.value( - javascriptEngineId, - 'javascriptEngineId', - 'Runtime not found for id', - ); - } - return runtime; + Future setIsInspectable(String javascriptEngineId, bool isInspectable) { + return pigeonPlatformApi.setIsInspectable( + javascriptEngineId, + isInspectable, + ); } } diff --git a/packages/javascript/javascript_android/lib/src/engine_context.dart b/packages/javascript/javascript_android/lib/src/engine_context.dart new file mode 100644 index 0000000..550baa8 --- /dev/null +++ b/packages/javascript/javascript_android/lib/src/engine_context.dart @@ -0,0 +1,17 @@ +import 'package:javascript_platform_interface/javascript_platform_interface.dart'; + +class EngineHostState { + final Map _enabledChannels = {}; + + void addChannel(String channelName, JavaScriptChannelParams channelParams) { + _enabledChannels[channelName] = channelParams; + } + + void removeChannel(String channelName) { + _enabledChannels.remove(channelName); + } + + void dispose() { + _enabledChannels.clear(); + } +} diff --git a/packages/javascript/javascript_android/lib/src/pigeons/messages.pigeon.dart b/packages/javascript/javascript_android/lib/src/pigeons/messages.pigeon.dart new file mode 100644 index 0000000..32051c5 --- /dev/null +++ b/packages/javascript/javascript_android/lib/src/pigeons/messages.pigeon.dart @@ -0,0 +1,146 @@ +// Copyright 2025, Reclaim Protocol. Use of this source code is governed by a license that can be found in the LICENSE file. +// Autogenerated from Pigeon (v26.0.0), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers + +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; + +import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; +import 'package:flutter/services.dart'; + +PlatformException _createConnectionError(String channelName) { + return PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); +} + + +class _PigeonCodec extends StandardMessageCodec { + const _PigeonCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is int) { + buffer.putUint8(4); + buffer.putInt64(value); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + default: + return super.readValueOfType(type, buffer); + } + } +} + +/// Apis implemented by the Reclaim module for use by the host. +class JavaScriptAndroidPlatformApi { + /// Constructor for [JavaScriptAndroidPlatformApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + JavaScriptAndroidPlatformApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + Future startJavaScriptEngine(String javascriptEngineId) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.startJavaScriptEngine$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([javascriptEngineId]); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + Future dispose(String javascriptEngineId) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.dispose$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([javascriptEngineId]); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + Future runJavaScriptReturningResult(String javascriptEngineId, String javaScript) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.runJavaScriptReturningResult$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([javascriptEngineId, javaScript]); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return pigeonVar_replyList[0]; + } + } + + Future setIsInspectable(String javascriptEngineId, bool isInspectable) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.setIsInspectable$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([javascriptEngineId, isInspectable]); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } +} diff --git a/packages/javascript/javascript_android/lib/src/scripts/messaging.dart b/packages/javascript/javascript_android/lib/src/scripts/messaging.dart new file mode 100644 index 0000000..b17122f --- /dev/null +++ b/packages/javascript/javascript_android/lib/src/scripts/messaging.dart @@ -0,0 +1,48 @@ +const String MESSAGING_SCRIPT = r''' +class HostMessenger { + constructor() { + this.pendingMessages = []; + this.id = 0; + } + + getPendingMessages() { + return this.pendingMessages.map(m => ({id: m.id, message: m.message})); + } + + removeMessageById(id) { + this.pendingMessages = this.pendingMessages.filter(m => m.id !== id); + } + + resolveById(id, response) { + let message = this.pendingMessages.find(m => m.id === id); + if (message) { + message.resolve(response); + this.removeMessageById(id); + return true; + } + return false; + } + + rejectById(id, error) { + let message = this.pendingMessages.find(m => m.id === id); + if (message) { + message.reject(error); + this.removeMessageById(id); + return true; + } + return false; + } + + postMessage(message) { + let promise = new Promise((resolve, reject) => { + this.pendingMessages.push({ + id: this.id++, + message, + resolve, + reject + }); + }); + return promise; + } +} +'''; \ No newline at end of file diff --git a/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/LICENSE b/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/LICENSE deleted file mode 100644 index 4ae93d7..0000000 --- a/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019 https://github.com/czy0729 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/flutter_qjs.dart b/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/flutter_qjs.dart deleted file mode 100644 index be401cf..0000000 --- a/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/flutter_qjs.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'dart:async'; -import 'dart:ffi'; -import 'dart:io'; -import 'dart:isolate'; -import 'dart:typed_data'; -import 'package:ffi/ffi.dart'; -import 'src/ffi.dart'; -export 'src/ffi.dart' show JSEvalFlag, JSRef; - -part 'src/engine.dart'; -part 'src/isolate.dart'; -part 'src/wrapper.dart'; -part 'src/object.dart'; diff --git a/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/engine.dart b/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/engine.dart deleted file mode 100644 index 82cf412..0000000 --- a/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/engine.dart +++ /dev/null @@ -1,182 +0,0 @@ -/* - * @Description: quickjs engine - * @Author: ekibun - * @Date: 2020-08-08 08:29:09 - * @LastEditors: ekibun - * @LastEditTime: 2020-10-06 23:47:13 - */ -part of '../flutter_qjs.dart'; - -/// Handler function to manage js module. -typedef _JsModuleHandler = String Function(String name); - -/// Handler to manage unhandled promise rejection. -typedef _JsHostPromiseRejectionHandler = void Function(dynamic reason); - -/// Quickjs engine for flutter. -class FlutterQjs { - Pointer? _rt; - Pointer? _ctx; - - /// Max stack size for quickjs. - final int? stackSize; - - /// Max stack size for quickjs. - final int? timeout; - - /// Max memory for quickjs. - final int? memoryLimit; - - /// Message Port for event loop. Close it to stop dispatching event loop. - ReceivePort port = ReceivePort(); - - /// Handler function to manage js module. - final _JsModuleHandler? moduleHandler; - - /// Handler function to manage js module. - final _JsHostPromiseRejectionHandler? hostPromiseRejectionHandler; - - FlutterQjs({ - this.moduleHandler, - this.stackSize, - this.timeout, - this.memoryLimit, - this.hostPromiseRejectionHandler, - }); - - _ensureEngine() { - if (_rt != null) return; - final rt = jsNewRuntime((ctx, type, ptr) { - try { - switch (type) { - case JSChannelType.METHON: - final pdata = ptr.cast>(); - final argc = pdata.elementAt(1).value.cast().value; - final pargs = []; - for (var i = 0; i < argc; ++i) { - pargs.add(_jsToDart( - ctx, - Pointer.fromAddress( - pdata.elementAt(2).value.address + sizeOfJSValue * i, - ), - )); - } - final JSInvokable func = _jsToDart( - ctx, - pdata.elementAt(3).value, - ); - return _dartToJs( - ctx, - func.invoke( - pargs, - _jsToDart(ctx, pdata.elementAt(0).value), - )); - case JSChannelType.MODULE: - if (moduleHandler == null) throw JSError('No ModuleHandler'); - final ret = moduleHandler!( - ptr.cast().toDartString(), - ).toNativeUtf8(); - Future.microtask(() { - malloc.free(ret); - }); - return ret.cast(); - case JSChannelType.PROMISE_TRACK: - final err = _parseJSException(ctx, ptr); - if (hostPromiseRejectionHandler != null) { - hostPromiseRejectionHandler!(err); - } else { - print('unhandled promise rejection: $err'); - } - return nullptr; - case JSChannelType.FREE_OBJECT: - final rt = ctx.cast(); - _DartObject.fromAddress(rt, ptr.address)?.free(); - return nullptr; - } - throw JSError('call channel with wrong type'); - } catch (e) { - if (type == JSChannelType.FREE_OBJECT) { - print('DartObject release error: $e'); - return nullptr; - } - if (type == JSChannelType.MODULE) { - print('host Promise Rejection Handler error: $e'); - return nullptr; - } - final throwObj = _dartToJs(ctx, e); - final err = jsThrow(ctx, throwObj); - jsFreeValue(ctx, throwObj); - if (type == JSChannelType.MODULE) { - jsFreeValue(ctx, err); - return nullptr; - } - return err; - } - }, timeout ?? 0, port); - final stackSize = this.stackSize ?? 0; - if (stackSize > 0) jsSetMaxStackSize(rt, stackSize); - final memoryLimit = this.memoryLimit ?? 0; - if (memoryLimit > 0) jsSetMemoryLimit(rt, memoryLimit); - _rt = rt; - _ctx = jsNewContext(rt); - } - - /// Free Runtime and Context which can be recreate when evaluate again. - close() { - final rt = _rt; - final ctx = _ctx; - _rt = null; - _ctx = null; - if (ctx != null) jsFreeContext(ctx); - if (rt == null) return; - _executePendingJob(); - try { - jsFreeRuntime(rt); - } on String catch (e) { - throw JSError(e); - } - } - - void _executePendingJob() { - final rt = _rt; - final ctx = _ctx; - if (rt == null || ctx == null) return; - while (true) { - int err = jsExecutePendingJob(rt); - if (err <= 0) { - if (err < 0) print(_parseJSException(ctx)); - break; - } - } - } - - /// Dispatch JavaScript Event loop. - Future dispatch() async { - await for (final _ in port) { - _executePendingJob(); - } - } - - /// Evaluate js script. - dynamic evaluate( - String command, { - String? name, - int? evalFlags, - }) { - _ensureEngine(); - final ctx = _ctx!; - final jsval = jsEval( - ctx, - command, - name ?? '', - evalFlags ?? JSEvalFlag.GLOBAL, - ); - if (jsIsException(jsval) != 0) { - jsFreeValue(ctx, jsval); - throw _parseJSException(ctx); - } - final result = _jsToDart(ctx, jsval); - jsFreeValue(ctx, jsval); - return result; - } -} diff --git a/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/ffi.dart b/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/ffi.dart deleted file mode 100644 index 5825955..0000000 --- a/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/ffi.dart +++ /dev/null @@ -1,1011 +0,0 @@ -/* - * @Description: ffi - * @Author: ekibun - * @Date: 2020-09-19 10:29:04 - * @LastEditors: ekibun - * @LastEditTime: 2020-12-02 11:14:35 - */ -import 'dart:ffi'; -import 'dart:io'; -import 'dart:isolate'; -import 'package:ffi/ffi.dart'; - -extension ListFirstWhere on Iterable { - T? firstWhereOrNull(bool Function(T) test) { - try { - return firstWhere(test); - } on StateError { - return null; - } - } -} - -abstract class JSRef { - int _refCount = 0; - void dup() { - _refCount++; - } - - void free() { - _refCount--; - if (_refCount < 0) destroy(); - } - - void destroy(); - - static void freeRecursive(dynamic obj) { - _callRecursive(obj, (ref) => ref.free()); - } - - static void dupRecursive(dynamic obj) { - _callRecursive(obj, (ref) => ref.dup()); - } - - static void _callRecursive( - dynamic obj, - void Function(JSRef) cb, [ - Set? cache, - ]) { - if (obj == null) return; - if (cache == null) cache = Set(); - if (cache.contains(obj)) return; - if (obj is List) { - cache.add(obj); - List.from(obj).forEach((e) => _callRecursive(e, cb, cache)); - } - if (obj is Map) { - cache.add(obj); - obj.values.toList().forEach((e) => _callRecursive(e, cb, cache)); - } - if (obj is JSRef) { - cb(obj); - } - } -} - -abstract class JSRefLeakable {} - -class JSEvalFlag { - static const GLOBAL = 0 << 0; - static const MODULE = 1 << 0; -} - -class JSChannelType { - static const METHON = 0; - static const MODULE = 1; - static const PROMISE_TRACK = 2; - static const FREE_OBJECT = 3; -} - -class JSProp { - static const CONFIGURABLE = (1 << 0); - static const WRITABLE = (1 << 1); - static const ENUMERABLE = (1 << 2); - static const C_W_E = (CONFIGURABLE | WRITABLE | ENUMERABLE); -} - -class JSTag { - static const FIRST = -11; /* first negative tag */ - static const BIG_DECIMAL = -11; - static const BIG_INT = -10; - static const BIG_FLOAT = -9; - static const SYMBOL = -8; - static const STRING = -7; - static const MODULE = -3; /* used internally */ - static const FUNCTION_BYTECODE = -2; /* used internally */ - static const OBJECT = -1; - - static const INT = 0; - static const BOOL = 1; - static const NULL = 2; - static const UNDEFINED = 3; - static const UNINITIALIZED = 4; - static const CATCH_OFFSET = 5; - static const EXCEPTION = 6; - static const FLOAT64 = 7; -} - -final class JSValue extends Opaque {} - -final class JSContext extends Opaque {} - -final class JSRuntime extends Opaque {} - -final class JSPropertyEnum extends Opaque {} - -final DynamicLibrary _qjsLib = Platform.environment['FLUTTER_TEST'] == 'true' - ? (Platform.isWindows - ? DynamicLibrary.open('test/build/Debug/ffiquickjs.dll') - : Platform.isMacOS - ? DynamicLibrary.open('test/build/libffiquickjs.dylib') - : DynamicLibrary.open('test/build/libffiquickjs.so')) - : (Platform.isWindows - ? DynamicLibrary.open('flutter_qjs_plugin.dll') - : Platform.isAndroid - ? DynamicLibrary.open('libqjs.so') - : DynamicLibrary.process()); - -/// DLLEXPORT JSValue *jsThrow(JSContext *ctx, JSValue *obj) -final Pointer Function( - Pointer ctx, - Pointer obj, -) jsThrow = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - Pointer, - )>>('jsThrow') - .asFunction(); - -/// JSValue *jsEXCEPTION() -final Pointer Function() jsEXCEPTION = _qjsLib - .lookup Function()>>('jsEXCEPTION') - .asFunction(); - -/// JSValue *jsUNDEFINED() -final Pointer Function() jsUNDEFINED = _qjsLib - .lookup Function()>>('jsUNDEFINED') - .asFunction(); - -typedef _JSChannel = Pointer Function( - Pointer ctx, int method, Pointer argv); -typedef _JSChannelNative = Pointer Function( - Pointer ctx, IntPtr method, Pointer argv); - -/// JSRuntime *jsNewRuntime(JSChannel channel) -final Pointer Function( - Pointer>, - int, -) _jsNewRuntime = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer>, - Int64, - )>>('jsNewRuntime') - .asFunction(); - -class _RuntimeOpaque { - final _JSChannel _channel; - List _ref = []; - final ReceivePort _port; - int? _dartObjectClassId; - _RuntimeOpaque(this._channel, this._port); - - int? get dartObjectClassId => _dartObjectClassId; - - void addRef(JSRef ref) => _ref.add(ref); - - bool removeRef(JSRef ref) => _ref.remove(ref); - - JSRef? getRef(bool Function(JSRef ref) test) { - return _ref.firstWhereOrNull(test); - } -} - -final Map, _RuntimeOpaque> runtimeOpaques = Map(); - -Pointer channelDispacher( - Pointer ctx, - int type, - Pointer argv, -) { - final rt = type == JSChannelType.FREE_OBJECT - ? ctx.cast() - : jsGetRuntime(ctx); - return runtimeOpaques[rt]!._channel(ctx, type, argv); -} - -Pointer jsNewRuntime( - _JSChannel callback, - int timeout, - ReceivePort port, -) { - final rt = _jsNewRuntime(Pointer.fromFunction(channelDispacher), timeout); - runtimeOpaques[rt] = _RuntimeOpaque(callback, port); - return rt; -} - -/// DLLEXPORT void jsSetMaxStackSize(JSRuntime *rt, size_t stack_size) -final void Function( - Pointer, - int, -) jsSetMaxStackSize = _qjsLib - .lookup< - NativeFunction< - Void Function( - Pointer, - IntPtr, - )>>('jsSetMaxStackSize') - .asFunction(); - -/// DLLEXPORT void jsSetMemoryLimit(JSRuntime *rt, size_t limit); -final void Function( - Pointer, - int, -) jsSetMemoryLimit = _qjsLib - .lookup< - NativeFunction< - Void Function( - Pointer, - IntPtr, - )>>('jsSetMemoryLimit') - .asFunction(); - -/// void jsFreeRuntime(JSRuntime *rt) -final void Function( - Pointer, -) _jsFreeRuntime = _qjsLib - .lookup< - NativeFunction< - Void Function( - Pointer, - )>>('jsFreeRuntime') - .asFunction(); - -void jsFreeRuntime( - Pointer rt, -) { - final referenceleak = []; - final opaque = runtimeOpaques[rt]; - if (opaque != null) { - while (true) { - final ref = opaque._ref.firstWhereOrNull((ref) => ref is JSRefLeakable); - if (ref == null) break; - ref.destroy(); - runtimeOpaques[rt]?._ref.remove(ref); - } - while (opaque._ref.isNotEmpty) { - final ref = opaque._ref.first; - final objStrs = ref.toString().split('\n'); - final objStr = objStrs.length > 0 ? objStrs[0] + " ..." : objStrs[0]; - referenceleak.add( - " ${identityHashCode(ref)}\t${ref._refCount + 1}\t${ref.runtimeType.toString()}\t$objStr"); - ref.destroy(); - } - } - _jsFreeRuntime(rt); - if (referenceleak.length > 0) { - throw ('reference leak:\n ADDR\tREF\tTYPE\tPROP\n' + - referenceleak.join('\n')); - } -} - -/// JSValue *jsNewCFunction(JSContext *ctx, JSValue *funcData) -final Pointer Function( - Pointer ctx, - Pointer funcData, -) jsNewCFunction = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - Pointer, - )>>('jsNewCFunction') - .asFunction(); - -/// JSContext *jsNewContext(JSRuntime *rt) -final Pointer Function( - Pointer rt, -) _jsNewContext = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - )>>('jsNewContext') - .asFunction(); - -Pointer jsNewContext(Pointer rt) { - final ctx = _jsNewContext(rt); - if (ctx.address == 0) throw Exception('Context create failed!'); - final runtimeOpaque = runtimeOpaques[rt]; - if (runtimeOpaque == null) throw Exception('Runtime has been released!'); - runtimeOpaque._dartObjectClassId = jsNewClass(ctx, 'DartObject'); - return ctx; -} - -/// void jsFreeContext(JSContext *ctx) -final void Function( - Pointer, -) jsFreeContext = _qjsLib - .lookup< - NativeFunction< - Void Function( - Pointer, - )>>('jsFreeContext') - .asFunction(); - -/// JSRuntime *jsGetRuntime(JSContext *ctx) -final Pointer Function( - Pointer, -) jsGetRuntime = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - )>>('jsGetRuntime') - .asFunction(); - -/// JSValue *jsEval(JSContext *ctx, const char *input, size_t input_len, const char *filename, int eval_flags) -final Pointer Function( - Pointer ctx, - Pointer input, - int inputLen, - Pointer filename, - int evalFlags, -) _jsEval = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - Pointer, - IntPtr, - Pointer, - Int32, - )>>('jsEval') - .asFunction(); - -Pointer jsEval( - Pointer ctx, - String input, - String filename, - int evalFlags, -) { - final utf8input = input.toNativeUtf8(); - final utf8filename = filename.toNativeUtf8(); - final val = _jsEval( - ctx, - utf8input, - utf8input.length, - utf8filename, - evalFlags, - ); - malloc.free(utf8input); - malloc.free(utf8filename); - runtimeOpaques[jsGetRuntime(ctx)]?._port.sendPort.send(#eval); - return val; -} - -/// DLLEXPORT int32_t jsValueGetTag(JSValue *val) -final int Function( - Pointer val, -) jsValueGetTag = _qjsLib - .lookup< - NativeFunction< - Int32 Function( - Pointer, - )>>('jsValueGetTag') - .asFunction(); - -/// void *jsValueGetPtr(JSValue *val) -final int Function( - Pointer val, -) jsValueGetPtr = _qjsLib - .lookup< - NativeFunction< - IntPtr Function( - Pointer, - )>>('jsValueGetPtr') - .asFunction(); - -/// DLLEXPORT bool jsTagIsFloat64(int32_t tag) -final int Function( - int val, -) jsTagIsFloat64 = _qjsLib - .lookup< - NativeFunction< - Int32 Function( - Int32, - )>>('jsTagIsFloat64') - .asFunction(); - -/// JSValue *jsNewBool(JSContext *ctx, int val) -final Pointer Function( - Pointer ctx, - int val, -) jsNewBool = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - Int32, - )>>('jsNewBool') - .asFunction(); - -/// JSValue *jsNewInt64(JSContext *ctx, int64_t val) -final Pointer Function( - Pointer ctx, - int val, -) jsNewInt64 = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - Int64, - )>>('jsNewInt64') - .asFunction(); - -/// JSValue *jsNewFloat64(JSContext *ctx, double val) -final Pointer Function( - Pointer ctx, - double val, -) jsNewFloat64 = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - Double, - )>>('jsNewFloat64') - .asFunction(); - -/// JSValue *jsNewString(JSContext *ctx, const char *str) -final Pointer Function( - Pointer ctx, - Pointer str, -) _jsNewString = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - Pointer, - )>>('jsNewString') - .asFunction(); - -Pointer jsNewString( - Pointer ctx, - String str, -) { - final utf8str = str.toNativeUtf8(); - final jsStr = _jsNewString(ctx, utf8str); - malloc.free(utf8str); - return jsStr; -} - -/// JSValue *jsNewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len) -final Pointer Function( - Pointer ctx, - Pointer buf, - int len, -) jsNewArrayBufferCopy = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - Pointer, - IntPtr, - )>>('jsNewArrayBufferCopy') - .asFunction(); - -/// JSValue *jsNewArray(JSContext *ctx) -final Pointer Function( - Pointer ctx, -) jsNewArray = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - )>>('jsNewArray') - .asFunction(); - -/// JSValue *jsNewObject(JSContext *ctx) -final Pointer Function( - Pointer ctx, -) jsNewObject = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - )>>('jsNewObject') - .asFunction(); - -/// void jsFreeValue(JSContext *ctx, JSValue *val, int32_t free) -final void Function( - Pointer ctx, - Pointer val, - int free, -) _jsFreeValue = _qjsLib - .lookup< - NativeFunction< - Void Function( - Pointer, - Pointer, - Int32, - )>>('jsFreeValue') - .asFunction(); - -void jsFreeValue( - Pointer ctx, - Pointer val, { - bool free = true, -}) { - _jsFreeValue(ctx, val, free ? 1 : 0); -} - -/// void jsFreeValue(JSRuntime *rt, JSValue *val, int32_t free) -final void Function( - Pointer rt, - Pointer val, - int free, -) _jsFreeValueRT = _qjsLib - .lookup< - NativeFunction< - Void Function( - Pointer, - Pointer, - Int32, - )>>('jsFreeValueRT') - .asFunction(); - -void jsFreeValueRT( - Pointer rt, - Pointer val, { - bool free = true, -}) { - _jsFreeValueRT(rt, val, free ? 1 : 0); -} - -/// JSValue *jsDupValue(JSContext *ctx, JSValueConst *v) -final Pointer Function( - Pointer ctx, - Pointer val, -) jsDupValue = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - Pointer, - )>>('jsDupValue') - .asFunction(); - -/// JSValue *jsDupValueRT(JSRuntime *rt, JSValue *v) -final Pointer Function( - Pointer rt, - Pointer val, -) jsDupValueRT = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - Pointer, - )>>('jsDupValueRT') - .asFunction(); - -/// int32_t jsToBool(JSContext *ctx, JSValueConst *val) -final int Function( - Pointer ctx, - Pointer val, -) jsToBool = _qjsLib - .lookup< - NativeFunction< - Int32 Function( - Pointer, - Pointer, - )>>('jsToBool') - .asFunction(); - -/// int64_t jsToFloat64(JSContext *ctx, JSValueConst *val) -final int Function( - Pointer ctx, - Pointer val, -) jsToInt64 = _qjsLib - .lookup< - NativeFunction< - Int64 Function( - Pointer, - Pointer, - )>>('jsToInt64') - .asFunction(); - -/// double jsToFloat64(JSContext *ctx, JSValueConst *val) -final double Function( - Pointer ctx, - Pointer val, -) jsToFloat64 = _qjsLib - .lookup< - NativeFunction< - Double Function( - Pointer, - Pointer, - )>>('jsToFloat64') - .asFunction(); - -/// const char *jsToCString(JSContext *ctx, JSValue *val) -final Pointer Function( - Pointer ctx, - Pointer val, -) _jsToCString = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - Pointer, - )>>('jsToCString') - .asFunction(); - -/// void jsFreeCString(JSContext *ctx, const char *ptr) -final void Function( - Pointer ctx, - Pointer val, -) jsFreeCString = _qjsLib - .lookup< - NativeFunction< - Void Function( - Pointer, - Pointer, - )>>('jsFreeCString') - .asFunction(); - -String jsToCString( - Pointer ctx, - Pointer val, -) { - final ptr = _jsToCString(ctx, val); - if (ptr.address == 0) throw Exception('JSValue cannot convert to string'); - final str = ptr.toDartString(); - jsFreeCString(ctx, ptr); - return str; -} - -/// DLLEXPORT uint32_t jsNewClass(JSContext *ctx, const char *name) -final int Function( - Pointer ctx, - Pointer name, -) _jsNewClass = _qjsLib - .lookup< - NativeFunction< - Uint32 Function( - Pointer, - Pointer, - )>>('jsNewClass') - .asFunction(); - -int jsNewClass( - Pointer ctx, - String name, -) { - final utf8name = name.toNativeUtf8(); - final val = _jsNewClass( - ctx, - utf8name, - ); - malloc.free(utf8name); - return val; -} - -/// DLLEXPORT JSValue *jsNewObjectClass(JSContext *ctx, uint32_t QJSClassId, void *opaque) -final Pointer Function( - Pointer ctx, - int classId, - int opaque, -) jsNewObjectClass = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - Uint32, - IntPtr, - )>>('jsNewObjectClass') - .asFunction(); - -/// DLLEXPORT void *jsGetObjectOpaque(JSValue *obj, uint32_t classid) -final int Function( - Pointer obj, - int classid, -) jsGetObjectOpaque = _qjsLib - .lookup< - NativeFunction< - IntPtr Function( - Pointer, - Uint32, - )>>('jsGetObjectOpaque') - .asFunction(); - -/// uint8_t *jsGetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst *obj) -final Pointer Function( - Pointer ctx, - Pointer psize, - Pointer val, -) jsGetArrayBuffer = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - Pointer, - Pointer, - )>>('jsGetArrayBuffer') - .asFunction(); - -/// int32_t jsIsFunction(JSContext *ctx, JSValueConst *val) -final int Function( - Pointer ctx, - Pointer val, -) jsIsFunction = _qjsLib - .lookup< - NativeFunction< - Int32 Function( - Pointer, - Pointer, - )>>('jsIsFunction') - .asFunction(); - -/// int32_t jsIsPromise(JSContext *ctx, JSValueConst *val) -final int Function( - Pointer ctx, - Pointer val, -) jsIsPromise = _qjsLib - .lookup< - NativeFunction< - Int32 Function( - Pointer, - Pointer, - )>>('jsIsPromise') - .asFunction(); - -/// int32_t jsIsArray(JSContext *ctx, JSValueConst *val) -final int Function( - Pointer ctx, - Pointer val, -) jsIsArray = _qjsLib - .lookup< - NativeFunction< - Int32 Function( - Pointer, - Pointer, - )>>('jsIsArray') - .asFunction(); - -/// DLLEXPORT int32_t jsIsError(JSContext *ctx, JSValueConst *val); -final int Function( - Pointer ctx, - Pointer val, -) jsIsError = _qjsLib - .lookup< - NativeFunction< - Int32 Function( - Pointer, - Pointer, - )>>('jsIsError') - .asFunction(); - -/// DLLEXPORT JSValue *jsNewError(JSContext *ctx); -final Pointer Function( - Pointer ctx, -) jsNewError = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - )>>('jsNewError') - .asFunction(); - -/// JSValue *jsGetProperty(JSContext *ctx, JSValueConst *this_obj, -/// JSAtom prop) -final Pointer Function( - Pointer ctx, - Pointer thisObj, - int prop, -) jsGetProperty = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - Pointer, - Uint32, - )>>('jsGetProperty') - .asFunction(); - -/// int jsDefinePropertyValue(JSContext *ctx, JSValueConst *this_obj, -/// JSAtom prop, JSValue *val, int flags) -final int Function( - Pointer ctx, - Pointer thisObj, - int prop, - Pointer val, - int flag, -) jsDefinePropertyValue = _qjsLib - .lookup< - NativeFunction< - Int32 Function( - Pointer, - Pointer, - Uint32, - Pointer, - Int32, - )>>('jsDefinePropertyValue') - .asFunction(); - -/// void jsFreeAtom(JSContext *ctx, JSAtom v) -final void Function( - Pointer ctx, - int v, -) jsFreeAtom = _qjsLib - .lookup< - NativeFunction< - Void Function( - Pointer, - Uint32, - )>>('jsFreeAtom') - .asFunction(); - -/// JSAtom jsValueToAtom(JSContext *ctx, JSValueConst *val) -final int Function( - Pointer ctx, - Pointer val, -) jsValueToAtom = _qjsLib - .lookup< - NativeFunction< - Uint32 Function( - Pointer, - Pointer, - )>>('jsValueToAtom') - .asFunction(); - -/// JSValue *jsAtomToValue(JSContext *ctx, JSAtom val) -final Pointer Function( - Pointer ctx, - int val, -) jsAtomToValue = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - Uint32, - )>>('jsAtomToValue') - .asFunction(); - -/// int jsGetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, -/// uint32_t *plen, JSValueConst *obj, int flags) -final int Function( - Pointer ctx, - Pointer> ptab, - Pointer plen, - Pointer obj, - int flags, -) jsGetOwnPropertyNames = _qjsLib - .lookup< - NativeFunction< - Int32 Function( - Pointer, - Pointer>, - Pointer, - Pointer, - Int32, - )>>('jsGetOwnPropertyNames') - .asFunction(); - -/// JSAtom jsPropertyEnumGetAtom(JSPropertyEnum *ptab, int i) -final int Function( - Pointer ptab, - int i, -) jsPropertyEnumGetAtom = _qjsLib - .lookup< - NativeFunction< - Uint32 Function( - Pointer, - Int32, - )>>('jsPropertyEnumGetAtom') - .asFunction(); - -/// uint32_t sizeOfJSValue() -final int Function() _sizeOfJSValue = _qjsLib - .lookup>('sizeOfJSValue') - .asFunction(); - -final sizeOfJSValue = _sizeOfJSValue(); - -/// void setJSValueList(JSValue *list, int i, JSValue *val) -final void Function( - Pointer list, - int i, - Pointer val, -) setJSValueList = _qjsLib - .lookup< - NativeFunction< - Void Function( - Pointer, - Uint32, - Pointer, - )>>('setJSValueList') - .asFunction(); - -/// JSValue *jsCall(JSContext *ctx, JSValueConst *func_obj, JSValueConst *this_obj, -/// int argc, JSValueConst *argv) -final Pointer Function( - Pointer ctx, - Pointer funcObj, - Pointer thisObj, - int argc, - Pointer argv, -) _jsCall = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - Pointer, - Pointer, - Int32, - Pointer, - )>>('jsCall') - .asFunction(); - -Pointer jsCall( - Pointer ctx, - Pointer funcObj, - Pointer thisObj, - List> argv, -) { - final jsArgs = calloc( - argv.length > 0 ? sizeOfJSValue * argv.length : 1, - ).cast(); - for (int i = 0; i < argv.length; ++i) { - Pointer jsArg = argv[i]; - setJSValueList(jsArgs, i, jsArg); - } - final func1 = jsDupValue(ctx, funcObj); - final _thisObj = thisObj; - final jsRet = _jsCall(ctx, funcObj, _thisObj, argv.length, jsArgs); - jsFreeValue(ctx, func1); - malloc.free(jsArgs); - runtimeOpaques[jsGetRuntime(ctx)]?._port.sendPort.send(#call); - return jsRet; -} - -/// int jsIsException(JSValueConst *val) -final int Function( - Pointer val, -) jsIsException = _qjsLib - .lookup< - NativeFunction< - Int32 Function( - Pointer, - )>>('jsIsException') - .asFunction(); - -/// JSValue *jsGetException(JSContext *ctx) -final Pointer Function( - Pointer ctx, -) jsGetException = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - )>>('jsGetException') - .asFunction(); - -/// int jsExecutePendingJob(JSRuntime *rt) -final int Function( - Pointer ctx, -) jsExecutePendingJob = _qjsLib - .lookup< - NativeFunction< - Int32 Function( - Pointer, - )>>('jsExecutePendingJob') - .asFunction(); - -/// JSValue *jsNewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs) -final Pointer Function( - Pointer ctx, - Pointer resolvingFuncs, -) jsNewPromiseCapability = _qjsLib - .lookup< - NativeFunction< - Pointer Function( - Pointer, - Pointer, - )>>('jsNewPromiseCapability') - .asFunction(); - -/// void jsFree(JSContext *ctx, void *ptab) -final void Function( - Pointer ctx, - Pointer ptab, -) jsFree = _qjsLib - .lookup< - NativeFunction< - Void Function( - Pointer, - Pointer, - )>>('jsFree') - .asFunction(); diff --git a/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/isolate.dart b/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/isolate.dart deleted file mode 100644 index 58b8f2d..0000000 --- a/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/isolate.dart +++ /dev/null @@ -1,291 +0,0 @@ -/* - * @Description: isolate - * @Author: ekibun - * @Date: 2020-10-02 13:49:03 - * @LastEditors: ekibun - * @LastEditTime: 2020-10-03 22:21:31 - */ -part of '../flutter_qjs.dart'; - -typedef dynamic _Decode(Map obj); -List<_Decode> _decoders = [ - JSError._decode, - IsolateFunction._decode, -]; - -abstract class _IsolateEncodable { - Map _encode(); -} - -dynamic _encodeData(dynamic data, {Map? cache}) { - if (cache == null) cache = Map(); - if (cache.containsKey(data)) return cache[data]; - if (data is Error || data is Exception) - return _encodeData(JSError(data), cache: cache); - if (data is _IsolateEncodable) return data._encode(); - if (data is List) { - final ret = []; - cache[data] = ret; - for (int i = 0; i < data.length; ++i) { - ret.add(_encodeData(data[i], cache: cache)); - } - return ret; - } - if (data is Map) { - final ret = {}; - cache[data] = ret; - for (final entry in data.entries) { - ret[_encodeData(entry.key, cache: cache)] = - _encodeData(entry.value, cache: cache); - } - return ret; - } - if (data is Future) { - final futurePort = ReceivePort(); - data.then((value) { - futurePort.first.then((port) { - futurePort.close(); - (port as SendPort).send(_encodeData(value)); - }); - }, onError: (e) { - futurePort.first.then((port) { - futurePort.close(); - (port as SendPort).send({#error: _encodeData(e)}); - }); - }); - return { - #jsFuturePort: futurePort.sendPort, - }; - } - return data; -} - -dynamic _decodeData(dynamic data, {Map? cache}) { - if (cache == null) cache = Map(); - if (cache.containsKey(data)) return cache[data]; - if (data is List) { - final ret = []; - cache[data] = ret; - for (int i = 0; i < data.length; ++i) { - ret.add(_decodeData(data[i], cache: cache)); - } - return ret; - } - if (data is Map) { - for (final decoder in _decoders) { - final decodeObj = decoder(data); - if (decodeObj != null) return decodeObj; - } - if (data.containsKey(#jsFuturePort)) { - SendPort port = data[#jsFuturePort]; - final futurePort = ReceivePort(); - port.send(futurePort.sendPort); - final futureCompleter = Completer(); - futureCompleter.future.catchError((e) {}); - futurePort.first.then((value) { - futurePort.close(); - if (value is Map && value.containsKey(#error)) { - futureCompleter.completeError(_decodeData(value[#error])); - } else { - futureCompleter.complete(_decodeData(value)); - } - }); - return futureCompleter.future; - } - final ret = {}; - cache[data] = ret; - for (final entry in data.entries) { - ret[_decodeData(entry.key, cache: cache)] = - _decodeData(entry.value, cache: cache); - } - return ret; - } - return data; -} - -void _runJsIsolate(Map spawnMessage) async { - SendPort sendPort = spawnMessage[#port]; - ReceivePort port = ReceivePort(); - sendPort.send(port.sendPort); - final qjs = FlutterQjs( - stackSize: spawnMessage[#stackSize], - timeout: spawnMessage[#timeout], - memoryLimit: spawnMessage[#memoryLimit], - hostPromiseRejectionHandler: (reason) { - sendPort.send({ - #type: #hostPromiseRejection, - #reason: _encodeData(reason), - }); - }, - moduleHandler: (name) { - final ptr = calloc>(); - ptr.value = Pointer.fromAddress(ptr.address); - sendPort.send({ - #type: #module, - #name: name, - #ptr: ptr.address, - }); - while (ptr.value.address == ptr.address) sleep(Duration(microseconds: 1)); - final ret = ptr.value; - malloc.free(ptr); - if (ret.address == -1) throw JSError('Module Not found'); - final retString = ret.toDartString(); - malloc.free(ret); - return retString; - }, - ); - port.listen((msg) async { - var data; - SendPort? msgPort = msg[#port]; - try { - switch (msg[#type]) { - case #evaluate: - data = await qjs.evaluate( - msg[#command], - name: msg[#name], - evalFlags: msg[#flag], - ); - break; - case #close: - data = false; - qjs.port.close(); - qjs.close(); - port.close(); - data = true; - break; - } - if (msgPort != null) msgPort.send(_encodeData(data)); - } catch (e) { - if (msgPort != null) - msgPort.send({ - #error: _encodeData(e), - }); - } - }); - await qjs.dispatch(); -} - -typedef _JsAsyncModuleHandler = Future Function(String name); - -class IsolateQjs { - Future? _sendPort; - - /// Max stack size for quickjs. - final int? stackSize; - - /// Max stack size for quickjs. - final int? timeout; - - /// Max memory for quickjs. - final int? memoryLimit; - - /// Asynchronously handler to manage js module. - final _JsAsyncModuleHandler? moduleHandler; - - /// Handler function to manage js module. - final _JsHostPromiseRejectionHandler? hostPromiseRejectionHandler; - - /// Quickjs engine runing on isolate thread. - /// - /// Pass handlers to implement js-dart interaction and resolving modules. The `methodHandler` is - /// used in isolate, so **the handler function must be a top-level function or a static method**. - IsolateQjs({ - this.moduleHandler, - this.stackSize, - this.timeout, - this.memoryLimit, - this.hostPromiseRejectionHandler, - }); - - _ensureEngine() { - if (_sendPort != null) return; - ReceivePort port = ReceivePort(); - Isolate.spawn( - _runJsIsolate, - { - #port: port.sendPort, - #stackSize: stackSize, - #timeout: timeout, - #memoryLimit: memoryLimit, - }, - errorsAreFatal: true, - ); - final completer = Completer(); - port.listen((msg) async { - if (msg is SendPort && !completer.isCompleted) { - completer.complete(msg); - return; - } - switch (msg[#type]) { - case #hostPromiseRejection: - try { - final err = _decodeData(msg[#reason]); - if (hostPromiseRejectionHandler != null) { - hostPromiseRejectionHandler!(err); - } else { - print('unhandled promise rejection: $err'); - } - } catch (e) { - print('host Promise Rejection Handler error: $e'); - } - break; - case #module: - final ptr = Pointer.fromAddress(msg[#ptr]); - try { - ptr.value = (await moduleHandler!(msg[#name])).toNativeUtf8(); - } catch (e) { - ptr.value = Pointer.fromAddress(-1); - } - break; - } - }, onDone: () { - close(); - if (!completer.isCompleted) - completer.completeError(JSError('isolate close')); - }); - _sendPort = completer.future; - } - - /// Free Runtime and close isolate thread that can be recreate when evaluate again. - close() { - final sendPort = _sendPort; - _sendPort = null; - if (sendPort == null) return; - final ret = sendPort.then((sendPort) async { - final closePort = ReceivePort(); - sendPort.send({ - #type: #close, - #port: closePort.sendPort, - }); - final result = await closePort.first; - closePort.close(); - if (result is Map && result.containsKey(#error)) - throw _decodeData(result[#error]); - return _decodeData(result); - }); - return ret; - } - - /// Evaluate js script. - Future evaluate( - String command, { - String? name, - int? evalFlags, - }) async { - _ensureEngine(); - final evaluatePort = ReceivePort(); - final sendPort = await _sendPort!; - sendPort.send({ - #type: #evaluate, - #command: command, - #name: name, - #flag: evalFlags, - #port: evaluatePort.sendPort, - }); - final result = await evaluatePort.first; - evaluatePort.close(); - if (result is Map && result.containsKey(#error)) - throw _decodeData(result[#error]); - return _decodeData(result); - } -} diff --git a/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/object.dart b/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/object.dart deleted file mode 100644 index eb0f79c..0000000 --- a/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/object.dart +++ /dev/null @@ -1,314 +0,0 @@ -/* - * @Description: wrap object - * @Author: ekibun - * @Date: 2020-10-02 13:49:03 - * @LastEditors: ekibun - * @LastEditTime: 2020-10-03 22:21:31 - */ -part of '../flutter_qjs.dart'; - -/// js invokable -abstract class JSInvokable extends JSRef { - dynamic invoke(List args, [dynamic thisVal]); - - static dynamic _wrap(dynamic func) { - return func is JSInvokable - ? func - : func is Function - ? _DartFunction(func) - : func; - } -} - -class _DartFunction extends JSInvokable { - final Function _func; - _DartFunction(this._func); - - @override - invoke(List args, [thisVal]) { - /// wrap this into function - final passThis = - RegExp('{.*thisVal.*}').hasMatch(_func.runtimeType.toString()); - final ret = - Function.apply(_func, args, passThis ? {#thisVal: thisVal} : null); - JSRef.freeRecursive(args); - JSRef.freeRecursive(thisVal); - return ret; - } - - @override - String toString() { - return _func.toString(); - } - - @override - destroy() {} -} - -/// implement this to capture js object release. - -class _DartObject extends JSRef implements JSRefLeakable { - Object? _obj; - Pointer? _ctx; - _DartObject(Pointer ctx, dynamic obj) { - _ctx = ctx; - _obj = obj; - if (obj is JSRef) obj.dup(); - runtimeOpaques[jsGetRuntime(ctx)]?.addRef(this); - } - - static _DartObject? fromAddress(Pointer rt, int val) { - return runtimeOpaques[rt]?.getRef((e) => identityHashCode(e) == val) - as _DartObject?; - } - - @override - String toString() { - if (_ctx == null) return "DartObject(released)"; - return _obj.toString(); - } - - @override - void destroy() { - final ctx = _ctx; - final obj = _obj; - _ctx = null; - _obj = null; - if (ctx == null) return; - runtimeOpaques[jsGetRuntime(ctx)]?.removeRef(this); - if (obj is JSRef) obj.free(); - } -} - -/// JS Error wrapper -class JSError extends _IsolateEncodable { - late String message; - late String stack; - JSError(message, [stack]) { - if (message is JSError) { - this.message = message.message; - this.stack = message.stack; - } else { - this.message = message.toString(); - this.stack = (stack ?? StackTrace.current).toString(); - } - } - - @override - String toString() { - return stack.isEmpty ? message.toString() : "$message\n$stack"; - } - - static JSError? _decode(Map obj) { - if (obj.containsKey(#jsError)) - return JSError(obj[#jsError], obj[#jsErrorStack]); - return null; - } - - @override - Map _encode() { - return { - #jsError: message, - #jsErrorStack: stack, - }; - } -} - -/// JS Object reference -/// call [release] to release js object. -class _JSObject extends JSRef { - Pointer? _val; - Pointer? _ctx; - - /// Create - _JSObject(Pointer ctx, Pointer val) { - this._ctx = ctx; - final rt = jsGetRuntime(ctx); - this._val = jsDupValue(ctx, val); - runtimeOpaques[rt]?.addRef(this); - } - - @override - void destroy() { - final ctx = _ctx; - final val = _val; - _val = null; - _ctx = null; - if (ctx == null || val == null) return; - final rt = jsGetRuntime(ctx); - runtimeOpaques[rt]?.removeRef(this); - jsFreeValue(ctx, val); - } - - @override - String toString() { - if (_ctx == null || _val == null) return "JSObject(released)"; - return jsToCString(_ctx!, _val!); - } -} - -/// JS function wrapper -class _JSFunction extends _JSObject implements JSInvokable, _IsolateEncodable { - _JSFunction(Pointer ctx, Pointer val) : super(ctx, val); - - @override - invoke(List arguments, [dynamic thisVal]) { - final jsRet = _invoke(arguments, thisVal); - final ctx = _ctx!; - bool isException = jsIsException(jsRet) != 0; - if (isException) { - jsFreeValue(ctx, jsRet); - throw _parseJSException(ctx); - } - final ret = _jsToDart(ctx, jsRet); - jsFreeValue(ctx, jsRet); - return ret; - } - - Pointer _invoke(List arguments, [dynamic thisVal]) { - final ctx = _ctx; - final val = _val; - if (ctx == null || val == null) - throw JSError("InternalError: JSValue released"); - final args = arguments - .map( - (e) => _dartToJs(ctx, e), - ) - .toList(); - final jsThis = _dartToJs(ctx, thisVal); - final jsRet = jsCall(ctx, val, jsThis, args); - jsFreeValue(ctx, jsThis); - for (final jsArg in args) { - jsFreeValue(ctx, jsArg); - } - return jsRet; - } - - @override - Map _encode() { - return IsolateFunction._new(this)._encode(); - } -} - -/// Dart function wrapper for isolate -class IsolateFunction extends JSInvokable implements _IsolateEncodable { - int? _isolateId; - SendPort? _port; - JSInvokable? _invokable; - IsolateFunction._fromId(this._isolateId, this._port); - - IsolateFunction._new(this._invokable) { - _handlers.add(this); - } - IsolateFunction(Function func) : this._new(_DartFunction(func)); - - static ReceivePort? _invokeHandler; - static Set _handlers = Set(); - - static get _handlePort { - if (_invokeHandler == null) { - _invokeHandler = ReceivePort(); - _invokeHandler!.listen((msg) async { - final msgPort = msg[#port]; - try { - final handler = _handlers.firstWhereOrNull( - (v) => identityHashCode(v) == msg[#handler], - ); - if (handler == null) throw JSError('handler released'); - final ret = _encodeData(await handler._handle(msg[#msg])); - if (msgPort != null) msgPort.send(ret); - } catch (e) { - final err = _encodeData(e); - if (msgPort != null) - msgPort.send({ - #error: err, - }); - } - }); - } - return _invokeHandler!.sendPort; - } - - _send(msg) async { - final port = _port; - if (port == null) return _handle(msg); - final evaluatePort = ReceivePort(); - port.send({ - #handler: _isolateId, - #msg: msg, - #port: evaluatePort.sendPort, - }); - final result = await evaluatePort.first; - if (result is Map && result.containsKey(#error)) - throw _decodeData(result[#error]); - return _decodeData(result); - } - - _destroy() { - _handlers.remove(this); - _invokable?.free(); - _invokable = null; - } - - _handle(msg) async { - switch (msg) { - case #dup: - _refCount++; - return null; - case #free: - _refCount--; - if (_refCount < 0) _destroy(); - return null; - case #destroy: - _destroy(); - return null; - } - final List args = _decodeData(msg[#args]); - final thisVal = _decodeData(msg[#thisVal]); - return _invokable?.invoke(args, thisVal); - } - - @override - Future invoke(List positionalArguments, [thisVal]) async { - final List dArgs = _encodeData(positionalArguments); - final dThisVal = _encodeData(thisVal); - return _send({ - #args: dArgs, - #thisVal: dThisVal, - }); - } - - static IsolateFunction? _decode(Map obj) { - if (obj.containsKey(#jsFunctionPort)) - return IsolateFunction._fromId( - obj[#jsFunctionId], - obj[#jsFunctionPort], - ); - return null; - } - - @override - Map _encode() { - return { - #jsFunctionId: _isolateId ?? identityHashCode(this), - #jsFunctionPort: _port ?? IsolateFunction._handlePort, - }; - } - - int _refCount = 0; - - @override - dup() { - _send(#dup); - } - - @override - free() { - _send(#free); - } - - @override - void destroy() { - _send(#destroy); - } -} diff --git a/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/wrapper.dart b/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/wrapper.dart deleted file mode 100644 index cb23d1d..0000000 --- a/packages/javascript/javascript_android/lib/src/third_party/flutter_qjs/lib/src/wrapper.dart +++ /dev/null @@ -1,249 +0,0 @@ -/* - * @Description: wrapper - * @Author: ekibun - * @Date: 2020-09-19 22:07:47 - * @LastEditors: ekibun - * @LastEditTime: 2020-12-02 11:14:03 - */ -part of '../flutter_qjs.dart'; - -dynamic _parseJSException(Pointer ctx, [Pointer? perr]) { - final e = perr ?? jsGetException(ctx); - var err; - try { - err = _jsToDart(ctx, e); - } catch (exception) { - err = exception; - } - if (perr == null) jsFreeValue(ctx, e); - return err; -} - -void _definePropertyValue( - Pointer ctx, - Pointer obj, - dynamic key, - dynamic val, { - Map>? cache, -}) { - final jsAtomVal = _dartToJs(ctx, key, cache: cache); - final jsAtom = jsValueToAtom(ctx, jsAtomVal); - jsDefinePropertyValue( - ctx, - obj, - jsAtom, - _dartToJs(ctx, val, cache: cache), - JSProp.C_W_E, - ); - jsFreeAtom(ctx, jsAtom); - jsFreeValue(ctx, jsAtomVal); -} - -Pointer _jsGetPropertyValue( - Pointer ctx, - Pointer obj, - dynamic key, { - Map>? cache, -}) { - final jsAtomVal = _dartToJs(ctx, key, cache: cache); - final jsAtom = jsValueToAtom(ctx, jsAtomVal); - final jsProp = jsGetProperty(ctx, obj, jsAtom); - jsFreeAtom(ctx, jsAtom); - jsFreeValue(ctx, jsAtomVal); - return jsProp; -} - -Pointer _dartToJs(Pointer ctx, dynamic val, - {Map>? cache}) { - if (val == null) return jsUNDEFINED(); - if (val is Error) return _dartToJs(ctx, JSError(val, val.stackTrace)); - if (val is Exception) return _dartToJs(ctx, JSError(val)); - if (val is JSError) { - final ret = jsNewError(ctx); - _definePropertyValue(ctx, ret, "name", ""); - _definePropertyValue(ctx, ret, "message", val.message); - _definePropertyValue(ctx, ret, "stack", val.stack); - return ret; - } - if (val is _JSObject) return jsDupValue(ctx, val._val!); - if (val is Future) { - final resolvingFunc = malloc(sizeOfJSValue * 2).cast(); - final resolvingFunc2 = - Pointer.fromAddress(resolvingFunc.address + sizeOfJSValue); - final ret = jsNewPromiseCapability(ctx, resolvingFunc); - final _JSFunction res = _jsToDart(ctx, resolvingFunc); - final _JSFunction rej = _jsToDart(ctx, resolvingFunc2); - jsFreeValue(ctx, resolvingFunc, free: false); - jsFreeValue(ctx, resolvingFunc2, free: false); - malloc.free(resolvingFunc); - final refRes = _DartObject(ctx, res); - final refRej = _DartObject(ctx, rej); - res.free(); - rej.free(); - val.then((value) { - res.invoke([value]); - }, onError: (e) { - rej.invoke([e]); - }).whenComplete(() { - refRes.free(); - refRej.free(); - }); - return ret; - } - if (cache == null) cache = Map(); - if (val is bool) return jsNewBool(ctx, val ? 1 : 0); - if (val is int) return jsNewInt64(ctx, val); - if (val is double) return jsNewFloat64(ctx, val); - if (val is String) return jsNewString(ctx, val); - if (val is Uint8List) { - final ptr = malloc(val.length); - final byteList = ptr.asTypedList(val.length); - byteList.setAll(0, val); - final ret = jsNewArrayBufferCopy(ctx, ptr, val.length); - malloc.free(ptr); - return ret; - } - if (cache.containsKey(val)) { - return jsDupValue(ctx, cache[val]!); - } - if (val is List) { - final ret = jsNewArray(ctx); - cache[val] = ret; - for (int i = 0; i < val.length; ++i) { - _definePropertyValue(ctx, ret, i, val[i], cache: cache); - } - return ret; - } - if (val is Map) { - final ret = jsNewObject(ctx); - cache[val] = ret; - for (MapEntry entry in val.entries) { - _definePropertyValue(ctx, ret, entry.key, entry.value, cache: cache); - } - return ret; - } - // wrap Function to JSInvokable - final valWrap = JSInvokable._wrap(val); - final dartObjectClassId = - runtimeOpaques[jsGetRuntime(ctx)]?.dartObjectClassId ?? 0; - if (dartObjectClassId == 0) return jsUNDEFINED(); - final dartObject = jsNewObjectClass( - ctx, - dartObjectClassId, - identityHashCode(_DartObject(ctx, valWrap)), - ); - if (valWrap is JSInvokable) { - final ret = jsNewCFunction(ctx, dartObject); - jsFreeValue(ctx, dartObject); - return ret; - } - return dartObject; -} - -dynamic _jsToDart(Pointer ctx, Pointer val, - {Map? cache}) { - if (cache == null) cache = Map(); - final tag = jsValueGetTag(val); - if (jsTagIsFloat64(tag) != 0) { - return jsToFloat64(ctx, val); - } - switch (tag) { - case JSTag.BOOL: - return jsToBool(ctx, val) != 0; - case JSTag.INT: - return jsToInt64(ctx, val); - case JSTag.STRING: - return jsToCString(ctx, val); - case JSTag.OBJECT: - final rt = jsGetRuntime(ctx); - final dartObjectClassId = runtimeOpaques[rt]?.dartObjectClassId; - if (dartObjectClassId != null) { - final dartObject = _DartObject.fromAddress( - rt, jsGetObjectOpaque(val, dartObjectClassId)); - if (dartObject != null) return dartObject._obj; - } - final psize = malloc(); - final buf = jsGetArrayBuffer(ctx, psize, val); - final size = psize.value; - malloc.free(psize); - if (buf.address != 0) { - return Uint8List.fromList(buf.asTypedList(size)); - } - final valptr = jsValueGetPtr(val); - if (cache.containsKey(valptr)) { - return cache[valptr]; - } - if (jsIsFunction(ctx, val) != 0) { - return _JSFunction(ctx, val); - } else if (jsIsError(ctx, val) != 0) { - final err = jsToCString(ctx, val); - final pstack = _jsGetPropertyValue(ctx, val, 'stack'); - final stack = - jsToBool(ctx, pstack) != 0 ? jsToCString(ctx, pstack) : null; - jsFreeValue(ctx, pstack); - return JSError(err, stack); - } else if (jsIsPromise(ctx, val) != 0) { - final jsPromiseThen = _jsGetPropertyValue(ctx, val, 'then'); - final _JSFunction promiseThen = - _jsToDart(ctx, jsPromiseThen, cache: cache); - jsFreeValue(ctx, jsPromiseThen); - final completer = Completer(); - completer.future.catchError((e) {}); - final jsPromise = _JSObject(ctx, val); - final jsRet = promiseThen._invoke([ - (v) { - JSRef.dupRecursive(v); - if (!completer.isCompleted) completer.complete(v); - }, - (e) { - JSRef.dupRecursive(e); - if (!completer.isCompleted) completer.completeError(e); - }, - ], jsPromise); - jsPromise.free(); - promiseThen.free(); - final isException = jsIsException(jsRet) != 0; - jsFreeValue(ctx, jsRet); - if (isException) throw _parseJSException(ctx); - return completer.future; - } else if (jsIsArray(ctx, val) != 0) { - final jslength = _jsGetPropertyValue(ctx, val, 'length'); - final length = jsToInt64(ctx, jslength); - final ret = []; - cache[valptr] = ret; - for (var i = 0; i < length; ++i) { - final jsProp = _jsGetPropertyValue(ctx, val, i); - ret.add(_jsToDart(ctx, jsProp, cache: cache)); - jsFreeValue(ctx, jsProp); - } - return ret; - } else { - final ptab = malloc>(); - final plen = malloc(); - if (jsGetOwnPropertyNames(ctx, ptab, plen, val, -1) != 0) { - malloc.free(plen); - malloc.free(ptab); - return null; - } - final len = plen.value; - malloc.free(plen); - final ret = Map(); - cache[valptr] = ret; - for (var i = 0; i < len; ++i) { - final jsAtom = jsPropertyEnumGetAtom(ptab.value, i); - final jsAtomValue = jsAtomToValue(ctx, jsAtom); - final jsProp = jsGetProperty(ctx, val, jsAtom); - ret[_jsToDart(ctx, jsAtomValue, cache: cache)] = - _jsToDart(ctx, jsProp, cache: cache); - jsFreeValue(ctx, jsAtomValue); - jsFreeValue(ctx, jsProp); - jsFreeAtom(ctx, jsAtom); - } - jsFree(ctx, ptab.value); - malloc.free(ptab); - return ret; - } - default: - } - return null; -} diff --git a/packages/javascript/javascript_android/lib/src/third_party/vendor-state.yaml b/packages/javascript/javascript_android/lib/src/third_party/vendor-state.yaml deleted file mode 100644 index aef615e..0000000 --- a/packages/javascript/javascript_android/lib/src/third_party/vendor-state.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# DO NOT EDIT: This file is generated by package:vendor version 0.9.6 -version: 0.9.6 -config: - import_rewrites: {} - vendored_dependencies: - flutter_qjs: - package: flutter_qjs - version: 0.3.7 - import_rewrites: {} - include: - - LICENSE - - analysis_options.yaml - - lib/** diff --git a/packages/javascript/javascript_android/lib/src/user_scripts.dart b/packages/javascript/javascript_android/lib/src/user_scripts.dart new file mode 100644 index 0000000..6249897 --- /dev/null +++ b/packages/javascript/javascript_android/lib/src/user_scripts.dart @@ -0,0 +1,5 @@ +import 'scripts/messaging.dart'; + +List getEngineStartupScripts() { + return [MESSAGING_SCRIPT]; +} \ No newline at end of file diff --git a/packages/javascript/javascript_android/lib/weak_reference_utils.dart b/packages/javascript/javascript_android/lib/weak_reference_utils.dart deleted file mode 100644 index f12485a..0000000 --- a/packages/javascript/javascript_android/lib/weak_reference_utils.dart +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/// Helper method for creating callbacks methods with a weak reference. -/// -/// Example: -/// ```dart -/// final JavascriptChannelRegistry javascriptChannelRegistry = ... -/// -/// final WKScriptMessageHandler handler = WKScriptMessageHandler( -/// didReceiveScriptMessage: withWeakReferenceTo( -/// javascriptChannelRegistry, -/// (WeakReference weakReference) { -/// return ( -/// WKUserContentController userContentController, -/// WKScriptMessage message, -/// ) { -/// weakReference.target?.onJavascriptChannelMessage( -/// message.name, -/// message.body!.toString(), -/// ); -/// }; -/// }, -/// ), -/// ); -/// ``` -S withWeakReferenceTo( - T reference, - S Function(WeakReference weakReference) onCreate, -) { - final WeakReference weakReference = WeakReference(reference); - return onCreate(weakReference); -} diff --git a/packages/javascript/javascript_android/pigeons/copyright.txt b/packages/javascript/javascript_android/pigeons/copyright.txt new file mode 100644 index 0000000..3f8e7cb --- /dev/null +++ b/packages/javascript/javascript_android/pigeons/copyright.txt @@ -0,0 +1 @@ +Copyright 2025, Reclaim Protocol. Use of this source code is governed by a license that can be found in the LICENSE file. \ No newline at end of file diff --git a/packages/javascript/javascript_android/pigeons/schema.dart b/packages/javascript/javascript_android/pigeons/schema.dart new file mode 100644 index 0000000..4d05e4c --- /dev/null +++ b/packages/javascript/javascript_android/pigeons/schema.dart @@ -0,0 +1,31 @@ +import 'package:pigeon/pigeon.dart'; + +@ConfigurePigeon( + PigeonOptions( + dartPackageName: 'javascript_android', + input: 'pigeons/schema.dart', + dartOut: 'lib/src/pigeons/messages.pigeon.dart', + kotlinOptions: KotlinOptions( + package: 'org.reclaimprotocol.javascript_android', + ), + kotlinOut: + 'android/src/main/java/org/reclaimprotocol/javascript_android/Messages.kt', + copyrightHeader: 'pigeons/copyright.txt', + ), +) + +/// Apis implemented by the Reclaim module for use by the host. +@HostApi() +abstract class JavaScriptAndroidPlatformApi { + @async + void startJavaScriptEngine(String javascriptEngineId); + @async + void dispose(String javascriptEngineId); + @async + Object? runJavaScriptReturningResult( + String javascriptEngineId, + String javaScript, + ); + @async + void setIsInspectable(String javascriptEngineId, bool isInspectable); +} diff --git a/packages/javascript/javascript_android/pubspec.yaml b/packages/javascript/javascript_android/pubspec.yaml index d9b6a80..1cda931 100644 --- a/packages/javascript/javascript_android/pubspec.yaml +++ b/packages/javascript/javascript_android/pubspec.yaml @@ -16,7 +16,6 @@ flutter: dartPluginClass: JavaScriptAndroid dependencies: - ffi: ^2.1.4 flutter: sdk: flutter javascript_platform_interface: @@ -28,4 +27,3 @@ dev_dependencies: plugin_platform_interface: ^2.1.8 flutter_lints: ^6.0.0 pigeon: ^26.0.0 - vendor: ^0.9.7 diff --git a/packages/javascript/javascript_android/vendor.yaml b/packages/javascript/javascript_android/vendor.yaml deleted file mode 100644 index 84e9d7a..0000000 --- a/packages/javascript/javascript_android/vendor.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# vendor.yaml -# import_rewrites: - # Map of rewrites that should be applied to lib/, bin/ and test/ in project. - # Example: - # import "package:/..." - # is rewritten to: - # import "package:myapp/src/third_party//lib/..." - # where 'myapp' is the root project name. - # flutter_qjs: flutter_qjs -vendored_dependencies: - # Specification of which packages to be vendor into: - # lib/src/third_party// - flutter_qjs: - package: flutter_qjs - version: 0.3.7 - # import_rewrites: - # # Rewrites to be applied inside: lib/src/third_party// - # flutter_qjs: flutter_qjs - include: - # Glob patterns for which files to include from the package. - # For syntax documentation see: https://pub.dev/packages/glob - # - # If not specified `include` will default to the following list: - - LICENSE - - analysis_options.yaml - - lib/** From 61d7f98e0bbd830ccef8b4aed98a67402524bd29 Mon Sep 17 00:00:00 2001 From: Mushaheed Syed Date: Thu, 14 Aug 2025 03:26:28 +0530 Subject: [PATCH 2/4] Fix evaluation and messaging for javascript_android --- .../javascript/example/lib/main.dart | 15 + .../javascript/example/lib/runtime.dart | 1 + .../example/lib/runtime_service.dart | 1 + .../javascript/example/pubspec.yaml | 1 + .../javascript_android/android/build.gradle | 3 +- .../javascript_android/Messages.kt | 162 ------ .../javascript_android/JavaScriptAndroid.kt | 74 ++- .../javascript_android/Messages.kt | 497 +----------------- .../lib/javascript_android.dart | 30 +- .../lib/src/engine_context.dart | 226 +++++++- .../javascript_android/lib/src/parse.dart | 15 + .../lib/src/pigeons/messages.pigeon.dart | 4 +- .../lib/src/scripts/messaging.dart | 49 +- .../lib/src/user_scripts.dart | 6 +- .../javascript_android/pigeons/schema.dart | 4 +- .../javascript_android/pubspec.yaml | 1 + 16 files changed, 347 insertions(+), 742 deletions(-) delete mode 100644 packages/javascript/javascript_android/android/src/main/java/org/reclaimprotocol/javascript_android/Messages.kt create mode 100644 packages/javascript/javascript_android/lib/src/parse.dart diff --git a/packages/javascript/javascript/example/lib/main.dart b/packages/javascript/javascript/example/lib/main.dart index 080dfac..f4dfbac 100644 --- a/packages/javascript/javascript/example/lib/main.dart +++ b/packages/javascript/javascript/example/lib/main.dart @@ -5,12 +5,27 @@ import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:javascript/javascript.dart'; import 'package:javascript_example/runtime_service.dart'; +import 'package:logging/logging.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); GoogleFonts.config.allowRuntimeFetching = true; GoogleFonts.pendingFonts([GoogleFonts.sourceCodePro()]); + hierarchicalLoggingEnabled = true; + Logger.root.level = Level.ALL; + Logger.root.onRecord.listen((record) { + debugPrint( + '(${record.sequenceNumber.toString().padLeft(4)}) ${record.level.name.padLeft(7)} [${record.time}]: ${record.message}', + ); + if (record.error != null) { + debugPrint(record.error.toString()); + if (record.stackTrace != null) { + debugPrintStack(stackTrace: record.stackTrace); + } + } + }); + runApp(const JsInterpreterApp()); } diff --git a/packages/javascript/javascript/example/lib/runtime.dart b/packages/javascript/javascript/example/lib/runtime.dart index 73e7a31..f328e50 100644 --- a/packages/javascript/javascript/example/lib/runtime.dart +++ b/packages/javascript/javascript/example/lib/runtime.dart @@ -56,6 +56,7 @@ final class JsRuntimeDefault implements JsRuntimeDelegate { JavaScriptChannelParams( name: channelName, onMessageReceived: (message) { + print('$channelName.onMessage: $message'); final data = fn(message.message); return JavaScriptReply(message: json.encode(data)); }, diff --git a/packages/javascript/javascript/example/lib/runtime_service.dart b/packages/javascript/javascript/example/lib/runtime_service.dart index a94cb37..fb2f074 100644 --- a/packages/javascript/javascript/example/lib/runtime_service.dart +++ b/packages/javascript/javascript/example/lib/runtime_service.dart @@ -65,6 +65,7 @@ class JsRuntimeService { // if (kDebugMode) { // print('ConsoleLog: ${args.runtimeType}:$args'); // } + print('message: (${args.runtimeType}) $args'); final data = args is List ? args : (args is String diff --git a/packages/javascript/javascript/example/pubspec.yaml b/packages/javascript/javascript/example/pubspec.yaml index d1594f8..1bae91e 100644 --- a/packages/javascript/javascript/example/pubspec.yaml +++ b/packages/javascript/javascript/example/pubspec.yaml @@ -38,6 +38,7 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ + logging: ^1.3.0 web_socket: ^1.0.1 dev_dependencies: diff --git a/packages/javascript/javascript_android/android/build.gradle b/packages/javascript/javascript_android/android/build.gradle index d9c9628..6d9bd31 100644 --- a/packages/javascript/javascript_android/android/build.gradle +++ b/packages/javascript/javascript_android/android/build.gradle @@ -40,10 +40,9 @@ android { dependencies { testImplementation 'org.jetbrains.kotlin:kotlin-test' - testImplementation 'org.mockito:mockito-core:5.0.0' + testImplementation 'org.mockito:mockito-core:5.18.0' implementation "androidx.javascriptengine:javascriptengine:1.0.0" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.6.0"` } testOptions { diff --git a/packages/javascript/javascript_android/android/src/main/java/org/reclaimprotocol/javascript_android/Messages.kt b/packages/javascript/javascript_android/android/src/main/java/org/reclaimprotocol/javascript_android/Messages.kt deleted file mode 100644 index 6cc0435..0000000 --- a/packages/javascript/javascript_android/android/src/main/java/org/reclaimprotocol/javascript_android/Messages.kt +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2025, Reclaim Protocol. Use of this source code is governed by a license that can be found in the LICENSE file. -// Autogenerated from Pigeon (v26.0.0), do not edit directly. -// See also: https://pub.dev/packages/pigeon -@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") - -package org.reclaimprotocol.javascript_android - -import android.util.Log -import io.flutter.plugin.common.BasicMessageChannel -import io.flutter.plugin.common.BinaryMessenger -import io.flutter.plugin.common.EventChannel -import io.flutter.plugin.common.MessageCodec -import io.flutter.plugin.common.StandardMethodCodec -import io.flutter.plugin.common.StandardMessageCodec -import java.io.ByteArrayOutputStream -import java.nio.ByteBuffer -private object MessagesPigeonUtils { - - fun wrapResult(result: Any?): List { - return listOf(result) - } - - fun wrapError(exception: Throwable): List { - return if (exception is FlutterError) { - listOf( - exception.code, - exception.message, - exception.details - ) - } else { - listOf( - exception.javaClass.simpleName, - exception.toString(), - "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception) - ) - } - } -} - -/** - * Error class for passing custom error details to Flutter via a thrown PlatformException. - * @property code The error code. - * @property message The error message. - * @property details The error details. Must be a datatype supported by the api codec. - */ -class FlutterError ( - val code: String, - override val message: String? = null, - val details: Any? = null -) : Throwable() -private open class MessagesPigeonCodec : StandardMessageCodec() { - override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { - return super.readValueOfType(type, buffer) - } - override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { - super.writeValue(stream, value) - } -} - - -/** - * Apis implemented by the Reclaim module for use by the host. - * - * Generated interface from Pigeon that represents a handler of messages from Flutter. - */ -interface JavaScriptAndroidPlatformApi { - fun startJavaScriptEngine(javascriptEngineId: String, callback: (Result) -> Unit) - fun dispose(javascriptEngineId: String, callback: (Result) -> Unit) - fun runJavaScriptReturningResult(javascriptEngineId: String, javaScript: String, callback: (Result) -> Unit) - fun setIsInspectable(javascriptEngineId: String, isInspectable: Boolean, callback: (Result) -> Unit) - - companion object { - /** The codec used by JavaScriptAndroidPlatformApi. */ - val codec: MessageCodec by lazy { - MessagesPigeonCodec() - } - /** Sets up an instance of `JavaScriptAndroidPlatformApi` to handle messages through the `binaryMessenger`. */ - @JvmOverloads - fun setUp(binaryMessenger: BinaryMessenger, api: JavaScriptAndroidPlatformApi?, messageChannelSuffix: String = "") { - val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.startJavaScriptEngine$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val javascriptEngineIdArg = args[0] as String - api.startJavaScriptEngine(javascriptEngineIdArg) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(MessagesPigeonUtils.wrapError(error)) - } else { - reply.reply(MessagesPigeonUtils.wrapResult(null)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.dispose$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val javascriptEngineIdArg = args[0] as String - api.dispose(javascriptEngineIdArg) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(MessagesPigeonUtils.wrapError(error)) - } else { - reply.reply(MessagesPigeonUtils.wrapResult(null)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.runJavaScriptReturningResult$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val javascriptEngineIdArg = args[0] as String - val javaScriptArg = args[1] as String - api.runJavaScriptReturningResult(javascriptEngineIdArg, javaScriptArg) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(MessagesPigeonUtils.wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(MessagesPigeonUtils.wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.setIsInspectable$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val javascriptEngineIdArg = args[0] as String - val isInspectableArg = args[1] as Boolean - api.setIsInspectable(javascriptEngineIdArg, isInspectableArg) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(MessagesPigeonUtils.wrapError(error)) - } else { - reply.reply(MessagesPigeonUtils.wrapResult(null)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - } - } -} diff --git a/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptAndroid.kt b/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptAndroid.kt index 4d4542d..c82f6e9 100644 --- a/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptAndroid.kt +++ b/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptAndroid.kt @@ -4,14 +4,12 @@ import android.util.Log import androidx.core.content.ContextCompat import androidx.javascriptengine.IsolateStartupParameters import androidx.javascriptengine.IsolateTerminatedException -import androidx.javascriptengine.JavaScriptException import androidx.javascriptengine.JavaScriptIsolate import androidx.javascriptengine.JavaScriptSandbox import com.google.common.util.concurrent.FutureCallback import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.ListenableFuture -import java.util.concurrent.TimeUnit - +import java.util.concurrent.Executor class JavaScriptAndroid(private var applicationContext: android.content.Context) : JavaScriptAndroidPlatformApi { @@ -19,8 +17,6 @@ class JavaScriptAndroid(private var applicationContext: android.content.Context) private const val TAG = "JavaScriptAndroid" private var sandbox: ListenableFuture? = null - - } private fun getJSSandbox(): ListenableFuture { @@ -31,21 +27,33 @@ class JavaScriptAndroid(private var applicationContext: android.content.Context) private val activeJsIsolates = mutableMapOf() + private fun getMainExecutor(): Executor { + val executor = ContextCompat.getMainExecutor(applicationContext) + return executor + } + override fun startJavaScriptEngine( javascriptEngineId: String, callback: (Result) -> Unit ) { try { val sandboxFuture = getJSSandbox() - val executor = ContextCompat.getMainExecutor(applicationContext) - Futures.transform(sandboxFuture, { sandbox -> - val startupParams = IsolateStartupParameters() - if (sandbox.isFeatureSupported(JavaScriptSandbox.JS_FEATURE_ISOLATE_MAX_HEAP_SIZE)) { - startupParams.setMaxHeapSizeBytes(100000000) - } - val jsIsolate = sandbox.createIsolate(startupParams) - activeJsIsolates.put(javascriptEngineId, jsIsolate) - callback(Result.success(Unit)) - }, executor) + Futures.addCallback( + sandboxFuture, object : FutureCallback { + override fun onSuccess(sandbox: JavaScriptSandbox) { + val startupParams = IsolateStartupParameters() + if (sandbox.isFeatureSupported(JavaScriptSandbox.JS_FEATURE_ISOLATE_MAX_HEAP_SIZE)) { + startupParams.setMaxHeapSizeBytes(IsolateStartupParameters.AUTOMATIC_MAX_HEAP_SIZE) + } + val jsIsolate = sandbox.createIsolate(startupParams) + activeJsIsolates.put(javascriptEngineId, jsIsolate) + callback(Result.success(Unit)) + } + + override fun onFailure(t: Throwable) { + callback(Result.failure(t)) + } + }, getMainExecutor() + ) } catch (e: Exception) { callback(Result.failure(e)) } @@ -78,15 +86,43 @@ class JavaScriptAndroid(private var applicationContext: android.content.Context) } override fun runJavaScriptReturningResult( - javascriptEngineId: String, javaScript: String, callback: (Result) -> Unit + javascriptEngineId: String, javaScript: String, callback: (Result) -> Unit ) { try { val js = requireJsIsolateById(javascriptEngineId) - val result = js.evaluateJavaScriptAsync(javaScript).get(10, TimeUnit.MINUTES) + var didSubmitResponse = false - Log.i("JavaScriptAndroid", "result: $result") - callback(Result.success(result)) + js.addOnTerminatedCallback(getMainExecutor(), { terminationInfo -> + Log.e(TAG, "The isolate crashed: $terminationInfo") + if (!didSubmitResponse) { + didSubmitResponse = true + callback(Result.failure(IsolateTerminatedException(terminationInfo.toString()))) + } + activeJsIsolates.remove(javascriptEngineId) + }) + + Futures.addCallback( + js.evaluateJavaScriptAsync(javaScript), object : FutureCallback { + override fun onSuccess(result: String) { + if (didSubmitResponse) { + Log.i("JavaScriptAndroid", "A response was received when didSubmitResponse is true: $result") + return + } + didSubmitResponse = true + callback(Result.success(result)) + } + + override fun onFailure(t: Throwable) { + if (didSubmitResponse) { + Log.e("JavaScriptAndroid", "An error was received when didSubmitResponse is true", t) + return + } + didSubmitResponse = true + callback(Result.failure(t)) + } + }, getMainExecutor() + ) } catch (e: Exception) { callback(Result.failure(e)) } diff --git a/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/Messages.kt b/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/Messages.kt index 2bc9c86..ff6963e 100644 --- a/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/Messages.kt +++ b/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/Messages.kt @@ -16,9 +16,6 @@ import java.io.ByteArrayOutputStream import java.nio.ByteBuffer private object MessagesPigeonUtils { - fun createConnectionError(channelName: String): FlutterError { - return FlutterError("channel-error", "Unable to establish connection on channel: '$channelName'.", "") } - fun wrapResult(result: Any?): List { return listOf(result) } @@ -51,373 +48,6 @@ class FlutterError ( override val message: String? = null, val details: Any? = null ) : Throwable() -/** - * Maintains instances used to communicate with the corresponding objects in Dart. - * - * Objects stored in this container are represented by an object in Dart that is also stored in - * an InstanceManager with the same identifier. - * - * When an instance is added with an identifier, either can be used to retrieve the other. - * - * Added instances are added as a weak reference and a strong reference. When the strong - * reference is removed with [remove] and the weak reference is deallocated, the - * `finalizationListener.onFinalize` is called with the instance's identifier. However, if the strong - * reference is removed and then the identifier is retrieved with the intention to pass the identifier - * to Dart (e.g. calling [getIdentifierForStrongReference]), the strong reference to the instance - * is recreated. The strong reference will then need to be removed manually again. - */ -@Suppress("UNCHECKED_CAST", "MemberVisibilityCanBePrivate") -class MessagesPigeonInstanceManager(private val finalizationListener: PigeonFinalizationListener) { - /** Interface for listening when a weak reference of an instance is removed from the manager. */ - interface PigeonFinalizationListener { - fun onFinalize(identifier: Long) - } - - private val identifiers = java.util.WeakHashMap() - private val weakInstances = HashMap>() - private val strongInstances = HashMap() - private val referenceQueue = java.lang.ref.ReferenceQueue() - private val weakReferencesToIdentifiers = HashMap, Long>() - private val handler = android.os.Handler(android.os.Looper.getMainLooper()) - private val releaseAllFinalizedInstancesRunnable = Runnable { - this.releaseAllFinalizedInstances() - } - private var nextIdentifier: Long = minHostCreatedIdentifier - private var hasFinalizationListenerStopped = false - - /** - * Modifies the time interval used to define how often this instance removes garbage collected - * weak references to native Android objects that this instance was managing. - */ - var clearFinalizedWeakReferencesInterval: Long = 3000 - set(value) { - handler.removeCallbacks(releaseAllFinalizedInstancesRunnable) - field = value - releaseAllFinalizedInstances() - } - - init { - handler.postDelayed(releaseAllFinalizedInstancesRunnable, clearFinalizedWeakReferencesInterval) - } - - companion object { - // Identifiers are locked to a specific range to avoid collisions with objects - // created simultaneously from Dart. - // Host uses identifiers >= 2^16 and Dart is expected to use values n where, - // 0 <= n < 2^16. - private const val minHostCreatedIdentifier: Long = 65536 - private const val tag = "PigeonInstanceManager" - - /** - * Instantiate a new manager with a listener for garbage collected weak - * references. - * - * When the manager is no longer needed, [stopFinalizationListener] must be called. - */ - fun create(finalizationListener: PigeonFinalizationListener): MessagesPigeonInstanceManager { - return MessagesPigeonInstanceManager(finalizationListener) - } - } - - /** - * Removes `identifier` and return its associated strongly referenced instance, if present, - * from the manager. - */ - fun remove(identifier: Long): T? { - logWarningIfFinalizationListenerHasStopped() - return strongInstances.remove(identifier) as T? - } - - /** - * Retrieves the identifier paired with an instance, if present, otherwise `null`. - * - * - * If the manager contains a strong reference to `instance`, it will return the identifier - * associated with `instance`. If the manager contains only a weak reference to `instance`, a new - * strong reference to `instance` will be added and will need to be removed again with [remove]. - * - * - * If this method returns a nonnull identifier, this method also expects the Dart - * `MessagesPigeonInstanceManager` to have, or recreate, a weak reference to the Dart instance the - * identifier is associated with. - */ - fun getIdentifierForStrongReference(instance: Any?): Long? { - logWarningIfFinalizationListenerHasStopped() - val identifier = identifiers[instance] - if (identifier != null) { - strongInstances[identifier] = instance!! - } - return identifier - } - - /** - * Adds a new instance that was instantiated from Dart. - * - * The same instance can be added multiple times, but each identifier must be unique. This - * allows two objects that are equivalent (e.g. the `equals` method returns true and their - * hashcodes are equal) to both be added. - * - * [identifier] must be >= 0 and unique. - */ - fun addDartCreatedInstance(instance: Any, identifier: Long) { - logWarningIfFinalizationListenerHasStopped() - addInstance(instance, identifier) - } - - /** - * Adds a new unique instance that was instantiated from the host platform. - * - * If the manager contains [instance], this returns the corresponding identifier. If the - * manager does not contain [instance], this adds the instance and returns a unique - * identifier for that [instance]. - */ - fun addHostCreatedInstance(instance: Any): Long { - logWarningIfFinalizationListenerHasStopped() - require(!containsInstance(instance)) { "Instance of ${instance.javaClass} has already been added." } - val identifier = nextIdentifier++ - addInstance(instance, identifier) - return identifier - } - - /** Retrieves the instance associated with identifier, if present, otherwise `null`. */ - fun getInstance(identifier: Long): T? { - logWarningIfFinalizationListenerHasStopped() - val instance = weakInstances[identifier] as java.lang.ref.WeakReference? - return instance?.get() - } - - /** Returns whether this manager contains the given `instance`. */ - fun containsInstance(instance: Any?): Boolean { - logWarningIfFinalizationListenerHasStopped() - return identifiers.containsKey(instance) - } - - /** - * Stops the periodic run of the [PigeonFinalizationListener] for instances that have been garbage - * collected. - * - * The InstanceManager can continue to be used, but the [PigeonFinalizationListener] will no - * longer be called and methods will log a warning. - */ - fun stopFinalizationListener() { - handler.removeCallbacks(releaseAllFinalizedInstancesRunnable) - hasFinalizationListenerStopped = true - } - - /** - * Removes all of the instances from this manager. - * - * The manager will be empty after this call returns. - */ - fun clear() { - identifiers.clear() - weakInstances.clear() - strongInstances.clear() - weakReferencesToIdentifiers.clear() - } - - /** - * Whether the [PigeonFinalizationListener] is still being called for instances that are garbage - * collected. - * - * See [stopFinalizationListener]. - */ - fun hasFinalizationListenerStopped(): Boolean { - return hasFinalizationListenerStopped - } - - private fun releaseAllFinalizedInstances() { - if (hasFinalizationListenerStopped()) { - return - } - var reference: java.lang.ref.WeakReference? - while ((referenceQueue.poll() as java.lang.ref.WeakReference?).also { reference = it } != null) { - val identifier = weakReferencesToIdentifiers.remove(reference) - if (identifier != null) { - weakInstances.remove(identifier) - strongInstances.remove(identifier) - finalizationListener.onFinalize(identifier) - } - } - handler.postDelayed(releaseAllFinalizedInstancesRunnable, clearFinalizedWeakReferencesInterval) - } - - private fun addInstance(instance: Any, identifier: Long) { - require(identifier >= 0) { "Identifier must be >= 0: $identifier" } - require(!weakInstances.containsKey(identifier)) { - "Identifier has already been added: $identifier" - } - val weakReference = java.lang.ref.WeakReference(instance, referenceQueue) - identifiers[instance] = identifier - weakInstances[identifier] = weakReference - weakReferencesToIdentifiers[weakReference] = identifier - strongInstances[identifier] = instance - } - - private fun logWarningIfFinalizationListenerHasStopped() { - if (hasFinalizationListenerStopped()) { - Log.w( - tag, - "The manager was used after calls to the PigeonFinalizationListener has been stopped." - ) - } - } -} - - -/** Generated API for managing the Dart and native `InstanceManager`s. */ -private class MessagesPigeonInstanceManagerApi(val binaryMessenger: BinaryMessenger) { - companion object { - /** The codec used by MessagesPigeonInstanceManagerApi. */ - val codec: MessageCodec by lazy { - MessagesPigeonCodec() - } - - /** - * Sets up an instance of `MessagesPigeonInstanceManagerApi` to handle messages from the - * `binaryMessenger`. - */ - fun setUpMessageHandlers(binaryMessenger: BinaryMessenger, instanceManager: MessagesPigeonInstanceManager?) { - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.PigeonInternalInstanceManager.removeStrongReference", codec) - if (instanceManager != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val identifierArg = args[0] as Long - val wrapped: List = try { - instanceManager.remove(identifierArg) - listOf(null) - } catch (exception: Throwable) { - MessagesPigeonUtils.wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.PigeonInternalInstanceManager.clear", codec) - if (instanceManager != null) { - channel.setMessageHandler { _, reply -> - val wrapped: List = try { - instanceManager.clear() - listOf(null) - } catch (exception: Throwable) { - MessagesPigeonUtils.wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - } - } - - fun removeStrongReference(identifierArg: Long, callback: (Result) -> Unit) -{ - val channelName = "dev.flutter.pigeon.javascript_android.PigeonInternalInstanceManager.removeStrongReference" - val channel = BasicMessageChannel(binaryMessenger, channelName, codec) - channel.send(listOf(identifierArg)) { - if (it is List<*>) { - if (it.size > 1) { - callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) - } else { - callback(Result.success(Unit)) - } - } else { - callback(Result.failure(MessagesPigeonUtils.createConnectionError(channelName))) - } - } - } -} -/** - * Provides implementations for each ProxyApi implementation and provides access to resources - * needed by any implementation. - */ -abstract class MessagesPigeonProxyApiRegistrar(val binaryMessenger: BinaryMessenger) { - /** Whether APIs should ignore calling to Dart. */ - public var ignoreCallsToDart = false - val instanceManager: MessagesPigeonInstanceManager - private var _codec: MessageCodec? = null - val codec: MessageCodec - get() { - if (_codec == null) { - _codec = MessagesPigeonProxyApiBaseCodec(this) - } - return _codec!! - } - - init { - val api = MessagesPigeonInstanceManagerApi(binaryMessenger) - instanceManager = MessagesPigeonInstanceManager.create( - object : MessagesPigeonInstanceManager.PigeonFinalizationListener { - override fun onFinalize(identifier: Long) { - api.removeStrongReference(identifier) { - if (it.isFailure) { - Log.e( - "PigeonProxyApiRegistrar", - "Failed to remove Dart strong reference with identifier: $identifier" - ) - } - } - } - } - ) - } - /** - * An implementation of [PigeonApiJavaScriptChannel] used to add a new Dart instance of - * `JavaScriptChannel` to the Dart `InstanceManager`. - */ - abstract fun getPigeonApiJavaScriptChannel(): PigeonApiJavaScriptChannel - - fun setUp() { - MessagesPigeonInstanceManagerApi.setUpMessageHandlers(binaryMessenger, instanceManager) - PigeonApiJavaScriptChannel.setUpMessageHandlers(binaryMessenger, getPigeonApiJavaScriptChannel()) - } - fun tearDown() { - MessagesPigeonInstanceManagerApi.setUpMessageHandlers(binaryMessenger, null) - PigeonApiJavaScriptChannel.setUpMessageHandlers(binaryMessenger, null) - } -} -private class MessagesPigeonProxyApiBaseCodec(val registrar: MessagesPigeonProxyApiRegistrar) : MessagesPigeonCodec() { - override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { - return when (type) { - 128.toByte() -> { - val identifier: Long = readValue(buffer) as Long - val instance: Any? = registrar.instanceManager.getInstance(identifier) - if (instance == null) { - Log.e( - "PigeonProxyApiBaseCodec", - "Failed to find instance with identifier: $identifier" - ) - } - return instance - } - else -> super.readValueOfType(type, buffer) - } - } - - override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { - if (value is Boolean || value is ByteArray || value is Double || value is DoubleArray || value is FloatArray || value is Int || value is IntArray || value is List<*> || value is Long || value is LongArray || value is Map<*, *> || value is String || value == null) { - super.writeValue(stream, value) - return - } - - if (value is JavaScriptChannel) { - registrar.getPigeonApiJavaScriptChannel().pigeon_newInstance(value) { } - } - - when { - registrar.instanceManager.containsInstance(value) -> { - stream.write(128) - writeValue(stream, registrar.instanceManager.getIdentifierForStrongReference(value)) - } - else -> throw IllegalArgumentException("Unsupported value: '$value' of type '${value.javaClass.name}'") - } - } -} private open class MessagesPigeonCodec : StandardMessageCodec() { override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { return super.readValueOfType(type, buffer) @@ -428,87 +58,6 @@ private open class MessagesPigeonCodec : StandardMessageCodec() { } -/** - * A JavaScript interface for exposing Javascript callbacks to Dart. - * - * This is a custom class for the wrapper that is annotated with - * [JavascriptInterface](https://developer.android.com/reference/android/webkit/JavascriptInterface). - */ -@Suppress("UNCHECKED_CAST") -abstract class PigeonApiJavaScriptChannel(open val pigeonRegistrar: MessagesPigeonProxyApiRegistrar) { - abstract fun pigeon_defaultConstructor(channelName: String): JavaScriptChannel - - companion object { - @Suppress("LocalVariableName") - fun setUpMessageHandlers(binaryMessenger: BinaryMessenger, api: PigeonApiJavaScriptChannel?) { - val codec = api?.pigeonRegistrar?.codec ?: MessagesPigeonCodec() - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptChannel.pigeon_defaultConstructor", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val pigeon_identifierArg = args[0] as Long - val channelNameArg = args[1] as String - val wrapped: List = try { - api.pigeonRegistrar.instanceManager.addDartCreatedInstance(api.pigeon_defaultConstructor(channelNameArg), pigeon_identifierArg) - listOf(null) - } catch (exception: Throwable) { - MessagesPigeonUtils.wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - } - } - - @Suppress("LocalVariableName", "FunctionName") - /** Creates a Dart instance of JavaScriptChannel and attaches it to [pigeon_instanceArg]. */ - fun pigeon_newInstance(pigeon_instanceArg: JavaScriptChannel, callback: (Result) -> Unit) -{ - if (pigeonRegistrar.ignoreCallsToDart) { - callback( - Result.failure( - FlutterError("ignore-calls-error", "Calls to Dart are being ignored.", ""))) - } else if (pigeonRegistrar.instanceManager.containsInstance(pigeon_instanceArg)) { - callback(Result.success(Unit)) - } else { - callback( - Result.failure( - FlutterError("new-instance-error", "Attempting to create a new Dart instance of JavaScriptChannel, but the class has a nonnull callback method.", ""))) - } - } - - /** Handles callbacks messages from JavaScript. */ - fun postMessage(pigeon_instanceArg: JavaScriptChannel, messageArg: String?, callback: (Result) -> Unit) -{ - if (pigeonRegistrar.ignoreCallsToDart) { - callback( - Result.failure( - FlutterError("ignore-calls-error", "Calls to Dart are being ignored.", ""))) - return - } - val binaryMessenger = pigeonRegistrar.binaryMessenger - val codec = pigeonRegistrar.codec - val channelName = "dev.flutter.pigeon.javascript_android.JavaScriptChannel.postMessage" - val channel = BasicMessageChannel(binaryMessenger, channelName, codec) - channel.send(listOf(pigeon_instanceArg, messageArg)) { - if (it is List<*>) { - if (it.size > 1) { - callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) - } else { - val output = it[0] as String? - callback(Result.success(output)) - } - } else { - callback(Result.failure(MessagesPigeonUtils.createConnectionError(channelName))) - } - } - } - -} /** * Apis implemented by the Reclaim module for use by the host. * @@ -516,10 +65,8 @@ abstract class PigeonApiJavaScriptChannel(open val pigeonRegistrar: MessagesPige */ interface JavaScriptAndroidPlatformApi { fun startJavaScriptEngine(javascriptEngineId: String, callback: (Result) -> Unit) - fun addJavaScriptChannel(javascriptEngineId: String, javaScriptChannelParams: JavaScriptChannel, callback: (Result) -> Unit) fun dispose(javascriptEngineId: String, callback: (Result) -> Unit) - fun removeJavaScriptChannel(javascriptEngineId: String, javaScriptChannelName: String, callback: (Result) -> Unit) - fun runJavaScriptReturningResult(javascriptEngineId: String, javaScript: String, callback: (Result) -> Unit) + fun runJavaScriptReturningResult(javascriptEngineId: String, javaScript: String, callback: (Result) -> Unit) fun setIsInspectable(javascriptEngineId: String, isInspectable: Boolean, callback: (Result) -> Unit) companion object { @@ -550,26 +97,6 @@ interface JavaScriptAndroidPlatformApi { channel.setMessageHandler(null) } } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.addJavaScriptChannel$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val javascriptEngineIdArg = args[0] as String - val javaScriptChannelParamsArg = args[1] as JavaScriptChannel - api.addJavaScriptChannel(javascriptEngineIdArg, javaScriptChannelParamsArg) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(MessagesPigeonUtils.wrapError(error)) - } else { - reply.reply(MessagesPigeonUtils.wrapResult(null)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } run { val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.dispose$separatedMessageChannelSuffix", codec) if (api != null) { @@ -589,26 +116,6 @@ interface JavaScriptAndroidPlatformApi { channel.setMessageHandler(null) } } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.removeJavaScriptChannel$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val javascriptEngineIdArg = args[0] as String - val javaScriptChannelNameArg = args[1] as String - api.removeJavaScriptChannel(javascriptEngineIdArg, javaScriptChannelNameArg) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(MessagesPigeonUtils.wrapError(error)) - } else { - reply.reply(MessagesPigeonUtils.wrapResult(null)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } run { val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.runJavaScriptReturningResult$separatedMessageChannelSuffix", codec) if (api != null) { @@ -616,7 +123,7 @@ interface JavaScriptAndroidPlatformApi { val args = message as List val javascriptEngineIdArg = args[0] as String val javaScriptArg = args[1] as String - api.runJavaScriptReturningResult(javascriptEngineIdArg, javaScriptArg) { result: Result -> + api.runJavaScriptReturningResult(javascriptEngineIdArg, javaScriptArg) { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(MessagesPigeonUtils.wrapError(error)) diff --git a/packages/javascript/javascript_android/lib/javascript_android.dart b/packages/javascript/javascript_android/lib/javascript_android.dart index c5253be..e86e0f5 100644 --- a/packages/javascript/javascript_android/lib/javascript_android.dart +++ b/packages/javascript/javascript_android/lib/javascript_android.dart @@ -2,9 +2,9 @@ import 'package:flutter/foundation.dart'; import 'package:javascript_android/src/user_scripts.dart'; import 'package:javascript_platform_interface/javascript_platform_interface.dart'; +import 'src/parse.dart'; import 'src/engine_context.dart'; import 'src/pigeons/messages.pigeon.dart'; -import 'src/scripts/messaging.dart'; /// The Android implementation of [JavaScriptPlatform]. class JavaScriptAndroid extends JavaScriptPlatform { @@ -17,19 +17,28 @@ class JavaScriptAndroid extends JavaScriptPlatform { JavaScriptPlatform.instance = JavaScriptAndroid(); } - final _activeEngines = {}; + final _activeEngineHostState = {}; EngineHostState _requireEngineState(String javascriptEngineId) { - if (!_activeEngines.containsKey(javascriptEngineId)) { + if (!_activeEngineHostState.containsKey(javascriptEngineId)) { throw Exception('Engine by id "$javascriptEngineId" is not found'); } - return _activeEngines[javascriptEngineId]!; + return _activeEngineHostState[javascriptEngineId]!; } @override - Future startJavaScriptEngine(String javascriptEngineId) async { + Future startJavaScriptEngine( + String javascriptEngineId, { + Duration messageListenerInterval = const Duration(milliseconds: 50), + }) async { await pigeonPlatformApi.startJavaScriptEngine(javascriptEngineId); - _activeEngines[javascriptEngineId] = EngineHostState(); + _activeEngineHostState[javascriptEngineId] = EngineHostState( + engineId: javascriptEngineId, + messageListenerInterval: messageListenerInterval, + runJavaScript: (javaScript) { + return runJavaScriptReturningResult(javascriptEngineId, javaScript); + }, + ); for (final script in getEngineStartupScripts()) { await runJavaScriptReturningResult(javascriptEngineId, script); } @@ -41,7 +50,7 @@ class JavaScriptAndroid extends JavaScriptPlatform { JavaScriptChannelParams javaScriptChannelParams, ) async { final engineState = _requireEngineState(javascriptEngineId); - engineState.addChannel( + await engineState.addChannel( javaScriptChannelParams.name, javaScriptChannelParams, ); @@ -60,7 +69,7 @@ class JavaScriptAndroid extends JavaScriptPlatform { Future dispose(String javascriptEngineId) { final engineState = _requireEngineState(javascriptEngineId); engineState.dispose(); - _activeEngines.remove(javascriptEngineId); + _activeEngineHostState.remove(javascriptEngineId); return pigeonPlatformApi.dispose(javascriptEngineId); } @@ -68,11 +77,12 @@ class JavaScriptAndroid extends JavaScriptPlatform { Future runJavaScriptReturningResult( String javascriptEngineId, String javaScript, - ) { - return pigeonPlatformApi.runJavaScriptReturningResult( + ) async { + final result = await pigeonPlatformApi.runJavaScriptReturningResult( javascriptEngineId, javaScript, ); + return parseValue(result); } @override diff --git a/packages/javascript/javascript_android/lib/src/engine_context.dart b/packages/javascript/javascript_android/lib/src/engine_context.dart index 550baa8..9238d0c 100644 --- a/packages/javascript/javascript_android/lib/src/engine_context.dart +++ b/packages/javascript/javascript_android/lib/src/engine_context.dart @@ -1,17 +1,241 @@ +import 'dart:async'; +import 'dart:convert'; +import 'package:logging/logging.dart'; + import 'package:javascript_platform_interface/javascript_platform_interface.dart'; +typedef RunJavascriptCallback = Future Function(String javaScript); + class EngineHostState { + EngineHostState({ + required this.messageListenerInterval, + required this.engineId, + required RunJavascriptCallback runJavaScript, + }) : _runJavaScript = runJavaScript, + _ensureInitialized = runJavaScript(_MESSAGING_SCRIPT); + + final String engineId; + final Duration messageListenerInterval; + final RunJavascriptCallback _runJavaScript; + final Future _ensureInitialized; + late final Logger _logger = Logger('EngineHostState.$engineId'); + final Map _enabledChannels = {}; - void addChannel(String channelName, JavaScriptChannelParams channelParams) { + Timer? _timer; + + void _ensureMessageListenerActive() { + if (_timer != null) { + return; + } + _startTimer(); + } + + void _startTimer() { + if (_isDisposed) { + return; + } + _timer = Timer.periodic(messageListenerInterval, _onTimerTick); + } + + Future> _getPendingMessages() async { + final channelPendingMessages = _enabledChannels.keys + .map((channelName) { + return '"$channelName": globalThis["$channelName"].getPendingMessages()'; + }) + .join(','); + + final messages = + await _runJavaScript('JSON.stringify({$channelPendingMessages})') + as Map; + + return messages; + } + + final Map> _processingMessages = {}; + + Future _evaluateSafely(String javascript) { + if (_isDisposed) return Future.value(null); + return _runJavaScript(javascript); + } + + void _onTimerTick(Timer timer) async { + timer.cancel(); + if (_isDisposed) { + return; + } + try { + // check for pending messages + final messages = await _getPendingMessages(); + for (final message in messages.entries) { + // send messages to channels and wait for responses + final channelName = message.key; + final events = message.value as List; + final channel = _enabledChannels[channelName]; + if (channel == null) { + _logger.severe('Channel $channelName not found'); + continue; + } + for (final event in events) { + if (event is! Map) { + _logger.severe( + 'Invalid event received for channel $channelName: $event', + ); + continue; + } + final id = event['id'] as int; + final message = event['message']; + final processingEventIds = _processingMessages.putIfAbsent( + channelName, + () => {}, + ); + if (!processingEventIds.contains(id)) { + _processMessage(channel, message, channelName, id); + processingEventIds.add(id); + } + } + // resolve/reject messages + } + } catch (e, s) { + _logger.severe('Error in message listener', e, s); + } + // resume timer + _startTimer(); + } + + Future _processMessage( + JavaScriptChannelParams channel, + Object? message, + String channelName, + int id, + ) async { + Future evaluationResult; + try { + _logger.finest( + 'Processing a new message by id $id for channel $channelName: (${message.runtimeType}) $message', + ); + final response = await channel.onMessageReceived( + JavaScriptMessage( + message: message is String ? message : json.encode(message), + ), + ); + final reply = response.message; + String encodedMessage = 'null'; + if (reply != null) { + encodedMessage = reply; + } + _logger.finest( + 'Resolved message by id $id for channel $channelName: $encodedMessage', + ); + evaluationResult = _evaluateSafely( + 'globalThis["$channelName"].resolveById($id, ${json.encode(encodedMessage)})', + ); + } catch (e) { + final encodedMessage = e.toString(); + _logger.finest( + 'Rejected message by id $id for channel $channelName: $encodedMessage', + ); + evaluationResult = _evaluateSafely( + 'globalThis["$channelName"].rejectById($id, ${json.encode(encodedMessage)})', + ); + } + try { + await evaluationResult; + } catch (e, s) { + _logger.severe('Error in message listener', e, s); + } + final processingEventIds = _processingMessages[channelName]; + processingEventIds?.remove(id); + } + + void _removeTimer() { + _timer?.cancel(); + _timer = null; + } + + Future addChannel( + String channelName, + JavaScriptChannelParams channelParams, + ) async { + await _ensureInitialized; _enabledChannels[channelName] = channelParams; + _ensureMessageListenerActive(); + try { + await _runJavaScript('globalThis["$channelName"] = new HostMessenger();'); + _logger.finest('Channel $channelName added'); + } catch (e, s) { + _logger.severe('Error adding channel $channelName', e, s); + rethrow; + } } void removeChannel(String channelName) { _enabledChannels.remove(channelName); + final events = _processingMessages.remove(channelName); + events?.clear(); + if (_enabledChannels.isEmpty) { + _removeTimer(); + } } + bool _isDisposed = false; + void dispose() { + _isDisposed = true; + _removeTimer(); _enabledChannels.clear(); } } + +const String _MESSAGING_SCRIPT = r''' +class HostMessenger { + constructor() { + this.pendingMessages = []; + this.id = 0; + } + + getPendingMessages() { + return this.pendingMessages.map(m => ({id: m.id, message: m.message})); + } + + removeMessageById(id) { + this.pendingMessages = this.pendingMessages.filter(m => m.id !== id); + } + + resolveById(id, response) { + let message = this.pendingMessages.find(m => m.id === id); + if (message) { + message.resolve(response); + this.removeMessageById(id); + return true; + } + return false; + } + + rejectById(id, error) { + let message = this.pendingMessages.find(m => m.id === id); + if (message) { + message.reject(error); + this.removeMessageById(id); + return true; + } + return false; + } + + postMessage(message) { + let promise = new Promise((resolve, reject) => { + this.pendingMessages.push({ + id: this.id++, + message, + resolve, + reject + }); + }); + return promise; + } +} + +globalThis.sendMessage = function(channelName, message) { + return globalThis[channelName].postMessage(message); +} +'''; diff --git a/packages/javascript/javascript_android/lib/src/parse.dart b/packages/javascript/javascript_android/lib/src/parse.dart new file mode 100644 index 0000000..dbace7d --- /dev/null +++ b/packages/javascript/javascript_android/lib/src/parse.dart @@ -0,0 +1,15 @@ +import 'dart:convert'; + +Object? parseValue(String? result) { + if (result == null) return null; + if (result == 'null') return null; + if (result == 'true') return true; + if (result == 'false') return false; + final numResult = num.tryParse(result); + if (numResult != null) return numResult; + try { + return json.decode(result); + } catch (_) { + return result; + } +} diff --git a/packages/javascript/javascript_android/lib/src/pigeons/messages.pigeon.dart b/packages/javascript/javascript_android/lib/src/pigeons/messages.pigeon.dart index 32051c5..fa8ad10 100644 --- a/packages/javascript/javascript_android/lib/src/pigeons/messages.pigeon.dart +++ b/packages/javascript/javascript_android/lib/src/pigeons/messages.pigeon.dart @@ -98,7 +98,7 @@ class JavaScriptAndroidPlatformApi { } } - Future runJavaScriptReturningResult(String javascriptEngineId, String javaScript) async { + Future runJavaScriptReturningResult(String javascriptEngineId, String javaScript) async { final String pigeonVar_channelName = 'dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.runJavaScriptReturningResult$pigeonVar_messageChannelSuffix'; final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, @@ -117,7 +117,7 @@ class JavaScriptAndroidPlatformApi { details: pigeonVar_replyList[2], ); } else { - return pigeonVar_replyList[0]; + return (pigeonVar_replyList[0] as String?); } } diff --git a/packages/javascript/javascript_android/lib/src/scripts/messaging.dart b/packages/javascript/javascript_android/lib/src/scripts/messaging.dart index b17122f..0b5b067 100644 --- a/packages/javascript/javascript_android/lib/src/scripts/messaging.dart +++ b/packages/javascript/javascript_android/lib/src/scripts/messaging.dart @@ -1,48 +1,7 @@ -const String MESSAGING_SCRIPT = r''' -class HostMessenger { - constructor() { - this.pendingMessages = []; - this.id = 0; - } +sealed class MessagingScript { + - getPendingMessages() { - return this.pendingMessages.map(m => ({id: m.id, message: m.message})); - } + static const String MESSAGE_LISTENER_SCRIPT = r''' - removeMessageById(id) { - this.pendingMessages = this.pendingMessages.filter(m => m.id !== id); - } - - resolveById(id, response) { - let message = this.pendingMessages.find(m => m.id === id); - if (message) { - message.resolve(response); - this.removeMessageById(id); - return true; - } - return false; - } - - rejectById(id, error) { - let message = this.pendingMessages.find(m => m.id === id); - if (message) { - message.reject(error); - this.removeMessageById(id); - return true; - } - return false; - } - - postMessage(message) { - let promise = new Promise((resolve, reject) => { - this.pendingMessages.push({ - id: this.id++, - message, - resolve, - reject - }); - }); - return promise; - } +'''; } -'''; \ No newline at end of file diff --git a/packages/javascript/javascript_android/lib/src/user_scripts.dart b/packages/javascript/javascript_android/lib/src/user_scripts.dart index 6249897..95873c8 100644 --- a/packages/javascript/javascript_android/lib/src/user_scripts.dart +++ b/packages/javascript/javascript_android/lib/src/user_scripts.dart @@ -1,5 +1,3 @@ -import 'scripts/messaging.dart'; - List getEngineStartupScripts() { - return [MESSAGING_SCRIPT]; -} \ No newline at end of file + return []; +} diff --git a/packages/javascript/javascript_android/pigeons/schema.dart b/packages/javascript/javascript_android/pigeons/schema.dart index 4d05e4c..ba9a7b7 100644 --- a/packages/javascript/javascript_android/pigeons/schema.dart +++ b/packages/javascript/javascript_android/pigeons/schema.dart @@ -9,7 +9,7 @@ import 'package:pigeon/pigeon.dart'; package: 'org.reclaimprotocol.javascript_android', ), kotlinOut: - 'android/src/main/java/org/reclaimprotocol/javascript_android/Messages.kt', + 'android/src/main/kotlin/org/reclaimprotocol/javascript_android/Messages.kt', copyrightHeader: 'pigeons/copyright.txt', ), ) @@ -22,7 +22,7 @@ abstract class JavaScriptAndroidPlatformApi { @async void dispose(String javascriptEngineId); @async - Object? runJavaScriptReturningResult( + String? runJavaScriptReturningResult( String javascriptEngineId, String javaScript, ); diff --git a/packages/javascript/javascript_android/pubspec.yaml b/packages/javascript/javascript_android/pubspec.yaml index 1cda931..f6313fd 100644 --- a/packages/javascript/javascript_android/pubspec.yaml +++ b/packages/javascript/javascript_android/pubspec.yaml @@ -20,6 +20,7 @@ dependencies: sdk: flutter javascript_platform_interface: path: ../javascript_platform_interface + logging: ^1.3.0 dev_dependencies: flutter_test: From 75d84b3196e803846ed31d4ff9de3c8e36a9ffcf Mon Sep 17 00:00:00 2001 From: Mushaheed Syed Date: Fri, 15 Aug 2025 21:54:39 +0530 Subject: [PATCH 3/4] Add javascript android --- .../ios/Runner.xcodeproj/project.pbxproj | 112 ++++ .../contents.xcworkspacedata | 3 + .../javascript/example/lib/json.dart | 60 -- .../javascript/example/lib/main.dart | 524 +----------------- .../javascript/example/lib/runtime.dart | 71 --- .../example/lib/runtime_service.dart | 321 ----------- .../javascript/example/lib/src/file.dart | 88 +++ .../javascript/example/lib/src/model.dart | 199 +++++++ .../example/lib/src/runtime_service.dart | 40 ++ .../example/lib/src/ui/command_input.dart | 96 ++++ .../example/lib/src/ui/console_output.dart | 107 ++++ .../example/lib/src/ui/url_input.dart | 54 ++ .../macos/Runner.xcodeproj/project.pbxproj | 98 +++- .../contents.xcworkspacedata | 3 + .../javascript/example/pubspec.yaml | 3 +- .../javascript/example/test/widget_test.dart | 1 + packages/javascript/javascript/lib/impl.dart | 5 + .../javascript/javascript/lib/javascript.dart | 8 + .../javascript_android/JavaScriptAndroid.kt | 56 +- .../javascript_android/JavaScriptPlugin.kt | 25 +- .../javascript_android/Messages.kt | 22 + .../lib/javascript_android.dart | 30 +- .../lib/src/host/scripts.dart | 90 +++ .../{engine_context.dart => host/state.dart} | 154 ++--- .../lib/src/pigeons/messages.pigeon.dart | 115 +++- .../lib/src/scripts/messaging.dart | 7 - .../lib/src/user_scripts.dart | 3 - .../javascript_android/pigeons/schema.dart | 6 +- .../javascript_android/pubspec.yaml | 1 + .../lib/javascript_darwin.dart | 11 + .../lib/javascript_platform_interface.dart | 9 + .../lib/src/method_channel_javascript.dart | 11 + .../javascript_platform_interface_test.dart | 12 + 33 files changed, 1252 insertions(+), 1093 deletions(-) delete mode 100644 packages/javascript/javascript/example/lib/json.dart delete mode 100644 packages/javascript/javascript/example/lib/runtime.dart delete mode 100644 packages/javascript/javascript/example/lib/runtime_service.dart create mode 100644 packages/javascript/javascript/example/lib/src/file.dart create mode 100644 packages/javascript/javascript/example/lib/src/model.dart create mode 100644 packages/javascript/javascript/example/lib/src/runtime_service.dart create mode 100644 packages/javascript/javascript/example/lib/src/ui/command_input.dart create mode 100644 packages/javascript/javascript/example/lib/src/ui/console_output.dart create mode 100644 packages/javascript/javascript/example/lib/src/ui/url_input.dart create mode 100644 packages/javascript/javascript_android/lib/src/host/scripts.dart rename packages/javascript/javascript_android/lib/src/{engine_context.dart => host/state.dart} (61%) delete mode 100644 packages/javascript/javascript_android/lib/src/scripts/messaging.dart delete mode 100644 packages/javascript/javascript_android/lib/src/user_scripts.dart diff --git a/packages/javascript/javascript/example/ios/Runner.xcodeproj/project.pbxproj b/packages/javascript/javascript/example/ios/Runner.xcodeproj/project.pbxproj index f73e4c0..50299ad 100644 --- a/packages/javascript/javascript/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/javascript/javascript/example/ios/Runner.xcodeproj/project.pbxproj @@ -14,6 +14,8 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + C18B3414394AF2B7D715038F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE53F133A9F3BB6133AF9097 /* Pods_Runner.framework */; }; + F4C7252B52516FA16F1A222C /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 35AEE5AE5D4DD0190C00785B /* Pods_RunnerTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -40,11 +42,16 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0CCFC7F62B43C040398F1023 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 310D22F9A35A3CF9422D69AE /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 35AEE5AE5D4DD0190C00785B /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 47634C540BFF1FDF01E5B0C0 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 71F017915446B3AE64C7186C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -55,13 +62,25 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 9B56F23C0F6328AB5ED79AA8 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + C7AD750105693F3956607AF2 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + CE53F133A9F3BB6133AF9097 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 562F4CC1C5DFE72356BA0E49 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + F4C7252B52516FA16F1A222C /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + C18B3414394AF2B7D715038F /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -94,6 +113,8 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, + F5C7AB9347B53C7AD92D7BE3 /* Pods */, + D79F224981C525B33C0BC556 /* Frameworks */, ); sourceTree = ""; }; @@ -121,6 +142,29 @@ path = Runner; sourceTree = ""; }; + D79F224981C525B33C0BC556 /* Frameworks */ = { + isa = PBXGroup; + children = ( + CE53F133A9F3BB6133AF9097 /* Pods_Runner.framework */, + 35AEE5AE5D4DD0190C00785B /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + F5C7AB9347B53C7AD92D7BE3 /* Pods */ = { + isa = PBXGroup; + children = ( + 9B56F23C0F6328AB5ED79AA8 /* Pods-Runner.debug.xcconfig */, + C7AD750105693F3956607AF2 /* Pods-Runner.release.xcconfig */, + 71F017915446B3AE64C7186C /* Pods-Runner.profile.xcconfig */, + 0CCFC7F62B43C040398F1023 /* Pods-RunnerTests.debug.xcconfig */, + 310D22F9A35A3CF9422D69AE /* Pods-RunnerTests.release.xcconfig */, + 47634C540BFF1FDF01E5B0C0 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -128,8 +172,10 @@ isa = PBXNativeTarget; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + 07B0E66F96123F84A12BE111 /* [CP] Check Pods Manifest.lock */, 331C807D294A63A400263BE5 /* Sources */, 331C807F294A63A400263BE5 /* Resources */, + 562F4CC1C5DFE72356BA0E49 /* Frameworks */, ); buildRules = ( ); @@ -145,12 +191,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 34771D4095194AD893A4FF68 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 6D85BD65D456EC00FD8C7CF9 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -222,6 +270,50 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 07B0E66F96123F84A12BE111 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 34771D4095194AD893A4FF68 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -238,6 +330,23 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; + 6D85BD65D456EC00FD8C7CF9 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -379,6 +488,7 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 0CCFC7F62B43C040398F1023 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -396,6 +506,7 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 310D22F9A35A3CF9422D69AE /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -411,6 +522,7 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 47634C540BFF1FDF01E5B0C0 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; diff --git a/packages/javascript/javascript/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/javascript/javascript/example/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/packages/javascript/javascript/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/packages/javascript/javascript/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/packages/javascript/javascript/example/lib/json.dart b/packages/javascript/javascript/example/lib/json.dart deleted file mode 100644 index da7c5b0..0000000 --- a/packages/javascript/javascript/example/lib/json.dart +++ /dev/null @@ -1,60 +0,0 @@ - -import 'dart:convert'; -import 'dart:typed_data'; - -final RegExp _base64 = RegExp(r'^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$'); - -/// check if a string is base64 encoded -bool _isBase64(String str) { - return _base64.hasMatch(str); -} - -Object? bytesToBase64Json(Uint8List bytes) { - final base64String = base64.encode(bytes); - return {'type': 'uint8array', 'value': base64String}; -} - -Object? _base64JsonReviver(Object? key, Object? value) { - if (value is Map) { - final hasStringKeys = value.keys.every((key) => key is String); - final hasIntValues = value.values.every((value) => value is int); - if (hasStringKeys && hasIntValues) { - final bytes = Uint8List(value.length); - for (final entry in value.entries) { - bytes[int.parse(entry.key)] = entry.value as int; - } - final base64String = base64.encode(bytes); - return {'type': 'uint8array', 'value': base64String}; - } - } - if (value is String && _isBase64(value)) { - return {'type': 'uint8array', 'value': value}; - } - return value; -} - -String reformatJsonStringForRPC(String jsonString) { - return json.encode(json.decode(jsonString, reviver: _base64JsonReviver)); -} - -Object? replaceBase64Json(Object? value) { - if (value is Map) { - if (value['type'] == 'uint8array') { - return value['value']; - } - final newMap = {}; - for (final entry in value.entries) { - newMap[entry.key] = replaceBase64Json(entry.value); - } - return newMap; - } - if (value is List) { - final newList = []; - for (final entry in value) { - newList.add(replaceBase64Json(entry)); - } - return newList; - } - - return value; -} \ No newline at end of file diff --git a/packages/javascript/javascript/example/lib/main.dart b/packages/javascript/javascript/example/lib/main.dart index f4dfbac..cfda069 100644 --- a/packages/javascript/javascript/example/lib/main.dart +++ b/packages/javascript/javascript/example/lib/main.dart @@ -1,17 +1,21 @@ -import 'dart:convert'; - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'package:javascript/javascript.dart'; -import 'package:javascript_example/runtime_service.dart'; +import 'package:javascript_example/src/runtime_service.dart'; import 'package:logging/logging.dart'; +import 'src/model.dart'; +import 'src/ui/command_input.dart'; +import 'src/ui/console_output.dart'; +import 'src/ui/url_input.dart'; + void main() { WidgetsFlutterBinding.ensureInitialized(); + + // Load fonts GoogleFonts.config.allowRuntimeFetching = true; GoogleFonts.pendingFonts([GoogleFonts.sourceCodePro()]); + // setup logging hierarchicalLoggingEnabled = true; Logger.root.level = Level.ALL; Logger.root.onRecord.listen((record) { @@ -55,228 +59,6 @@ class JsInterpreterApp extends StatelessWidget { } } -// Repository Layer -class JsCodeRepository { - final JsRuntimeService _jsService; - - JsCodeRepository(this._jsService); - - Future executeCode(String code) async { - return await _jsService.evaluate(code); - } - - Future loadFromUrl(String url) async { - return await _jsService.loadJsFromUrl(url); - } - - void setConsole({ - required void Function(String message) log, - required void Function(String message) error, - required void Function(String message) info, - required void Function(String message) warn, - }) { - return _jsService.setConsole( - log: log, - error: error, - info: info, - warn: warn, - ); - } - - void setRPCMessageHandler( - String module, - void Function(dynamic args) handler, - ) { - return _jsService.setRPCMessageHandler(module, handler); - } -} - -// Use Case Layer -class ExecuteJsUseCase { - final JsCodeRepository _repository; - - ExecuteJsUseCase(this._repository); - - Future execute(String code) async { - return await _repository.executeCode(code); - } - - Future loadFromUrl(String url) async { - return await _repository.loadFromUrl(url); - } - - void setConsole({ - required void Function(String message) log, - required void Function(String message) error, - required void Function(String message) info, - required void Function(String message) warn, - }) { - return _repository.setConsole( - log: log, - error: error, - info: info, - warn: warn, - ); - } - - void setRPCMessageHandler( - String module, - void Function(dynamic args) handler, - ) { - return _repository.setRPCMessageHandler(module, handler); - } -} - -// ViewModel -class JsInterpreterViewModel extends ChangeNotifier { - final ExecuteJsUseCase _useCase; - - Object? _result; - Object? _error; - bool _isLoading = false; - final List _consoleHistory = []; - final TextEditingController _inputController = TextEditingController(); - final TextEditingController _urlController = TextEditingController(); - - JsInterpreterViewModel(this._useCase) { - _useCase.setConsole( - log: (message) => _addToHistory(ConsoleEntry.output(message)), - error: (message) => _addToHistory(ConsoleEntry.error(message)), - info: (message) => _addToHistory(ConsoleEntry.info(message)), - warn: (message) => _addToHistory(ConsoleEntry.warn(message)), - ); - _useCase.setRPCMessageHandler('attestor-core', (args) { - try { - _addToHistory( - ConsoleEntry.output(args is String ? args : json.encode(args)), - ); - } catch (e, s) { - _addToHistory(ConsoleEntry.error('Error parsing RPC message: $e\n$s')); - } - }); - } - - Object? get result => _result; - Object? get error => _error; - bool get isLoading => _isLoading; - List get consoleHistory => _consoleHistory; - TextEditingController get inputController => _inputController; - TextEditingController get urlController => _urlController; - - Future executeCode() async { - final code = _inputController.text.trim(); - if (code.isEmpty) { - if (kDebugMode) { - print('no code entered'); - } - return; - } - - _addToHistory(ConsoleEntry.input(code)); - _setLoading(true); - _clearError(); - - try { - _result = await _useCase.execute(code); - _addToHistory(ConsoleEntry.output(_result.toString())); - clearInput(); - } catch (e) { - _error = e; - _addToHistory( - ConsoleEntry.error( - e is JavaScriptExecutionException ? e.message : e.toString(), - ), - ); - } finally { - _setLoading(false); - } - } - - Future loadFromUrl() async { - final url = _urlController.text.trim(); - if (url.isEmpty) return; - - _setLoading(true); - _clearError(); - - try { - final code = await _useCase.loadFromUrl(url); - _inputController.text = code; - _addToHistory(ConsoleEntry.info('Loaded code from: $url')); - } catch (e) { - _error = e; - _addToHistory( - ConsoleEntry.error('Failed to load from URL: ${e.toString()}'), - ); - } finally { - _setLoading(false); - } - } - - void clearAll() { - _inputController.clear(); - _urlController.clear(); - _clearResult(); - _clearError(); - _consoleHistory.clear(); - notifyListeners(); - } - - void clearInput() { - _inputController.clear(); - notifyListeners(); - } - - void _setLoading(bool loading) { - _isLoading = loading; - notifyListeners(); - } - - void _clearError() { - _error = null; - notifyListeners(); - } - - void _clearResult() { - _result = null; - notifyListeners(); - } - - void _addToHistory(ConsoleEntry entry) { - _consoleHistory.add(entry); - notifyListeners(); - } - - @override - void dispose() { - _inputController.dispose(); - _urlController.dispose(); - super.dispose(); - } -} - -// Models -class ConsoleEntry { - final String content; - final ConsoleEntryType type; - final DateTime timestamp; - - ConsoleEntry(this.content, this.type) : timestamp = DateTime.now(); - - factory ConsoleEntry.input(String content) => - ConsoleEntry(content, ConsoleEntryType.input); - factory ConsoleEntry.output(String content) => - ConsoleEntry(content, ConsoleEntryType.output); - factory ConsoleEntry.error(String content) => - ConsoleEntry(content, ConsoleEntryType.error); - factory ConsoleEntry.info(String content) => - ConsoleEntry(content, ConsoleEntryType.info); - factory ConsoleEntry.warn(String content) => - ConsoleEntry(content, ConsoleEntryType.warn); -} - -enum ConsoleEntryType { input, output, error, info, warn } - // Main Page class JsInterpreterPage extends StatefulWidget { const JsInterpreterPage({super.key}); @@ -286,25 +68,26 @@ class JsInterpreterPage extends StatefulWidget { } class _JsInterpreterPageState extends State { - JsInterpreterViewModel? _viewModel; - JsRuntimeService? _jsService; - ExecuteJsUseCase? _useCase; - JsCodeRepository? _repository; + final JsRuntimeService _jsService = JsRuntimeService(); + late final JsInterpreterViewModel _viewModel = JsInterpreterViewModel( + _jsService, + ); final ScrollController _scrollController = ScrollController(); @override void initState() { super.initState(); + _viewModel.addListener(_onViewModelChanged); _initializeServices(); } + bool _isInitialized = false; + Future _initializeServices() async { - _jsService = JsRuntimeService(); - await _jsService!.initialize(); - _repository = JsCodeRepository(_jsService!); - _useCase = ExecuteJsUseCase(_repository!); - _viewModel = JsInterpreterViewModel(_useCase!); - _viewModel!.addListener(_onViewModelChanged); + if (_isInitialized) return; + await _jsService.initialize(); + await _viewModel.initialize(); + _isInitialized = true; setState(() {}); } @@ -325,15 +108,15 @@ class _JsInterpreterPageState extends State { @override void dispose() { - _viewModel?.dispose(); - _jsService?.dispose(); + _viewModel.dispose(); + _jsService.dispose(); _scrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { - if (_viewModel == null) { + if (!_isInitialized) { return const Scaffold( body: Center(child: CircularProgressIndicator(color: Colors.green)), ); @@ -344,7 +127,7 @@ class _JsInterpreterPageState extends State { title: const Text('JS Interpreter Console'), actions: [ IconButton( - onPressed: _viewModel?.clearAll, + onPressed: _viewModel.clearAll, icon: const Icon(Icons.clear_all), tooltip: 'Clear All', ), @@ -352,269 +135,16 @@ class _JsInterpreterPageState extends State { ), body: Column( children: [ - // URL Input Section - UrlInputSection(viewModel: _viewModel!), + UrlInputSection(viewModel: _viewModel), - // Console Output Expanded( child: ConsoleOutputSection( - viewModel: _viewModel!, + viewModel: _viewModel, scrollController: _scrollController, ), ), - // Command Input Section - CommandInputSection(viewModel: _viewModel!), - ], - ), - ); - } -} - -// Widget Components -class UrlInputSection extends StatelessWidget { - final JsInterpreterViewModel viewModel; - - const UrlInputSection({super.key, required this.viewModel}); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: const Color(0xFF161B22), - border: Border(bottom: BorderSide(color: Colors.grey[800]!, width: 1)), - ), - child: Row( - children: [ - const Icon(Icons.link, color: Colors.green, size: 20), - const SizedBox(width: 8), - Expanded( - child: TextField( - controller: viewModel.urlController, - style: const TextStyle(color: Colors.white, fontSize: 14), - decoration: InputDecoration( - hintText: 'Enter JS source URL (optional)', - hintStyle: TextStyle(color: Colors.grey[600]), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide(color: Colors.grey[700]!), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: const BorderSide(color: Colors.green), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - ), - onSubmitted: (_) => viewModel.loadFromUrl(), - ), - ), - const SizedBox(width: 8), - IconButton( - onPressed: viewModel.loadFromUrl, - icon: const Icon(Icons.download, color: Colors.green), - tooltip: 'Load from URL', - ), - ], - ), - ); - } -} - -class ConsoleOutputSection extends StatelessWidget { - final JsInterpreterViewModel viewModel; - final ScrollController scrollController; - - const ConsoleOutputSection({ - super.key, - required this.viewModel, - required this.scrollController, - }); - - @override - Widget build(BuildContext context) { - return Container( - color: const Color(0xFF0D1117), - child: ListView.builder( - controller: scrollController, - padding: const EdgeInsets.all(16), - itemCount: viewModel.consoleHistory.length, - itemBuilder: (context, index) { - final entry = viewModel.consoleHistory[index]; - return ConsoleEntryWidget(entry: entry); - }, - ), - ); - } -} - -class ConsoleEntryWidget extends StatelessWidget { - final ConsoleEntry entry; - - const ConsoleEntryWidget({super.key, required this.entry}); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 2), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildPrefix(), - const SizedBox(width: 8), - Expanded( - child: ConstrainedBox( - constraints: BoxConstraints(maxHeight: 1.2 * 14 * 20), - child: Text( - entry.content, - style: _getTextStyle(), - softWrap: true, - ), - ), - ), - ], - ), - ); - } - - Widget _buildPrefix() { - switch (entry.type) { - case ConsoleEntryType.input: - return const Text( - '> ', - style: TextStyle(color: Colors.green, fontWeight: FontWeight.bold), - ); - case ConsoleEntryType.output: - return const Text( - '← ', - style: TextStyle(color: Colors.blue, fontWeight: FontWeight.bold), - ); - case ConsoleEntryType.error: - return const Text( - '✗ ', - style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold), - ); - case ConsoleEntryType.warn: - return const Text( - '! ', - style: TextStyle(color: Colors.orange, fontWeight: FontWeight.bold), - ); - case ConsoleEntryType.info: - return const Text( - 'ℹ ', - style: TextStyle(color: Colors.yellow, fontWeight: FontWeight.bold), - ); - } - } - - TextStyle _getTextStyle() { - final baseStyle = GoogleFonts.sourceCodePro(fontSize: 14); - - switch (entry.type) { - case ConsoleEntryType.input: - return baseStyle.copyWith(color: Colors.green); - case ConsoleEntryType.output: - return baseStyle.copyWith(color: Colors.white); - case ConsoleEntryType.error: - return baseStyle.copyWith(color: Colors.red); - case ConsoleEntryType.warn: - return baseStyle.copyWith(color: Colors.orange); - case ConsoleEntryType.info: - return baseStyle.copyWith(color: Colors.yellow); - } - } -} - -class CommandInputSection extends StatelessWidget { - final JsInterpreterViewModel viewModel; - - const CommandInputSection({super.key, required this.viewModel}); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: const Color(0xFF161B22), - border: Border(top: BorderSide(color: Colors.grey[800]!, width: 1)), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(top: 12.0), - child: const Icon( - Icons.chevron_right, - color: Colors.green, - size: 16, - ), - ), - Expanded( - child: TextField( - controller: viewModel.inputController, - style: const TextStyle( - color: Colors.white, - fontSize: 16, - fontFamily: 'monospace', - ), - decoration: const InputDecoration( - border: InputBorder.none, - hintText: 'Enter JavaScript code...', - hintStyle: TextStyle(color: Colors.grey), - ), - onSubmitted: (_) => viewModel.executeCode(), - maxLines: 5, - textCapitalization: TextCapitalization.none, - keyboardType: TextInputType.text, - textInputAction: TextInputAction.done, - ), - ), - const SizedBox(width: 8), - if (viewModel.isLoading) - const SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - strokeWidth: 2, - color: Colors.green, - ), - ) - else - Column( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - onPressed: viewModel.executeCode, - icon: const Icon(Icons.play_arrow, color: Colors.green), - tooltip: 'Execute (Enter)', - ), - ], - ), - ], - ), - Row( - children: [ - AnimatedBuilder( - animation: viewModel._inputController, - builder: (context, child) { - if (viewModel._inputController.text.isEmpty) { - return const SizedBox(height: kMinInteractiveDimension); - } - return OutlinedButton.icon( - onPressed: viewModel.clearInput, - icon: const Icon(Icons.close, color: Colors.green), - label: const Text('Clear'), - ); - }, - ), - ], - ), + CommandInputSection(viewModel: _viewModel), ], ), ); diff --git a/packages/javascript/javascript/example/lib/runtime.dart b/packages/javascript/javascript/example/lib/runtime.dart deleted file mode 100644 index f328e50..0000000 --- a/packages/javascript/javascript/example/lib/runtime.dart +++ /dev/null @@ -1,71 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/foundation.dart'; -import 'package:javascript/javascript.dart'; - -abstract interface class JsRuntimeDelegate { - factory JsRuntimeDelegate() { - return JsRuntimeDefault(); - } - - Future initialize(); - - Future evaluate(String source); - dynamic onMessage(String channelName, dynamic Function(dynamic args) fn); - - void dispose(); -} - -final class JsRuntimeDefault implements JsRuntimeDelegate { - JsRuntimeDefault(); - - late final JavaScript _jsRuntime; - - @override - Future initialize() async { - try { - _jsRuntime = await JavaScript.createNew(); - if (kDebugMode) { - print('kDebugMode: $kDebugMode, ${_jsRuntime.runtimeType}'); - } - _jsRuntime.setIsInspectable(kDebugMode); - _jsRuntime.runJavaScriptReturningResult(""" - console.info = function() { - sendMessage('ConsoleLog', JSON.stringify(['info', ...arguments])); - } - """); - } catch (e, stackTrace) { - if (kDebugMode) { - print('Error initializing JS runtime: $e'); - print('Stack trace: $stackTrace'); - } - rethrow; - } - } - - @override - Future evaluate(String source) async { - final value = await _jsRuntime.runJavaScriptReturningResult(source); - print('evaluate: $value'); - return value; - } - - @override - dynamic onMessage(String channelName, dynamic Function(dynamic args) fn) { - return _jsRuntime.addJavaScriptChannel( - JavaScriptChannelParams( - name: channelName, - onMessageReceived: (message) { - print('$channelName.onMessage: $message'); - final data = fn(message.message); - return JavaScriptReply(message: json.encode(data)); - }, - ), - ); - } - - @override - void dispose() { - _jsRuntime.dispose(); - } -} diff --git a/packages/javascript/javascript/example/lib/runtime_service.dart b/packages/javascript/javascript/example/lib/runtime_service.dart deleted file mode 100644 index fb2f074..0000000 --- a/packages/javascript/javascript/example/lib/runtime_service.dart +++ /dev/null @@ -1,321 +0,0 @@ -import 'dart:convert'; -import 'dart:math'; - -import 'package:flutter/foundation.dart'; -import 'package:http/http.dart' as http; -import 'package:javascript_example/json.dart'; -import 'package:javascript_example/runtime.dart'; -import 'package:web_socket/web_socket.dart'; - -// Service Layer -class JsRuntimeService { - late JsRuntimeDelegate _jsRuntime; - late http.Client _httpClient; - - Future initialize() async { - _jsRuntime = JsRuntimeDelegate(); - _httpClient = http.Client(); - return _jsRuntime.initialize(); - } - - Future evaluate(String source) async { - return await _jsRuntime.evaluate(source); - } - - Future loadJsFromUrl(String url) async { - if (url.isEmpty) { - throw Exception('URL is empty'); - } - final response = await _httpClient.get(Uri.parse(url)); - if (response.statusCode >= 200 && response.statusCode < 300) { - return response.body; - } else { - throw Exception('Failed to load JS from URL: ${response.statusCode}'); - } - } - - void dispose() { - _httpClient.close(); - _jsRuntime.dispose(); - } - - void setConsole({ - required void Function(String message) log, - required void Function(String message) info, - required void Function(String message) warn, - required void Function(String message) error, - }) { - try { - debugPrint('Setting console'); - _jsRuntime.evaluate(""" - console.log = function() { - sendMessage('AppConsoleLog', JSON.stringify(['log', ...arguments])); - } - console.info = function() { - sendMessage('AppConsoleLog', JSON.stringify(['info', ...arguments])); - } - console.warn = function() { - sendMessage('AppConsoleLog', JSON.stringify(['warn', ...arguments])); - } - console.error = function() { - sendMessage('AppConsoleLog', JSON.stringify(['error', ...arguments])); - } - """); - _jsRuntime.onMessage('AppConsoleLog', (dynamic args) { - // if (kDebugMode) { - // print('ConsoleLog: ${args.runtimeType}:$args'); - // } - print('message: (${args.runtimeType}) $args'); - final data = args is List - ? args - : (args is String - ? json.decode(args) as List - : throw FormatException('Invalid console log format')); - final logType = data.removeAt(0); - String output = data.join(' '); - debugPrint('jsconsole [$logType]: $output'); - switch (logType) { - case 'info': - info(output); - break; - case 'warn': - warn(output); - break; - case 'error': - error(output); - break; - case 'log': - default: - log(output); - break; - } - }); - } catch (e, s) { - if (kDebugMode) { - print('Error setting console: $e'); - print('Stack trace: $s'); - } - rethrow; - } - } - - final Map _sockets = {}; - - void _addSocket(String id, WebSocket ws) { - _sockets[id] = ws; - } - - bool _isSetDebug = false; - - void setRPCMessageHandler( - String module, - void Function(dynamic args) handler, - ) { - if (kDebugMode) { - print('setRPCMessageHandler: $module'); - } - _jsRuntime.onMessage(module, (args) async { - try { - final cmd = args is Map - ? args - : (args is String - ? json.decode(args) as Map - : throw FormatException('Invalid RPC message format')); - final response = await (args) async { - try { - debugPrint('jsconsole-rpc [$module]: $args'); - handler(args); - switch (cmd['type']) { - case 'connectWs': - if (!_isSetDebug) { - _isSetDebug = true; - sendRPCMessage( - requestId: generateRequestId(), - type: 'setLogLevel', - request: {'logLevel': 'debug', 'sendLogsToApp': true}, - ); - await Future.delayed(const Duration(seconds: 1)); - } - - final request = cmd['request'] as Map?; - if (request == null) { - throw Exception('Invalid request: $cmd'); - } - final id = request['id'] as String?; - final url = request['url'] as String?; - if (id == null || url == null) { - throw Exception('Invalid request: $cmd'); - } - final ws = await WebSocket.connect(Uri.parse(url)); - _addSocket(id, ws); - ws.events.listen((ev) { - switch (ev) { - case TextDataReceived(): - final data = ev.text; - debugPrint('jsconsole-rpc [$module]: TEXT RECEIVED: $ev'); - sendRPCMessage( - requestId: generateRequestId(), - type: 'sendWsMessage', - request: {'id': id, 'data': data}, - ); - break; - case BinaryDataReceived(): - final data = ev.data; - debugPrint( - 'jsconsole-rpc [$module]: BINARY RECEIVED: $ev', - ); - sendRPCMessage( - requestId: generateRequestId(), - type: 'sendWsMessage', - request: {'id': id, 'data': bytesToBase64Json(data)}, - ); - break; - case CloseReceived(): - debugPrint( - 'jsconsole-rpc [$module]: CLOSE RECEIVED: $ev', - ); - sendRPCMessage( - requestId: generateRequestId(), - type: 'disconnectWs', - request: {'id': id}, - ); - _sockets.remove(id); - break; - } - }); - return {}; - case 'setLogLevelDone': - case 'createClaimDone': - case 'log': - case 'console': - debugPrint('jsconsole-rpc [$module]: console: $cmd'); - return null; - case 'error': - debugPrint('jsconsole-rpc [$module]: err: $cmd'); - return null; - case 'disconnectWs': - final request = cmd['request'] as Map; - final id = request['id'] as String; - final ws = _sockets[id]; - if (ws == null) { - throw Exception('WebSocket not found'); - } - ws.close(); - _sockets.remove(id); - return {}; - case 'sendWsMessage': - final request = cmd['request'] as Map; - final id = request['id'] as String; - final data = request['data']; - final ws = _sockets[id]; - debugPrint( - 'jsconsole-rpc [$module]: sendWsMessage SENDING TO WS: $id => (${data.runtimeType}) $data', - ); - if (ws == null) { - throw Exception('WebSocket not found'); - } - if (data is String) { - ws.sendText(data); - } else if (data is Map && data['type'] == 'uint8array') { - final bytes = base64.decode(data['value'] as String); - ws.sendBytes(bytes); - } else { - throw Exception('Invalid data type: ${data.runtimeType}'); - } - return {}; - case 'createClaimStep': - debugPrint('jsconsole-rpc [$module]: createClaimStep'); - return null; - default: - debugPrint('jsconsole-rpc [$module]: UNKNOWN COMMAND: $cmd'); - throw UnsupportedError('Unknown RPC command: ${cmd['type']}'); - } - } catch (e, s) { - debugPrint('jsconsole-rpc [$module]: $e\n$s'); - debugPrintStack(stackTrace: s); - rethrow; - } - }(args); - if (response == null) { - return; - } - sendRPCResponse( - requestId: cmd['id'] ?? generateRequestId(), - type: cmd['type'] ?? 'unknown', - response: response, - ); - } catch (e, s) { - debugPrint('jsconsole-rpc ERROR [$module]: $e\n$s'); - debugPrintStack(stackTrace: s); - sendRPCErrorResponse( - requestId: generateRequestId(), - message: e.toString(), - stack: s.toString(), - ); - } - }); - if (kDebugMode) { - print('setRPCMessageHandler: $module: done'); - } - } - - void sendRPCMessage({ - required String requestId, - required String type, - required Map request, - }) { - _jsRuntime.evaluate(''' - handleIncomingMessage(${json.encode(json.encode({ - // this is a random ID you generate, - // use to match the response to the request - 'id': requestId, - // the type of request you want to make - 'type': type, - 'request': request, - }))}); -'''); - } - - void sendRPCResponse({ - required String requestId, - required String type, - required Map response, - }) { - _jsRuntime.evaluate(''' - handleIncomingMessage(${json.encode({ - // this is a random ID you generate, - // use to match the response to the request - 'id': requestId, - // the type of request you want to make - 'type': '${type}Done', - 'isResponse': true, - 'response': response, - })}); -'''); - } - - void sendRPCErrorResponse({ - required String requestId, - required String message, - required String stack, - }) { - _jsRuntime.evaluate(''' - handleIncomingMessage(${json.encode({ - // this is a random ID you generate, - // use to match the response to the request - 'id': requestId, - // the type of request you want to make - 'type': 'error', - 'isResponse': true, - 'data': {'message': message, 'stack': stack}, - })}); -'''); - } - - static String generateRequestId() { - final random = Random.secure(); - final randomNumber = random.nextDouble(); - final hexString = randomNumber.toStringAsFixed(16).substring(2); - return hexString; - } -} diff --git a/packages/javascript/javascript/example/lib/src/file.dart b/packages/javascript/javascript/example/lib/src/file.dart new file mode 100644 index 0000000..9011f9f --- /dev/null +++ b/packages/javascript/javascript/example/lib/src/file.dart @@ -0,0 +1,88 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:crypto/crypto.dart'; +import 'package:logging/logging.dart'; +import 'package:http/http.dart' as http; + +Future getFileForUrl(String url, [String extension = '']) async { + final dir = Directory.systemTemp; + await dir.create(recursive: true); + final fileHash = sha1.convert(utf8.encode(url)).toString(); + final file = File('${dir.path}/$fileHash$extension'); + if (file.existsSync()) { + await file.delete(); + } + await file.create(recursive: true); + return file; +} + +Future readResponseToFile( + http.StreamedResponse response, { + String extension = '', +}) async { + final logger = Logger('readResponseToFile'); + + final request = response.request; + if (request == null) { + throw Exception('request is null'); + } + if (response.statusCode < 200 || response.statusCode >= 300) { + throw Exception('response status code is not 2xx'); + } + final file = await getFileForUrl(request.url.toString(), extension); + + final sink = file.openWrite(mode: FileMode.writeOnlyAppend); + + bool isFileClosed = false; + + try { + final doneCompleter = Completer(); + + response.stream.listen( + sink.add, + onError: (e, s) { + isFileClosed = false; + doneCompleter.completeError(e, s); + sink.close(); + }, + onDone: () async { + try { + await sink.flush(); + await sink.close(); + isFileClosed = true; + doneCompleter.complete(); + } catch (e, s) { + logger.severe('Error flushing file', e, s); + doneCompleter.completeError(e, s); + } + }, + cancelOnError: true, + ); + + await doneCompleter.future; + } catch (e, s) { + logger.severe('Error downloading file', e, s); + rethrow; + } finally { + try { + if (!isFileClosed) { + await sink.close(); + } + } catch (e, s) { + logger.severe('Error closing file', e, s); + } + } + + return file; +} + +final _client = http.Client(); + +Future downloadFromUrl(String url, {String extension = ''}) async { + final response = await _client.send(http.Request('GET', Uri.parse(url))); + final file = await readResponseToFile(response, extension: extension); + + return file; +} diff --git a/packages/javascript/javascript/example/lib/src/model.dart b/packages/javascript/javascript/example/lib/src/model.dart new file mode 100644 index 0000000..85ef793 --- /dev/null +++ b/packages/javascript/javascript/example/lib/src/model.dart @@ -0,0 +1,199 @@ +import 'dart:convert'; + +import 'package:flutter/widgets.dart'; +import 'package:javascript/javascript.dart'; +import 'package:logging/logging.dart'; + +import 'runtime_service.dart'; + +final Logger _log = Logger('JsInterpreterViewModel'); + +class JsInterpreterViewModel extends ChangeNotifier { + final JsRuntimeService _service; + + Object? _result; + Object? _error; + bool _isLoading = false; + final List _consoleHistory = []; + final TextEditingController _inputController = TextEditingController(); + final TextEditingController _urlController = TextEditingController(); + + JsInterpreterViewModel(this._service); + + Future initialize() async { + await _service.useJsRuntime((js) async { + await js.runJavaScriptReturningResult(""" + console.log = function() { + sendMessage('AppConsoleLog', JSON.stringify(['log', ...arguments])); + } + console.info = function() { + sendMessage('AppConsoleLog', JSON.stringify(['info', ...arguments])); + } + console.warn = function() { + sendMessage('AppConsoleLog', JSON.stringify(['warn', ...arguments])); + } + console.error = function() { + sendMessage('AppConsoleLog', JSON.stringify(['error', ...arguments])); + } + """); + await js.addJavaScriptChannel( + JavaScriptChannelParams( + name: 'AppConsoleLog', + onMessageReceived: (JavaScriptMessage message) async { + final data = json.decode(message.message ?? '[]') as List; + final logType = data.removeAt(0); + final output = data.join(' '); + _log.info('jsconsole [$logType]: $output'); + + final ConsoleEntry entry = switch (logType) { + 'info' => ConsoleEntry.info(output), + 'warn' => ConsoleEntry.warn(output), + 'error' => ConsoleEntry.error(output), + _ => ConsoleEntry.output(output), + }; + + _addToHistory(entry); + + return JavaScriptReply(message: ''); + }, + ), + ); + + /// Add your own code to evaluate javascript or add javascript channels here + await js.addJavaScriptChannel( + JavaScriptChannelParams( + name: 'ExampleChannel', + onMessageReceived: (message) { + _log.info( + 'Received message from ExampleChannel: ${message.message}', + ); + return JavaScriptReply( + message: 'replying from host: ${message.message}', + ); + }, + ), + ); + print('done viewmodel'); + }); + } + + Object? get result => _result; + Object? get error => _error; + bool get isLoading => _isLoading; + List get consoleHistory => _consoleHistory; + TextEditingController get inputController => _inputController; + TextEditingController get urlController => _urlController; + + Future executeCode() async { + final code = _inputController.text.trim(); + if (code.isEmpty) { + _log.info('no code entered'); + return; + } + + _addToHistory(ConsoleEntry.input(code)); + _setLoading(true); + _clearError(); + + try { + _result = await _service.evaluate(code); + _addToHistory(ConsoleEntry.output(_result.toString())); + clearInput(); + } catch (e) { + _error = e; + _addToHistory( + ConsoleEntry.error( + e is JavaScriptExecutionException ? e.message : e.toString(), + ), + ); + } finally { + _setLoading(false); + } + } + + Future loadFromUrl() async { + final url = _urlController.text.trim(); + if (url.isEmpty) return; + + _addToHistory(ConsoleEntry.info('Loading from URL: $url')); + _setLoading(true); + _clearError(); + + try { + _result = await _service.loadJsFromUrlAndEvaluate(url); + _addToHistory(ConsoleEntry.output(_result.toString())); + _addToHistory(ConsoleEntry.info('Loaded code & evaluated from: $url')); + } catch (e) { + _error = e; + _addToHistory( + ConsoleEntry.error( + 'Failed to load from URL: ${e is JavaScriptExecutionException ? e.message : e.toString()}', + ), + ); + } finally { + _setLoading(false); + } + } + + void clearAll() { + _inputController.clear(); + _urlController.clear(); + _clearResult(); + _clearError(); + _consoleHistory.clear(); + notifyListeners(); + } + + void clearInput() { + _inputController.clear(); + notifyListeners(); + } + + void _setLoading(bool loading) { + _isLoading = loading; + notifyListeners(); + } + + void _clearError() { + _error = null; + notifyListeners(); + } + + void _clearResult() { + _result = null; + notifyListeners(); + } + + void _addToHistory(ConsoleEntry entry) { + _consoleHistory.add(entry); + notifyListeners(); + } + + @override + void dispose() { + _inputController.dispose(); + _urlController.dispose(); + super.dispose(); + } +} + +class ConsoleEntry { + final String content; + final ConsoleEntryType type; + final DateTime timestamp; + + ConsoleEntry(this.content, this.type) : timestamp = DateTime.now(); + + factory ConsoleEntry.input(String content) => + ConsoleEntry(content, ConsoleEntryType.input); + factory ConsoleEntry.output(String content) => + ConsoleEntry(content, ConsoleEntryType.output); + factory ConsoleEntry.error(String content) => + ConsoleEntry(content, ConsoleEntryType.error); + factory ConsoleEntry.info(String content) => + ConsoleEntry(content, ConsoleEntryType.info); + factory ConsoleEntry.warn(String content) => + ConsoleEntry(content, ConsoleEntryType.warn); +} + +enum ConsoleEntryType { input, output, error, info, warn } diff --git a/packages/javascript/javascript/example/lib/src/runtime_service.dart b/packages/javascript/javascript/example/lib/src/runtime_service.dart new file mode 100644 index 0000000..1f7773b --- /dev/null +++ b/packages/javascript/javascript/example/lib/src/runtime_service.dart @@ -0,0 +1,40 @@ +import 'package:http/http.dart' as http; +import 'package:javascript/javascript.dart'; +import 'package:logging/logging.dart'; + +import 'file.dart'; + +class JsRuntimeService { + final _log = Logger('JsRuntimeService'); + + late JavaScript _jsRuntime; + late http.Client _httpClient; + + Future initialize() async { + _jsRuntime = await JavaScript.createNew(); + _httpClient = http.Client(); + } + + Future evaluate(String source) { + return _jsRuntime.runJavaScriptReturningResult(source); + } + + Future loadJsFromUrlAndEvaluate(String url) async { + final file = await downloadFromUrl(url); + + return _jsRuntime.runJavaScriptFromFileReturningResult(file.absolute.path); + } + + void dispose() { + _httpClient.close(); + _jsRuntime.dispose(); + } + + Future useJsRuntime(Future Function(JavaScript) onEngine) async { + try { + return await onEngine(_jsRuntime); + } catch (e, s) { + _log.severe('Error when running a callback with [useJsRuntime]', e, s); + } + } +} diff --git a/packages/javascript/javascript/example/lib/src/ui/command_input.dart b/packages/javascript/javascript/example/lib/src/ui/command_input.dart new file mode 100644 index 0000000..1700ef8 --- /dev/null +++ b/packages/javascript/javascript/example/lib/src/ui/command_input.dart @@ -0,0 +1,96 @@ +import 'package:flutter/material.dart'; + +import '../model.dart'; + +class CommandInputSection extends StatelessWidget { + final JsInterpreterViewModel viewModel; + + const CommandInputSection({super.key, required this.viewModel}); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: const Color(0xFF161B22), + border: Border(top: BorderSide(color: Colors.grey[800]!, width: 1)), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(top: 12.0), + child: const Icon( + Icons.chevron_right, + color: Colors.green, + size: 16, + ), + ), + Expanded( + child: TextField( + controller: viewModel.inputController, + style: const TextStyle( + color: Colors.white, + fontSize: 16, + fontFamily: 'monospace', + ), + decoration: const InputDecoration( + border: InputBorder.none, + hintText: 'Enter JavaScript code...', + hintStyle: TextStyle(color: Colors.grey), + ), + onSubmitted: (_) => viewModel.executeCode(), + maxLines: 5, + textCapitalization: TextCapitalization.none, + keyboardType: TextInputType.text, + textInputAction: TextInputAction.done, + ), + ), + const SizedBox(width: 8), + if (viewModel.isLoading) + const SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Colors.green, + ), + ) + else + Column( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + onPressed: viewModel.executeCode, + icon: const Icon(Icons.play_arrow, color: Colors.green), + tooltip: 'Execute (Enter)', + ), + ], + ), + ], + ), + Row( + children: [ + AnimatedBuilder( + animation: viewModel.inputController, + builder: (context, child) { + if (viewModel.inputController.text.isEmpty) { + return const SizedBox(height: kMinInteractiveDimension); + } + return OutlinedButton.icon( + onPressed: viewModel.clearInput, + icon: const Icon(Icons.close, color: Colors.green), + label: const Text('Clear'), + ); + }, + ), + ], + ), + ], + ), + ); + } +} diff --git a/packages/javascript/javascript/example/lib/src/ui/console_output.dart b/packages/javascript/javascript/example/lib/src/ui/console_output.dart new file mode 100644 index 0000000..b6edee6 --- /dev/null +++ b/packages/javascript/javascript/example/lib/src/ui/console_output.dart @@ -0,0 +1,107 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:javascript_example/src/model.dart'; + +class ConsoleOutputSection extends StatelessWidget { + final JsInterpreterViewModel viewModel; + final ScrollController scrollController; + + const ConsoleOutputSection({ + super.key, + required this.viewModel, + required this.scrollController, + }); + + @override + Widget build(BuildContext context) { + return Container( + color: const Color(0xFF0D1117), + child: ListView.builder( + controller: scrollController, + padding: const EdgeInsets.all(16), + itemCount: viewModel.consoleHistory.length, + itemBuilder: (context, index) { + final entry = viewModel.consoleHistory[index]; + return ConsoleEntryWidget(entry: entry); + }, + ), + ); + } +} + +class ConsoleEntryWidget extends StatelessWidget { + final ConsoleEntry entry; + + const ConsoleEntryWidget({super.key, required this.entry}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 2), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildPrefix(), + const SizedBox(width: 8), + Expanded( + child: ConstrainedBox( + constraints: BoxConstraints(maxHeight: 1.2 * 14 * 20), + child: Text( + entry.content, + style: _getTextStyle(), + softWrap: true, + ), + ), + ), + ], + ), + ); + } + + Widget _buildPrefix() { + switch (entry.type) { + case ConsoleEntryType.input: + return const Text( + '> ', + style: TextStyle(color: Colors.green, fontWeight: FontWeight.bold), + ); + case ConsoleEntryType.output: + return const Text( + '← ', + style: TextStyle(color: Colors.blue, fontWeight: FontWeight.bold), + ); + case ConsoleEntryType.error: + return const Text( + '✗ ', + style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold), + ); + case ConsoleEntryType.warn: + return const Text( + '! ', + style: TextStyle(color: Colors.orange, fontWeight: FontWeight.bold), + ); + case ConsoleEntryType.info: + return const Text( + 'ℹ ', + style: TextStyle(color: Colors.yellow, fontWeight: FontWeight.bold), + ); + } + } + + TextStyle _getTextStyle() { + final baseStyle = GoogleFonts.sourceCodePro(fontSize: 14); + + switch (entry.type) { + case ConsoleEntryType.input: + return baseStyle.copyWith(color: Colors.green); + case ConsoleEntryType.output: + return baseStyle.copyWith(color: Colors.white); + case ConsoleEntryType.error: + return baseStyle.copyWith(color: Colors.red); + case ConsoleEntryType.warn: + return baseStyle.copyWith(color: Colors.orange); + case ConsoleEntryType.info: + return baseStyle.copyWith(color: Colors.yellow); + } + } +} diff --git a/packages/javascript/javascript/example/lib/src/ui/url_input.dart b/packages/javascript/javascript/example/lib/src/ui/url_input.dart new file mode 100644 index 0000000..216d8a6 --- /dev/null +++ b/packages/javascript/javascript/example/lib/src/ui/url_input.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; +import 'package:javascript_example/src/model.dart'; + +class UrlInputSection extends StatelessWidget { + final JsInterpreterViewModel viewModel; + + const UrlInputSection({super.key, required this.viewModel}); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: const Color(0xFF161B22), + border: Border(bottom: BorderSide(color: Colors.grey[800]!, width: 1)), + ), + child: Row( + children: [ + const Icon(Icons.link, color: Colors.green, size: 20), + const SizedBox(width: 8), + Expanded( + child: TextField( + controller: viewModel.urlController, + style: const TextStyle(color: Colors.white, fontSize: 14), + decoration: InputDecoration( + hintText: 'Enter JS source URL (optional)', + hintStyle: TextStyle(color: Colors.grey[600]), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey[700]!), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: const BorderSide(color: Colors.green), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 8, + ), + ), + onSubmitted: (_) => viewModel.loadFromUrl(), + ), + ), + const SizedBox(width: 8), + IconButton( + onPressed: viewModel.loadFromUrl, + icon: const Icon(Icons.download, color: Colors.green), + tooltip: 'Load from URL', + ), + ], + ), + ); + } +} diff --git a/packages/javascript/javascript/example/macos/Runner.xcodeproj/project.pbxproj b/packages/javascript/javascript/example/macos/Runner.xcodeproj/project.pbxproj index 6e1d34d..a34b90f 100644 --- a/packages/javascript/javascript/example/macos/Runner.xcodeproj/project.pbxproj +++ b/packages/javascript/javascript/example/macos/Runner.xcodeproj/project.pbxproj @@ -27,6 +27,8 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + BFBAC3B16D53ABFF5C6010E4 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A6547DC87827AD27ACE252A1 /* Pods_Runner.framework */; }; + DF9FBC1EF83BCFBD15188341 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 755B3F1CAC14D191EC1E0EA5 /* Pods_RunnerTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -60,11 +62,12 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 14FD868C341BBC91A8708987 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* _example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "_example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* _example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = _example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -76,8 +79,15 @@ 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 6180346A1182816A5005AED2 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 666B6E5BAEFF77984EEF17DA /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 755B3F1CAC14D191EC1E0EA5 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + A6547DC87827AD27ACE252A1 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D8FC23FD36FE2E7C26B23A57 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + EFFE11C9CB78D133520718F3 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + F25B4AE472230037926A3740 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -85,6 +95,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + DF9FBC1EF83BCFBD15188341 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -92,6 +103,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + BFBAC3B16D53ABFF5C6010E4 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -125,6 +137,7 @@ 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, + B3E19D78F2422C6236282864 /* Pods */, ); sourceTree = ""; }; @@ -172,9 +185,25 @@ path = Runner; sourceTree = ""; }; + B3E19D78F2422C6236282864 /* Pods */ = { + isa = PBXGroup; + children = ( + 14FD868C341BBC91A8708987 /* Pods-Runner.debug.xcconfig */, + 6180346A1182816A5005AED2 /* Pods-Runner.release.xcconfig */, + EFFE11C9CB78D133520718F3 /* Pods-Runner.profile.xcconfig */, + D8FC23FD36FE2E7C26B23A57 /* Pods-RunnerTests.debug.xcconfig */, + 666B6E5BAEFF77984EEF17DA /* Pods-RunnerTests.release.xcconfig */, + F25B4AE472230037926A3740 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( + A6547DC87827AD27ACE252A1 /* Pods_Runner.framework */, + 755B3F1CAC14D191EC1E0EA5 /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -186,6 +215,7 @@ isa = PBXNativeTarget; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + FB52D41D073454F57E72BEBD /* [CP] Check Pods Manifest.lock */, 331C80D1294CF70F00263BE5 /* Sources */, 331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D3294CF70F00263BE5 /* Resources */, @@ -204,11 +234,13 @@ isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + E749E1299F7CFA72A3083211 /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, + 5365244B2192E9C98378034D /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -329,6 +361,67 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; + 5365244B2192E9C98378034D /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + E749E1299F7CFA72A3083211 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + FB52D41D073454F57E72BEBD /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -380,6 +473,7 @@ /* Begin XCBuildConfiguration section */ 331C80DB294CF71000263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = D8FC23FD36FE2E7C26B23A57 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -394,6 +488,7 @@ }; 331C80DC294CF71000263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 666B6E5BAEFF77984EEF17DA /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -408,6 +503,7 @@ }; 331C80DD294CF71000263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = F25B4AE472230037926A3740 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; diff --git a/packages/javascript/javascript/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/packages/javascript/javascript/example/macos/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/packages/javascript/javascript/example/macos/Runner.xcworkspace/contents.xcworkspacedata +++ b/packages/javascript/javascript/example/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/packages/javascript/javascript/example/pubspec.yaml b/packages/javascript/javascript/example/pubspec.yaml index 1bae91e..801570d 100644 --- a/packages/javascript/javascript/example/pubspec.yaml +++ b/packages/javascript/javascript/example/pubspec.yaml @@ -28,9 +28,11 @@ environment: # the latest version available on pub.dev. To see which dependencies have newer # versions available, run `flutter pub outdated`. dependencies: + crypto: ^3.0.6 flutter: sdk: flutter google_fonts: ^6.3.0 + http: ^1.5.0 javascript: # When depending on this package from a real application you should use: # javascript: ^x.y.z @@ -39,7 +41,6 @@ dependencies: # the parent directory to use the current plugin's version. path: ../ logging: ^1.3.0 - web_socket: ^1.0.1 dev_dependencies: flutter_driver: diff --git a/packages/javascript/javascript/example/test/widget_test.dart b/packages/javascript/javascript/example/test/widget_test.dart index e69de29..8b13789 100644 --- a/packages/javascript/javascript/example/test/widget_test.dart +++ b/packages/javascript/javascript/example/test/widget_test.dart @@ -0,0 +1 @@ + diff --git a/packages/javascript/javascript/lib/impl.dart b/packages/javascript/javascript/lib/impl.dart index 1ceae57..91b8c57 100644 --- a/packages/javascript/javascript/lib/impl.dart +++ b/packages/javascript/javascript/lib/impl.dart @@ -32,4 +32,9 @@ class JavaScriptImpl implements JavaScript { Future runJavaScriptReturningResult(String javaScript) { return _platform.runJavaScriptReturningResult(_engineId, javaScript); } + + @override + Future runJavaScriptFromFileReturningResult(String javaScriptFilePath) { + return _platform.runJavaScriptFromFileReturningResult(_engineId, javaScriptFilePath); + } } diff --git a/packages/javascript/javascript/lib/javascript.dart b/packages/javascript/javascript/lib/javascript.dart index 32b37e4..bfbed47 100644 --- a/packages/javascript/javascript/lib/javascript.dart +++ b/packages/javascript/javascript/lib/javascript.dart @@ -41,4 +41,12 @@ abstract interface class JavaScript { /// The Future completes with an error if a JavaScript error occurred, or if the /// type the given expression evaluates to is unsupported. Future runJavaScriptReturningResult(String javaScript); + + /// Runs the JavaScript file in the context of the current page, and returns the result. + /// + /// The Future completes with an error if a JavaScript error occurred, or if the + /// type the given expression evaluates to is unsupported. + Future runJavaScriptFromFileReturningResult( + String javaScriptFilePath, + ); } diff --git a/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptAndroid.kt b/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptAndroid.kt index c82f6e9..70201f7 100644 --- a/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptAndroid.kt +++ b/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptAndroid.kt @@ -2,13 +2,16 @@ package org.reclaimprotocol.javascript_android import android.util.Log import androidx.core.content.ContextCompat +import androidx.core.util.Consumer import androidx.javascriptengine.IsolateStartupParameters import androidx.javascriptengine.IsolateTerminatedException import androidx.javascriptengine.JavaScriptIsolate import androidx.javascriptengine.JavaScriptSandbox +import androidx.javascriptengine.TerminationInfo import com.google.common.util.concurrent.FutureCallback import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.ListenableFuture +import java.io.File import java.util.concurrent.Executor class JavaScriptAndroid(private var applicationContext: android.content.Context) : @@ -44,6 +47,10 @@ class JavaScriptAndroid(private var applicationContext: android.content.Context) if (sandbox.isFeatureSupported(JavaScriptSandbox.JS_FEATURE_ISOLATE_MAX_HEAP_SIZE)) { startupParams.setMaxHeapSizeBytes(IsolateStartupParameters.AUTOMATIC_MAX_HEAP_SIZE) } + Log.i("JavaScriptAndroid", mapOf( + "JS_FEATURE_EVALUATE_WITHOUT_TRANSACTION_LIMIT" to sandbox.isFeatureSupported(JavaScriptSandbox.JS_FEATURE_EVALUATE_WITHOUT_TRANSACTION_LIMIT), + "JS_FEATURE_ISOLATE_MAX_HEAP_SIZE" to sandbox.isFeatureSupported(JavaScriptSandbox.JS_FEATURE_ISOLATE_MAX_HEAP_SIZE) + ).toString()) val jsIsolate = sandbox.createIsolate(startupParams) activeJsIsolates.put(javascriptEngineId, jsIsolate) callback(Result.success(Unit)) @@ -85,6 +92,20 @@ class JavaScriptAndroid(private var applicationContext: android.content.Context) } } + override fun runJavaScriptFromFileReturningResult( + javascriptEngineId: String, + javaScriptFilePath: String, + callback: (Result) -> Unit + ) { + try { + val javaScriptFile = File(javaScriptFilePath) + val javascript = javaScriptFile.readText() + return runJavaScriptReturningResult(javascriptEngineId, javascript, callback) + } catch (e: Exception) { + callback(Result.failure(e)) + } + } + override fun runJavaScriptReturningResult( javascriptEngineId: String, javaScript: String, callback: (Result) -> Unit ) { @@ -93,14 +114,18 @@ class JavaScriptAndroid(private var applicationContext: android.content.Context) var didSubmitResponse = false - js.addOnTerminatedCallback(getMainExecutor(), { terminationInfo -> - Log.e(TAG, "The isolate crashed: $terminationInfo") - if (!didSubmitResponse) { - didSubmitResponse = true - callback(Result.failure(IsolateTerminatedException(terminationInfo.toString()))) + val terminationCallback: Consumer = object : Consumer { + override fun accept(value: TerminationInfo) { + Log.e(TAG, "The isolate crashed: $value") + if (!didSubmitResponse) { + didSubmitResponse = true + callback(Result.failure(IsolateTerminatedException(value.toString()))) + } + activeJsIsolates.remove(javascriptEngineId) } - activeJsIsolates.remove(javascriptEngineId) - }) + } + + js.addOnTerminatedCallback(getMainExecutor(), terminationCallback) Futures.addCallback( js.evaluateJavaScriptAsync(javaScript), object : FutureCallback { @@ -120,6 +145,7 @@ class JavaScriptAndroid(private var applicationContext: android.content.Context) } didSubmitResponse = true callback(Result.failure(t)) + js.removeOnTerminatedCallback(terminationCallback) } }, getMainExecutor() ) @@ -140,4 +166,20 @@ class JavaScriptAndroid(private var applicationContext: android.content.Context) } } + fun onDetachedFromActivity() { + val sandbox = getJSSandbox() + Futures.addCallback( + sandbox, object : FutureCallback { + override fun onSuccess(sandbox: JavaScriptSandbox) { + Log.i("JavaScriptAndroid", "Closing sandbox") + activeJsIsolates.clear() + sandbox.close() + } + override fun onFailure(t: Throwable) { + Log.e("JavaScriptAndroid", "Failed to close sandbox", t) + } + }, getMainExecutor() + ) + } + } \ No newline at end of file diff --git a/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptPlugin.kt b/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptPlugin.kt index 7d0d4d7..78740ed 100644 --- a/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptPlugin.kt +++ b/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/JavaScriptPlugin.kt @@ -6,13 +6,7 @@ import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding import io.flutter.embedding.engine.plugins.activity.ActivityAware import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding -/** - * Plugin implementation that uses the new `io.flutter.embedding` package. - * - * - * Instantiate this in an add to app scenario to gracefully handle activity and context changes. - */ -public class JavaScriptPlugin : FlutterPlugin { +public class JavaScriptPlugin : FlutterPlugin, ActivityAware { private var javaScriptAndroid: JavaScriptAndroid? = null override fun onAttachedToEngine(binding: FlutterPluginBinding) { @@ -31,6 +25,23 @@ public class JavaScriptPlugin : FlutterPlugin { javaScriptAndroid = null } + override fun onAttachedToActivity(binding: ActivityPluginBinding) { + // + } + + override fun onDetachedFromActivityForConfigChanges() { + // + } + + override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { + // + } + + override fun onDetachedFromActivity() { + Log.i("JavaScriptPlugin", "closing javascript android on detached from activity") + javaScriptAndroid?.onDetachedFromActivity() + } + companion object { private const val TAG = "UrlLauncherPlugin" } diff --git a/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/Messages.kt b/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/Messages.kt index ff6963e..70823ba 100644 --- a/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/Messages.kt +++ b/packages/javascript/javascript_android/android/src/main/kotlin/org/reclaimprotocol/javascript_android/Messages.kt @@ -67,6 +67,7 @@ interface JavaScriptAndroidPlatformApi { fun startJavaScriptEngine(javascriptEngineId: String, callback: (Result) -> Unit) fun dispose(javascriptEngineId: String, callback: (Result) -> Unit) fun runJavaScriptReturningResult(javascriptEngineId: String, javaScript: String, callback: (Result) -> Unit) + fun runJavaScriptFromFileReturningResult(javascriptEngineId: String, javaScriptFilePath: String, callback: (Result) -> Unit) fun setIsInspectable(javascriptEngineId: String, isInspectable: Boolean, callback: (Result) -> Unit) companion object { @@ -137,6 +138,27 @@ interface JavaScriptAndroidPlatformApi { channel.setMessageHandler(null) } } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.runJavaScriptFromFileReturningResult$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val javascriptEngineIdArg = args[0] as String + val javaScriptFilePathArg = args[1] as String + api.runJavaScriptFromFileReturningResult(javascriptEngineIdArg, javaScriptFilePathArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(MessagesPigeonUtils.wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(MessagesPigeonUtils.wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } run { val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.setIsInspectable$separatedMessageChannelSuffix", codec) if (api != null) { diff --git a/packages/javascript/javascript_android/lib/javascript_android.dart b/packages/javascript/javascript_android/lib/javascript_android.dart index e86e0f5..68bb795 100644 --- a/packages/javascript/javascript_android/lib/javascript_android.dart +++ b/packages/javascript/javascript_android/lib/javascript_android.dart @@ -1,9 +1,8 @@ import 'package:flutter/foundation.dart'; -import 'package:javascript_android/src/user_scripts.dart'; import 'package:javascript_platform_interface/javascript_platform_interface.dart'; import 'src/parse.dart'; -import 'src/engine_context.dart'; +import 'src/host/state.dart'; import 'src/pigeons/messages.pigeon.dart'; /// The Android implementation of [JavaScriptPlatform]. @@ -30,18 +29,18 @@ class JavaScriptAndroid extends JavaScriptPlatform { Future startJavaScriptEngine( String javascriptEngineId, { Duration messageListenerInterval = const Duration(milliseconds: 50), + bool implementJsSetTimeout = true, }) async { await pigeonPlatformApi.startJavaScriptEngine(javascriptEngineId); - _activeEngineHostState[javascriptEngineId] = EngineHostState( + final engineHostState = await EngineHostState.create( engineId: javascriptEngineId, messageListenerInterval: messageListenerInterval, + implementJsSetTimeout: implementJsSetTimeout, runJavaScript: (javaScript) { return runJavaScriptReturningResult(javascriptEngineId, javaScript); }, ); - for (final script in getEngineStartupScripts()) { - await runJavaScriptReturningResult(javascriptEngineId, script); - } + _activeEngineHostState[javascriptEngineId] = engineHostState; } @override @@ -50,10 +49,7 @@ class JavaScriptAndroid extends JavaScriptPlatform { JavaScriptChannelParams javaScriptChannelParams, ) async { final engineState = _requireEngineState(javascriptEngineId); - await engineState.addChannel( - javaScriptChannelParams.name, - javaScriptChannelParams, - ); + await engineState.addChannel(javaScriptChannelParams); } @override @@ -82,6 +78,20 @@ class JavaScriptAndroid extends JavaScriptPlatform { javascriptEngineId, javaScript, ); + + return parseValue(result); + } + + @override + Future runJavaScriptFromFileReturningResult( + String javascriptEngineId, + String javaScriptFilePath, + ) async { + final result = await pigeonPlatformApi.runJavaScriptFromFileReturningResult( + javascriptEngineId, + javaScriptFilePath, + ); + return parseValue(result); } diff --git a/packages/javascript/javascript_android/lib/src/host/scripts.dart b/packages/javascript/javascript_android/lib/src/host/scripts.dart new file mode 100644 index 0000000..cae9536 --- /dev/null +++ b/packages/javascript/javascript_android/lib/src/host/scripts.dart @@ -0,0 +1,90 @@ +part of 'state.dart'; + +const String _MESSAGING_SCRIPT = r''' +class HostMessenger { + constructor() { + this.pendingMessages = []; + this.id = 0; + } + + getPendingMessages() { + return this.pendingMessages.map(m => ({id: m.id, message: m.message})); + } + + removeMessageById(id) { + this.pendingMessages = this.pendingMessages.filter(m => m.id !== id); + } + + resolveById(id, response) { + let message = this.pendingMessages.find(m => m.id === id); + if (message) { + message.resolve(response); + this.removeMessageById(id); + return true; + } + return false; + } + + rejectById(id, error) { + let message = this.pendingMessages.find(m => m.id === id); + if (message) { + message.reject(error); + this.removeMessageById(id); + return true; + } + return false; + } + + postMessage(message) { + if (typeof message !== 'string') { + throw new Error(`Message must be a string, got ${typeof message}`); + } + let promise = new Promise((resolve, reject) => { + this.pendingMessages.push({ + id: this.id++, + message, + resolve, + reject + }); + }); + return promise; + } +} + +globalThis.HostMessengerRegisteredChannels = {} + +/// Similar to sendMessage available from ios plugin implementation +globalThis.sendMessage = function(channelName, message) { + return globalThis.HostMessengerRegisteredChannels[channelName].postMessage(message); +} + +globalThis.getPendingMessages = function(channelName) { + try { + const registeredChannels = globalThis.HostMessengerRegisteredChannels; + if (registeredChannels[channelName] && registeredChannels[channelName].getPendingMessages) { + return registeredChannels[channelName].getPendingMessages(); + } else { + console.error({reason: `Channel ${channelName} is not found`, channel: registeredChannels[channelName] }); + } + return []; + } catch (e) { + console.error(`Error when getting pending messages for channel $channelName`, e); + return []; + } +} +'''; + +const String _TIMEOUT_SCRIPT = r''' +var __NATIVE_HOST_JS__setTimeoutCount = -1; +var __NATIVE_HOST_JS__setTimeoutCallbacks = {}; +function setTimeout(fnTimeout, timeout) { + try { + __NATIVE_HOST_JS__setTimeoutCount += 1; + var timeoutIndex = '' + __NATIVE_HOST_JS__setTimeoutCount; + __NATIVE_HOST_JS__setTimeoutCallbacks[timeoutIndex] = fnTimeout; + sendMessage('SetTimeout', JSON.stringify({ timeoutIndex, timeout})); + } catch (e) { + console.error('ERROR HERE', e.message); + } +}; +'''; diff --git a/packages/javascript/javascript_android/lib/src/engine_context.dart b/packages/javascript/javascript_android/lib/src/host/state.dart similarity index 61% rename from packages/javascript/javascript_android/lib/src/engine_context.dart rename to packages/javascript/javascript_android/lib/src/host/state.dart index 9238d0c..01a81ee 100644 --- a/packages/javascript/javascript_android/lib/src/engine_context.dart +++ b/packages/javascript/javascript_android/lib/src/host/state.dart @@ -4,20 +4,48 @@ import 'package:logging/logging.dart'; import 'package:javascript_platform_interface/javascript_platform_interface.dart'; +part 'scripts.dart'; + typedef RunJavascriptCallback = Future Function(String javaScript); class EngineHostState { - EngineHostState({ + EngineHostState._({ required this.messageListenerInterval, required this.engineId, required RunJavascriptCallback runJavaScript, - }) : _runJavaScript = runJavaScript, - _ensureInitialized = runJavaScript(_MESSAGING_SCRIPT); + }) { + _runJavaScript = (String javascript) { + if (_isDisposed) return Future.value(null); + return runJavaScript(javascript); + }; + } + + static Future create({ + required String engineId, + required Duration messageListenerInterval, + bool implementJsSetTimeout = true, + required RunJavascriptCallback runJavaScript, + }) async { + final state = EngineHostState._( + messageListenerInterval: messageListenerInterval, + engineId: engineId, + runJavaScript: runJavaScript, + ); + + await state._runJavaScript(_MESSAGING_SCRIPT); + if (implementJsSetTimeout) { + await state._runJavaScript(_TIMEOUT_SCRIPT); + await state._setupJsSetTimeoutMessaging(); + } + + return state; + } final String engineId; final Duration messageListenerInterval; - final RunJavascriptCallback _runJavaScript; - final Future _ensureInitialized; + + late final RunJavascriptCallback _runJavaScript; + late final Logger _logger = Logger('EngineHostState.$engineId'); final Map _enabledChannels = {}; @@ -41,7 +69,7 @@ class EngineHostState { Future> _getPendingMessages() async { final channelPendingMessages = _enabledChannels.keys .map((channelName) { - return '"$channelName": globalThis["$channelName"].getPendingMessages()'; + return '"$channelName": globalThis.getPendingMessages("$channelName")'; }) .join(','); @@ -54,11 +82,6 @@ class EngineHostState { final Map> _processingMessages = {}; - Future _evaluateSafely(String javascript) { - if (_isDisposed) return Future.value(null); - return _runJavaScript(javascript); - } - void _onTimerTick(Timer timer) async { timer.cancel(); if (_isDisposed) { @@ -84,7 +107,7 @@ class EngineHostState { continue; } final id = event['id'] as int; - final message = event['message']; + final message = event['message'] as String; final processingEventIds = _processingMessages.putIfAbsent( channelName, () => {}, @@ -105,7 +128,7 @@ class EngineHostState { Future _processMessage( JavaScriptChannelParams channel, - Object? message, + String message, String channelName, int id, ) async { @@ -115,9 +138,7 @@ class EngineHostState { 'Processing a new message by id $id for channel $channelName: (${message.runtimeType}) $message', ); final response = await channel.onMessageReceived( - JavaScriptMessage( - message: message is String ? message : json.encode(message), - ), + JavaScriptMessage(message: message), ); final reply = response.message; String encodedMessage = 'null'; @@ -127,16 +148,16 @@ class EngineHostState { _logger.finest( 'Resolved message by id $id for channel $channelName: $encodedMessage', ); - evaluationResult = _evaluateSafely( - 'globalThis["$channelName"].resolveById($id, ${json.encode(encodedMessage)})', + evaluationResult = _runJavaScript( + 'globalThis.HostMessengerRegisteredChannels["$channelName"].resolveById($id, ${json.encode(encodedMessage)})', ); } catch (e) { final encodedMessage = e.toString(); _logger.finest( 'Rejected message by id $id for channel $channelName: $encodedMessage', ); - evaluationResult = _evaluateSafely( - 'globalThis["$channelName"].rejectById($id, ${json.encode(encodedMessage)})', + evaluationResult = _runJavaScript( + 'globalThis.HostMessengerRegisteredChannels["$channelName"].rejectById($id, ${json.encode(encodedMessage)})', ); } try { @@ -153,15 +174,14 @@ class EngineHostState { _timer = null; } - Future addChannel( - String channelName, - JavaScriptChannelParams channelParams, - ) async { - await _ensureInitialized; + Future addChannel(JavaScriptChannelParams channelParams) async { + final channelName = channelParams.name; _enabledChannels[channelName] = channelParams; _ensureMessageListenerActive(); try { - await _runJavaScript('globalThis["$channelName"] = new HostMessenger();'); + await _runJavaScript('''globalThis.HostMessengerRegisteredChannels["$channelName"] = new HostMessenger(); + // for compatibility with popular webview plugins receiving messages + globalThis["$channelName"] = globalThis.HostMessengerRegisteredChannels["$channelName"];'''); _logger.finest('Channel $channelName added'); } catch (e, s) { _logger.severe('Error adding channel $channelName', e, s); @@ -185,57 +205,37 @@ class EngineHostState { _removeTimer(); _enabledChannels.clear(); } -} - -const String _MESSAGING_SCRIPT = r''' -class HostMessenger { - constructor() { - this.pendingMessages = []; - this.id = 0; - } - getPendingMessages() { - return this.pendingMessages.map(m => ({id: m.id, message: m.message})); - } - - removeMessageById(id) { - this.pendingMessages = this.pendingMessages.filter(m => m.id !== id); - } - - resolveById(id, response) { - let message = this.pendingMessages.find(m => m.id === id); - if (message) { - message.resolve(response); - this.removeMessageById(id); - return true; - } - return false; - } - - rejectById(id, error) { - let message = this.pendingMessages.find(m => m.id === id); - if (message) { - message.reject(error); - this.removeMessageById(id); - return true; - } - return false; - } - - postMessage(message) { - let promise = new Promise((resolve, reject) => { - this.pendingMessages.push({ - id: this.id++, - message, - resolve, - reject + Future _setupJsSetTimeoutMessaging() async { + await addChannel( + JavaScriptChannelParams( + name: 'SetTimeout', + onMessageReceived: (message) async { + try { + final args = json.decode(message.message ?? '{}'); + final int duration = args['timeout'] ?? 0; + final String idx = args['timeoutIndex']; + + Future.delayed(Duration(milliseconds: duration), () async { + try { + await _runJavaScript(""" + __NATIVE_HOST_JS__setTimeoutCallbacks[$idx].call(); + delete __NATIVE_HOST_JS__setTimeoutCallbacks[$idx]; + """); + } catch (e, s) { + _logger.severe( + 'Error when running setTimeout callback by id $idx', + e, + s, + ); + } }); - }); - return promise; - } -} - -globalThis.sendMessage = function(channelName, message) { - return globalThis[channelName].postMessage(message); + } catch (e, s) { + _logger.severe('Exception no setTimeout: $e', s); + } + return JavaScriptReply(message: ''); + }, + ), + ); + } } -'''; diff --git a/packages/javascript/javascript_android/lib/src/pigeons/messages.pigeon.dart b/packages/javascript/javascript_android/lib/src/pigeons/messages.pigeon.dart index fa8ad10..e149bfb 100644 --- a/packages/javascript/javascript_android/lib/src/pigeons/messages.pigeon.dart +++ b/packages/javascript/javascript_android/lib/src/pigeons/messages.pigeon.dart @@ -16,7 +16,6 @@ PlatformException _createConnectionError(String channelName) { ); } - class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override @@ -43,9 +42,13 @@ class JavaScriptAndroidPlatformApi { /// Constructor for [JavaScriptAndroidPlatformApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. - JavaScriptAndroidPlatformApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) - : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + JavaScriptAndroidPlatformApi({ + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty + ? '.$messageChannelSuffix' + : ''; final BinaryMessenger? pigeonVar_binaryMessenger; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); @@ -53,13 +56,17 @@ class JavaScriptAndroidPlatformApi { final String pigeonVar_messageChannelSuffix; Future startJavaScriptEngine(String javascriptEngineId) async { - final String pigeonVar_channelName = 'dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.startJavaScriptEngine$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, + final String pigeonVar_channelName = + 'dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.startJavaScriptEngine$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [javascriptEngineId], ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([javascriptEngineId]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -76,13 +83,17 @@ class JavaScriptAndroidPlatformApi { } Future dispose(String javascriptEngineId) async { - final String pigeonVar_channelName = 'dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.dispose$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, + final String pigeonVar_channelName = + 'dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.dispose$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [javascriptEngineId], ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([javascriptEngineId]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -98,14 +109,51 @@ class JavaScriptAndroidPlatformApi { } } - Future runJavaScriptReturningResult(String javascriptEngineId, String javaScript) async { - final String pigeonVar_channelName = 'dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.runJavaScriptReturningResult$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, + Future runJavaScriptReturningResult( + String javascriptEngineId, + String javaScript, + ) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.runJavaScriptReturningResult$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [javascriptEngineId, javaScript], + ); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as String?); + } + } + + Future runJavaScriptFromFileReturningResult( + String javascriptEngineId, + String javaScriptFilePath, + ) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.runJavaScriptFromFileReturningResult$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [javascriptEngineId, javaScriptFilePath], ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([javascriptEngineId, javaScript]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { @@ -121,14 +169,21 @@ class JavaScriptAndroidPlatformApi { } } - Future setIsInspectable(String javascriptEngineId, bool isInspectable) async { - final String pigeonVar_channelName = 'dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.setIsInspectable$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, + Future setIsInspectable( + String javascriptEngineId, + bool isInspectable, + ) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.javascript_android.JavaScriptAndroidPlatformApi.setIsInspectable$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [javascriptEngineId, isInspectable], ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([javascriptEngineId, isInspectable]); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; if (pigeonVar_replyList == null) { diff --git a/packages/javascript/javascript_android/lib/src/scripts/messaging.dart b/packages/javascript/javascript_android/lib/src/scripts/messaging.dart deleted file mode 100644 index 0b5b067..0000000 --- a/packages/javascript/javascript_android/lib/src/scripts/messaging.dart +++ /dev/null @@ -1,7 +0,0 @@ -sealed class MessagingScript { - - - static const String MESSAGE_LISTENER_SCRIPT = r''' - -'''; -} diff --git a/packages/javascript/javascript_android/lib/src/user_scripts.dart b/packages/javascript/javascript_android/lib/src/user_scripts.dart deleted file mode 100644 index 95873c8..0000000 --- a/packages/javascript/javascript_android/lib/src/user_scripts.dart +++ /dev/null @@ -1,3 +0,0 @@ -List getEngineStartupScripts() { - return []; -} diff --git a/packages/javascript/javascript_android/pigeons/schema.dart b/packages/javascript/javascript_android/pigeons/schema.dart index ba9a7b7..9103fd4 100644 --- a/packages/javascript/javascript_android/pigeons/schema.dart +++ b/packages/javascript/javascript_android/pigeons/schema.dart @@ -13,7 +13,6 @@ import 'package:pigeon/pigeon.dart'; copyrightHeader: 'pigeons/copyright.txt', ), ) - /// Apis implemented by the Reclaim module for use by the host. @HostApi() abstract class JavaScriptAndroidPlatformApi { @@ -27,5 +26,10 @@ abstract class JavaScriptAndroidPlatformApi { String javaScript, ); @async + String? runJavaScriptFromFileReturningResult( + String javascriptEngineId, + String javaScriptFilePath, + ); + @async void setIsInspectable(String javascriptEngineId, bool isInspectable); } diff --git a/packages/javascript/javascript_android/pubspec.yaml b/packages/javascript/javascript_android/pubspec.yaml index f6313fd..e5ca369 100644 --- a/packages/javascript/javascript_android/pubspec.yaml +++ b/packages/javascript/javascript_android/pubspec.yaml @@ -21,6 +21,7 @@ dependencies: javascript_platform_interface: path: ../javascript_platform_interface logging: ^1.3.0 + path: ^1.9.1 dev_dependencies: flutter_test: diff --git a/packages/javascript/javascript_darwin/lib/javascript_darwin.dart b/packages/javascript/javascript_darwin/lib/javascript_darwin.dart index 2ccd9ad..94691d8 100644 --- a/packages/javascript/javascript_darwin/lib/javascript_darwin.dart +++ b/packages/javascript/javascript_darwin/lib/javascript_darwin.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:javascript_darwin/src/third_party/flutter_js/lib/extensions/fetch.dart'; @@ -180,6 +181,16 @@ class JavaScriptDarwin extends JavaScriptPlatform { } } + @override + Future runJavaScriptFromFileReturningResult( + String javascriptEngineId, + String javaScriptFilePath, + ) async { + final file = File(javaScriptFilePath); + final javaScript = await file.readAsString(); + return runJavaScriptReturningResult(javascriptEngineId, javaScript); + } + @override Future setIsInspectable( String javascriptEngineId, diff --git a/packages/javascript/javascript_platform_interface/lib/javascript_platform_interface.dart b/packages/javascript/javascript_platform_interface/lib/javascript_platform_interface.dart index 7238f45..8dc8586 100644 --- a/packages/javascript/javascript_platform_interface/lib/javascript_platform_interface.dart +++ b/packages/javascript/javascript_platform_interface/lib/javascript_platform_interface.dart @@ -49,6 +49,15 @@ abstract class JavaScriptPlatform extends PlatformInterface { /// type the given expression evaluates to is unsupported. Future runJavaScriptReturningResult(String javascriptEngineId, String javaScript); + /// Runs the JavaScript file in the context of the current page, and returns the result. + /// + /// The Future completes with an error if a JavaScript error occurred, or if the + /// type the given expression evaluates to is unsupported. + Future runJavaScriptFromFileReturningResult( + String javascriptEngineId, + String javaScriptFilePath, + ); + /// Adds a new JavaScript channel to the set of enabled channels. Future addJavaScriptChannel( String javascriptEngineId, diff --git a/packages/javascript/javascript_platform_interface/lib/src/method_channel_javascript.dart b/packages/javascript/javascript_platform_interface/lib/src/method_channel_javascript.dart index 30913e0..5915311 100644 --- a/packages/javascript/javascript_platform_interface/lib/src/method_channel_javascript.dart +++ b/packages/javascript/javascript_platform_interface/lib/src/method_channel_javascript.dart @@ -60,4 +60,15 @@ class MethodChannelJavaScript extends JavaScriptPlatform { javaScript, ]); } + + @override + Future runJavaScriptFromFileReturningResult( + String javascriptEngineId, + String javaScriptFilePath, + ) { + return methodChannel.invokeMethod('runJavaScriptFromFileReturningResult', [ + javascriptEngineId, + javaScriptFilePath, + ]); + } } diff --git a/packages/javascript/javascript_platform_interface/test/javascript_platform_interface_test.dart b/packages/javascript/javascript_platform_interface/test/javascript_platform_interface_test.dart index 23d75b2..8793af2 100644 --- a/packages/javascript/javascript_platform_interface/test/javascript_platform_interface_test.dart +++ b/packages/javascript/javascript_platform_interface/test/javascript_platform_interface_test.dart @@ -37,6 +37,14 @@ class JavaScriptMock extends JavaScriptPlatform { Future runJavaScriptReturningResult(String javascriptEngineId, String javaScript) async { return Future.value(); } + + @override + Future runJavaScriptFromFileReturningResult( + String javascriptEngineId, + String javaScriptFilePath, + ) async { + return Future.value(); + } } void main() { @@ -66,5 +74,9 @@ void main() { test('runJavaScriptReturningResult', () async { await javascriptPlatform.runJavaScriptReturningResult('test', 'console.log("test")'); }); + + test('runJavaScriptFromFileReturningResult', () async { + await javascriptPlatform.runJavaScriptFromFileReturningResult('test', 'test.js'); + }); }); } From dbe40fc863b638309004e30315da32cc0bf5ff5e Mon Sep 17 00:00:00 2001 From: Mushaheed Syed Date: Sat, 16 Aug 2025 04:25:50 +0530 Subject: [PATCH 4/4] Update docs --- packages/javascript/javascript/README.md | 30 +++++++- .../javascript/example/lib/src/model.dart | 11 ++- .../javascript/example/pubspec.yaml | 63 +--------------- .../javascript/javascript/lib/javascript.dart | 72 +++++++++++++++---- .../javascript/javascript_android/README.md | 12 +++- .../javascript/javascript_darwin/README.md | 10 ++- 6 files changed, 117 insertions(+), 81 deletions(-) diff --git a/packages/javascript/javascript/README.md b/packages/javascript/javascript/README.md index d78427a..d747e7c 100644 --- a/packages/javascript/javascript/README.md +++ b/packages/javascript/javascript/README.md @@ -1,6 +1,32 @@ -# Javascript +# JavaScript -Enable your app to evaluate javascript programs. A simple library that provides a javascript runtime where you can run your javascript. +Enable your app to evaluate javascript programs. A simple library that provides a javascript environment where you can run your javascript code. + +## Advantages + +For applications requiring non-interactive JavaScript evaluation, using this JavaScript library has the following advantages: + +- Lower resource consumption, since there is no need to allocate a WebView instance. +- Multiple isolated javascript environments with low overhead, enabling the application to run several JavaScript snippets simultaneously. +- Provides implementation for setTimeout in the javascript environment. +- Support for javascript channels for sending asynchronous messages from javascript environment to host and then receive a reply asynchronously as Promise. +- Supports loading javaScript code from a file and then evaluate it for efficient evaluation of large scripts that may be expensive to pass as a String. + +## Implementation + +### Android + +The Android plugin [javascript_android] implementation uses the [JavaScriptIsolate](https://developer.android.com/reference/kotlin/androidx/javascriptengine/JavaScriptIsolate) as the javascript environment from the [Android Jetpack JavaScript Engine](https://developer.android.com/reference/kotlin/androidx/javascriptengine) library. + +### iOS & MacOS + +The iOS, & MacOS plugin [javascript_darwin] implementation uses [JSContext](https://developer.apple.com/documentation/javascriptcore/jscontext) from [Apple's JavaScriptCore](https://developer.apple.com/documentation/javascriptcore) framework. + +## Using + +The easiest way to use this library is via the high-level interface defined by [JavaScript] class. + +___ Developed with 💙 by [Reclaim Protocol Team][reclaimprotocol_link] ✨ diff --git a/packages/javascript/javascript/example/lib/src/model.dart b/packages/javascript/javascript/example/lib/src/model.dart index 85ef793..9dbb77d 100644 --- a/packages/javascript/javascript/example/lib/src/model.dart +++ b/packages/javascript/javascript/example/lib/src/model.dart @@ -59,6 +59,16 @@ class JsInterpreterViewModel extends ChangeNotifier { ), ); + await js.addJavaScriptChannel( + JavaScriptChannelParams( + name: 'Sum', + onMessageReceived: (message) { + final data = json.decode(message.message!); + return JavaScriptReply(message: json.encode(data['a'] + data['b'])); + }, + ), + ); + /// Add your own code to evaluate javascript or add javascript channels here await js.addJavaScriptChannel( JavaScriptChannelParams( @@ -73,7 +83,6 @@ class JsInterpreterViewModel extends ChangeNotifier { }, ), ); - print('done viewmodel'); }); } diff --git a/packages/javascript/javascript/example/pubspec.yaml b/packages/javascript/javascript/example/pubspec.yaml index 801570d..a4adda2 100644 --- a/packages/javascript/javascript/example/pubspec.yaml +++ b/packages/javascript/javascript/example/pubspec.yaml @@ -1,38 +1,19 @@ name: javascript_example -description: "A new Flutter project." -# The following line prevents the package from being accidentally published to -# pub.dev using `flutter pub publish`. This is preferred for private packages. +description: A example application for the javascript package. publish_to: 'none' # Remove this line if you wish to publish to pub.dev -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# In Android, build-name is used as versionName while build-number used as versionCode. -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. -# Read more about iOS versioning at -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -# In Windows, build-name is used as the major, minor, and patch parts -# of the product and file versions while build-number is used as the build suffix. version: 1.0.0+1 environment: sdk: ^3.8.1 -# Dependencies specify other packages that your package needs in order to work. -# To automatically upgrade your package dependencies to the latest versions -# consider running `flutter pub upgrade --major-versions`. Alternatively, -# dependencies can be manually updated by changing the version numbers below to -# the latest version available on pub.dev. To see which dependencies have newer -# versions available, run `flutter pub outdated`. dependencies: crypto: ^3.0.6 flutter: sdk: flutter google_fonts: ^6.3.0 http: ^1.5.0 + logging: ^1.3.0 javascript: # When depending on this package from a real application you should use: # javascript: ^x.y.z @@ -40,7 +21,6 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ - logging: ^1.3.0 dev_dependencies: flutter_driver: @@ -51,44 +31,5 @@ dev_dependencies: sdk: flutter flutter_lints: ^6.0.0 -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/to/resolution-aware-images - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/to/asset-from-package - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/to/font-from-package diff --git a/packages/javascript/javascript/lib/javascript.dart b/packages/javascript/javascript/lib/javascript.dart index bfbed47..d44970c 100644 --- a/packages/javascript/javascript/lib/javascript.dart +++ b/packages/javascript/javascript/lib/javascript.dart @@ -4,48 +4,94 @@ export 'package:javascript_platform_interface/javascript_platform_interface.dart part 'impl.dart'; +/// Represents a connection to an environment where JavaScript code can be evaluated. +/// +/// Each [JavaScript] instance has its own isolated state, and cannot interact with other [JavaScript] instances. +/// +/// There is no guarantee of security boundary between [JavaScript] instances in a single application. +/// If the code in one [JavaScript] instance is able to compromise the security, then it may be able +/// to observe or manipulate other [JavaScript] instances abstract interface class JavaScript { - /// Creates a new JavaScript engine. + /// Creates & returns a new [JavaScript] instance by the [JavaScriptPlatform]. /// - /// The [platform] is used to start a engine. If not provided, the default - /// platform is used. + /// The [platform] manages the control of the underlying javascript environment. + /// If not provided, the default platform is used. static Future createNew({JavaScriptPlatform? platform}) async { final p = platform ?? JavaScriptPlatform.instance; + + // A unique id for identifying the javascript environment. final id = Object().hashCode.toString(); + // Start a new javascript environment using the platform. await p.startJavaScriptEngine(id); return JavaScriptImpl._(p, id); } - /// Disposes of the JavaScript runtime. + /// Disposes of the underlying javascript environment. Future dispose(); - /// Sets whether the JavaScript engine is inspectable. + /// Sets whether the underlying javascript environment is inspectable. + /// + /// This is only applicable to some runtime engines. Future setIsInspectable(bool isInspectable); - /// Adds a new JavaScript channel to the set of enabled channels. + /// Adds a new JavaScript channel to the set of enabled channels for the context of the current [JavaScript] instance. + /// + /// The JavaScript code can then call `sendMessage('channelName', JSON.stringify("data"))` to send a message that + /// will be passed to [JavaScriptChannelParams.onMessageReceived] and a reply will be sent back to the JavaScript code. + /// + /// For example, after adding the following JavaScript channel: + /// ```dart + /// engine.addJavaScriptChannel( + /// JavaScriptChannelParams( + /// name: 'Sum', + /// onMessageReceived: (message) { + /// final data = json.decode(message.message!); + /// return JavaScriptReply( + /// message: json.encode(data['a'] + data['b']), + /// ); + /// }, + /// ), + /// ); + /// ``` + /// + /// The JavaScript code can then call: + /// ```dart + /// sendMessage('Sum', JSON.stringify({a: 1, b: 2})) + /// ``` + /// + /// to asynchronously send a message that will be passed to [JavaScriptChannelParams.onMessageReceived] and a reply + /// will be sent back to the JavaScript code. + /// + /// As per the example, the reply back to javascript will be a promise that resolves to `"3"`. Future addJavaScriptChannel( JavaScriptChannelParams javaScriptChannelParams, ); /// Removes the JavaScript channel with the matching name from the set of - /// enabled channels. + /// enabled channels for the context of the current [JavaScript] instance. /// /// This disables the channel with the matching name if it was previously /// enabled through the [addJavaScriptChannel]. Future removeJavaScriptChannel(String javaScriptChannelName); - /// Runs the given JavaScript in the context of the current page, and returns the result. + /// Evaluates the given JavaScript code [javaScript] in the context of the current [JavaScript] instance, and returns the result. + /// + /// {@template javascript_run_javascript_returning_result_behavior} + /// There are multiple possible behaviors based on the output of the expression: + /// 1. If the JS expression evaluates to a JS String or a Promise of a JS String, then the [Future] resolves to a [Map], [List], [String], [num], [bool], or [Null] if the string can be decoded as JSON, otherwise the [Future] resolves to the string. + /// 2. If the JS expression evaluates to another data type, then the [Future] resolves to an **empty** [String] on some platforms. + /// 3. The [Future] completes with an error if a JavaScript error occurred. /// - /// The Future completes with an error if a JavaScript error occurred, or if the - /// type the given expression evaluates to is unsupported. + /// The global variables set by one evaluation are visible for later evaluations. This is similar to adding multiple `