diff --git a/.idea/libraries/Dart_SDK.xml b/.idea/libraries/Dart_SDK.xml
deleted file mode 100644
index 70af93c..0000000
--- a/.idea/libraries/Dart_SDK.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index 4f16f99..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/.idea/runConfigurations/example_lib_main_dart.xml b/.idea/runConfigurations/example_lib_main_dart.xml
deleted file mode 100644
index 5fd9159..0000000
--- a/.idea/runConfigurations/example_lib_main_dart.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
deleted file mode 100644
index e513d54..0000000
--- a/.idea/workspace.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
new file mode 100644
index 0000000..1cc6949
--- /dev/null
+++ b/.vscode/c_cpp_properties.json
@@ -0,0 +1,22 @@
+{
+ "configurations": [
+ {
+ "name": "Linux",
+ "includePath": [
+ "${workspaceFolder}/**",
+ "C:\\Users\\ekibun\\AppData\\Local\\Android\\Sdk\\ndk\\21.3.6528147\\toolchains\\llvm\\prebuilt\\windows-x86_64\\sysroot\\usr\\include"
+ ],
+ "defines": [
+ "_DEBUG",
+ "UNICODE",
+ "_UNICODE"
+ ],
+ "windowsSdkVersion": "10.0.18362.0",
+ "compilerPath": "C:\\Users\\ekibun\\AppData\\Local\\Android\\Sdk\\cmake\\3.10.2.4988404\\bin\\cmake.exe",
+ "cStandard": "c11",
+ "cppStandard": "c++17",
+ "intelliSenseMode": "gcc-x64"
+ }
+ ],
+ "version": 4
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index ade0a35..f487e24 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -57,6 +57,48 @@
"xstring": "cpp",
"xtr1common": "cpp",
"xtree": "cpp",
- "xutility": "cpp"
- }
+ "xutility": "cpp",
+ "array": "cpp",
+ "bit": "cpp",
+ "bitset": "cpp",
+ "clocale": "cpp",
+ "cstdarg": "cpp",
+ "ctime": "cpp",
+ "cwctype": "cpp",
+ "fstream": "cpp",
+ "locale": "cpp",
+ "optional": "cpp",
+ "variant": "cpp",
+ "xlocbuf": "cpp",
+ "xlocmes": "cpp",
+ "xlocmon": "cpp",
+ "xloctime": "cpp",
+ "cerrno": "cpp",
+ "__bit_reference": "cpp",
+ "__config": "cpp",
+ "__debug": "cpp",
+ "__errc": "cpp",
+ "__functional_base": "cpp",
+ "__hash_table": "cpp",
+ "__locale": "cpp",
+ "__mutex_base": "cpp",
+ "__node_handle": "cpp",
+ "__nullptr": "cpp",
+ "__split_buffer": "cpp",
+ "__string": "cpp",
+ "__threading_support": "cpp",
+ "__tree": "cpp",
+ "__tuple": "cpp",
+ "complex": "cpp",
+ "iomanip": "cpp",
+ "string_view": "cpp",
+ "strstream": "cpp",
+ "*.tcc": "cpp",
+ "memory_resource": "cpp",
+ "numeric": "cpp",
+ "cfenv": "cpp",
+ "cinttypes": "cpp",
+ "typeindex": "cpp"
+ },
+ "java.configuration.updateBuildConfiguration": "interactive"
}
\ No newline at end of file
diff --git a/android/.classpath b/android/.classpath
new file mode 100644
index 0000000..4a04201
--- /dev/null
+++ b/android/.classpath
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/android/.gitignore b/android/.gitignore
new file mode 100644
index 0000000..50e9674
--- /dev/null
+++ b/android/.gitignore
@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+/.cxx
diff --git a/android/.idea/.gitignore b/android/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/android/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/android/.idea/.name b/android/.idea/.name
new file mode 100644
index 0000000..c516c6f
--- /dev/null
+++ b/android/.idea/.name
@@ -0,0 +1 @@
+flutter_qjs
\ No newline at end of file
diff --git a/android/.idea/caches/build_file_checksums.ser b/android/.idea/caches/build_file_checksums.ser
new file mode 100644
index 0000000..d1a54c1
Binary files /dev/null and b/android/.idea/caches/build_file_checksums.ser differ
diff --git a/android/.idea/compiler.xml b/android/.idea/compiler.xml
new file mode 100644
index 0000000..fb7f4a8
--- /dev/null
+++ b/android/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/.idea/gradle.xml b/android/.idea/gradle.xml
new file mode 100644
index 0000000..611e7c8
--- /dev/null
+++ b/android/.idea/gradle.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/.idea/jarRepositories.xml b/android/.idea/jarRepositories.xml
new file mode 100644
index 0000000..2370474
--- /dev/null
+++ b/android/.idea/jarRepositories.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/.idea/misc.xml b/android/.idea/misc.xml
new file mode 100644
index 0000000..c532fb7
--- /dev/null
+++ b/android/.idea/misc.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/.idea/vcs.xml b/android/.idea/vcs.xml
new file mode 100644
index 0000000..6c0b863
--- /dev/null
+++ b/android/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/.project b/android/.project
new file mode 100644
index 0000000..fffdd44
--- /dev/null
+++ b/android/.project
@@ -0,0 +1,23 @@
+
+
+ flutter_qjs
+ Project android created by Buildship.
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectbuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.buildship.core.gradleprojectnature
+
+
diff --git a/android/.settings/org.eclipse.buildship.core.prefs b/android/.settings/org.eclipse.buildship.core.prefs
new file mode 100644
index 0000000..a423bb9
--- /dev/null
+++ b/android/.settings/org.eclipse.buildship.core.prefs
@@ -0,0 +1,13 @@
+arguments=
+auto.sync=false
+build.scans.enabled=false
+connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(6.3))
+connection.project.dir=
+eclipse.preferences.version=1
+gradle.user.home=
+java.home=C\:/Program Files/JetBrains/IntelliJ IDEA Community Edition 2019.3.2/jbr
+jvm.arguments=
+offline.mode=false
+override.workspace.settings=true
+show.console.view=true
+show.executions.view=true
diff --git a/android/build.gradle b/android/build.gradle
new file mode 100644
index 0000000..7d22609
--- /dev/null
+++ b/android/build.gradle
@@ -0,0 +1,59 @@
+group 'soko.ekibun.flutter_qjs'
+version '1.0-SNAPSHOT'
+
+buildscript {
+ ext.kotlin_version = '1.3.50'
+ repositories {
+ google()
+ jcenter()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.5.0'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
+
+rootProject.allprojects {
+ repositories {
+ google()
+ jcenter()
+ maven { url 'https://jitpack.io' }
+ }
+}
+
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+
+android {
+ compileSdkVersion 28
+
+ sourceSets {
+ main.java.srcDirs += 'src/main/kotlin'
+ }
+ defaultConfig {
+ minSdkVersion 21
+ externalNativeBuild {
+ cmake {
+ cppFlags "-std=c++17"
+ }
+ }
+ }
+ lintOptions {
+ disable 'InvalidPackage'
+ }
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+ externalNativeBuild {
+ cmake {
+ path "src/main/jni/CMakeLists.txt"
+ version "3.10.2"
+ }
+ }
+}
+
+dependencies {
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ // implementation 'com.github.abner.oasis-jsbridge-android:oasis-jsbridge-quickjs:0.11.0'
+}
diff --git a/android/gradle.properties b/android/gradle.properties
new file mode 100644
index 0000000..38c8d45
--- /dev/null
+++ b/android/gradle.properties
@@ -0,0 +1,4 @@
+org.gradle.jvmargs=-Xmx1536M
+android.enableR8=true
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..01a286e
--- /dev/null
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
diff --git a/android/settings.gradle b/android/settings.gradle
new file mode 100644
index 0000000..4acab51
--- /dev/null
+++ b/android/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'flutter_qjs'
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..6cfef06
--- /dev/null
+++ b/android/src/main/AndroidManifest.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/android/src/main/jni/CMakeLists.txt b/android/src/main/jni/CMakeLists.txt
new file mode 100644
index 0000000..de5c3fd
--- /dev/null
+++ b/android/src/main/jni/CMakeLists.txt
@@ -0,0 +1,56 @@
+# 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 3.4.1)
+set(JNI_LIB_NAME libjsengine)
+
+
+# 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.
+
+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).
+ native-lib.cpp )
+
+# quickjs
+file (STRINGS "quickjs/VERSION" QUICKJS_VERSION)
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DCONFIG_VERSION=\\\"${QUICKJS_VERSION}\\\"")
+target_sources(${JNI_LIB_NAME} PUBLIC
+ quickjs/cutils.c
+ quickjs/libregexp.c
+ quickjs/libunicode.c
+ quickjs/quickjs.c
+)
+
+# 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}
+
+ # Links the target library to the log library
+ # included in the NDK.
+ ${log-lib} )
\ No newline at end of file
diff --git a/android/src/main/jni/js_dart_promise.hpp b/android/src/main/jni/js_dart_promise.hpp
new file mode 100644
index 0000000..27e5e82
--- /dev/null
+++ b/android/src/main/jni/js_dart_promise.hpp
@@ -0,0 +1,182 @@
+/*
+ * @Description:
+ * @Author: ekibun
+ * @Date: 2020-08-07 13:55:52
+ * @LastEditors: ekibun
+ * @LastEditTime: 2020-08-12 14:24:42
+ */
+#pragma once
+#include "quickjs/quickjspp.hpp"
+#include "quickjs/list.h"
+#include
+#include
+
+namespace qjs
+{
+ static JSClassID js_dart_promise_class_id;
+
+ typedef struct
+ {
+ int count;
+ JSValue *argv;
+ } JSOSFutureArgv;
+
+ using JSFutureReturn = std::function;
+ using DartChannel = std::function(std::string, std::string)>;
+
+ typedef struct
+ {
+ struct list_head link;
+ std::shared_future future;
+ JSValue resolve;
+ JSValue reject;
+ } JSOSFuture;
+
+ typedef struct JSThreadState
+ {
+ struct list_head os_future; /* list of JSOSFuture.link */
+ std::function(std::string, std::string)> channel;
+ } JSThreadState;
+
+ static JSValue js_add_future(Value resolve, Value reject, std::shared_future future)
+ {
+ JSRuntime *rt = JS_GetRuntime(resolve.ctx);
+ JSThreadState *ts = (JSThreadState *)JS_GetRuntimeOpaque(rt);
+ JSValueConst jsResolve, jsReject;
+ JSOSFuture *th;
+ JSValue obj;
+
+ jsResolve = resolve.v;
+ if (!JS_IsFunction(resolve.ctx, jsResolve))
+ return JS_ThrowTypeError(resolve.ctx, "resolve not a function");
+ jsReject = reject.v;
+ if (!JS_IsFunction(reject.ctx, jsReject))
+ return JS_ThrowTypeError(reject.ctx, "reject not a function");
+ obj = JS_NewObjectClass(resolve.ctx, js_dart_promise_class_id);
+ if (JS_IsException(obj))
+ return obj;
+ th = (JSOSFuture *)js_mallocz(resolve.ctx, sizeof(*th));
+ if (!th)
+ {
+ JS_FreeValue(resolve.ctx, obj);
+ return JS_EXCEPTION;
+ }
+ th->future = future;
+ th->resolve = JS_DupValue(resolve.ctx, jsResolve);
+ th->reject = JS_DupValue(reject.ctx, jsReject);
+ list_add_tail(&th->link, &ts->os_future);
+ JS_SetOpaque(obj, th);
+ return obj;
+ }
+
+ JSValue js_dart_future(Value resolve, Value reject, std::string name, std::string args)
+ {
+ JSRuntime *rt = JS_GetRuntime(resolve.ctx);
+ JSThreadState *ts = (JSThreadState *)JS_GetRuntimeOpaque(rt);
+ return js_add_future(resolve, reject, ts->channel(name, args));
+ }
+
+ static void unlink_future(JSRuntime *rt, JSOSFuture *th)
+ {
+ if (th->link.prev)
+ {
+ list_del(&th->link);
+ th->link.prev = th->link.next = NULL;
+ }
+ }
+
+ static void free_future(JSRuntime *rt, JSOSFuture *th)
+ {
+ JS_FreeValueRT(rt, th->resolve);
+ JS_FreeValueRT(rt, th->reject);
+ js_free_rt(rt, th);
+ }
+
+ void js_init_handlers(JSRuntime *rt, DartChannel channel)
+ {
+ JSThreadState *ts = (JSThreadState *)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_future);
+ ts->channel = channel;
+
+ JS_SetRuntimeOpaque(rt, ts);
+ }
+
+ void js_free_handlers(JSRuntime *rt)
+ {
+ JSThreadState *ts = (JSThreadState *)JS_GetRuntimeOpaque(rt);
+ struct list_head *el, *el1;
+
+ list_for_each_safe(el, el1, &ts->os_future)
+ {
+ JSOSFuture *th = list_entry(el, JSOSFuture, link);
+ th->future.get();
+ unlink_future(rt, th);
+ free_future(rt, th);
+ }
+ ts->channel = nullptr;
+ free(ts);
+ JS_SetRuntimeOpaque(rt, NULL); /* fail safe */
+ }
+
+ static void call_handler(JSContext *ctx, JSValueConst func, int count, JSValue *argv)
+ {
+ 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, count, argv);
+ JS_FreeValue(ctx, func1);
+ if (JS_IsException(ret))
+ throw exception{};
+ JS_FreeValue(ctx, ret);
+ }
+
+ static int js_dart_poll(JSContext *ctx)
+ {
+ JSRuntime *rt = JS_GetRuntime(ctx);
+ JSThreadState *ts = (JSThreadState *)JS_GetRuntimeOpaque(rt);
+ struct list_head *el;
+
+ /* XXX: handle signals if useful */
+
+ if (list_empty(&ts->os_future))
+ return -1; /* no more events */
+
+ /* XXX: only timers and basic console input are supported */
+ if (!list_empty(&ts->os_future))
+ {
+ list_for_each(el, &ts->os_future)
+ {
+ JSOSFuture *th = list_entry(el, JSOSFuture, link);
+ auto status = th->future.wait_for(std::chrono::seconds(0));
+ if (status == std::future_status::ready)
+ {
+ JSOSFutureArgv argv = th->future.get()(ctx);
+ JSValue resolve, reject;
+ int64_t delay;
+ /* the timer expired */
+ resolve = th->resolve;
+ th->resolve = JS_UNDEFINED;
+ reject = th->reject;
+ th->reject = JS_UNDEFINED;
+ unlink_future(rt, th);
+ free_future(rt, th);
+ call_handler(ctx, argv.count < 0 ? reject : resolve, abs(argv.count), argv.argv);
+ for (int i = 0; i < abs(argv.count); ++i)
+ JS_FreeValue(ctx, argv.argv[i]);
+ JS_FreeValue(ctx, resolve);
+ JS_FreeValue(ctx, reject);
+ delete argv.argv;
+ return 0;
+ }
+ }
+ }
+ return 0;
+ }
+} // namespace qjs
\ No newline at end of file
diff --git a/android/src/main/jni/js_engine.hpp b/android/src/main/jni/js_engine.hpp
new file mode 100644
index 0000000..188fd77
--- /dev/null
+++ b/android/src/main/jni/js_engine.hpp
@@ -0,0 +1,192 @@
+/*
+ * @Description:
+ * @Author: ekibun
+ * @Date: 2020-08-08 10:30:59
+ * @LastEditors: ekibun
+ * @LastEditTime: 2020-08-12 13:53:59
+ */
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "js_dart_promise.hpp"
+#include "quickjs/quickjspp.hpp"
+
+namespace qjs
+{
+ struct EngineTask
+ {
+ std::string command;
+ std::string name;
+ std::function resolve;
+ std::function reject;
+ };
+
+ struct EngineTaskResolver
+ {
+ Value result;
+ std::function resolve;
+ std::function reject;
+ };
+
+ std::string getStackTrack(Value exc)
+ {
+ std::string err = (std::string)exc;
+ if ((bool)exc["stack"])
+ err += "\n" + (std::string)exc["stack"];
+ return err;
+ }
+
+ class Engine
+ {
+ // 引擎线程
+ std::thread thread;
+ // 任务队列
+ std::queue tasks;
+ // 同步
+ std::mutex m_lock;
+ // 是否关闭提交
+ std::atomic stoped;
+
+ void handleException(qjs::Value exc)
+ {
+ std::cout << getStackTrack(exc) << std::endl;
+ }
+
+ public:
+ inline Engine(DartChannel channel) : stoped{false}
+ {
+ thread = std::thread([this, channel] { // 工作线程函数
+ // 创建运行环境
+ Runtime rt;
+ js_init_handlers(rt.rt, channel);
+ Context ctx(rt);
+ auto &module = ctx.addModule("__DartImpl");
+ module.function<&js_dart_future>("__invoke");
+ ctx.eval(
+ R"xxx(
+ import * as __DartImpl from "__DartImpl";
+ globalThis.dart = (method, ...args) => new Promise((res, rej) =>
+ __DartImpl.__invoke((v) => res(JSON.parse(v)), rej, method, JSON.stringify(args)));
+ )xxx",
+ "", JS_EVAL_TYPE_MODULE);
+ std::vector unresolvedTask;
+ // 循环
+ while (!this->stoped)
+ {
+ // 获取待执行的task
+ EngineTask task;
+ { // 获取一个待执行的 task
+ std::unique_lock lock{this->m_lock}; // unique_lock 相比 lock_guard 的好处是:可以随时 unlock() 和 lock()
+ if (!this->tasks.empty())
+ {
+ task = this->tasks.front(); // 取一个 task
+ this->tasks.pop();
+ }
+ }
+ // 执行task
+ if (task.resolve)
+ try
+ {
+ ctx.global()["__evalstr"] = JS_NewString(ctx.ctx, task.command.c_str());
+ Value ret = ctx.eval(
+ R"xxx(
+ (() => {
+ const __ret = Promise.resolve(eval(__evalstr))
+ .then(v => {
+ __ret.__value = v;
+ __ret.__resolved = true;
+ }).catch(e => {
+ __ret.__error = e;
+ __ret.__rejected = true;
+ });
+ return __ret;
+ })()
+ )xxx",
+ task.name.c_str());
+ unresolvedTask.emplace_back(EngineTaskResolver{ret, std::move(task.resolve), std::move(task.reject)});
+ }
+ catch (exception e)
+ {
+ task.reject(getStackTrack(ctx.getException()));
+ }
+ // 执行microtask
+ JSContext *pctx;
+ for (;;)
+ {
+ int err = JS_ExecutePendingJob(rt.rt, &pctx);
+ if (err <= 0)
+ {
+ if (err < 0)
+ std::cout << getStackTrack(ctx.getException()) << std::endl;
+ break;
+ }
+ }
+ // TODO 检查promise状态
+ for (auto it = unresolvedTask.begin(); it != unresolvedTask.end();)
+ {
+ bool finished = false;
+ if (it->result["__resolved"])
+ {
+ it->resolve((std::string)it->result["__value"]);
+ finished = true;
+ };
+ if (it->result["__rejected"])
+ {
+ it->reject(getStackTrack(it->result["__error"]));
+ finished = true;
+ };
+ if (finished)
+ it = unresolvedTask.erase(it);
+ else
+ ++it;
+ }
+ // 检查dart交互
+ bool idle = true;
+ try
+ {
+ idle = js_dart_poll(ctx.ctx);
+ }
+ catch (exception e)
+ {
+ handleException(ctx.getException());
+ }
+ // 空闲时reject所有task
+ if (idle && !JS_IsJobPending(rt.rt) && !unresolvedTask.empty())
+ {
+ for (EngineTaskResolver &task : unresolvedTask)
+ {
+ task.reject("Promise cannot resolve");
+ }
+ unresolvedTask.clear();
+ }
+ }
+ js_free_handlers(rt.rt);
+ });
+ }
+ inline ~Engine()
+ {
+ stoped.store(true);
+ if (thread.joinable())
+ thread.join(); // 等待任务结束, 前提:线程一定会执行完
+ }
+
+ public:
+ // 提交一个任务
+ void commit(EngineTask task)
+ {
+ if (stoped.load()) // stop == true ??
+ throw std::runtime_error("commit on stopped engine.");
+ { // 添加任务到队列
+ std::lock_guard lock{m_lock}; //对当前块的语句加锁 lock_guard 是 mutex 的 stack 封装类,构造的时候 lock(),析构的时候 unlock()
+ tasks.emplace(task);
+ }
+ }
+ };
+
+} // namespace qjs
diff --git a/android/src/main/jni/native-lib.cpp b/android/src/main/jni/native-lib.cpp
new file mode 100644
index 0000000..1640387
--- /dev/null
+++ b/android/src/main/jni/native-lib.cpp
@@ -0,0 +1,164 @@
+/*
+ * @Description:
+ * @Author: ekibun
+ * @Date: 2020-08-09 18:16:11
+ * @LastEditors: ekibun
+ * @LastEditTime: 2020-08-12 23:11:35
+ */
+#include
+#include
+#include "js_engine.hpp"
+
+qjs::Engine *engine = nullptr;
+
+// static jobject gClassLoader;
+// static jmethodID gFindClassMethod;
+
+JNIEnv *getEnv(JavaVM *gJvm)
+{
+ JNIEnv *env;
+ int status = gJvm->GetEnv((void **)&env, JNI_VERSION_1_6);
+ if (status < 0)
+ {
+ status = gJvm->AttachCurrentThread(&env, NULL);
+ if (status < 0)
+ {
+ return nullptr;
+ }
+ }
+ return env;
+}
+
+// JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved)
+// {
+// JNIEnv *env = getEnv(pjvm);
+// auto randomClass = env->FindClass("soko/ekibun/flutter_qjs/ResultWrapper");
+// jclass classClass = env->GetObjectClass(randomClass);
+// auto classLoaderClass = env->FindClass("java/lang/ClassLoader");
+// auto getClassLoaderMethod = env->GetMethodID(classClass, "getClassLoader",
+// "()Ljava/lang/ClassLoader;");
+// gClassLoader = env->NewGlobalRef(env->CallObjectMethod(randomClass, getClassLoaderMethod));
+// gFindClassMethod = env->GetMethodID(classLoaderClass, "findClass",
+// "(Ljava/lang/String;)Ljava/lang/Class;");
+
+// return JNI_VERSION_1_6;
+// }
+
+// jclass findClass(JNIEnv *env, const char *name)
+// {
+// return static_cast(env->CallObjectMethod(gClassLoader, gFindClassMethod, env->NewStringUTF(name)));
+// }
+
+void jniResultResolve(JavaVM *jvm, jobject result, std::string data)
+{
+ JNIEnv *env = getEnv(jvm);
+ jclass jclazz = env->GetObjectClass(result);
+ jmethodID jmethod = env->GetMethodID(jclazz, "success", "(Ljava/lang/String;)V");
+ jstring jdata = env->NewStringUTF(data.c_str());
+ env->CallVoidMethod(result, jmethod, jdata);
+ env->DeleteLocalRef(jdata);
+ env->DeleteGlobalRef(result);
+ jvm->DetachCurrentThread();
+}
+
+void jniResultReject(JavaVM *jvm, jobject result, std::string reason)
+{
+ JNIEnv *env = getEnv(jvm);
+ jclass jclazz = env->GetObjectClass(result);
+ jmethodID jmethod = env->GetMethodID(jclazz, "error", "(Ljava/lang/String;)V");
+ jstring jreason = env->NewStringUTF(reason.c_str());
+ env->CallVoidMethod(result, jmethod, jreason);
+ env->DeleteLocalRef(jreason);
+ env->DeleteGlobalRef(result);
+ jvm->DetachCurrentThread();
+}
+
+void jniChannelInvoke(JavaVM *jvm, jobject channel, std::promise *promise, std::string method, std::string argv)
+{
+ JNIEnv *env = nullptr;
+ jvm->GetEnv((void **)&env, JNI_VERSION_1_2);
+ jvm->AttachCurrentThread(&env, NULL);
+ jclass jclazz = env->GetObjectClass(channel);
+ jmethodID jmethod = env->GetMethodID(jclazz, "invokeMethod", "(Ljava/lang/String;Ljava/lang/String;J)V");
+ jstring jstrmethod = env->NewStringUTF(method.c_str());
+ jstring jstrargv = env->NewStringUTF(argv.c_str());
+
+ env->CallVoidMethod(channel, jmethod, jstrmethod, jstrargv, (jlong)promise);
+ env->DeleteLocalRef(jstrmethod);
+ env->DeleteLocalRef(jstrargv);
+ jvm->DetachCurrentThread();
+}
+
+extern "C" JNIEXPORT jint JNICALL
+Java_soko_ekibun_flutter_1qjs_JniBridge_initEngine(
+ JNIEnv *env,
+ jobject thiz,
+ jobject channel)
+{
+ JavaVM *jvm = nullptr;
+ env->GetJavaVM(&jvm);
+ jobject gchannel = env->NewGlobalRef(channel);
+ engine = new qjs::Engine([jvm, gchannel](std::string name, std::string args) {
+ auto promise = new std::promise();
+ jniChannelInvoke(jvm, gchannel, promise, name, args);
+ return promise->get_future();
+ });
+ return (jlong)engine;
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_soko_ekibun_flutter_1qjs_JniBridge_evaluate(
+ JNIEnv *env,
+ jobject thiz,
+ jstring script,
+ jstring name,
+ jobject result)
+{
+ JavaVM *jvm = nullptr;
+ env->GetJavaVM(&jvm);
+ jobject gresult = env->NewGlobalRef(result);
+ engine->commit(qjs::EngineTask{
+ env->GetStringUTFChars(script, 0),
+ env->GetStringUTFChars(name, 0),
+ [jvm, gresult](std::string resolve) {
+ jniResultResolve(jvm, gresult, resolve);
+ // flutter::EncodableValue response(resolve);
+ // presult->Success(&response);
+ },
+ [jvm, gresult](std::string reject) {
+ jniResultReject(jvm, gresult, reject);
+ // presult->Error("FlutterJSException", reject);
+ }});
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_soko_ekibun_flutter_1qjs_JniBridge_close(
+ JNIEnv *env,
+ jobject /* this */)
+{
+ delete engine;
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_soko_ekibun_flutter_1qjs_JniBridge_resolve(
+ JNIEnv *env,
+ jobject clazz,
+ jlong promise, jstring data)
+{
+ ((std::promise *)promise)->set_value((qjs::JSFutureReturn)[data = std::string(env->GetStringUTFChars(data, 0))](qjs::JSContext * ctx) {
+ qjs::JSValue *ret = new qjs::JSValue{JS_NewString(ctx, data.c_str())};
+ return qjs::JSOSFutureArgv{1, ret};
+ });
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_soko_ekibun_flutter_1qjs_JniBridge_reject(
+ JNIEnv *env,
+ jobject clazz,
+ jlong promise, jstring data)
+{
+ ((std::promise *)promise)->set_value((qjs::JSFutureReturn)[data = std::string(env->GetStringUTFChars(data, 0))](qjs::JSContext * ctx) {
+ qjs::JSValue *ret = new qjs::JSValue{JS_NewString(ctx, data.c_str())};
+ return qjs::JSOSFutureArgv{-1, ret};
+ });
+}
\ No newline at end of file
diff --git a/android/src/main/jni/quickjs/VERSION b/android/src/main/jni/quickjs/VERSION
new file mode 100644
index 0000000..e970cf6
--- /dev/null
+++ b/android/src/main/jni/quickjs/VERSION
@@ -0,0 +1 @@
+2020-07-05
diff --git a/android/src/main/jni/quickjs/cutils.c b/android/src/main/jni/quickjs/cutils.c
new file mode 100644
index 0000000..64a32d3
--- /dev/null
+++ b/android/src/main/jni/quickjs/cutils.c
@@ -0,0 +1,620 @@
+/*
+ * 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(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 < 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 ... 0xdf:
+ l = 1;
+ break;
+ case 0xe0 ... 0xef:
+ l = 2;
+ break;
+ case 0xf0 ... 0xf7:
+ l = 3;
+ break;
+ case 0xf8 ... 0xfb:
+ l = 4;
+ break;
+ case 0xfc ... 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/android/src/main/jni/quickjs/cutils.h b/android/src/main/jni/quickjs/cutils.h
new file mode 100644
index 0000000..31f7cd8
--- /dev/null
+++ b/android/src/main/jni/quickjs/cutils.h
@@ -0,0 +1,297 @@
+/*
+ * 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
+
+/* set if CPU is big endian */
+#undef WORDS_BIGENDIAN
+
+#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
+
+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);
+
+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;
+}
+
+static inline uint16_t bswap16(uint16_t x)
+{
+ return (x >> 8) | (x << 8);
+}
+
+static inline uint32_t bswap32(uint32_t v)
+{
+ return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) |
+ ((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24);
+}
+
+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));
+}
+
+/* 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 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);
+
+#endif /* CUTILS_H */
diff --git a/android/src/main/jni/quickjs/libregexp-opcode.h b/android/src/main/jni/quickjs/libregexp-opcode.h
new file mode 100644
index 0000000..f90c23b
--- /dev/null
+++ b/android/src/main/jni/quickjs/libregexp-opcode.h
@@ -0,0 +1,58 @@
+/*
+ * 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(char32, 5)
+DEF(dot, 1)
+DEF(any, 1) /* same as dot but match any character including line terminator */
+DEF(line_start, 1)
+DEF(line_end, 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(not_word_boundary, 1)
+DEF(back_reference, 2)
+DEF(backward_back_reference, 2) /* must come after back_reference */
+DEF(range, 3) /* variable length */
+DEF(range32, 3) /* variable length */
+DEF(lookahead, 5)
+DEF(negative_lookahead, 5)
+DEF(push_char_pos, 1) /* push the character position on the stack */
+DEF(bne_char_pos, 5) /* pop one stack element and jump if equal to the character
+ position */
+DEF(prev, 1) /* go to the previous char */
+DEF(simple_greedy_quant, 17)
+
+#endif /* DEF */
diff --git a/android/src/main/jni/quickjs/libregexp.c b/android/src/main/jni/quickjs/libregexp.c
new file mode 100644
index 0000000..b455bf2
--- /dev/null
+++ b/android/src/main/jni/quickjs/libregexp.c
@@ -0,0 +1,2588 @@
+/*
+ * 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"
+
+/*
+ TODO:
+
+ - Add full unicode canonicalize rules for character ranges (not
+ really useful but needed for exact "ignorecase" compatibility).
+
+ - 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
+
+/* 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_utf16;
+ BOOL ignore_case;
+ 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 *mem_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 1
+#define RE_HEADER_STACK_SIZE 2
+
+#define RE_HEADER_LEN 7
+
+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;
+}
+
+/* canonicalize with the specific JS regexp rules */
+static uint32_t lre_canonicalize(uint32_t c, BOOL is_utf16)
+{
+ uint32_t res[LRE_CC_RES_LEN_MAX];
+ int len;
+ if (is_utf16) {
+ if (likely(c < 128)) {
+ if (c >= 'A' && c <= 'Z')
+ c = c - 'A' + 'a';
+ } else {
+ lre_case_conv(res, c, 2);
+ c = res[0];
+ }
+ } 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(res, c, FALSE);
+ if (len == 1 && res[0] >= 128)
+ c = res[0];
+ }
+ }
+ return c;
+}
+
+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,
+};
+
+BOOL lre_is_space(int c)
+{
+ int i, n, low, high;
+ n = (countof(char_range_s) - 1) / 2;
+ for(i = 0; i < n; i++) {
+ low = char_range_s[2 * i + 1];
+ if (c < low)
+ return FALSE;
+ high = char_range_s[2 * i + 2];
+ if (c < high)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+uint32_t const lre_id_start_table_ascii[4] = {
+ /* $ A-Z _ a-z */
+ 0x00000000, 0x00000010, 0x87FFFFFE, 0x07FFFFFE
+};
+
+uint32_t const lre_id_continue_table_ascii[4] = {
+ /* $ 0-9 A-Z _ a-z */
+ 0x00000000, 0x03FF0010, 0x87FFFFFE, 0x07FFFFFE
+};
+
+
+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 *char_range_table[] = {
+ char_range_d,
+ char_range_s,
+ char_range_w,
+};
+
+static int cr_init_char_range(REParseState *s, CharRange *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++;
+ cr_init(cr, s->mem_opaque, lre_realloc);
+ for(i = 0; i < len * 2; i++) {
+ if (cr_add_point(cr, c_pt[i]))
+ goto fail;
+ }
+ if (invert) {
+ if (cr_invert(cr))
+ goto fail;
+ }
+ return 0;
+ fail:
+ cr_free(cr);
+ return -1;
+}
+
+static int cr_canonicalize(CharRange *cr)
+{
+ CharRange a;
+ uint32_t pt[2];
+ int i, ret;
+
+ cr_init(&a, cr->mem_opaque, lre_realloc);
+ pt[0] = 'a';
+ pt[1] = 'z' + 1;
+ ret = cr_op(&a, cr->points, cr->len, pt, 2, CR_OP_INTER);
+ if (ret)
+ goto fail;
+ /* convert to upper case */
+ /* XXX: the generic unicode case would be much more complicated
+ and not really useful */
+ for(i = 0; i < a.len; i++) {
+ a.points[i] += 'A' - 'a';
+ }
+ /* Note: for simplicity we keep the lower case ranges */
+ ret = cr_union1(cr, a.points, a.len);
+ fail:
+ cr_free(&a);
+ return ret;
+}
+
+#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= buf[0];
+ bc_len = get_u32(buf + 3);
+ assert(bc_len + RE_HEADER_LEN <= buf_len);
+ printf("flags: 0x%x capture_count=%d stack_size=%d\n",
+ re_flags, buf[1], buf[2]);
+ 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[1]; 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:
+ val = get_u16(buf + pos + 1);
+ if (val >= ' ' && val <= 126)
+ printf(" '%c'", val);
+ else
+ printf(" 0x%04x", val);
+ break;
+ case REOP_char32:
+ 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:
+ case REOP_bne_char_pos:
+ 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_backward_back_reference:
+ 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:
+ {
+ 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:
+ {
+ 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 (c >= 0xd800 && c < 0xdc00 &&
+ 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 && c1 >= 0xdc00 && c1 < 0xe000) {
+ p += 6;
+ c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
+ }
+ }
+ }
+ }
+ break;
+ case '0' ... '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 == '_'));
+}
+
+static int parse_unicode_property(REParseState *s, CharRange *cr,
+ const uint8_t **pp, BOOL is_inv)
+{
+ 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:
+ cr_init(cr, s->mem_opaque, lre_realloc);
+ ret = unicode_script(cr, value, script_ext);
+ if (ret) {
+ cr_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")) {
+ cr_init(cr, s->mem_opaque, lre_realloc);
+ ret = unicode_general_category(cr, value);
+ if (ret) {
+ cr_free(cr);
+ if (ret == -2)
+ return re_parse_error(s, "unknown unicode general category");
+ else
+ goto out_of_memory;
+ }
+ } else if (value[0] == '\0') {
+ cr_init(cr, s->mem_opaque, lre_realloc);
+ ret = unicode_general_category(cr, name);
+ if (ret == -1) {
+ cr_free(cr);
+ goto out_of_memory;
+ }
+ if (ret < 0) {
+ ret = unicode_prop(cr, name);
+ if (ret) {
+ cr_free(cr);
+ if (ret == -2)
+ goto unknown_property_name;
+ else
+ goto out_of_memory;
+ }
+ }
+ } else {
+ unknown_property_name:
+ return re_parse_error(s, "unknown unicode property name");
+ }
+
+ if (is_inv) {
+ if (cr_invert(cr)) {
+ cr_free(cr);
+ return -1;
+ }
+ }
+ *pp = p;
+ return 0;
+ out_of_memory:
+ return re_parse_out_of_memory(s);
+}
+#endif /* CONFIG_ALL_UNICODE */
+
+/* return -1 if error otherwise the character or a class range
+ (CLASS_RANGE_BASE). In case of class range, 'cr' is
+ initialized. Otherwise, it is ignored. */
+static int get_class_atom(REParseState *s, CharRange *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_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_utf16)) { /* Annex B.1.4 */
+ c &= 0x1f;
+ p++;
+ } else if (s->is_utf16) {
+ goto invalid_escape;
+ } else {
+ /* otherwise return '\' and 'c' */
+ p--;
+ c = '\\';
+ }
+ break;
+#ifdef CONFIG_ALL_UNICODE
+ case 'p':
+ case 'P':
+ if (s->is_utf16) {
+ if (parse_unicode_property(s, cr, &p, (c == 'P')))
+ return -1;
+ c = CLASS_RANGE_BASE;
+ break;
+ }
+ /* fall thru */
+#endif
+ default:
+ p--;
+ ret = lre_parse_escape(&p, s->is_utf16 * 2);
+ if (ret >= 0) {
+ c = ret;
+ } else {
+ if (ret == -2 && *p != '\0' && strchr("^$\\.*+?()[]{}|/", *p)) {
+ /* always valid to escape these characters */
+ goto normal_char;
+ } else if (s->is_utf16) {
+ 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 */
+ default:
+ normal_char:
+ /* normal char */
+ if (c >= 128) {
+ c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
+ if ((unsigned)c > 0xffff && !s->is_utf16) {
+ /* 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) {
+ /* not sure it can really happen. Emit a match that is always
+ false */
+ 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, 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, 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_parse_char_class(REParseState *s, const uint8_t **pp)
+{
+ const uint8_t *p;
+ uint32_t c1, c2;
+ CharRange cr_s, *cr = &cr_s;
+ CharRange cr1_s, *cr1 = &cr1_s;
+ BOOL invert;
+
+ cr_init(cr, s->mem_opaque, lre_realloc);
+ p = *pp;
+ p++; /* skip '[' */
+ invert = FALSE;
+ if (*p == '^') {
+ p++;
+ invert = TRUE;
+ }
+ for(;;) {
+ if (*p == ']')
+ break;
+ 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 (c1 >= CLASS_RANGE_BASE) {
+ if (s->is_utf16) {
+ cr_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) {
+ cr_free(cr1);
+ if (s->is_utf16) {
+ 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 (cr_union_interval(cr, c1, c2))
+ goto memory_error;
+ } else {
+ class_atom:
+ if (c1 >= CLASS_RANGE_BASE) {
+ int ret;
+ ret = cr_union1(cr, cr1->points, cr1->len);
+ cr_free(cr1);
+ if (ret)
+ goto memory_error;
+ } else {
+ if (cr_union_interval(cr, c1, c1))
+ goto memory_error;
+ }
+ }
+ }
+ if (s->ignore_case) {
+ if (cr_canonicalize(cr))
+ goto memory_error;
+ }
+ if (invert) {
+ if (cr_invert(cr))
+ goto memory_error;
+ }
+ if (re_emit_range(s, cr))
+ goto fail;
+ cr_free(cr);
+ p++; /* skip ']' */
+ *pp = p;
+ return 0;
+ memory_error:
+ re_parse_out_of_memory(s);
+ fail:
+ cr_free(cr);
+ return -1;
+}
+
+/* Return:
+ 1 if the opcodes in bc_buf[] always advance the character pointer.
+ 0 if the character pointer may not be advanced.
+ -1 if the code may depend on side effects of its previous execution (backreference)
+*/
+static int re_check_advance(const uint8_t *bc_buf, int bc_buf_len)
+{
+ int pos, opcode, ret, len, i;
+ uint32_t val, last;
+ BOOL has_back_reference;
+ uint8_t capture_bitmap[CAPTURE_COUNT_MAX];
+
+ ret = -2; /* not known yet */
+ pos = 0;
+ has_back_reference = FALSE;
+ memset(capture_bitmap, 0, sizeof(capture_bitmap));
+
+ while (pos < bc_buf_len) {
+ opcode = bc_buf[pos];
+ len = reopcode_info[opcode].size;
+ switch(opcode) {
+ case REOP_range:
+ val = get_u16(bc_buf + pos + 1);
+ len += val * 4;
+ goto simple_char;
+ case REOP_range32:
+ val = get_u16(bc_buf + pos + 1);
+ len += val * 8;
+ goto simple_char;
+ case REOP_char:
+ case REOP_char32:
+ case REOP_dot:
+ case REOP_any:
+ simple_char:
+ if (ret == -2)
+ ret = 1;
+ break;
+ case REOP_line_start:
+ case REOP_line_end:
+ case REOP_push_i32:
+ case REOP_push_char_pos:
+ case REOP_drop:
+ case REOP_word_boundary:
+ case REOP_not_word_boundary:
+ case REOP_prev:
+ /* no effect */
+ break;
+ case REOP_save_start:
+ case REOP_save_end:
+ val = bc_buf[pos + 1];
+ capture_bitmap[val] |= 1;
+ break;
+ case REOP_save_reset:
+ {
+ val = bc_buf[pos + 1];
+ last = bc_buf[pos + 2];
+ while (val < last)
+ capture_bitmap[val++] |= 1;
+ }
+ break;
+ case REOP_back_reference:
+ case REOP_backward_back_reference:
+ val = bc_buf[pos + 1];
+ capture_bitmap[val] |= 2;
+ has_back_reference = TRUE;
+ break;
+ default:
+ /* safe behvior: we cannot predict the outcome */
+ if (ret == -2)
+ ret = 0;
+ break;
+ }
+ pos += len;
+ }
+ if (has_back_reference) {
+ /* check if there is back reference which references a capture
+ made in the some code */
+ for(i = 0; i < CAPTURE_COUNT_MAX; i++) {
+ if (capture_bitmap[i] == 3)
+ return -1;
+ }
+ }
+ if (ret == -2)
+ ret = 0;
+ 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:
+ val = get_u16(bc_buf + pos + 1);
+ len += val * 4;
+ goto simple_char;
+ case REOP_range32:
+ val = get_u16(bc_buf + pos + 1);
+ len += val * 8;
+ goto simple_char;
+ case REOP_char:
+ case REOP_char32:
+ case REOP_dot:
+ case REOP_any:
+ simple_char:
+ count++;
+ break;
+ case REOP_line_start:
+ case REOP_line_end:
+ case REOP_word_boundary:
+ case REOP_not_word_boundary:
+ 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, BOOL is_utf16)
+{
+ const uint8_t *p;
+ uint32_t c;
+ char *q;
+
+ p = *pp;
+ q = buf;
+ for(;;) {
+ c = *p;
+ if (c == '\\') {
+ p++;
+ if (*p != 'u')
+ return -1;
+ c = lre_parse_escape(&p, is_utf16 * 2);
+ } else if (c == '>') {
+ break;
+ } else if (c >= 128) {
+ c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
+ } 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,
+ s->is_utf16) == 0) {
+ if (!strcmp(name, capture_name))
+ return capture_index;
+ }
+ }
+ capture_index++;
+ }
+ } else {
+ capture_index++;
+ }
+ break;
+ case '\\':
+ p++;
+ break;
+ case '[':
+ for (p += 1 + (*p == ']'); p < s->buf_end && *p != ']'; p++) {
+ if (*p == '\\')
+ p++;
+ }
+ break;
+ }
+ }
+ 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;
+
+ name_len = strlen(name);
+ p = (char *)s->group_names.buf;
+ buf_end = (char *)s->group_names.buf + s->group_names.size;
+ 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_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;
+ CharRange 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, REOP_line_start);
+ break;
+ case '$':
+ p++;
+ re_emit_op(s, 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_utf16) {
+ 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] == '=' || 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_utf16 && !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, s->is_utf16)) {
+ 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':
+ re_emit_op(s, REOP_word_boundary + (p[1] != 'b'));
+ 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_utf16 || 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, s->is_utf16)) {
+ if (s->is_utf16 || 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_utf16 || 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_utf16) {
+ 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' ... '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_utf16) {
+ /* 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 reguar 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 + is_backward_dir, 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_utf16)
+ 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;
+ /* Note: canonicalization is not needed */
+ ret = re_emit_range(s, cr);
+ cr_free(cr);
+ if (ret)
+ return -1;
+ } else {
+ if (s->ignore_case)
+ c = lre_canonicalize(c, s->is_utf16);
+ if (c <= 0xffff)
+ re_emit_op_u16(s, REOP_char, c);
+ else
+ re_emit_op_u32(s, REOP_char32, 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_utf16)
+ 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_utf16) {
+ /* 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;
+ add_zero_advance_check = (re_check_advance(s->byte_code.buf + last_atom_start,
+ s->byte_code.size - last_atom_start) == 0);
+ } else {
+ add_zero_advance_check = FALSE;
+ }
+
+ {
+ 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) {
+ if (dbuf_insert(&s->byte_code, last_atom_start, 5))
+ 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);
+ } else if (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 + add_zero_advance_check);
+ if (add_zero_advance_check) {
+ /* avoid infinite loop by stoping the
+ recursion if no advance was made in the
+ atom (only works if the atom has no
+ side effect) */
+ s->byte_code.buf[last_atom_start + 1 + 4] = REOP_push_char_pos;
+ re_emit_goto(s, REOP_bne_char_pos, last_atom_start);
+ } else {
+ re_emit_goto(s, REOP_goto, last_atom_start);
+ }
+ } else {
+ if (dbuf_insert(&s->byte_code, last_atom_start, 10))
+ 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);
+ 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);
+ 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_goto(s, REOP_bne_char_pos, pos);
+ else
+ 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);
+ /* copy the atom */
+ dbuf_put_self(&s->byte_code, last_atom_start, len);
+
+ 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;
+
+ 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_bne_char_pos:
+ assert(stack_size > 0);
+ stack_size--;
+ break;
+ case REOP_range:
+ val = get_u16(bc_buf + pos + 1);
+ len += val * 4;
+ break;
+ case REOP_range32:
+ 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->mem_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_utf16 = ((re_flags & LRE_FLAG_UTF16) != 0);
+ is_sticky = ((re_flags & LRE_FLAG_STICKY) != 0);
+ s->ignore_case = ((re_flags & LRE_FLAG_IGNORECASE) != 0);
+ s->dotall = ((re_flags & LRE_FLAG_DOTALL) != 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_putc(&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 + 3, 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);
+ s->byte_code.buf[RE_HEADER_FLAGS] |= 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) \
+ do { \
+ if (cbuf_type == 0) { \
+ c = *cptr++; \
+ } else { \
+ uint32_t __c1; \
+ c = *(uint16_t *)cptr; \
+ cptr += 2; \
+ if (c >= 0xd800 && c < 0xdc00 && \
+ cbuf_type == 2 && cptr < cbuf_end) { \
+ __c1 = *(uint16_t *)cptr; \
+ if (__c1 >= 0xdc00 && __c1 < 0xe000) { \
+ c = (((c & 0x3ff) << 10) | (__c1 & 0x3ff)) + 0x10000; \
+ cptr += 2; \
+ } \
+ } \
+ } \
+ } while (0)
+
+#define PEEK_CHAR(c, cptr, cbuf_end) \
+ do { \
+ if (cbuf_type == 0) { \
+ c = cptr[0]; \
+ } else { \
+ uint32_t __c1; \
+ c = ((uint16_t *)cptr)[0]; \
+ if (c >= 0xd800 && c < 0xdc00 && \
+ cbuf_type == 2 && (cptr + 2) < cbuf_end) { \
+ __c1 = ((uint16_t *)cptr)[1]; \
+ if (__c1 >= 0xdc00 && __c1 < 0xe000) { \
+ c = (((c & 0x3ff) << 10) | (__c1 & 0x3ff)) + 0x10000; \
+ } \
+ } \
+ } \
+ } while (0)
+
+#define PEEK_PREV_CHAR(c, cptr, cbuf_start) \
+ do { \
+ if (cbuf_type == 0) { \
+ c = cptr[-1]; \
+ } else { \
+ uint32_t __c1; \
+ c = ((uint16_t *)cptr)[-1]; \
+ if (c >= 0xdc00 && c < 0xe000 && \
+ cbuf_type == 2 && (cptr - 4) >= cbuf_start) { \
+ __c1 = ((uint16_t *)cptr)[-2]; \
+ if (__c1 >= 0xd800 && __c1 < 0xdc00 ) { \
+ c = (((__c1 & 0x3ff) << 10) | (c & 0x3ff)) + 0x10000; \
+ } \
+ } \
+ } \
+ } while (0)
+
+#define GET_PREV_CHAR(c, cptr, cbuf_start) \
+ do { \
+ if (cbuf_type == 0) { \
+ cptr--; \
+ c = cptr[0]; \
+ } else { \
+ uint32_t __c1; \
+ cptr -= 2; \
+ c = ((uint16_t *)cptr)[0]; \
+ if (c >= 0xdc00 && c < 0xe000 && \
+ cbuf_type == 2 && cptr > cbuf_start) { \
+ __c1 = ((uint16_t *)cptr)[-1]; \
+ if (__c1 >= 0xd800 && __c1 < 0xdc00 ) { \
+ cptr -= 2; \
+ c = (((__c1 & 0x3ff) << 10) | (c & 0x3ff)) + 0x10000; \
+ } \
+ } \
+ } \
+ } while (0)
+
+#define PREV_CHAR(cptr, cbuf_start) \
+ do { \
+ if (cbuf_type == 0) { \
+ cptr--; \
+ } else { \
+ cptr -= 2; \
+ if (cbuf_type == 2) { \
+ c = ((uint16_t *)cptr)[0]; \
+ if (c >= 0xdc00 && c < 0xe000 && cptr > cbuf_start) { \
+ c = ((uint16_t *)cptr)[-1]; \
+ if (c >= 0xd800 && c < 0xdc00) \
+ cptr -= 2; \
+ } \
+ } \
+ } \
+ } 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 multi_line;
+ BOOL ignore_case;
+ BOOL is_utf16;
+ 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;
+}
+
+/* return 1 if match, 0 if not match or -1 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 (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);
+ }
+ 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:
+ val = get_u32(pc);
+ pc += 4;
+ goto test_char;
+ case REOP_char:
+ val = get_u16(pc);
+ pc += 2;
+ test_char:
+ if (cptr >= cbuf_end)
+ goto no_match;
+ GET_CHAR(c, cptr, cbuf_end);
+ if (s->ignore_case) {
+ c = lre_canonicalize(c, s->is_utf16);
+ }
+ 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 -1;
+ 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 -1;
+ break;
+
+ case REOP_goto:
+ val = get_u32(pc);
+ pc += 4 + (int)val;
+ break;
+ case REOP_line_start:
+ if (cptr == s->cbuf)
+ break;
+ if (!s->multi_line)
+ goto no_match;
+ PEEK_PREV_CHAR(c, cptr, s->cbuf);
+ if (!is_line_terminator(c))
+ goto no_match;
+ break;
+ case REOP_line_end:
+ if (cptr == cbuf_end)
+ break;
+ if (!s->multi_line)
+ goto no_match;
+ PEEK_CHAR(c, cptr, cbuf_end);
+ 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);
+ 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);
+ 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;
+ }
+ break;
+ case REOP_push_char_pos:
+ stack[stack_len++] = (uintptr_t)cptr;
+ break;
+ case REOP_bne_char_pos:
+ val = get_u32(pc);
+ pc += 4;
+ if (stack[--stack_len] != (uintptr_t)cptr)
+ pc += (int)val;
+ break;
+ case REOP_word_boundary:
+ case REOP_not_word_boundary:
+ {
+ BOOL v1, v2;
+ /* char before */
+ if (cptr == s->cbuf) {
+ v1 = FALSE;
+ } else {
+ PEEK_PREV_CHAR(c, cptr, s->cbuf);
+ v1 = is_word_char(c);
+ }
+ /* current char */
+ if (cptr >= cbuf_end) {
+ v2 = FALSE;
+ } else {
+ PEEK_CHAR(c, cptr, cbuf_end);
+ v2 = is_word_char(c);
+ }
+ if (v1 ^ v2 ^ (REOP_not_word_boundary - opcode))
+ goto no_match;
+ }
+ break;
+ case REOP_back_reference:
+ case REOP_backward_back_reference:
+ {
+ 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) {
+ cptr1 = cptr1_start;
+ while (cptr1 < cptr1_end) {
+ if (cptr >= cbuf_end)
+ goto no_match;
+ GET_CHAR(c1, cptr1, cptr1_end);
+ GET_CHAR(c2, cptr, cbuf_end);
+ if (s->ignore_case) {
+ c1 = lre_canonicalize(c1, s->is_utf16);
+ c2 = lre_canonicalize(c2, s->is_utf16);
+ }
+ 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);
+ GET_PREV_CHAR(c2, cptr, s->cbuf);
+ if (s->ignore_case) {
+ c1 = lre_canonicalize(c1, s->is_utf16);
+ c2 = lre_canonicalize(c2, s->is_utf16);
+ }
+ if (c1 != c2)
+ goto no_match;
+ }
+ }
+ }
+ break;
+ case REOP_range:
+ {
+ 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);
+ if (s->ignore_case) {
+ c = lre_canonicalize(c, s->is_utf16);
+ }
+ 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:
+ {
+ 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);
+ if (s->ignore_case) {
+ c = lre_canonicalize(c, s->is_utf16);
+ }
+ 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);
+ 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(;;) {
+ res = lre_exec_backtrack(s, capture, stack, stack_len,
+ pc1, cptr, TRUE);
+ if (res == -1)
+ 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 -1;
+ }
+ }
+ break;
+ default:
+ abort();
+ }
+ }
+}
+
+/* Return 1 if match, 0 if not match or -1 if error. 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 = bc_buf[RE_HEADER_FLAGS];
+ s->multi_line = (re_flags & LRE_FLAG_MULTILINE) != 0;
+ s->ignore_case = (re_flags & LRE_FLAG_IGNORECASE) != 0;
+ s->is_utf16 = (re_flags & LRE_FLAG_UTF16) != 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_utf16)
+ s->cbuf_type = 2;
+ 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 bc_buf[RE_HEADER_FLAGS];
+}
+
+#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, 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 < 3) {
+ printf("usage: %s regexp input\n", argv[0]);
+ exit(1);
+ }
+ bc = lre_compile(&len, error_msg, sizeof(error_msg), argv[1],
+ strlen(argv[1]), 0, NULL);
+ if (!bc) {
+ fprintf(stderr, "error: %s\n", error_msg);
+ exit(1);
+ }
+
+ input = argv[2];
+ 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/android/src/main/jni/quickjs/libregexp.h b/android/src/main/jni/quickjs/libregexp.h
new file mode 100644
index 0000000..cd0b24f
--- /dev/null
+++ b/android/src/main/jni/quickjs/libregexp.h
@@ -0,0 +1,91 @@
+/*
+ * 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 "libunicode.h"
+
+#define LRE_BOOL int /* for documentation purposes */
+
+#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_UTF16 (1 << 4)
+#define LRE_FLAG_STICKY (1 << 5)
+
+#define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */
+
+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);
+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);
+LRE_BOOL lre_is_space(int c);
+
+/* must be provided by the user */
+LRE_BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size);
+void *lre_realloc(void *opaque, void *ptr, size_t size);
+
+/* JS identifier test */
+extern uint32_t const lre_id_start_table_ascii[4];
+extern uint32_t const lre_id_continue_table_ascii[4];
+
+static inline int lre_js_is_ident_first(int c)
+{
+ if ((uint32_t)c < 128) {
+ return (lre_id_start_table_ascii[c >> 5] >> (c & 31)) & 1;
+ } else {
+#ifdef CONFIG_ALL_UNICODE
+ return lre_is_id_start(c);
+#else
+ return !lre_is_space(c);
+#endif
+ }
+}
+
+static inline int lre_js_is_ident_next(int c)
+{
+ if ((uint32_t)c < 128) {
+ return (lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1;
+ } else {
+ /* ZWNJ and ZWJ are accepted in identifiers */
+#ifdef CONFIG_ALL_UNICODE
+ return lre_is_id_continue(c) || c == 0x200C || c == 0x200D;
+#else
+ return !lre_is_space(c) || c == 0x200C || c == 0x200D;
+#endif
+ }
+}
+
+#undef LRE_BOOL
+
+#endif /* LIBREGEXP_H */
diff --git a/android/src/main/jni/quickjs/libunicode-table.h b/android/src/main/jni/quickjs/libunicode-table.h
new file mode 100644
index 0000000..0ef2113
--- /dev/null
+++ b/android/src/main/jni/quickjs/libunicode-table.h
@@ -0,0 +1,4368 @@
+/* Compressed unicode tables */
+/* Automatically generated file - do not edit */
+
+#include
+
+static const uint32_t case_conv_table1[361] = {
+ 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, 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, 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,
+ 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, 0x0fbb0200, 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,
+ 0x0fe80200, 0x0fe901d0, 0x0fe981d0, 0x0feb01b0,
+ 0x0feb81d0, 0x0fec0230, 0x0fed0230, 0x0ff00201,
+ 0x0ff101d3, 0x0ff181d3, 0x0ff201ba, 0x0ff28101,
+ 0x0ff301b0, 0x0ff381d3, 0x0ff40230, 0x0ff50230,
+ 0x0ff60131, 0x0ff901ba, 0x0ff981b2, 0x0ffa01bb,
+ 0x0ffb01b2, 0x0ffb81d9, 0x0ffc0230, 0x0ffd0230,
+ 0x0ffe0162, 0x109301a0, 0x109501a0, 0x109581a0,
+ 0x10990131, 0x10a70101, 0x10b01031, 0x10b81001,
+ 0x10c18240, 0x125b1a31, 0x12681a01, 0x16002f31,
+ 0x16182f01, 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, 0x53da0c40, 0x53e10240,
+ 0x53e20131, 0x53e28130, 0x53e30130, 0x53e38440,
+ 0x53fa8240, 0x55a98101, 0x55b85020, 0x7d8001b2,
+ 0x7d8081b2, 0x7d8101b2, 0x7d8181da, 0x7d8201da,
+ 0x7d8281b3, 0x7d8301b3, 0x7d8981bb, 0x7d8a01bb,
+ 0x7d8a81bb, 0x7d8b01bc, 0x7d8b81bb, 0x7f909a31,
+ 0x7fa09a01, 0x82002831, 0x82142801, 0x82582431,
+ 0x826c2401, 0x86403331, 0x86603301, 0x8c502031,
+ 0x8c602001, 0xb7202031, 0xb7302001, 0xf4802231,
+ 0xf4912201,
+};
+
+static const uint8_t case_conv_table2[361] = {
+ 0x01, 0x00, 0x9c, 0x06, 0x07, 0x4d, 0x03, 0x04,
+ 0x10, 0x00, 0x8f, 0x0b, 0x00, 0x00, 0x11, 0x00,
+ 0x08, 0x00, 0x53, 0x4a, 0x51, 0x00, 0x52, 0x00,
+ 0x53, 0x00, 0x3a, 0x54, 0x55, 0x00, 0x57, 0x59,
+ 0x3f, 0x5d, 0x5c, 0x00, 0x46, 0x61, 0x63, 0x42,
+ 0x64, 0x00, 0x66, 0x00, 0x68, 0x00, 0x6a, 0x00,
+ 0x6c, 0x00, 0x6e, 0x00, 0x00, 0x40, 0x00, 0x00,
+ 0x00, 0x00, 0x1a, 0x00, 0x93, 0x00, 0x00, 0x20,
+ 0x35, 0x00, 0x27, 0x00, 0x21, 0x00, 0x24, 0x22,
+ 0x2a, 0x00, 0x13, 0x6b, 0x6d, 0x00, 0x26, 0x24,
+ 0x27, 0x14, 0x16, 0x18, 0x1b, 0x1c, 0x3e, 0x1e,
+ 0x3f, 0x1f, 0x39, 0x3d, 0x22, 0x21, 0x41, 0x1e,
+ 0x40, 0x25, 0x25, 0x26, 0x28, 0x20, 0x2a, 0x49,
+ 0x2c, 0x43, 0x2e, 0x4b, 0x30, 0x4c, 0x32, 0x44,
+ 0x42, 0x99, 0x00, 0x00, 0x95, 0x8f, 0x7d, 0x7e,
+ 0x83, 0x84, 0x12, 0x80, 0x82, 0x76, 0x77, 0x12,
+ 0x7b, 0xa3, 0x7c, 0x78, 0x79, 0x8a, 0x92, 0x98,
+ 0xa6, 0xa0, 0x85, 0x00, 0x9a, 0xa1, 0x93, 0x75,
+ 0x33, 0x95, 0x00, 0x8e, 0x00, 0x74, 0x99, 0x98,
+ 0x97, 0x96, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00,
+ 0xa1, 0xa0, 0x15, 0x2e, 0x2f, 0x30, 0xb4, 0xb5,
+ 0x4e, 0xaa, 0xa9, 0x12, 0x14, 0x1e, 0x21, 0x22,
+ 0x22, 0x2a, 0x34, 0x35, 0xa6, 0xa7, 0x36, 0x1f,
+ 0x4a, 0x00, 0x00, 0x97, 0x01, 0x5a, 0xda, 0x1d,
+ 0x36, 0x05, 0x00, 0xc4, 0xc3, 0xc6, 0xc5, 0xc8,
+ 0xc7, 0xca, 0xc9, 0xcc, 0xcb, 0xc4, 0xd5, 0x45,
+ 0xd6, 0x42, 0xd7, 0x46, 0xd8, 0xce, 0xd0, 0xd2,
+ 0xd4, 0xda, 0xd9, 0xee, 0xf6, 0xfe, 0x0e, 0x07,
+ 0x0f, 0x80, 0x9f, 0x00, 0x21, 0x80, 0xa3, 0xed,
+ 0x00, 0xc0, 0x40, 0xc6, 0x60, 0xe7, 0xdb, 0xe6,
+ 0x99, 0xc0, 0x00, 0x00, 0x06, 0x60, 0xdc, 0x29,
+ 0xfd, 0x15, 0x12, 0x06, 0x16, 0xf8, 0xdd, 0x06,
+ 0x15, 0x12, 0x84, 0x08, 0xc6, 0x16, 0xff, 0xdf,
+ 0x03, 0xc0, 0x40, 0x00, 0x46, 0x60, 0xde, 0xe0,
+ 0x6d, 0x37, 0x38, 0x39, 0x15, 0x14, 0x17, 0x16,
+ 0x00, 0x1a, 0x19, 0x1c, 0x1b, 0x00, 0x5f, 0xb7,
+ 0x65, 0x44, 0x47, 0x00, 0x4f, 0x62, 0x4e, 0x50,
+ 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xa3, 0xa4,
+ 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x00,
+ 0x00, 0x5a, 0x00, 0x48, 0x00, 0x5b, 0x56, 0x58,
+ 0x60, 0x5e, 0x70, 0x69, 0x6f, 0x4d, 0x00, 0x00,
+ 0x3b, 0x67, 0xb8, 0x00, 0x00, 0x45, 0xa8, 0x8a,
+ 0x8b, 0x8c, 0xab, 0xac, 0x58, 0x58, 0xaf, 0x94,
+ 0xb0, 0x6f, 0xb2, 0x5c, 0x5b, 0x5e, 0x5d, 0x60,
+ 0x5f, 0x62, 0x61, 0x64, 0x63, 0x66, 0x65, 0x68,
+ 0x67,
+};
+
+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[172] = {
+ 0x40, 0xa9, 0x80, 0x8e, 0x80, 0xfc, 0x80, 0xd3,
+ 0x80, 0x8c, 0x80, 0x8d, 0x81, 0x8d, 0x02, 0x80,
+ 0xe1, 0x80, 0x91, 0x85, 0x9a, 0x01, 0x00, 0x01,
+ 0x11, 0x00, 0x01, 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, 0x57, 0x76,
+ 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, 0xc7, 0x82, 0x43, 0x34,
+ 0xa2, 0x06, 0x80, 0x8c, 0x61, 0x28, 0x96, 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, 0x59, 0x63, 0x99,
+ 0x85, 0x99, 0x85, 0x99,
+};
+
+static const uint8_t unicode_prop_Cased1_index[18] = {
+ 0xb9, 0x02, 0xe0, 0xa0, 0x1e, 0x40, 0x9e, 0xa6,
+ 0x40, 0xba, 0xd4, 0x01, 0x89, 0xd7, 0x01, 0x8a,
+ 0xf1, 0x01,
+};
+
+static const uint8_t unicode_prop_Case_Ignorable_table[692] = {
+ 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, 0xf6, 0xaf, 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, 0xb8, 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, 0x85, 0xc9, 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, 0x82, 0x9c, 0x81, 0x9d, 0x81,
+ 0xbf, 0x08, 0x37, 0x01, 0x8a, 0x10, 0x20, 0xac,
+ 0x83, 0xb3, 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, 0x90, 0xbe, 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, 0xde, 0x04, 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,
+ 0xec, 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, 0x8f, 0x42, 0x3d, 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, 0x46,
+ 0x85, 0x10, 0x0c, 0x83, 0xa7, 0x13, 0x80, 0x40,
+ 0xa4, 0x81, 0x42, 0x3c, 0x83, 0x41, 0x82, 0x81,
+ 0x40, 0x98, 0x8a, 0x40, 0xaf, 0x80, 0xb5, 0x8e,
+ 0xb7, 0x82, 0xb0, 0x19, 0x09, 0x80, 0x8e, 0x80,
+ 0xb1, 0x82, 0xa3, 0x20, 0x87, 0xbd, 0x80, 0x8b,
+ 0x81, 0xb3, 0x88, 0x89, 0x19, 0x80, 0xde, 0x11,
+ 0x00, 0x0d, 0x80, 0x40, 0x9f, 0x02, 0x87, 0x94,
+ 0x81, 0xb8, 0x0a, 0x80, 0xa4, 0x32, 0x84, 0x40,
+ 0xc2, 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, 0x11, 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,
+ 0x55, 0x3a, 0x88, 0x60, 0x36, 0xb6, 0x84, 0xba,
+ 0x86, 0x88, 0x83, 0x44, 0x0a, 0x80, 0xbe, 0x90,
+ 0xbf, 0x08, 0x81, 0x60, 0x4c, 0xb7, 0x08, 0x83,
+ 0x54, 0xc2, 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, 0x41, 0x04, 0x8d,
+ 0x41, 0xad, 0x83, 0x45, 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[66] = {
+ 0xbe, 0x05, 0x00, 0xfe, 0x07, 0x00, 0x52, 0x0a,
+ 0x20, 0x05, 0x0c, 0x20, 0x3b, 0x0e, 0x40, 0x61,
+ 0x10, 0x40, 0x0f, 0x18, 0x20, 0x43, 0x1b, 0x60,
+ 0x79, 0x1d, 0x00, 0xf1, 0x20, 0x00, 0x0d, 0xa6,
+ 0x40, 0x2e, 0xa9, 0x20, 0xde, 0xaa, 0x00, 0x0f,
+ 0xff, 0x20, 0xe7, 0x0a, 0x41, 0x82, 0x11, 0x21,
+ 0xc4, 0x14, 0x61, 0x44, 0x19, 0x01, 0x48, 0x1d,
+ 0x21, 0xa4, 0xbc, 0x01, 0x3e, 0xe1, 0x01, 0xf0,
+ 0x01, 0x0e,
+};
+
+static const uint8_t unicode_prop_ID_Start_table[1045] = {
+ 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,
+ 0xb4, 0x94, 0x80, 0x91, 0xbb, 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, 0x14, 0x81, 0x9d, 0x03, 0x38, 0x10,
+ 0x96, 0x80, 0x89, 0x04, 0x10, 0x9f, 0x00, 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, 0x8c, 0x03, 0x8d, 0x91, 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, 0x86, 0xb6, 0x9d, 0x8c, 0x81, 0x89,
+ 0xab, 0x99, 0xa3, 0xa8, 0x82, 0x89, 0xa3, 0x81,
+ 0x88, 0x86, 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, 0xae, 0x80, 0xae, 0x80,
+ 0x40, 0x84, 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, 0x51, 0xfc, 0x82, 0x44, 0x8c, 0xc2, 0xad,
+ 0x81, 0x41, 0x0c, 0x82, 0x8f, 0x89, 0x81, 0x93,
+ 0xae, 0x8f, 0x9e, 0x81, 0xcf, 0xa6, 0x88, 0x81,
+ 0xe6, 0x81, 0xb4, 0x81, 0x88, 0xa9, 0x8c, 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, 0x40,
+ 0x9b, 0x41, 0x36, 0x88, 0x95, 0x89, 0x87, 0x40,
+ 0x97, 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, 0x41, 0x5b, 0xa9, 0x29, 0xcd,
+ 0x9c, 0x89, 0x07, 0x95, 0xe9, 0x94, 0x9a, 0x96,
+ 0x8b, 0xb4, 0xca, 0xac, 0x9f, 0x98, 0x99, 0xa3,
+ 0x9c, 0x01, 0x07, 0xa2, 0x10, 0x8b, 0xaf, 0x8d,
+ 0x83, 0x94, 0x00, 0x80, 0xa2, 0x91, 0x80, 0x98,
+ 0xd3, 0x30, 0x00, 0x18, 0x8e, 0x80, 0x89, 0x86,
+ 0xae, 0xa5, 0x39, 0x09, 0x95, 0x06, 0x01, 0x04,
+ 0x10, 0x91, 0x80, 0x8b, 0x84, 0x40, 0x9d, 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,
+ 0x40, 0xe4, 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, 0xa1,
+ 0xb8, 0x41, 0x06, 0x88, 0x80, 0xa4, 0x90, 0x80,
+ 0xb0, 0x9d, 0xef, 0x30, 0x08, 0xa5, 0x94, 0x80,
+ 0x98, 0x28, 0x08, 0x9f, 0x8d, 0x80, 0x41, 0x46,
+ 0x92, 0x40, 0xbc, 0x80, 0xce, 0x43, 0x99, 0xe5,
+ 0xee, 0x90, 0x40, 0xc3, 0x4a, 0xbb, 0x44, 0x2e,
+ 0x4f, 0xd0, 0x42, 0x46, 0x60, 0x21, 0xb8, 0x42,
+ 0x38, 0x86, 0x9e, 0xf0, 0x9d, 0x91, 0xaf, 0x8f,
+ 0x83, 0x9e, 0x94, 0x84, 0x92, 0x42, 0xaf, 0xbf,
+ 0xff, 0xca, 0x20, 0xc1, 0x8c, 0xbf, 0x08, 0x80,
+ 0x9b, 0x57, 0xf7, 0x87, 0x44, 0xd5, 0xa9, 0x88,
+ 0x60, 0x22, 0xf6, 0x41, 0x1e, 0xb0, 0x82, 0x90,
+ 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, 0x49, 0x33, 0xac, 0x89,
+ 0x86, 0x8f, 0x80, 0x41, 0x70, 0xab, 0x45, 0x13,
+ 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,
+ 0xdd, 0xa1, 0x50, 0x34, 0x8a, 0x40, 0xdd, 0x81,
+ 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x4c, 0x1e, 0x42,
+ 0x1d, 0x45, 0xe1, 0x53, 0x4a,
+};
+
+static const uint8_t unicode_prop_ID_Start_index[99] = {
+ 0xf6, 0x03, 0x20, 0xa6, 0x07, 0x00, 0xa9, 0x09,
+ 0x00, 0xb4, 0x0a, 0x00, 0xba, 0x0b, 0x00, 0x3e,
+ 0x0d, 0x00, 0xe0, 0x0e, 0x20, 0x57, 0x12, 0x00,
+ 0xeb, 0x16, 0x00, 0xca, 0x19, 0x20, 0xc0, 0x1d,
+ 0x60, 0x80, 0x20, 0x00, 0x2e, 0x2d, 0x00, 0xc0,
+ 0x31, 0x20, 0x89, 0xa7, 0x20, 0xf0, 0xa9, 0x00,
+ 0xe3, 0xab, 0x00, 0x3e, 0xfd, 0x00, 0xfb, 0x00,
+ 0x21, 0x37, 0x07, 0x61, 0x01, 0x0a, 0x01, 0x1d,
+ 0x0f, 0x21, 0x2c, 0x12, 0x01, 0xc8, 0x14, 0x21,
+ 0xd1, 0x19, 0x21, 0x47, 0x1d, 0x01, 0x39, 0x6a,
+ 0x21, 0x09, 0x8d, 0x01, 0xbc, 0xd4, 0x01, 0xa9,
+ 0xd7, 0x21, 0x3a, 0xee, 0x01, 0xde, 0xa6, 0x22,
+ 0x4b, 0x13, 0x03,
+};
+
+static const uint8_t unicode_prop_ID_Continue1_table[626] = {
+ 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, 0xf6, 0x8e, 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,
+ 0xb8, 0x30, 0x10, 0x1e, 0x81, 0x8a, 0x09, 0x89,
+ 0x90, 0x82, 0xb7, 0x00, 0x30, 0x10, 0x1e, 0x81,
+ 0x8a, 0x09, 0x89, 0x8f, 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, 0x29, 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, 0x82, 0x9c, 0x82, 0x9c, 0x81, 0x9d,
+ 0x81, 0xbf, 0x9f, 0x88, 0x01, 0x89, 0xa0, 0x11,
+ 0x89, 0x40, 0x8e, 0x80, 0xf5, 0x8b, 0x83, 0x8b,
+ 0x89, 0x89, 0xff, 0x8a, 0xbb, 0x84, 0xb8, 0x89,
+ 0x80, 0x9c, 0x81, 0x8a, 0x85, 0x89, 0x95, 0x8d,
+ 0x01, 0xbe, 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, 0xb9,
+ 0x04, 0x42, 0x3e, 0x81, 0x92, 0x80, 0xfa, 0x8c,
+ 0x18, 0x82, 0x8b, 0x4b, 0xfd, 0x82, 0x40, 0x8c,
+ 0x80, 0xdf, 0x9f, 0x42, 0x29, 0x85, 0xe8, 0x81,
+ 0x60, 0x75, 0x84, 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, 0x42, 0xbc, 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, 0x41, 0x70, 0x81,
+ 0x40, 0x98, 0x8a, 0x40, 0xae, 0x82, 0xb4, 0x8e,
+ 0x9e, 0x89, 0x8e, 0x83, 0xac, 0x8a, 0xb4, 0x89,
+ 0x2a, 0xa3, 0x8d, 0x80, 0x89, 0x21, 0xab, 0x80,
+ 0x8b, 0x82, 0xaf, 0x8d, 0x3b, 0x80, 0x8b, 0xd1,
+ 0x8b, 0x28, 0x40, 0x9f, 0x8b, 0x84, 0x89, 0x2b,
+ 0xb6, 0x08, 0x31, 0x09, 0x82, 0x88, 0x80, 0x89,
+ 0x09, 0x32, 0x84, 0x40, 0xbf, 0x91, 0x88, 0x89,
+ 0x18, 0xd0, 0x93, 0x8b, 0x89, 0x40, 0xd4, 0x31,
+ 0x88, 0x9a, 0x81, 0xd1, 0x90, 0x8e, 0x89, 0xd0,
+ 0x8c, 0x87, 0x89, 0xd2, 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, 0x94, 0x38, 0x87, 0x8f,
+ 0x89, 0xb7, 0x95, 0x80, 0x8d, 0xf9, 0x2a, 0x00,
+ 0x08, 0x30, 0x07, 0x89, 0xaf, 0x20, 0x08, 0x27,
+ 0x89, 0x41, 0x48, 0x83, 0x60, 0x4b, 0x68, 0x89,
+ 0x40, 0x85, 0x84, 0xba, 0x86, 0x98, 0x89, 0x43,
+ 0xf4, 0x00, 0xb6, 0x33, 0xd0, 0x80, 0x8a, 0x81,
+ 0x60, 0x4c, 0xaa, 0x81, 0x54, 0xc5, 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, 0x41, 0x04, 0x86, 0x88,
+ 0x89, 0x41, 0xa1, 0x8d, 0x45, 0xd5, 0x86, 0xec,
+ 0x34, 0x89, 0x52, 0x95, 0x89, 0x6c, 0x05, 0x05,
+ 0x40, 0xef,
+};
+
+static const uint8_t unicode_prop_ID_Continue1_index[60] = {
+ 0xfa, 0x06, 0x00, 0x84, 0x09, 0x00, 0xf0, 0x0a,
+ 0x00, 0x70, 0x0c, 0x00, 0xf4, 0x0d, 0x00, 0x4a,
+ 0x10, 0x20, 0x1a, 0x18, 0x20, 0x74, 0x1b, 0x20,
+ 0xdd, 0x20, 0x00, 0x0c, 0xa8, 0x00, 0x5a, 0xaa,
+ 0x20, 0x1a, 0xff, 0x00, 0xad, 0x0e, 0x01, 0x38,
+ 0x12, 0x21, 0xc1, 0x15, 0x21, 0xe5, 0x19, 0x21,
+ 0xaa, 0x1d, 0x21, 0x8c, 0xd1, 0x41, 0x4a, 0xe1,
+ 0x21, 0xf0, 0x01, 0x0e,
+};
+
+#ifdef CONFIG_ALL_UNICODE
+
+static const uint8_t unicode_cc_table[851] = {
+ 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, 0x46, 0x00, 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, 0x4e, 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, 0x00, 0x09, 0x9e, 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, 0xb0, 0x42, 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, 0x80, 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, 0xb1, 0x52,
+ 0xc1, 0xb0, 0x68, 0x01, 0xdc, 0xc2, 0x00, 0xdc,
+ 0xc0, 0x03, 0xdc, 0xb0, 0xc4, 0x00, 0x09, 0xb0,
+ 0x07, 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, 0x9c, 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, 0xb8,
+ 0x45, 0x27, 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, 0xd4, 0xc6, 0xb1,
+ 0x84, 0xc3, 0xb5, 0xaf, 0x06, 0xdc, 0xb0, 0x3c,
+ 0xc5, 0x00, 0x07,
+};
+
+static const uint8_t unicode_cc_index[81] = {
+ 0x4d, 0x03, 0x00, 0x97, 0x05, 0x20, 0xc6, 0x05,
+ 0x00, 0xe7, 0x06, 0x00, 0x45, 0x07, 0x00, 0xe2,
+ 0x08, 0x00, 0x53, 0x09, 0x00, 0xcd, 0x0b, 0x20,
+ 0x38, 0x0e, 0x00, 0x73, 0x0f, 0x20, 0x5d, 0x13,
+ 0x20, 0x60, 0x1a, 0x20, 0xaa, 0x1b, 0x00, 0xf4,
+ 0x1c, 0x00, 0xfe, 0x1d, 0x20, 0x7f, 0x2d, 0x20,
+ 0xf0, 0xa6, 0x00, 0xb2, 0xaa, 0x00, 0xfe, 0x01,
+ 0x01, 0xab, 0x0e, 0x01, 0x73, 0x11, 0x21, 0x70,
+ 0x13, 0x01, 0xb8, 0x16, 0x01, 0x9a, 0x1a, 0x01,
+ 0x9f, 0xbc, 0x01, 0x22, 0xe0, 0x01, 0x4b, 0xe9,
+ 0x01,
+};
+
+static const uint32_t unicode_decomp_table1[690] = {
+ 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, 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, 0x44268192, 0x442ac092,
+ 0x444b8112, 0x44d2c112, 0x452ec212, 0x456e8112,
+ 0x464e0092, 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, 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[690] = {
+ 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, 0x11b3, 0x028d, 0x11bb, 0x120d, 0x130b, 0x1409,
+ 0x148d, 0x1492, 0x1550, 0x1569, 0x156f, 0x1575, 0x157b, 0x1587,
+ 0x1593, 0x002b, 0x159e, 0x15b6, 0x15ba, 0x15be, 0x15c2, 0x15c6,
+ 0x15ca, 0x15de, 0x15e2, 0x1646, 0x165f, 0x1685, 0x168b, 0x1749,
+ 0x174f, 0x1754, 0x1774, 0x1874, 0x187a, 0x190e, 0x19d0, 0x1a74,
+ 0x1a7c, 0x1a9a, 0x1a9f, 0x1ab3, 0x1abd, 0x1ac3, 0x1ad7, 0x1adc,
+ 0x1ae2, 0x1af0, 0x1b20, 0x1b2d, 0x1b35, 0x1b39, 0x1b4f, 0x1bc6,
+ 0x1bd8, 0x1bda, 0x1bdc, 0x3164, 0x1c1d, 0x1c1f, 0x1c21, 0x1c23,
+ 0x1c25, 0x1c27, 0x1c45, 0x1c53, 0x1c58, 0x1c61, 0x1c6a, 0x1c7c,
+ 0x1c85, 0x1c8a, 0x1caa, 0x1cc5, 0x1cc7, 0x1cc9, 0x1ccb, 0x1ccd,
+ 0x1ccf, 0x1cd1, 0x1cd3, 0x1cf3, 0x1cf5, 0x1cf7, 0x1cf9, 0x1cfb,
+ 0x1d02, 0x1d04, 0x1d06, 0x1d08, 0x1d17, 0x1d19, 0x1d1b, 0x1d1d,
+ 0x1d1f, 0x1d21, 0x1d23, 0x1d25, 0x1d27, 0x1d29, 0x1d2b, 0x1d2d,
+ 0x1d2f, 0x1d31, 0x1d33, 0x1d37, 0x03f4, 0x1d39, 0x2207, 0x1d3b,
+ 0x2202, 0x1d3d, 0x1d45, 0x03f4, 0x1d47, 0x2207, 0x1d49, 0x2202,
+ 0x1d4b, 0x1d53, 0x03f4, 0x1d55, 0x2207, 0x1d57, 0x2202, 0x1d59,
+ 0x1d61, 0x03f4, 0x1d63, 0x2207, 0x1d65, 0x2202, 0x1d67, 0x1d6f,
+ 0x03f4, 0x1d71, 0x2207, 0x1d73, 0x2202, 0x1d75, 0x1d7f, 0x1d81,
+ 0x1d83, 0x1d85, 0x1d87, 0x1d89, 0x1d8f, 0x1dac, 0x062d, 0x1db4,
+ 0x1dc0, 0x062c, 0x1dd0, 0x1e40, 0x1e4c, 0x1e5f, 0x1e71, 0x1e84,
+ 0x1e86, 0x1e8a, 0x1e90, 0x1e96, 0x1e98, 0x1e9c, 0x1e9e, 0x1ea6,
+ 0x1ea9, 0x1eab, 0x1eb1, 0x1eb3, 0x30b5, 0x1eb9, 0x1f11, 0x1f27,
+ 0x1f2b, 0x1f2d, 0x1f32, 0x1f7f, 0x1f90, 0x2091, 0x20a1, 0x20a7,
+ 0x21a1, 0x22bf,
+};
+
+static const uint8_t unicode_decomp_data[9165] = {
+ 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, 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, 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, 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, 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, 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[945] = {
+ 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, 0x8e80, 0x8e82, 0x8ec0, 0x8f00,
+ 0x8f01, 0x8f40, 0x8f41, 0x8f81, 0x8f80, 0x8f83, 0x8fc0, 0x8fc1,
+ 0x9000,
+};
+
+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[3790] = {
+ 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, 0x00, 0x36, 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,
+ 0xe0, 0x2d, 0xe5, 0x0d, 0x00, 0xe5, 0x0a, 0xe0,
+ 0x03, 0xe6, 0x07, 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, 0x40, 0x05, 0x46,
+ 0x67, 0x00, 0x46, 0x00, 0x66, 0xc0, 0x26, 0x00,
+ 0x45, 0x80, 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, 0xc0, 0x05, 0x00, 0x25, 0x26, 0x20, 0xe9,
+ 0x02, 0x00, 0x25, 0xe0, 0x05, 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,
+ 0xa6, 0x20, 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, 0x05, 0x00,
+ 0x65, 0x46, 0xe0, 0x03, 0xe5, 0x0a, 0x46, 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, 0x00, 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, 0x26, 0xe0, 0x37, 0x66, 0x07,
+ 0xe5, 0x27, 0x06, 0x07, 0x86, 0x07, 0x06, 0x87,
+ 0x06, 0x27, 0xc5, 0x60, 0xe9, 0x02, 0xd6, 0xef,
+ 0x02, 0xe6, 0x01, 0xef, 0x01, 0x40, 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, 0xc0, 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, 0x32, 0x00, 0x86, 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, 0x18, 0xe0,
+ 0x08, 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, 0x3d, 0xe0, 0x11, 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, 0x27, 0x00, 0xe2, 0x27, 0x00, 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, 0x16, 0xe0, 0x25,
+ 0xef, 0x12, 0x00, 0xef, 0x51, 0xe0, 0x04, 0xef,
+ 0x80, 0x4e, 0xe0, 0x12, 0xef, 0x04, 0x60, 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, 0x1c, 0xe0, 0x04, 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,
+ 0x75, 0x40, 0xe5, 0x0d, 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,
+ 0x02, 0x20, 0x5f, 0x41, 0x02, 0x3f, 0xe0, 0x22,
+ 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, 0x08, 0xe0, 0x09, 0xe5,
+ 0x80, 0xe3, 0x13, 0x12, 0xe0, 0x08, 0xe5, 0x38,
+ 0x20, 0xe5, 0x2e, 0xe0, 0x20, 0xe5, 0x04, 0x0d,
+ 0x0f, 0x20, 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, 0xe0,
+ 0x80, 0x08, 0xe5, 0x80, 0xaf, 0xe0, 0x01, 0xe5,
+ 0x0e, 0xe0, 0x02, 0xe5, 0x00, 0xe0, 0x80, 0x10,
+ 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, 0xe0, 0x80, 0x9e, 0xeb,
+ 0x17, 0x00, 0xe5, 0x22, 0x00, 0x26, 0x11, 0x20,
+ 0x25, 0xe0, 0x46, 0xe5, 0x15, 0xeb, 0x02, 0x05,
+ 0xe0, 0x00, 0xe5, 0x0e, 0xe6, 0x03, 0x6b, 0x96,
+ 0xe0, 0x4e, 0xe5, 0x0d, 0xcb, 0xe0, 0x0c, 0xe5,
+ 0x0f, 0xe0, 0x01, 0x07, 0x06, 0x07, 0xe5, 0x2d,
+ 0xe6, 0x07, 0xd6, 0x60, 0xeb, 0x0c, 0xe9, 0x02,
+ 0xe0, 0x07, 0x46, 0x07, 0xe5, 0x25, 0x47, 0x66,
+ 0x27, 0x26, 0x36, 0x1b, 0x76, 0xe0, 0x03, 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, 0xe0, 0x39, 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, 0x80, 0x03, 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, 0xc0, 0xe9, 0x02, 0xe0, 0x2e, 0xe5,
+ 0x13, 0x20, 0x46, 0x27, 0x66, 0x07, 0x86, 0x60,
+ 0xe9, 0x02, 0x2b, 0x56, 0x0f, 0xe0, 0x80, 0x38,
+ 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,
+ 0x15, 0xe5, 0x31, 0xe0, 0x80, 0x7f, 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, 0xe0,
+ 0x80, 0x2f, 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, 0x8a, 0x34,
+ 0xe5, 0x83, 0xa7, 0x00, 0xfb, 0x01, 0xe0, 0x8f,
+ 0x3f, 0xe5, 0x81, 0xbf, 0xe0, 0xa1, 0x31, 0xe5,
+ 0x81, 0xb1, 0xc0, 0xe5, 0x17, 0x00, 0xe9, 0x02,
+ 0x60, 0x36, 0xe0, 0x58, 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,
+ 0x82, 0x28, 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, 0x22, 0xe5, 0x01, 0xe0, 0xa2, 0x6f,
+ 0xe5, 0x80, 0x97, 0xe0, 0x29, 0x45, 0xe0, 0x09,
+ 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, 0x92, 0xd4, 0xef, 0x80, 0x6e, 0xe0,
+ 0x02, 0xef, 0x1f, 0x20, 0xef, 0x34, 0x27, 0x46,
+ 0x4f, 0xa7, 0xfb, 0x00, 0xe6, 0x00, 0x2f, 0xc6,
+ 0xef, 0x16, 0x66, 0xef, 0x33, 0xe0, 0x0f, 0xef,
+ 0x3a, 0x46, 0x0f, 0xe0, 0x80, 0x12, 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, 0x84, 0xc8,
+ 0xc6, 0x00, 0xe6, 0x09, 0x20, 0xc6, 0x00, 0x26,
+ 0x00, 0x86, 0xe0, 0x80, 0x4d, 0xe5, 0x25, 0x40,
+ 0xc6, 0xc4, 0x20, 0xe9, 0x02, 0x60, 0x05, 0x0f,
+ 0xe0, 0x80, 0xe8, 0xe5, 0x24, 0x66, 0xe9, 0x02,
+ 0x80, 0x0d, 0xe0, 0x84, 0x78, 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, 0xe0, 0x00, 0xef, 0x05, 0x40,
+ 0xef, 0x05, 0x40, 0xef, 0x6c, 0xe0, 0x04, 0xef,
+ 0x51, 0xc0, 0xef, 0x04, 0xe0, 0x0c, 0xef, 0x04,
+ 0x60, 0xef, 0x30, 0xe0, 0x00, 0xef, 0x02, 0xa0,
+ 0xef, 0x20, 0xe0, 0x00, 0xef, 0x16, 0x20, 0x2f,
+ 0xe0, 0x46, 0xef, 0x71, 0x00, 0xef, 0x4a, 0x00,
+ 0xef, 0x7f, 0xe0, 0x04, 0xef, 0x06, 0x20, 0x8f,
+ 0x40, 0x4f, 0x80, 0xcf, 0xe0, 0x01, 0xef, 0x11,
+ 0xc0, 0xcf, 0xe0, 0x01, 0x4f, 0xe0, 0x05, 0xcf,
+ 0xe0, 0x21, 0xef, 0x80, 0x0b, 0x00, 0xef, 0x2f,
+ 0xe0, 0x1d, 0xe9, 0x02, 0xe0, 0x83, 0x7e, 0xe5,
+ 0xc0, 0x66, 0x56, 0xe0, 0x1a, 0xe5, 0x8f, 0xad,
+ 0xe0, 0x03, 0xe5, 0x80, 0x56, 0x20, 0xe5, 0x95,
+ 0xfa, 0xe0, 0x06, 0xe5, 0x9c, 0xa9, 0xe0, 0x8b,
+ 0x97, 0xe5, 0x81, 0x96, 0xe0, 0x85, 0x5a, 0xe5,
+ 0x92, 0xc3, 0xe0, 0xca, 0xac, 0x2e, 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_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_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_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_Kayah_Li,
+ UNICODE_SCRIPT_Kharoshthi,
+ UNICODE_SCRIPT_Khmer,
+ UNICODE_SCRIPT_Khojki,
+ UNICODE_SCRIPT_Khitan_Small_Script,
+ UNICODE_SCRIPT_Khudawadi,
+ 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_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_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_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_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_Ugaritic,
+ UNICODE_SCRIPT_Vai,
+ 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[] =
+ "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"
+ "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"
+ "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"
+ "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"
+ "Kayah_Li,Kali" "\0"
+ "Kharoshthi,Khar" "\0"
+ "Khmer,Khmr" "\0"
+ "Khojki,Khoj" "\0"
+ "Khitan_Small_Script,Kits" "\0"
+ "Khudawadi,Sind" "\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"
+ "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"
+ "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"
+ "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"
+ "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"
+ "Ugaritic,Ugar" "\0"
+ "Vai,Vaii" "\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[2609] = {
+ 0xc0, 0x19, 0x99, 0x45, 0x85, 0x19, 0x99, 0x45,
+ 0xae, 0x19, 0x80, 0x45, 0x8e, 0x19, 0x80, 0x45,
+ 0x84, 0x19, 0x96, 0x45, 0x80, 0x19, 0x9e, 0x45,
+ 0x80, 0x19, 0xe1, 0x60, 0x45, 0xa6, 0x19, 0x84,
+ 0x45, 0x84, 0x19, 0x81, 0x0d, 0x93, 0x19, 0xe0,
+ 0x0f, 0x37, 0x83, 0x2b, 0x80, 0x19, 0x82, 0x2b,
+ 0x01, 0x83, 0x2b, 0x80, 0x19, 0x80, 0x2b, 0x03,
+ 0x80, 0x2b, 0x80, 0x19, 0x80, 0x2b, 0x80, 0x19,
+ 0x82, 0x2b, 0x00, 0x80, 0x2b, 0x00, 0x93, 0x2b,
+ 0x00, 0xbe, 0x2b, 0x8d, 0x1a, 0x8f, 0x2b, 0xe0,
+ 0x24, 0x1d, 0x81, 0x37, 0xe0, 0x48, 0x1d, 0x00,
+ 0xa5, 0x05, 0x01, 0xb1, 0x05, 0x01, 0x82, 0x05,
+ 0x00, 0xb6, 0x34, 0x07, 0x9a, 0x34, 0x03, 0x85,
+ 0x34, 0x0a, 0x84, 0x04, 0x80, 0x19, 0x85, 0x04,
+ 0x80, 0x19, 0x8d, 0x04, 0x80, 0x19, 0x80, 0x04,
+ 0x00, 0x80, 0x04, 0x80, 0x19, 0x9f, 0x04, 0x80,
+ 0x19, 0x89, 0x04, 0x8a, 0x37, 0x99, 0x04, 0x80,
+ 0x37, 0xe0, 0x0b, 0x04, 0x80, 0x19, 0xa1, 0x04,
+ 0x8d, 0x87, 0x00, 0xbb, 0x87, 0x01, 0x82, 0x87,
+ 0xaf, 0x04, 0xb1, 0x91, 0x0d, 0xba, 0x63, 0x01,
+ 0x82, 0x63, 0xad, 0x7b, 0x01, 0x8e, 0x7b, 0x00,
+ 0x9b, 0x50, 0x01, 0x80, 0x50, 0x00, 0x8a, 0x87,
+ 0x34, 0x94, 0x04, 0x00, 0x91, 0x04, 0x0a, 0x8e,
+ 0x04, 0x80, 0x19, 0x9c, 0x04, 0xd0, 0x1f, 0x83,
+ 0x37, 0x8e, 0x1f, 0x81, 0x19, 0x99, 0x1f, 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, 0x2e, 0x00, 0x85, 0x2e, 0x03, 0x81,
+ 0x2e, 0x01, 0x95, 0x2e, 0x00, 0x86, 0x2e, 0x00,
+ 0x81, 0x2e, 0x00, 0x81, 0x2e, 0x00, 0x81, 0x2e,
+ 0x01, 0x80, 0x2e, 0x00, 0x84, 0x2e, 0x03, 0x81,
+ 0x2e, 0x01, 0x82, 0x2e, 0x02, 0x80, 0x2e, 0x06,
+ 0x83, 0x2e, 0x00, 0x80, 0x2e, 0x06, 0x90, 0x2e,
+ 0x09, 0x82, 0x2c, 0x00, 0x88, 0x2c, 0x00, 0x82,
+ 0x2c, 0x00, 0x95, 0x2c, 0x00, 0x86, 0x2c, 0x00,
+ 0x81, 0x2c, 0x00, 0x84, 0x2c, 0x01, 0x89, 0x2c,
+ 0x00, 0x82, 0x2c, 0x00, 0x82, 0x2c, 0x01, 0x80,
+ 0x2c, 0x0e, 0x83, 0x2c, 0x01, 0x8b, 0x2c, 0x06,
+ 0x86, 0x2c, 0x00, 0x82, 0x70, 0x00, 0x87, 0x70,
+ 0x01, 0x81, 0x70, 0x01, 0x95, 0x70, 0x00, 0x86,
+ 0x70, 0x00, 0x81, 0x70, 0x00, 0x84, 0x70, 0x01,
+ 0x88, 0x70, 0x01, 0x81, 0x70, 0x01, 0x82, 0x70,
+ 0x06, 0x82, 0x70, 0x03, 0x81, 0x70, 0x00, 0x84,
+ 0x70, 0x01, 0x91, 0x70, 0x09, 0x81, 0x8e, 0x00,
+ 0x85, 0x8e, 0x02, 0x82, 0x8e, 0x00, 0x83, 0x8e,
+ 0x02, 0x81, 0x8e, 0x00, 0x80, 0x8e, 0x00, 0x81,
+ 0x8e, 0x02, 0x81, 0x8e, 0x02, 0x82, 0x8e, 0x02,
+ 0x8b, 0x8e, 0x03, 0x84, 0x8e, 0x02, 0x82, 0x8e,
+ 0x00, 0x83, 0x8e, 0x01, 0x80, 0x8e, 0x05, 0x80,
+ 0x8e, 0x0d, 0x94, 0x8e, 0x04, 0x8c, 0x90, 0x00,
+ 0x82, 0x90, 0x00, 0x96, 0x90, 0x00, 0x8f, 0x90,
+ 0x02, 0x87, 0x90, 0x00, 0x82, 0x90, 0x00, 0x83,
+ 0x90, 0x06, 0x81, 0x90, 0x00, 0x82, 0x90, 0x04,
+ 0x83, 0x90, 0x01, 0x89, 0x90, 0x06, 0x88, 0x90,
+ 0x8c, 0x3c, 0x00, 0x82, 0x3c, 0x00, 0x96, 0x3c,
+ 0x00, 0x89, 0x3c, 0x00, 0x84, 0x3c, 0x01, 0x88,
+ 0x3c, 0x00, 0x82, 0x3c, 0x00, 0x83, 0x3c, 0x06,
+ 0x81, 0x3c, 0x06, 0x80, 0x3c, 0x00, 0x83, 0x3c,
+ 0x01, 0x89, 0x3c, 0x00, 0x81, 0x3c, 0x0c, 0x8c,
+ 0x4f, 0x00, 0x82, 0x4f, 0x00, 0xb2, 0x4f, 0x00,
+ 0x82, 0x4f, 0x00, 0x85, 0x4f, 0x03, 0x8f, 0x4f,
+ 0x01, 0x99, 0x4f, 0x00, 0x82, 0x81, 0x00, 0x91,
+ 0x81, 0x02, 0x97, 0x81, 0x00, 0x88, 0x81, 0x00,
+ 0x80, 0x81, 0x01, 0x86, 0x81, 0x02, 0x80, 0x81,
+ 0x03, 0x85, 0x81, 0x00, 0x80, 0x81, 0x00, 0x87,
+ 0x81, 0x05, 0x89, 0x81, 0x01, 0x82, 0x81, 0x0b,
+ 0xb9, 0x92, 0x03, 0x80, 0x19, 0x9b, 0x92, 0x24,
+ 0x81, 0x44, 0x00, 0x80, 0x44, 0x00, 0x84, 0x44,
+ 0x00, 0x97, 0x44, 0x00, 0x80, 0x44, 0x00, 0x96,
+ 0x44, 0x01, 0x84, 0x44, 0x00, 0x80, 0x44, 0x00,
+ 0x85, 0x44, 0x01, 0x89, 0x44, 0x01, 0x83, 0x44,
+ 0x1f, 0xc7, 0x93, 0x00, 0xa3, 0x93, 0x03, 0xa6,
+ 0x93, 0x00, 0xa3, 0x93, 0x00, 0x8e, 0x93, 0x00,
+ 0x86, 0x93, 0x83, 0x19, 0x81, 0x93, 0x24, 0xe0,
+ 0x3f, 0x5e, 0xa5, 0x27, 0x00, 0x80, 0x27, 0x04,
+ 0x80, 0x27, 0x01, 0xaa, 0x27, 0x80, 0x19, 0x83,
+ 0x27, 0xe0, 0x9f, 0x30, 0xc8, 0x26, 0x00, 0x83,
+ 0x26, 0x01, 0x86, 0x26, 0x00, 0x80, 0x26, 0x00,
+ 0x83, 0x26, 0x01, 0xa8, 0x26, 0x00, 0x83, 0x26,
+ 0x01, 0xa0, 0x26, 0x00, 0x83, 0x26, 0x01, 0x86,
+ 0x26, 0x00, 0x80, 0x26, 0x00, 0x83, 0x26, 0x01,
+ 0x8e, 0x26, 0x00, 0xb8, 0x26, 0x00, 0x83, 0x26,
+ 0x01, 0xc2, 0x26, 0x01, 0x9f, 0x26, 0x02, 0x99,
+ 0x26, 0x05, 0xd5, 0x17, 0x01, 0x85, 0x17, 0x01,
+ 0xe2, 0x1f, 0x12, 0x9c, 0x66, 0x02, 0xca, 0x7a,
+ 0x82, 0x19, 0x8a, 0x7a, 0x06, 0x8c, 0x88, 0x00,
+ 0x86, 0x88, 0x0a, 0x94, 0x32, 0x81, 0x19, 0x08,
+ 0x93, 0x11, 0x0b, 0x8c, 0x89, 0x00, 0x82, 0x89,
+ 0x00, 0x81, 0x89, 0x0b, 0xdd, 0x40, 0x01, 0x89,
+ 0x40, 0x05, 0x89, 0x40, 0x05, 0x81, 0x5b, 0x81,
+ 0x19, 0x80, 0x5b, 0x80, 0x19, 0x88, 0x5b, 0x00,
+ 0x89, 0x5b, 0x05, 0xd8, 0x5b, 0x06, 0xaa, 0x5b,
+ 0x04, 0xc5, 0x12, 0x09, 0x9e, 0x47, 0x00, 0x8b,
+ 0x47, 0x03, 0x8b, 0x47, 0x03, 0x80, 0x47, 0x02,
+ 0x8b, 0x47, 0x9d, 0x8a, 0x01, 0x84, 0x8a, 0x0a,
+ 0xab, 0x61, 0x03, 0x99, 0x61, 0x05, 0x8a, 0x61,
+ 0x02, 0x81, 0x61, 0x9f, 0x40, 0x9b, 0x10, 0x01,
+ 0x81, 0x10, 0xbe, 0x8b, 0x00, 0x9c, 0x8b, 0x01,
+ 0x8a, 0x8b, 0x05, 0x89, 0x8b, 0x05, 0x8d, 0x8b,
+ 0x01, 0x90, 0x37, 0x3e, 0xcb, 0x07, 0x03, 0xac,
+ 0x07, 0x02, 0xbf, 0x85, 0xb3, 0x0a, 0x07, 0x83,
+ 0x0a, 0xb7, 0x46, 0x02, 0x8e, 0x46, 0x02, 0x82,
+ 0x46, 0xaf, 0x67, 0x88, 0x1d, 0x06, 0xaa, 0x27,
+ 0x01, 0x82, 0x27, 0x87, 0x85, 0x07, 0x82, 0x37,
+ 0x80, 0x19, 0x8c, 0x37, 0x80, 0x19, 0x86, 0x37,
+ 0x83, 0x19, 0x80, 0x37, 0x85, 0x19, 0x80, 0x37,
+ 0x82, 0x19, 0x81, 0x37, 0x80, 0x19, 0x04, 0xa5,
+ 0x45, 0x84, 0x2b, 0x80, 0x1d, 0xb0, 0x45, 0x84,
+ 0x2b, 0x83, 0x45, 0x84, 0x2b, 0x8c, 0x45, 0x80,
+ 0x1d, 0xc5, 0x45, 0x80, 0x2b, 0xb9, 0x37, 0x00,
+ 0x84, 0x37, 0xe0, 0x9f, 0x45, 0x95, 0x2b, 0x01,
+ 0x85, 0x2b, 0x01, 0xa5, 0x2b, 0x01, 0x85, 0x2b,
+ 0x01, 0x87, 0x2b, 0x00, 0x80, 0x2b, 0x00, 0x80,
+ 0x2b, 0x00, 0x80, 0x2b, 0x00, 0x9e, 0x2b, 0x01,
+ 0xb4, 0x2b, 0x00, 0x8e, 0x2b, 0x00, 0x8d, 0x2b,
+ 0x01, 0x85, 0x2b, 0x00, 0x92, 0x2b, 0x01, 0x82,
+ 0x2b, 0x00, 0x88, 0x2b, 0x00, 0x8b, 0x19, 0x81,
+ 0x37, 0xd6, 0x19, 0x00, 0x8a, 0x19, 0x80, 0x45,
+ 0x01, 0x8a, 0x19, 0x80, 0x45, 0x8e, 0x19, 0x00,
+ 0x8c, 0x45, 0x02, 0x9f, 0x19, 0x0f, 0xa0, 0x37,
+ 0x0e, 0xa5, 0x19, 0x80, 0x2b, 0x82, 0x19, 0x81,
+ 0x45, 0x85, 0x19, 0x80, 0x45, 0x9a, 0x19, 0x80,
+ 0x45, 0x90, 0x19, 0xa8, 0x45, 0x82, 0x19, 0x03,
+ 0xe2, 0x36, 0x19, 0x18, 0x8a, 0x19, 0x14, 0xe3,
+ 0x3f, 0x19, 0xe0, 0x9f, 0x0f, 0xe2, 0x13, 0x19,
+ 0x01, 0x9f, 0x19, 0x00, 0xe0, 0x08, 0x19, 0xae,
+ 0x28, 0x00, 0xae, 0x28, 0x00, 0x9f, 0x45, 0xe0,
+ 0x13, 0x1a, 0x04, 0x86, 0x1a, 0xa5, 0x27, 0x00,
+ 0x80, 0x27, 0x04, 0x80, 0x27, 0x01, 0xb7, 0x94,
+ 0x06, 0x81, 0x94, 0x0d, 0x80, 0x94, 0x96, 0x26,
+ 0x08, 0x86, 0x26, 0x00, 0x86, 0x26, 0x00, 0x86,
+ 0x26, 0x00, 0x86, 0x26, 0x00, 0x86, 0x26, 0x00,
+ 0x86, 0x26, 0x00, 0x86, 0x26, 0x00, 0x86, 0x26,
+ 0x00, 0x9f, 0x1d, 0xd2, 0x19, 0x2c, 0x99, 0x2f,
+ 0x00, 0xd8, 0x2f, 0x0b, 0xe0, 0x75, 0x2f, 0x19,
+ 0x8b, 0x19, 0x03, 0x84, 0x19, 0x80, 0x2f, 0x80,
+ 0x19, 0x80, 0x2f, 0x98, 0x19, 0x88, 0x2f, 0x83,
+ 0x37, 0x81, 0x30, 0x87, 0x19, 0x83, 0x2f, 0x83,
+ 0x19, 0x00, 0xd5, 0x35, 0x01, 0x81, 0x37, 0x81,
+ 0x19, 0x82, 0x35, 0x80, 0x19, 0xd9, 0x3d, 0x81,
+ 0x19, 0x82, 0x3d, 0x04, 0xaa, 0x0d, 0x00, 0xdd,
+ 0x30, 0x00, 0x8f, 0x19, 0x9f, 0x0d, 0xa3, 0x19,
+ 0x0b, 0x8f, 0x3d, 0x9e, 0x30, 0x00, 0xbf, 0x19,
+ 0x9e, 0x30, 0xd0, 0x19, 0xae, 0x3d, 0x80, 0x19,
+ 0xd7, 0x3d, 0xe0, 0x47, 0x19, 0xf0, 0x09, 0x5f,
+ 0x2f, 0xbf, 0x19, 0xf0, 0x41, 0x9c, 0x2f, 0x02,
+ 0xe4, 0x2c, 0x9b, 0x02, 0xb6, 0x9b, 0x08, 0xaf,
+ 0x4a, 0xe0, 0xcb, 0x97, 0x13, 0xdf, 0x1d, 0xd7,
+ 0x08, 0x07, 0xa1, 0x19, 0xe0, 0x05, 0x45, 0x82,
+ 0x19, 0xb4, 0x45, 0x01, 0x88, 0x45, 0x29, 0x8a,
+ 0x45, 0xac, 0x86, 0x02, 0x89, 0x19, 0x05, 0xb7,
+ 0x76, 0x07, 0xc5, 0x7c, 0x07, 0x8b, 0x7c, 0x05,
+ 0x9f, 0x1f, 0xad, 0x3e, 0x80, 0x19, 0x80, 0x3e,
+ 0xa3, 0x79, 0x0a, 0x80, 0x79, 0x9c, 0x30, 0x02,
+ 0xcd, 0x3a, 0x00, 0x80, 0x19, 0x89, 0x3a, 0x03,
+ 0x81, 0x3a, 0x9e, 0x5e, 0x00, 0xb6, 0x16, 0x08,
+ 0x8d, 0x16, 0x01, 0x89, 0x16, 0x01, 0x83, 0x16,
+ 0x9f, 0x5e, 0xc2, 0x8c, 0x17, 0x84, 0x8c, 0x96,
+ 0x55, 0x09, 0x85, 0x26, 0x01, 0x85, 0x26, 0x01,
+ 0x85, 0x26, 0x08, 0x86, 0x26, 0x00, 0x86, 0x26,
+ 0x00, 0xaa, 0x45, 0x80, 0x19, 0x88, 0x45, 0x80,
+ 0x2b, 0x83, 0x45, 0x81, 0x19, 0x03, 0xcf, 0x17,
+ 0xad, 0x55, 0x01, 0x89, 0x55, 0x05, 0xf0, 0x1b,
+ 0x43, 0x30, 0x0b, 0x96, 0x30, 0x03, 0xb0, 0x30,
+ 0x70, 0x10, 0xa3, 0xe1, 0x0d, 0x2f, 0x01, 0xe0,
+ 0x09, 0x2f, 0x25, 0x86, 0x45, 0x0b, 0x84, 0x05,
+ 0x04, 0x99, 0x34, 0x00, 0x84, 0x34, 0x00, 0x80,
+ 0x34, 0x00, 0x81, 0x34, 0x00, 0x81, 0x34, 0x00,
+ 0x89, 0x34, 0xe0, 0x11, 0x04, 0x10, 0xe1, 0x0a,
+ 0x04, 0x81, 0x19, 0x0f, 0xbf, 0x04, 0x01, 0xb5,
+ 0x04, 0x27, 0x8d, 0x04, 0x01, 0x8f, 0x37, 0x89,
+ 0x19, 0x05, 0x8d, 0x37, 0x81, 0x1d, 0xa2, 0x19,
+ 0x00, 0x92, 0x19, 0x00, 0x83, 0x19, 0x03, 0x84,
+ 0x04, 0x00, 0xe0, 0x26, 0x04, 0x01, 0x80, 0x19,
+ 0x00, 0x9f, 0x19, 0x99, 0x45, 0x85, 0x19, 0x99,
+ 0x45, 0x8a, 0x19, 0x89, 0x3d, 0x80, 0x19, 0xac,
+ 0x3d, 0x81, 0x19, 0x9e, 0x30, 0x02, 0x85, 0x30,
+ 0x01, 0x85, 0x30, 0x01, 0x85, 0x30, 0x01, 0x82,
+ 0x30, 0x02, 0x86, 0x19, 0x00, 0x86, 0x19, 0x09,
+ 0x84, 0x19, 0x01, 0x8b, 0x49, 0x00, 0x99, 0x49,
+ 0x00, 0x92, 0x49, 0x00, 0x81, 0x49, 0x00, 0x8e,
+ 0x49, 0x01, 0x8d, 0x49, 0x21, 0xe0, 0x1a, 0x49,
+ 0x04, 0x82, 0x19, 0x03, 0xac, 0x19, 0x02, 0x88,
+ 0x19, 0xce, 0x2b, 0x00, 0x8c, 0x19, 0x02, 0x80,
+ 0x2b, 0x2e, 0xac, 0x19, 0x80, 0x37, 0x60, 0x21,
+ 0x9c, 0x4b, 0x02, 0xb0, 0x13, 0x0e, 0x80, 0x37,
+ 0x9a, 0x19, 0x03, 0xa3, 0x69, 0x08, 0x82, 0x69,
+ 0x9a, 0x29, 0x04, 0xaa, 0x6b, 0x04, 0x9d, 0x96,
+ 0x00, 0x80, 0x96, 0xa3, 0x6c, 0x03, 0x8d, 0x6c,
+ 0x29, 0xcf, 0x1e, 0xaf, 0x7e, 0x9d, 0x72, 0x01,
+ 0x89, 0x72, 0x05, 0xa3, 0x71, 0x03, 0xa3, 0x71,
+ 0x03, 0xa7, 0x24, 0x07, 0xb3, 0x14, 0x0a, 0x80,
+ 0x14, 0x60, 0x2f, 0xe0, 0xd6, 0x48, 0x08, 0x95,
+ 0x48, 0x09, 0x87, 0x48, 0x60, 0x37, 0x85, 0x1c,
+ 0x01, 0x80, 0x1c, 0x00, 0xab, 0x1c, 0x00, 0x81,
+ 0x1c, 0x02, 0x80, 0x1c, 0x01, 0x80, 0x1c, 0x95,
+ 0x36, 0x00, 0x88, 0x36, 0x9f, 0x74, 0x9e, 0x5f,
+ 0x07, 0x88, 0x5f, 0x2f, 0x92, 0x33, 0x00, 0x81,
+ 0x33, 0x04, 0x84, 0x33, 0x9b, 0x77, 0x02, 0x80,
+ 0x77, 0x99, 0x4c, 0x04, 0x80, 0x4c, 0x3f, 0x9f,
+ 0x58, 0x97, 0x57, 0x03, 0x93, 0x57, 0x01, 0xad,
+ 0x57, 0x83, 0x3f, 0x00, 0x81, 0x3f, 0x04, 0x87,
+ 0x3f, 0x00, 0x82, 0x3f, 0x00, 0x9c, 0x3f, 0x01,
+ 0x82, 0x3f, 0x03, 0x89, 0x3f, 0x06, 0x88, 0x3f,
+ 0x06, 0x9f, 0x6e, 0x9f, 0x6a, 0x1f, 0xa6, 0x51,
+ 0x03, 0x8b, 0x51, 0x08, 0xb5, 0x06, 0x02, 0x86,
+ 0x06, 0x95, 0x39, 0x01, 0x87, 0x39, 0x92, 0x38,
+ 0x04, 0x87, 0x38, 0x91, 0x78, 0x06, 0x83, 0x78,
+ 0x0b, 0x86, 0x78, 0x4f, 0xc8, 0x6f, 0x36, 0xb2,
+ 0x68, 0x0c, 0xb2, 0x68, 0x06, 0x85, 0x68, 0xa7,
+ 0x31, 0x07, 0x89, 0x31, 0x60, 0xc5, 0x9e, 0x04,
+ 0x00, 0xa9, 0x9a, 0x00, 0x82, 0x9a, 0x01, 0x81,
+ 0x9a, 0x4d, 0xa7, 0x6d, 0x07, 0xa9, 0x82, 0x55,
+ 0x9b, 0x18, 0x13, 0x96, 0x25, 0x08, 0xcd, 0x0e,
+ 0x03, 0x9d, 0x0e, 0x0e, 0x80, 0x0e, 0xc1, 0x3b,
+ 0x0a, 0x80, 0x3b, 0x01, 0x98, 0x83, 0x06, 0x89,
+ 0x83, 0x05, 0xb4, 0x15, 0x00, 0x91, 0x15, 0x07,
+ 0xa6, 0x4e, 0x08, 0xdf, 0x7d, 0x00, 0x93, 0x81,
+ 0x0a, 0x91, 0x41, 0x00, 0xab, 0x41, 0x40, 0x86,
+ 0x5d, 0x00, 0x80, 0x5d, 0x00, 0x83, 0x5d, 0x00,
+ 0x8e, 0x5d, 0x00, 0x8a, 0x5d, 0x05, 0xba, 0x43,
+ 0x04, 0x89, 0x43, 0x05, 0x83, 0x2a, 0x00, 0x87,
+ 0x2a, 0x01, 0x81, 0x2a, 0x01, 0x95, 0x2a, 0x00,
+ 0x86, 0x2a, 0x00, 0x81, 0x2a, 0x00, 0x84, 0x2a,
+ 0x00, 0x80, 0x37, 0x88, 0x2a, 0x01, 0x81, 0x2a,
+ 0x01, 0x82, 0x2a, 0x01, 0x80, 0x2a, 0x05, 0x80,
+ 0x2a, 0x04, 0x86, 0x2a, 0x01, 0x86, 0x2a, 0x02,
+ 0x84, 0x2a, 0x60, 0x2a, 0xdb, 0x62, 0x00, 0x84,
+ 0x62, 0x1d, 0xc7, 0x95, 0x07, 0x89, 0x95, 0x60,
+ 0x45, 0xb5, 0x7f, 0x01, 0xa5, 0x7f, 0x21, 0xc4,
+ 0x5a, 0x0a, 0x89, 0x5a, 0x05, 0x8c, 0x5b, 0x12,
+ 0xb8, 0x8d, 0x06, 0x89, 0x8d, 0x35, 0x9a, 0x02,
+ 0x01, 0x8e, 0x02, 0x03, 0x8f, 0x02, 0x60, 0x5f,
+ 0xbb, 0x21, 0x60, 0x03, 0xd2, 0x99, 0x0b, 0x80,
+ 0x99, 0x86, 0x20, 0x01, 0x80, 0x20, 0x01, 0x87,
+ 0x20, 0x00, 0x81, 0x20, 0x00, 0x9d, 0x20, 0x00,
+ 0x81, 0x20, 0x01, 0x8b, 0x20, 0x08, 0x89, 0x20,
+ 0x45, 0x87, 0x60, 0x01, 0xad, 0x60, 0x01, 0x8a,
+ 0x60, 0x1a, 0xc7, 0x9c, 0x07, 0xd2, 0x84, 0x1c,
+ 0xb8, 0x75, 0x60, 0xa6, 0x88, 0x0c, 0x00, 0xac,
+ 0x0c, 0x00, 0x8d, 0x0c, 0x09, 0x9c, 0x0c, 0x02,
+ 0x9f, 0x52, 0x01, 0x95, 0x52, 0x00, 0x8d, 0x52,
+ 0x48, 0x86, 0x53, 0x00, 0x81, 0x53, 0x00, 0xab,
+ 0x53, 0x02, 0x80, 0x53, 0x00, 0x81, 0x53, 0x00,
+ 0x88, 0x53, 0x07, 0x89, 0x53, 0x05, 0x85, 0x2d,
+ 0x00, 0x81, 0x2d, 0x00, 0xa4, 0x2d, 0x00, 0x81,
+ 0x2d, 0x00, 0x85, 0x2d, 0x06, 0x89, 0x2d, 0x60,
+ 0xd5, 0x98, 0x4d, 0x60, 0x56, 0x80, 0x4a, 0x0e,
+ 0xb1, 0x8e, 0x0c, 0x80, 0x8e, 0xe3, 0x39, 0x1b,
+ 0x60, 0x05, 0xe0, 0x0e, 0x1b, 0x00, 0x84, 0x1b,
+ 0x0a, 0xe0, 0x63, 0x1b, 0x6a, 0x5b, 0xe3, 0xce,
+ 0x23, 0x00, 0x88, 0x23, 0x6f, 0x66, 0xe1, 0xe6,
+ 0x03, 0x70, 0x11, 0x58, 0xe1, 0xd8, 0x08, 0x06,
+ 0x9e, 0x5c, 0x00, 0x89, 0x5c, 0x03, 0x81, 0x5c,
+ 0x5f, 0x9d, 0x09, 0x01, 0x85, 0x09, 0x09, 0xc5,
+ 0x73, 0x09, 0x89, 0x73, 0x00, 0x86, 0x73, 0x00,
+ 0x94, 0x73, 0x04, 0x92, 0x73, 0x62, 0x4f, 0xda,
+ 0x54, 0x60, 0x04, 0xca, 0x59, 0x03, 0xb8, 0x59,
+ 0x06, 0x90, 0x59, 0x3f, 0x80, 0x8f, 0x80, 0x64,
+ 0x81, 0x19, 0x80, 0x42, 0x0a, 0x81, 0x2f, 0x0d,
+ 0xf0, 0x07, 0x97, 0x8f, 0x07, 0xe2, 0x9f, 0x8f,
+ 0xe1, 0x75, 0x42, 0x29, 0x88, 0x8f, 0x70, 0x12,
+ 0x96, 0x80, 0x3d, 0xe0, 0xbd, 0x35, 0x30, 0x82,
+ 0x35, 0x10, 0x83, 0x3d, 0x07, 0xe1, 0x2b, 0x64,
+ 0x68, 0xa3, 0xe0, 0x0a, 0x22, 0x04, 0x8c, 0x22,
+ 0x02, 0x88, 0x22, 0x06, 0x89, 0x22, 0x01, 0x83,
+ 0x22, 0x83, 0x19, 0x70, 0x02, 0xfb, 0xe0, 0x95,
+ 0x19, 0x09, 0xa6, 0x19, 0x01, 0xbd, 0x19, 0x82,
+ 0x37, 0x90, 0x19, 0x87, 0x37, 0x81, 0x19, 0x86,
+ 0x37, 0x9d, 0x19, 0x83, 0x37, 0xba, 0x19, 0x16,
+ 0xc5, 0x2b, 0x60, 0x39, 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,
+ 0x80, 0x0e, 0x84, 0x80, 0x00, 0x8e, 0x80, 0x64,
+ 0xef, 0x86, 0x28, 0x00, 0x90, 0x28, 0x01, 0x86,
+ 0x28, 0x00, 0x81, 0x28, 0x00, 0x84, 0x28, 0x60,
+ 0x74, 0xac, 0x65, 0x02, 0x8d, 0x65, 0x01, 0x89,
+ 0x65, 0x03, 0x81, 0x65, 0x61, 0x0f, 0xb9, 0x98,
+ 0x04, 0x80, 0x98, 0x64, 0x9f, 0xe0, 0x64, 0x56,
+ 0x01, 0x8f, 0x56, 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, 0x35, 0x81,
+ 0x19, 0x0c, 0xab, 0x19, 0x03, 0x88, 0x19, 0x06,
+ 0x81, 0x19, 0x0d, 0x85, 0x19, 0x60, 0x39, 0xe3,
+ 0x77, 0x19, 0x07, 0x8c, 0x19, 0x02, 0x8c, 0x19,
+ 0x02, 0xe0, 0x13, 0x19, 0x0b, 0xd8, 0x19, 0x06,
+ 0x8b, 0x19, 0x13, 0x8b, 0x19, 0x03, 0xb7, 0x19,
+ 0x07, 0x89, 0x19, 0x05, 0xa7, 0x19, 0x07, 0x9d,
+ 0x19, 0x01, 0x81, 0x19, 0x4d, 0xe0, 0x18, 0x19,
+ 0x00, 0xd1, 0x19, 0x00, 0xe0, 0x26, 0x19, 0x0b,
+ 0x8d, 0x19, 0x01, 0x84, 0x19, 0x02, 0x82, 0x19,
+ 0x04, 0x86, 0x19, 0x08, 0x98, 0x19, 0x06, 0x86,
+ 0x19, 0x08, 0x82, 0x19, 0x0c, 0x86, 0x19, 0x28,
+ 0xe0, 0x32, 0x19, 0x00, 0xb6, 0x19, 0x24, 0x89,
+ 0x19, 0x63, 0xa5, 0xf0, 0x96, 0x7d, 0x2f, 0x21,
+ 0xef, 0xd4, 0x2f, 0x0a, 0xe0, 0x7d, 0x2f, 0x01,
+ 0xf0, 0x06, 0x21, 0x2f, 0x0d, 0xf0, 0x0c, 0xd0,
+ 0x2f, 0x6b, 0xbe, 0xe1, 0xbd, 0x2f, 0x65, 0x81,
+ 0xf0, 0x02, 0xea, 0x2f, 0x7a, 0xdc, 0x55, 0x80,
+ 0x19, 0x1d, 0xdf, 0x19, 0x60, 0x1f, 0xe0, 0x8f,
+ 0x37,
+};
+
+static const uint8_t unicode_script_ext_table[799] = {
+ 0x82, 0xc1, 0x00, 0x00, 0x01, 0x2b, 0x01, 0x00,
+ 0x00, 0x01, 0x2b, 0x1c, 0x00, 0x0c, 0x01, 0x45,
+ 0x80, 0x92, 0x00, 0x00, 0x02, 0x1d, 0x6b, 0x00,
+ 0x02, 0x1d, 0x28, 0x01, 0x02, 0x1d, 0x45, 0x00,
+ 0x02, 0x1d, 0x28, 0x81, 0x03, 0x00, 0x00, 0x05,
+ 0x04, 0x31, 0x87, 0x91, 0x9a, 0x0d, 0x00, 0x00,
+ 0x05, 0x04, 0x31, 0x87, 0x91, 0x9a, 0x00, 0x03,
+ 0x04, 0x87, 0x91, 0x01, 0x00, 0x00, 0x05, 0x04,
+ 0x31, 0x87, 0x91, 0x9a, 0x1f, 0x00, 0x00, 0x08,
+ 0x01, 0x04, 0x50, 0x51, 0x78, 0x31, 0x82, 0x87,
+ 0x09, 0x00, 0x0a, 0x02, 0x04, 0x87, 0x09, 0x00,
+ 0x09, 0x03, 0x04, 0x91, 0x9a, 0x05, 0x00, 0x00,
+ 0x02, 0x04, 0x87, 0x62, 0x00, 0x00, 0x02, 0x04,
+ 0x31, 0x81, 0xfb, 0x00, 0x00, 0x0d, 0x0b, 0x1f,
+ 0x2a, 0x2c, 0x2e, 0x3c, 0x45, 0x4f, 0x70, 0x7d,
+ 0x8e, 0x90, 0x95, 0x00, 0x0c, 0x0b, 0x1f, 0x2a,
+ 0x2c, 0x2e, 0x3c, 0x45, 0x4f, 0x70, 0x8e, 0x90,
+ 0x95, 0x10, 0x00, 0x00, 0x14, 0x0b, 0x1f, 0x21,
+ 0x2d, 0x53, 0x2a, 0x2c, 0x2e, 0x3c, 0x4e, 0x4f,
+ 0x60, 0x70, 0x43, 0x81, 0x86, 0x8d, 0x8e, 0x90,
+ 0x95, 0x00, 0x15, 0x0b, 0x1f, 0x21, 0x2d, 0x53,
+ 0x2a, 0x2c, 0x2e, 0x3c, 0x47, 0x4e, 0x4f, 0x60,
+ 0x70, 0x43, 0x81, 0x86, 0x8d, 0x8e, 0x90, 0x95,
+ 0x09, 0x04, 0x1f, 0x21, 0x3b, 0x4e, 0x75, 0x00,
+ 0x09, 0x03, 0x0b, 0x15, 0x86, 0x75, 0x00, 0x09,
+ 0x02, 0x2e, 0x5d, 0x75, 0x00, 0x09, 0x02, 0x2c,
+ 0x41, 0x80, 0x75, 0x00, 0x0d, 0x02, 0x2a, 0x8e,
+ 0x80, 0x71, 0x00, 0x09, 0x02, 0x3c, 0x60, 0x82,
+ 0xcf, 0x00, 0x09, 0x03, 0x15, 0x5e, 0x8a, 0x80,
+ 0x30, 0x00, 0x00, 0x02, 0x27, 0x45, 0x85, 0xb8,
+ 0x00, 0x01, 0x04, 0x11, 0x32, 0x89, 0x88, 0x80,
+ 0x4a, 0x00, 0x01, 0x02, 0x5b, 0x76, 0x00, 0x00,
+ 0x00, 0x02, 0x5b, 0x76, 0x84, 0x49, 0x00, 0x00,
+ 0x04, 0x0b, 0x1f, 0x2a, 0x3c, 0x00, 0x01, 0x1f,
+ 0x00, 0x04, 0x0b, 0x1f, 0x2a, 0x3c, 0x00, 0x02,
+ 0x1f, 0x2a, 0x00, 0x01, 0x1f, 0x01, 0x02, 0x0b,
+ 0x1f, 0x00, 0x02, 0x1f, 0x7d, 0x00, 0x02, 0x0b,
+ 0x1f, 0x00, 0x02, 0x1f, 0x7d, 0x00, 0x06, 0x1f,
+ 0x3c, 0x4f, 0x70, 0x8e, 0x90, 0x00, 0x01, 0x1f,
+ 0x01, 0x02, 0x1f, 0x7d, 0x01, 0x01, 0x1f, 0x00,
+ 0x02, 0x1f, 0x7d, 0x00, 0x02, 0x0b, 0x1f, 0x06,
+ 0x01, 0x1f, 0x00, 0x02, 0x1f, 0x60, 0x00, 0x02,
+ 0x0b, 0x1f, 0x01, 0x01, 0x1f, 0x00, 0x02, 0x0b,
+ 0x1f, 0x03, 0x01, 0x1f, 0x00, 0x08, 0x0b, 0x1f,
+ 0x2a, 0x3c, 0x60, 0x70, 0x90, 0x95, 0x00, 0x02,
+ 0x1f, 0x2a, 0x00, 0x03, 0x1f, 0x2a, 0x3c, 0x01,
+ 0x02, 0x0b, 0x1f, 0x00, 0x01, 0x0b, 0x01, 0x02,
+ 0x1f, 0x2a, 0x00, 0x01, 0x60, 0x80, 0x44, 0x00,
+ 0x01, 0x01, 0x2b, 0x35, 0x00, 0x00, 0x02, 0x1d,
+ 0x87, 0x81, 0xb5, 0x00, 0x00, 0x02, 0x45, 0x5b,
+ 0x80, 0x3f, 0x00, 0x00, 0x03, 0x1f, 0x2a, 0x45,
+ 0x8c, 0xd1, 0x00, 0x00, 0x02, 0x1d, 0x28, 0x81,
+ 0x3c, 0x00, 0x01, 0x06, 0x0d, 0x30, 0x2f, 0x35,
+ 0x3d, 0x9b, 0x00, 0x05, 0x0d, 0x30, 0x2f, 0x35,
+ 0x3d, 0x01, 0x00, 0x00, 0x01, 0x2f, 0x00, 0x00,
+ 0x09, 0x06, 0x0d, 0x30, 0x2f, 0x35, 0x3d, 0x9b,
+ 0x00, 0x00, 0x00, 0x05, 0x0d, 0x30, 0x2f, 0x35,
+ 0x3d, 0x07, 0x06, 0x0d, 0x30, 0x2f, 0x35, 0x3d,
+ 0x9b, 0x03, 0x05, 0x0d, 0x30, 0x2f, 0x35, 0x3d,
+ 0x09, 0x00, 0x03, 0x02, 0x0d, 0x2f, 0x01, 0x00,
+ 0x00, 0x05, 0x0d, 0x30, 0x2f, 0x35, 0x3d, 0x04,
+ 0x02, 0x35, 0x3d, 0x00, 0x00, 0x00, 0x05, 0x0d,
+ 0x30, 0x2f, 0x35, 0x3d, 0x03, 0x00, 0x01, 0x03,
+ 0x2f, 0x35, 0x3d, 0x01, 0x01, 0x2f, 0x58, 0x00,
+ 0x03, 0x02, 0x35, 0x3d, 0x02, 0x00, 0x00, 0x02,
+ 0x35, 0x3d, 0x59, 0x00, 0x00, 0x06, 0x0d, 0x30,
+ 0x2f, 0x35, 0x3d, 0x9b, 0x00, 0x02, 0x35, 0x3d,
+ 0x80, 0x12, 0x00, 0x0f, 0x01, 0x2f, 0x1f, 0x00,
+ 0x23, 0x01, 0x2f, 0x3b, 0x00, 0x27, 0x01, 0x2f,
+ 0x37, 0x00, 0x30, 0x01, 0x2f, 0x0e, 0x00, 0x0b,
+ 0x01, 0x2f, 0x32, 0x00, 0x00, 0x01, 0x2f, 0x57,
+ 0x00, 0x18, 0x01, 0x2f, 0x09, 0x00, 0x04, 0x01,
+ 0x2f, 0x5f, 0x00, 0x1e, 0x01, 0x2f, 0xc0, 0x31,
+ 0xef, 0x00, 0x00, 0x02, 0x1d, 0x28, 0x80, 0x0f,
+ 0x00, 0x07, 0x02, 0x2f, 0x45, 0x80, 0xa7, 0x00,
+ 0x02, 0x0e, 0x1f, 0x21, 0x2c, 0x2e, 0x41, 0x3c,
+ 0x3b, 0x4e, 0x4f, 0x5a, 0x60, 0x43, 0x8d, 0x95,
+ 0x02, 0x0d, 0x1f, 0x21, 0x2c, 0x2e, 0x41, 0x3c,
+ 0x3b, 0x4e, 0x5a, 0x60, 0x43, 0x8d, 0x95, 0x03,
+ 0x0b, 0x1f, 0x21, 0x2c, 0x2e, 0x41, 0x3b, 0x4e,
+ 0x5a, 0x43, 0x8d, 0x95, 0x80, 0x36, 0x00, 0x00,
+ 0x02, 0x0b, 0x1f, 0x00, 0x00, 0x00, 0x02, 0x1f,
+ 0x8e, 0x39, 0x00, 0x00, 0x03, 0x3e, 0x45, 0x5e,
+ 0x80, 0x1f, 0x00, 0x00, 0x02, 0x10, 0x3a, 0xc0,
+ 0x13, 0xa1, 0x00, 0x00, 0x02, 0x04, 0x91, 0x09,
+ 0x00, 0x00, 0x02, 0x04, 0x91, 0x46, 0x00, 0x01,
+ 0x05, 0x0d, 0x30, 0x2f, 0x35, 0x3d, 0x80, 0x99,
+ 0x00, 0x04, 0x06, 0x0d, 0x30, 0x2f, 0x35, 0x3d,
+ 0x9b, 0x09, 0x00, 0x00, 0x02, 0x35, 0x3d, 0x2c,
+ 0x00, 0x01, 0x02, 0x35, 0x3d, 0x80, 0xdf, 0x00,
+ 0x02, 0x02, 0x1c, 0x49, 0x03, 0x00, 0x2c, 0x03,
+ 0x1c, 0x48, 0x49, 0x02, 0x00, 0x08, 0x02, 0x1c,
+ 0x49, 0x81, 0x1f, 0x00, 0x1b, 0x02, 0x04, 0x1a,
+ 0x8f, 0x84, 0x00, 0x00, 0x02, 0x2a, 0x8e, 0x00,
+ 0x00, 0x00, 0x02, 0x2a, 0x8e, 0x36, 0x00, 0x01,
+ 0x02, 0x2a, 0x8e, 0x8c, 0x12, 0x00, 0x01, 0x02,
+ 0x2a, 0x8e, 0x00, 0x00, 0x00, 0x02, 0x2a, 0x8e,
+ 0xc0, 0x5c, 0x4b, 0x00, 0x03, 0x01, 0x22, 0x96,
+ 0x3b, 0x00, 0x11, 0x01, 0x2f, 0x9e, 0x5d, 0x00,
+ 0x01, 0x01, 0x2f, 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[411] = {
+ 0x43, 0x44, 0x80, 0x42, 0x69, 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, 0x40, 0xa6, 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, 0x83, 0xb9,
+ 0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x9c, 0x82,
+ 0xb9, 0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x9b,
+ 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, 0x90, 0x8a,
+ 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, 0xbe,
+ 0x84, 0xaf, 0x8e, 0xbb, 0x82, 0x9d, 0x88, 0x09,
+ 0xb8, 0x8a, 0xb1, 0x92, 0x41, 0xaf, 0x8d, 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, 0x41, 0x82, 0x81, 0x41, 0x52,
+ 0x82, 0xb4, 0x8d, 0xbb, 0x80, 0xac, 0x88, 0xc6,
+ 0x82, 0xa3, 0x8b, 0x91, 0x81, 0xb8, 0x82, 0xaf,
+ 0x8c, 0x8d, 0x81, 0xdb, 0x88, 0x08, 0x28, 0x40,
+ 0x9f, 0x89, 0x96, 0x83, 0xb9, 0x31, 0x09, 0x81,
+ 0x89, 0x80, 0x89, 0x81, 0x40, 0xd0, 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, 0x60, 0x50, 0x57,
+ 0x00, 0xb6, 0x33, 0xdc, 0x81, 0x60, 0x4c, 0xab,
+ 0x80, 0x60, 0x23, 0x60, 0x30, 0x90, 0x0e, 0x01,
+ 0x04, 0x49, 0x1b, 0x80, 0x47, 0xe7, 0x99, 0x85,
+ 0x99, 0x85, 0x99,
+};
+
+static const uint8_t unicode_prop_Other_Lowercase_table[51] = {
+ 0x40, 0xa9, 0x80, 0x8e, 0x80, 0x41, 0xf4, 0x88,
+ 0x31, 0x9d, 0x84, 0xdf, 0x80, 0xb3, 0x80, 0x59,
+ 0xb0, 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, 0x86, 0x81,
+ 0x43, 0x61, 0x83,
+};
+
+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[65] = {
+ 0x49, 0xbd, 0x80, 0x97, 0x80, 0x41, 0x65, 0x80,
+ 0x97, 0x80, 0xe5, 0x80, 0x97, 0x80, 0x40, 0xe9,
+ 0x80, 0x91, 0x81, 0xe6, 0x80, 0x97, 0x80, 0xf6,
+ 0x80, 0x8e, 0x80, 0x4d, 0x54, 0x80, 0x44, 0xd5,
+ 0x80, 0x50, 0x20, 0x81, 0x60, 0xcf, 0x6d, 0x81,
+ 0x53, 0x9d, 0x80, 0x97, 0x80, 0x41, 0x57, 0x80,
+ 0x8b, 0x80, 0x40, 0xf0, 0x80, 0x43, 0x7f, 0x80,
+ 0x60, 0xb8, 0x33, 0x07, 0x84, 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[12] = {
+ 0x40, 0xb6, 0x80, 0x42, 0xce, 0x80, 0x4f, 0xe0,
+ 0x88, 0x46, 0x67, 0x80,
+};
+
+static const uint8_t unicode_prop_Prepended_Concatenation_Mark_table[17] = {
+ 0x45, 0xff, 0x85, 0x40, 0xd6, 0x80, 0xb0, 0x80,
+ 0x41, 0xd1, 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[33] = {
+ 0x40, 0xde, 0x80, 0xcf, 0x80, 0x97, 0x80, 0x44,
+ 0x3c, 0x80, 0x59, 0x11, 0x80, 0x40, 0xe4, 0x3f,
+ 0x3f, 0x87, 0x89, 0x11, 0x05, 0x02, 0x11, 0x80,
+ 0xa9, 0x11, 0x80, 0x60, 0xdb, 0x07, 0x86, 0x8b,
+ 0x84,
+};
+
+static const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[441] = {
+ 0x40, 0x9f, 0x06, 0x00, 0x01, 0x00, 0x01, 0x12,
+ 0x10, 0x82, 0x9f, 0x80, 0xcf, 0x01, 0x80, 0x8b,
+ 0x07, 0x80, 0xfb, 0x01, 0x01, 0x80, 0xa5, 0x80,
+ 0x40, 0xbb, 0x88, 0x9e, 0x29, 0x84, 0xda, 0x08,
+ 0x81, 0x89, 0x80, 0xa3, 0x04, 0x02, 0x04, 0x08,
+ 0x80, 0xc9, 0x82, 0x9c, 0x80, 0x41, 0x93, 0x80,
+ 0x40, 0x93, 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, 0x83, 0x45, 0x1c, 0x10,
+ 0x8a, 0x80, 0x91, 0x80, 0x9b, 0x8c, 0x80, 0xa1,
+ 0xa4, 0x40, 0xd9, 0x80, 0x40, 0xd5, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x3f, 0x3f, 0x87,
+ 0x89, 0x11, 0x04, 0x00, 0x29, 0x04, 0x12, 0x80,
+ 0x88, 0x12, 0x80, 0x88, 0x11, 0x11, 0x04, 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,
+ 0x86, 0x81, 0x43, 0x61, 0x83, 0x88, 0x80, 0x60,
+ 0x4d, 0x95, 0x41, 0x0d, 0x08, 0x00, 0x81, 0x89,
+ 0x00, 0x00, 0x09, 0x82, 0xc3, 0x81, 0xe9, 0xa5,
+ 0x86, 0x8b, 0x24, 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,
+ 0x60, 0xbc, 0xa6, 0x83, 0x54, 0xb9, 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, 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, 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_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[53] = {
+ 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,
+ 0x41, 0xda, 0x80, 0x92, 0x80, 0xee, 0x80, 0x60,
+ 0xcd, 0x8f, 0x81, 0xa4, 0x80, 0x89, 0x80, 0x40,
+ 0xa8, 0x80, 0x4f, 0x9e, 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[358] = {
+ 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, 0x40, 0xc8, 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,
+ 0xfe, 0x80, 0xed, 0x80, 0x8f, 0x80, 0xec, 0x81,
+ 0x8f, 0x80, 0xfb, 0x80, 0xfb, 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, 0x44, 0x68, 0x8a,
+ 0x88, 0x80, 0x41, 0x5a, 0x82, 0x41, 0x38, 0x39,
+ 0x80, 0xaf, 0x8d, 0xf5, 0x80, 0x8e, 0x80, 0xa5,
+ 0x88, 0xb5, 0x81, 0x40, 0x89, 0x81, 0xbf, 0x85,
+ 0xd1, 0x98, 0x18, 0x28, 0x0a, 0xb1, 0xbe, 0xd8,
+ 0x8b, 0xa4, 0x22, 0x82, 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, 0x40, 0xc9,
+ 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, 0x48, 0x03,
+ 0x81, 0x42, 0x3a, 0x85, 0x42, 0x1d, 0x8a, 0x41,
+ 0x67, 0x81, 0xf7, 0x81, 0xbd, 0x80, 0xcb, 0x80,
+ 0x88, 0x82, 0xe7, 0x81, 0x40, 0xb1, 0x81, 0xd0,
+ 0x80, 0x8f, 0x80, 0x97, 0x32, 0x84, 0x40, 0xcc,
+ 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, 0x60, 0x4d,
+ 0x57, 0x84, 0xba, 0x86, 0x44, 0x57, 0x90, 0xcf,
+ 0x81, 0x60, 0x61, 0x74, 0x12, 0x2f, 0x39, 0x86,
+ 0x9d, 0x83, 0x4f, 0x81, 0x86, 0x41, 0xb4, 0x83,
+ 0x45, 0xdf, 0x86, 0xec, 0x10, 0x82,
+};
+
+static const uint8_t unicode_prop_Extender_table[89] = {
+ 0x40, 0xb6, 0x80, 0x42, 0x17, 0x81, 0x43, 0x6d,
+ 0x80, 0x41, 0xb8, 0x80, 0x43, 0x59, 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, 0x53, 0xeb, 0x80, 0x42, 0x67, 0x82, 0x44,
+ 0xce, 0x80, 0x60, 0x50, 0xa8, 0x81, 0x44, 0x9b,
+ 0x08, 0x80, 0x60, 0x71, 0x57, 0x81, 0x48, 0x05,
+ 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_Binary_Operator_table[5] = {
+ 0x60, 0x2f, 0xef, 0x09, 0x87,
+};
+
+static const uint8_t unicode_prop_IDS_Trinary_Operator_table[4] = {
+ 0x60, 0x2f, 0xf1, 0x81,
+};
+
+static const uint8_t unicode_prop_Ideographic_table[66] = {
+ 0x60, 0x30, 0x05, 0x81, 0x98, 0x88, 0x8d, 0x82,
+ 0x43, 0xc4, 0x59, 0xbf, 0xbf, 0x60, 0x51, 0xfc,
+ 0x60, 0x59, 0x02, 0x41, 0x6d, 0x81, 0xe9, 0x60,
+ 0x75, 0x09, 0x80, 0x9a, 0x57, 0xf7, 0x87, 0x44,
+ 0xd5, 0xa9, 0x88, 0x60, 0x24, 0x66, 0x41, 0x8b,
+ 0x60, 0x4d, 0x03, 0x60, 0xa6, 0xdd, 0xa1, 0x50,
+ 0x34, 0x8a, 0x40, 0xdd, 0x81, 0x56, 0x81, 0x8d,
+ 0x5d, 0x30, 0x4c, 0x1e, 0x42, 0x1d, 0x45, 0xe1,
+ 0x53, 0x4a,
+};
+
+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_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[188] = {
+ 0xa0, 0x80, 0x8b, 0x80, 0x8f, 0x80, 0x45, 0x48,
+ 0x80, 0x40, 0x93, 0x81, 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, 0xcb, 0x04, 0x80, 0x41, 0x39, 0x81, 0x41,
+ 0x61, 0x83, 0x40, 0xad, 0x09, 0x81, 0x40, 0xda,
+ 0x81, 0xc0, 0x81, 0x43, 0xbb, 0x81, 0x88, 0x82,
+ 0x4d, 0xe3, 0x80, 0x8c, 0x80, 0x41, 0xc4, 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,
+ 0x65, 0x02, 0x81, 0x40, 0xa8, 0x80, 0x8b, 0x80,
+ 0x8f, 0x80, 0xc0, 0x80, 0x4a, 0xf3, 0x81, 0x44,
+ 0xfc, 0x84, 0x40, 0xec, 0x81, 0xf4, 0x83, 0xfe,
+ 0x82, 0x40, 0x80, 0x0d, 0x80, 0x8f, 0x81, 0xd7,
+ 0x08, 0x81, 0xeb, 0x80, 0x41, 0xa0, 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, 0x60,
+ 0x4b, 0x74, 0x81, 0x40, 0x84, 0x80, 0xc0, 0x81,
+ 0x8a, 0x80, 0x43, 0x52, 0x80, 0x60, 0x4e, 0x05,
+ 0x80, 0x5d, 0xe7, 0x80,
+};
+
+static const uint8_t unicode_prop_Soft_Dotted_table[71] = {
+ 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,
+};
+
+static const uint8_t unicode_prop_Terminal_Punctuation_table[241] = {
+ 0xa0, 0x80, 0x89, 0x00, 0x80, 0x8a, 0x0a, 0x80,
+ 0x43, 0x3d, 0x07, 0x80, 0x42, 0x00, 0x80, 0xb8,
+ 0x80, 0xc7, 0x80, 0x8d, 0x01, 0x81, 0x40, 0xb3,
+ 0x80, 0xaa, 0x8a, 0x00, 0x40, 0xea, 0x81, 0xb5,
+ 0x8e, 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,
+ 0xad, 0x08, 0x82, 0x40, 0xda, 0x84, 0xbd, 0x81,
+ 0x43, 0xbb, 0x81, 0x88, 0x82, 0x4d, 0xe3, 0x80,
+ 0x8c, 0x03, 0x80, 0x89, 0x00, 0x81, 0x41, 0xb0,
+ 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, 0x63, 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,
+ 0x40, 0xec, 0x86, 0xef, 0x83, 0xfe, 0x82, 0x40,
+ 0x80, 0x0d, 0x80, 0x8f, 0x81, 0xd7, 0x84, 0xeb,
+ 0x80, 0x41, 0xa0, 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, 0x45, 0x76, 0x84, 0x60, 0x45, 0xf8, 0x81,
+ 0x40, 0x84, 0x80, 0xc0, 0x82, 0x89, 0x80, 0x43,
+ 0x51, 0x81, 0x60, 0x4e, 0x05, 0x80, 0x5d, 0xe6,
+ 0x83,
+};
+
+static const uint8_t unicode_prop_Unified_Ideograph_table[42] = {
+ 0x60, 0x33, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x51,
+ 0xfc, 0x60, 0x5a, 0x10, 0x08, 0x00, 0x81, 0x89,
+ 0x00, 0x00, 0x09, 0x82, 0x61, 0x05, 0xd5, 0x60,
+ 0xa6, 0xdd, 0xa1, 0x50, 0x34, 0x8a, 0x40, 0xdd,
+ 0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x54, 0x1e,
+ 0x53, 0x4a,
+};
+
+static const uint8_t unicode_prop_Variation_Selector_table[12] = {
+ 0x58, 0x0a, 0x82, 0x60, 0xe5, 0xf1, 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[171] = {
+ 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, 0x39, 0x9e, 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,
+ 0x41, 0xdd, 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, 0x3d,
+ 0x10, 0x01, 0x10, 0x81, 0x89, 0x40, 0xe2, 0x8b,
+ 0x41, 0x1f, 0xae, 0x80, 0x89, 0x80, 0xb1, 0x80,
+ 0xd1, 0x80, 0xb2, 0xef, 0x22, 0x14, 0x86, 0x88,
+ 0x98, 0x36, 0x88, 0x82, 0x8c, 0x86,
+};
+
+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[66] = {
+ 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,
+};
+
+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, 0x92, 0x0e, 0x88, 0x40,
+ 0xe2, 0x8b, 0x41, 0x1f, 0xae, 0x80, 0x89, 0x80,
+ 0xb1, 0x80, 0xd1, 0x80, 0xb2, 0xef, 0x22, 0x14,
+ 0x86, 0x88, 0x98, 0x36, 0x88, 0x82, 0x8c, 0x86,
+};
+
+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,
+ 0x83, 0x47, 0xfb, 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_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_Binary_Operator,
+ UNICODE_PROP_IDS_Trinary_Operator,
+ UNICODE_PROP_Ideographic,
+ UNICODE_PROP_Join_Control,
+ UNICODE_PROP_Logical_Order_Exception,
+ 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_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_Binary_Operator,IDSB" "\0"
+ "IDS_Trinary_Operator,IDST" "\0"
+ "Ideographic,Ideo" "\0"
+ "Join_Control,Join_C" "\0"
+ "Logical_Order_Exception,LOE" "\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"
+ "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_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_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_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_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_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_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),
+};
+
+#endif /* CONFIG_ALL_UNICODE */
diff --git a/android/src/main/jni/quickjs/libunicode.c b/android/src/main/jni/quickjs/libunicode.c
new file mode 100644
index 0000000..96ff002
--- /dev/null
+++ b/android/src/main/jni/quickjs/libunicode.c
@@ -0,0 +1,1538 @@
+/*
+ * 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_U_EXT2,
+ RUN_TYPE_L_EXT2,
+ RUN_TYPE_U_EXT3,
+};
+
+/* 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, data, type, len, a, is_lower;
+ int idx, idx_min, idx_max;
+
+ is_lower = (conv_type != 0);
+ 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 {
+ type = (v >> (32 - 17 - 7 - 4)) & 0xf;
+ data = ((v & 0xf) << 8) | case_conv_table2[idx];
+ 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_U_EXT2:
+ case RUN_TYPE_L_EXT2:
+ if (conv_type != (type - RUN_TYPE_U_EXT2))
+ break;
+ res[0] = c - code + case_conv_ext[data >> 6];
+ res[1] = case_conv_ext[data & 0x3f];
+ return 2;
+ default:
+ case RUN_TYPE_U_EXT3:
+ if (conv_type != 0)
+ break;
+ res[0] = case_conv_ext[data >> 8];
+ res[1] = case_conv_ext[(data >> 4) & 0xf];
+ res[2] = case_conv_ext[data & 0xf];
+ return 3;
+ }
+ break;
+ }
+ }
+ }
+ res[0] = c;
+ return 1;
+}
+
+static uint32_t get_le24(const uint8_t *ptr)
+{
+#if defined(__x86__) || defined(__x86_64__)
+ return *(uint16_t *)ptr | (ptr[2] << 16);
+#else
+ return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16);
+#endif
+}
+
+#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;
+ 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;
+ default:
+ abort();
+ }
+ if (is_in != (cr->len & 1)) {
+ if (cr_add_point(cr, v))
+ return -1;
+ }
+ }
+ cr_compress(cr);
+ return 0;
+}
+
+int cr_union1(CharRange *cr, const uint32_t *b_pt, int b_len)
+{
+ 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, CR_OP_UNION);
+ 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;
+}
+
+#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 ... 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 ... 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 ... 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 ... 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;
+ 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;
+ /* Note: we remove the "Unknown" Script */
+ script_idx += UNICODE_SCRIPT_Unknown + 1;
+
+ 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);
+ }
+ if (type == 0)
+ v = 0;
+ else
+ v = *p++;
+ c1 = c + n + 1;
+ if (v == script_idx) {
+ if (cr_add_interval(cr1, c, c1))
+ goto fail;
+ }
+ c = c1;
+ }
+
+ 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;
+ 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;
+ 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;
+}
+
+#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(U_EXT2) | MR(U_EXT3),
+
+ MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(L_EXT2),
+
+ MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT),
+ };
+#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;
+}
+
+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);
+ 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 */
diff --git a/android/src/main/jni/quickjs/libunicode.h b/android/src/main/jni/quickjs/libunicode.h
new file mode 100644
index 0000000..cfa600a
--- /dev/null
+++ b/android/src/main/jni/quickjs/libunicode.h
@@ -0,0 +1,124 @@
+/*
+ * 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 LRE_BOOL int /* for documentation purposes */
+
+/* define it to include all the unicode tables (40KB larger) */
+#define CONFIG_ALL_UNICODE
+
+#define LRE_CC_RES_LEN_MAX 3
+
+typedef enum {
+ UNICODE_NFC,
+ UNICODE_NFD,
+ UNICODE_NFKC,
+ UNICODE_NFKD,
+} UnicodeNormalizationEnum;
+
+int lre_case_conv(uint32_t *res, uint32_t c, int conv_type);
+LRE_BOOL lre_is_cased(uint32_t c);
+LRE_BOOL lre_is_case_ignorable(uint32_t c);
+
+/* 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,
+} 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_union1(CharRange *cr, const uint32_t *b_pt, int b_len);
+
+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_union1(cr, b_pt, 2);
+}
+
+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_invert(CharRange *cr);
+
+#ifdef CONFIG_ALL_UNICODE
+
+LRE_BOOL lre_is_id_start(uint32_t c);
+LRE_BOOL lre_is_id_continue(uint32_t c);
+
+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, LRE_BOOL is_ext);
+int unicode_general_category(CharRange *cr, const char *gc_name);
+int unicode_prop(CharRange *cr, const char *prop_name);
+
+#endif /* CONFIG_ALL_UNICODE */
+
+#undef LRE_BOOL
+
+#endif /* LIBUNICODE_H */
diff --git a/android/src/main/jni/quickjs/list.h b/android/src/main/jni/quickjs/list.h
new file mode 100644
index 0000000..0a1bc5a
--- /dev/null
+++ b/android/src/main/jni/quickjs/list.h
@@ -0,0 +1,100 @@
+/*
+ * 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) \
+ ((type *)((uint8_t *)(el) - offsetof(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/android/src/main/jni/quickjs/quickjs-atom.h b/android/src/main/jni/quickjs/quickjs-atom.h
new file mode 100644
index 0000000..a353ad4
--- /dev/null
+++ b/android/src/main/jni/quickjs/quickjs-atom.h
@@ -0,0 +1,272 @@
+/*
+ * 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(message, "message")
+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(_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(status, "status")
+DEF(reason, "reason")
+DEF(globalThis, "globalThis")
+#ifdef CONFIG_BIGNUM
+DEF(bigint, "bigint")
+DEF(bigfloat, "bigfloat")
+DEF(bigdecimal, "bigdecimal")
+DEF(roundingMode, "roundingMode")
+DEF(maximumSignificantDigits, "maximumSignificantDigits")
+DEF(maximumFractionDigits, "maximumFractionDigits")
+#endif
+#ifdef CONFIG_ATOMICS
+DEF(not_equal, "not-equal")
+DEF(timed_out, "timed-out")
+DEF(ok, "ok")
+#endif
+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")
+#ifdef CONFIG_BIGNUM
+DEF(BigInt64Array, "BigInt64Array")
+DEF(BigUint64Array, "BigUint64Array")
+#endif
+DEF(Float32Array, "Float32Array")
+DEF(Float64Array, "Float64Array")
+DEF(DataView, "DataView")
+#ifdef CONFIG_BIGNUM
+DEF(BigInt, "BigInt")
+DEF(BigFloat, "BigFloat")
+DEF(BigFloatEnv, "BigFloatEnv")
+DEF(BigDecimal, "BigDecimal")
+DEF(OperatorSet, "OperatorSet")
+DEF(Operators, "Operators")
+#endif
+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")
+#ifdef CONFIG_BIGNUM
+DEF(Symbol_operatorSet, "Symbol.operatorSet")
+#endif
+
+#endif /* DEF */
diff --git a/android/src/main/jni/quickjs/quickjs-opcode.h b/android/src/main/jni/quickjs/quickjs-opcode.h
new file mode 100644
index 0000000..230f6e4
--- /dev/null
+++ b/android/src/main/jni/quickjs/quickjs-opcode.h
@@ -0,0 +1,367 @@
+/*
+ * 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( 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_var, 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, 1, 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( 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_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( to_object, 1, 1, 1, none)
+//DEF( to_string, 1, 1, 1, none)
+DEF( to_propkey, 1, 1, 1, none)
+DEF( to_propkey2, 1, 2, 2, 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(with_get_ref_undef, 10, 1, 0, atom_label_u8)
+
+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)
+DEF(iterator_get_value_done, 1, 1, 2, none)
+DEF( iterator_close, 1, 3, 0, none)
+DEF(iterator_close_return, 1, 4, 4, none)
+DEF(async_iterator_close, 1, 3, 2, none)
+DEF(async_iterator_next, 1, 4, 4, none)
+DEF(async_iterator_get, 2, 4, 5, u8)
+DEF( initial_yield, 1, 0, 0, none)
+DEF( yield, 1, 1, 2, none)
+DEF( yield_star, 1, 2, 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)
+#ifdef CONFIG_BIGNUM
+DEF( mul_pow10, 1, 2, 1, none)
+DEF( math_mod, 1, 2, 1, none)
+#endif
+/* 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(set_arg_valid_upto, 3, 0, 0, arg) /* emitted in phase 1, removed in phase 2 */
+
+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 */
+
+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_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, 1, 1, atom_u16) /* obj value ->, 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( is_function, 1, 1, 1, none)
+#endif
+
+#undef DEF
+#undef def
+#endif /* DEF */
diff --git a/android/src/main/jni/quickjs/quickjs.c b/android/src/main/jni/quickjs/quickjs.c
new file mode 100644
index 0000000..da12317
--- /dev/null
+++ b/android/src/main/jni/quickjs/quickjs.c
@@ -0,0 +1,53312 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2020 Fabrice Bellard
+ * Copyright (c) 2017-2020 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__)
+#include
+#endif
+
+#include "cutils.h"
+#include "list.h"
+#include "quickjs.h"
+#include "libregexp.h"
+#ifdef CONFIG_BIGNUM
+#include "libbf.h"
+#endif
+
+#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
+ */
+//#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_PROMISE
+//#define DUMP_READ_OBJECT
+
+/* 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) */
+#ifdef CONFIG_BIGNUM
+ JS_CLASS_BIG_INT64_ARRAY, /* u.array (typed_array) */
+ JS_CLASS_BIG_UINT64_ARRAY, /* u.array (typed_array) */
+#endif
+ JS_CLASS_FLOAT32_ARRAY, /* u.array (typed_array) */
+ JS_CLASS_FLOAT64_ARRAY, /* u.array (typed_array) */
+ JS_CLASS_DATAVIEW, /* u.typed_array */
+#ifdef CONFIG_BIGNUM
+ JS_CLASS_BIG_INT, /* u.object_data */
+ JS_CLASS_BIG_FLOAT, /* u.object_data */
+ JS_CLASS_FLOAT_ENV, /* u.float_env */
+ JS_CLASS_BIG_DECIMAL, /* u.object_data */
+ JS_CLASS_OPERATOR_SET, /* u.operator_set */
+#endif
+ 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_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;
+
+#define JS_MAX_LOCAL_VARS 65536
+#define JS_STACK_SIZE_MAX 65536
+#define JS_STRING_LEN_MAX ((1 << 30) - 1)
+
+#define __exception __attribute__((warn_unused_result))
+
+typedef struct JSShape JSShape;
+typedef struct JSString JSString;
+typedef struct JSString JSAtomStruct;
+
+typedef enum {
+ JS_GC_PHASE_NONE,
+ JS_GC_PHASE_DECREF,
+ JS_GC_PHASE_REMOVE_CYCLES,
+} JSGCPhaseEnum;
+
+typedef enum OPCodeEnum OPCodeEnum;
+
+#ifdef CONFIG_BIGNUM
+/* function pointers are used for numeric operations so that it is
+ possible to remove some numeric types */
+typedef struct {
+ JSValue (*to_string)(JSContext *ctx, JSValueConst val);
+ JSValue (*from_string)(JSContext *ctx, const char *buf,
+ int radix, int flags, slimb_t *pexponent);
+ int (*unary_arith)(JSContext *ctx,
+ JSValue *pres, OPCodeEnum op, JSValue op1);
+ int (*binary_arith)(JSContext *ctx, OPCodeEnum op,
+ JSValue *pres, JSValue op1, JSValue op2);
+ int (*compare)(JSContext *ctx, OPCodeEnum op,
+ JSValue op1, JSValue op2);
+ /* only for bigfloat: */
+ JSValue (*mul_pow10_to_float64)(JSContext *ctx, const bf_t *a,
+ int64_t exponent);
+ int (*mul_pow10)(JSContext *ctx, JSValue *sp);
+} JSNumericOperations;
+#endif
+
+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;
+#ifdef DUMP_LEAKS
+ struct list_head string_list; /* list of JSString.link */
+#endif
+ /* stack limitation */
+ const uint8_t *stack_top;
+ size_t stack_size; /* in bytes */
+
+ JSValue current_exception;
+ /* 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;
+ JSModuleLoaderFunc *module_loader_func;
+ void *module_loader_opaque;
+
+ BOOL can_block : 8; /* TRUE if Atomics.wait can block */
+ /* used to allocate, free and clone SharedArrayBuffers */
+ JSSharedArrayBufferFunctions sab_funcs;
+
+ /* Shape hash table */
+ int shape_hash_bits;
+ int shape_hash_size;
+ int shape_hash_count; /* number of hashed shapes */
+ JSShape **shape_hash;
+#ifdef CONFIG_BIGNUM
+ bf_context_t bf_ctx;
+ JSNumericOperations bigint_ops;
+ JSNumericOperations bigfloat_ops;
+ JSNumericOperations bigdecimal_ops;
+ uint32_t operator_count;
+#endif
+ 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_STRIP (1 << 1)
+#define JS_MODE_MATH (1 << 2)
+
+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.link */
+ const uint8_t *cur_pc; /* only used in bytecode functions : PC of the
+ instruction after the call */
+ int arg_count;
+ int js_mode; /* 0 or JS_MODE_MATH 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,
+} 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 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 */
+
+ /* 0 : the JSVarRef is on the stack. header.link is an element
+ of JSStackFrame.var_ref_list.
+ 1 : the JSVarRef is detached. header.link has the normal meanning
+ */
+ uint8_t is_detached : 1;
+ uint8_t is_arg : 1;
+ uint16_t var_idx; /* index of the corresponding function variable on
+ the stack */
+ };
+ };
+ JSValue *pvalue; /* pointer to the value, either on the stack or
+ to 'value' */
+ JSValue value; /* used when the variable is no longer on the stack */
+} JSVarRef;
+
+#ifdef CONFIG_BIGNUM
+typedef struct JSFloatEnv {
+ limb_t prec;
+ bf_flags_t flags;
+ unsigned int status;
+} JSFloatEnv;
+
+/* the same structure is used for big integers and big floats. Big
+ integers are never infinite or NaNs */
+typedef struct JSBigFloat {
+ JSRefCountHeader header; /* must come first, 32-bit */
+ bf_t num;
+} JSBigFloat;
+
+typedef struct JSBigDecimal {
+ JSRefCountHeader header; /* must come first, 32-bit */
+ bfdec_t num;
+} JSBigDecimal;
+#endif
+
+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;
+#ifdef CONFIG_BIGNUM
+ bf_context_t *bf_ctx; /* points to rt->bf_ctx, shared by all contexts */
+ JSFloatEnv fp_env; /* global FP environment */
+ BOOL bignum_ext : 8; /* enable math mode */
+ BOOL allow_operator_overloading : 8;
+#endif
+ /* when the counter reaches zero, JSRutime.interrupt_handler is called */
+ int interrupt_counter;
+ BOOL is_error_property_enabled;
+
+ 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,
+};
+
+enum {
+ JS_ATOM_HASH_SYMBOL,
+ JS_ATOM_HASH_PRIVATE,
+};
+
+typedef enum {
+ JS_ATOM_KIND_STRING,
+ JS_ATOM_KIND_SYMBOL,
+ JS_ATOM_KIND_PRIVATE,
+} JSAtomKindEnum;
+
+#define JS_ATOM_HASH_MASK ((1 << 30) - 1)
+
+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 = 0, atom_type = 3,
+ for JS_ATOM_TYPE_PRIVATE: hash = 1, 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 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 : 3; /* see JSVarKindEnum */
+ /* 9 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;
+
+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_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;
+
+typedef struct JSVarDef {
+ JSAtom var_name;
+ int scope_level; /* index into fd->scopes of this variable lexical scope */
+ int scope_next; /* index into fd->vars of the next variable in the
+ * same or enclosing lexical scope */
+ uint8_t is_func_var : 1; /* used for the function self reference */
+ uint8_t is_const : 1;
+ uint8_t is_lexical : 1;
+ uint8_t is_captured : 1;
+ 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_or_scope_idx : 24; /* only used during compilation */
+} 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 backtrace_barrier : 1; /* stop backtrace on this function */
+ uint8_t read_only_bytecode : 1;
+ /* XXX: 4 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 line_num;
+ 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;
+ BOOL is_array;
+ uint32_t array_length;
+ uint32_t idx;
+} 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 {
+ JSValue this_val; /* 'this' generator argument */
+ int argc; /* number of function arguments */
+ BOOL throw_flag; /* used to throw an exception in JS_CallInternal() */
+ JSStackFrame frame;
+} JSAsyncFunctionState;
+
+/* XXX: could use an object instead to avoid the
+ JS_TAG_ASYNC_FUNCTION tag for the GC */
+typedef struct JSAsyncFunctionData {
+ JSGCObjectHeader header; /* must come first */
+ JSValue resolving_funcs[2];
+ BOOL is_active; /* true if the async function state is valid */
+ JSAsyncFunctionState func_state;
+} JSAsyncFunctionData;
+
+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 */
+} 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 */
+ JSAtom import_name;
+ int req_module_idx; /* in req_module_entries */
+} JSImportEntry;
+
+struct JSModuleDef {
+ JSRefCountHeader header; /* must come first, 32-bit */
+ 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 resolved : 8;
+ BOOL func_created : 8;
+ BOOL instantiated : 8;
+ BOOL evaluated : 8;
+ BOOL eval_mark : 8; /* temporary use during js_evaluate_module() */
+ /* 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 */
+};
+
+typedef struct JSJobEntry {
+ struct list_head link;
+ JSContext *ctx;
+ 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 {
+ uint32_t prop_hash_end[0]; /* hash table of size hash_mask + 1
+ before the start of the structure. */
+ 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 */
+ uint8_t is_constructor : 1; /* TRUE if object is a constructor function */
+ uint8_t is_uncatchable_error : 1; /* if TRUE, error is not catchable */
+ uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */
+ uint16_t class_id; /* see JS_CLASS_x */
+ };
+ };
+ /* byte offsets: 16/24 */
+ JSShape *shape; /* prototype and property names + flag */
+ JSProperty *prop; /* array of properties */
+ /* byte offsets: 24/40 */
+ struct JSMapRecord *first_weak_ref; /* XXX: use a bit and an external hash table? */
+ /* byte offsets: 28/48 */
+ 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 */
+#ifdef CONFIG_BIGNUM
+ struct JSFloatEnv *float_env; /* JS_CLASS_FLOAT_ENV */
+ struct JSOperatorSetData *operator_set; /* JS_CLASS_OPERATOR_SET */
+#endif
+ 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 JSAsyncFunctionData *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 */
+ 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;
+ /* byte sizes: 40/48/72 */
+};
+enum {
+ 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);
+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_DumpValueShort(JSRuntime *rt,
+ JSValueConst val);
+static __maybe_unused void JS_DumpValue(JSContext *ctx, JSValueConst val);
+static __maybe_unused void JS_PrintValue(JSContext *ctx,
+ const char *str,
+ JSValueConst val);
+static __maybe_unused void JS_DumpShapes(JSRuntime *rt);
+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);
+#ifdef CONFIG_BIGNUM
+static void js_operator_set_finalizer(JSRuntime *rt, JSValue val);
+static void js_operator_set_mark(JSRuntime *rt, JSValueConst val,
+ JS_MarkFunc *mark_func);
+#endif
+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_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, JSValue op1, JSValue 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);
+#ifdef CONFIG_BIGNUM
+static void js_float_env_finalizer(JSRuntime *rt, JSValue val);
+static JSValue JS_NewBigFloat(JSContext *ctx);
+static inline bf_t *JS_GetBigFloat(JSValueConst val)
+{
+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ return &p->num;
+}
+static JSValue JS_NewBigDecimal(JSContext *ctx);
+static inline bfdec_t *JS_GetBigDecimal(JSValueConst val)
+{
+ JSBigDecimal *p = JS_VALUE_GET_PTR(val);
+ return &p->num;
+}
+static JSValue JS_NewBigInt(JSContext *ctx);
+static inline bf_t *JS_GetBigInt(JSValueConst val)
+{
+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ return &p->num;
+}
+static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
+ BOOL convert_to_safe_integer);
+static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val);
+static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val);
+static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val);
+static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf);
+static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val);
+static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
+ BOOL allow_null_or_undefined);
+static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val);
+#endif
+JSValue JS_ThrowOutOfMemory(JSContext *ctx);
+static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx);
+static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj);
+static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
+ JSValueConst proto_val, BOOL throw_flag);
+static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj);
+static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj);
+static int js_proxy_isArray(JSContext *ctx, JSValueConst obj);
+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, const JSString *p2, int len);
+static void reset_weak_ref(JSRuntime *rt, JSObject *p);
+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 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 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(JSContext *ctx, 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);
+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 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 async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s,
+ JS_MarkFunc *mark_func);
+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 void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s);
+static int js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
+static int js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
+ void *opaque);
+static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p,
+ JSAtom atom, void *opaque);
+void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag);
+
+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);
+}
+
+#ifdef CONFIG_BIGNUM
+/* called by libbf */
+static void *js_bf_realloc(void *opaque, void *ptr, size_t size)
+{
+ JSRuntime *rt = opaque;
+ return js_realloc_rt(rt, ptr, size);
+}
+#endif /* CONFIG_BIGNUM */
+
+/* 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';
+}
+
+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 */
+#ifdef CONFIG_BIGNUM
+ { 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 */
+#endif
+ { 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 */
+#ifdef CONFIG_BIGNUM
+ { JS_ATOM_BigInt, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_INT */
+ { JS_ATOM_BigFloat, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_FLOAT */
+ { JS_ATOM_BigFloatEnv, js_float_env_finalizer, NULL }, /* JS_CLASS_FLOAT_ENV */
+ { JS_ATOM_BigDecimal, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_DECIMAL */
+ { JS_ATOM_OperatorSet, js_operator_set_finalizer, js_operator_set_mark }, /* JS_CLASS_OPERATOR_SET */
+#endif
+ { 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;
+}
+
+#ifdef CONFIG_BIGNUM
+static JSValue JS_ThrowUnsupportedOperation(JSContext *ctx)
+{
+ return JS_ThrowTypeError(ctx, "unsupported operation");
+}
+
+static JSValue invalid_to_string(JSContext *ctx, JSValueConst val)
+{
+ return JS_ThrowUnsupportedOperation(ctx);
+}
+
+static JSValue invalid_from_string(JSContext *ctx, const char *buf,
+ int radix, int flags, slimb_t *pexponent)
+{
+ return JS_NAN;
+}
+
+static int invalid_unary_arith(JSContext *ctx,
+ JSValue *pres, OPCodeEnum op, JSValue op1)
+{
+ JS_FreeValue(ctx, op1);
+ JS_ThrowUnsupportedOperation(ctx);
+ return -1;
+}
+
+static int invalid_binary_arith(JSContext *ctx, OPCodeEnum op,
+ JSValue *pres, JSValue op1, JSValue op2)
+{
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ JS_ThrowUnsupportedOperation(ctx);
+ return -1;
+}
+
+static JSValue invalid_mul_pow10_to_float64(JSContext *ctx, const bf_t *a,
+ int64_t exponent)
+{
+ return JS_ThrowUnsupportedOperation(ctx);
+}
+
+static int invalid_mul_pow10(JSContext *ctx, JSValue *sp)
+{
+ JS_ThrowUnsupportedOperation(ctx);
+ return -1;
+}
+
+static void set_dummy_numeric_ops(JSNumericOperations *ops)
+{
+ ops->to_string = invalid_to_string;
+ ops->from_string = invalid_from_string;
+ ops->unary_arith = invalid_unary_arith;
+ ops->binary_arith = invalid_binary_arith;
+ ops->mul_pow10_to_float64 = invalid_mul_pow10_to_float64;
+ ops->mul_pow10 = invalid_mul_pow10;
+}
+
+#endif /* CONFIG_BIGNUM */
+
+#if !defined(CONFIG_STACK_CHECK)
+/* no stack limitation */
+static inline uint8_t *js_get_stack_pointer(void)
+{
+ return NULL;
+}
+
+static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
+{
+ return FALSE;
+}
+#else
+/* Note: OS and CPU dependent */
+static inline uint8_t *js_get_stack_pointer(void)
+{
+ return __builtin_frame_address(0);
+}
+
+static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
+{
+ size_t size;
+ size = rt->stack_top - js_get_stack_pointer();
+ return unlikely((size + alloca_size) > rt->stack_size);
+}
+#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;
+
+#ifdef CONFIG_BIGNUM
+ bf_context_init(&rt->bf_ctx, js_bf_realloc, rt);
+ set_dummy_numeric_ops(&rt->bigint_ops);
+ set_dummy_numeric_ops(&rt->bigfloat_ops);
+ set_dummy_numeric_ops(&rt->bigdecimal_ops);
+#endif
+
+ 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;
+
+#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_top = js_get_stack_pointer();
+ rt->stack_size = JS_DEFAULT_STACK_SIZE;
+ rt->current_exception = JS_NULL;
+
+ 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 inline size_t js_def_malloc_usable_size(void *ptr)
+{
+#if defined(__APPLE__)
+ return malloc_size(ptr);
+#elif defined(_WIN32)
+ return _msize(ptr);
+#elif defined(EMSCRIPTEN)
+ return 0;
+#elif defined(__linux__)
+ return 0; //malloc_usable_size(ptr);
+#else
+ /* change this to `return 0;` if compilation fails */
+ return 0; //malloc_usable_size(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,
+#if defined(__APPLE__)
+ malloc_size,
+#elif defined(_WIN32)
+ (size_t (*)(const void *))_msize,
+#elif defined(EMSCRIPTEN)
+ NULL,
+#elif defined(__linux__)
+ NULL, //(size_t (*)(const void *))malloc_usable_size,
+#else
+ /* change this to `NULL,` if compilation fails */
+ NULL, //malloc_usable_size,
+#endif
+};
+
+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;
+}
+
+/* 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->ctx = 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' */
+int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx)
+{
+ JSContext *ctx;
+ JSJobEntry *e;
+ JSValue res;
+ int i, ret;
+
+ if (list_empty(&rt->job_list)) {
+ *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->ctx;
+ res = e->job_func(e->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);
+ *pctx = 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_free_rt(rt, e);
+ }
+ init_list_head(&rt->job_list);
+
+ JS_RunGC(rt);
+
+#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));
+
+ /* 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 CONFIG_BIGNUM
+ bf_context_end(&rt->bf_ctx);
+#endif
+
+#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_SYMBOL) {
+ 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);
+#ifdef CONFIG_BIGNUM
+ ctx->bf_ctx = &rt->bf_ctx;
+ ctx->fp_env.prec = 113;
+ ctx->fp_env.flags = bf_set_exp_bits(15) | BF_RNDN | BF_FLAG_SUBNORMAL;
+#endif
+ 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);
+#ifdef CONFIG_BIGNUM
+ JS_AddIntrinsicBigInt(ctx);
+#endif
+ 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,
+ JS_FREE_MODULE_NOT_EVALUATED,
+} 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) ||
+ (flag == JS_FREE_MODULE_NOT_EVALUATED && !m->evaluated)) {
+ js_free_module_def(ctx, 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;
+
+ /* modules are not seen by the GC, so we directly mark the objects
+ referenced by each module */
+ list_for_each(el, &ctx->loaded_modules) {
+ JSModuleDef *m = list_entry(el, JSModuleDef, link);
+ js_mark_module_def(rt, 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;
+}
+
+void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size)
+{
+ rt->stack_size = stack_size;
+}
+
+static inline BOOL is_strict_mode(JSContext *ctx)
+{
+ JSStackFrame *sf = ctx->rt->current_stack_frame;
+ return (sf && (sf->js_mode & JS_MODE_STRICT));
+}
+
+#ifdef CONFIG_BIGNUM
+static inline BOOL is_math_mode(JSContext *ctx)
+{
+ JSStackFrame *sf = ctx->rt->current_stack_frame;
+ return (sf && (sf->js_mode & JS_MODE_MATH));
+}
+#endif
+
+/* 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;
+ if (p->is_wide_char)
+ c = p->u.str16[0];
+ else
+ c = p->u.str8[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++) {
+ if (p->is_wide_char)
+ c = p->u.str16[i];
+ else
+ c = p->u.str8[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 __maybe_unused void JS_DumpString(JSRuntime *rt,
+ const JSString *p)
+{
+ int i, c, 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++) {
+ if (p->is_wide_char)
+ c = p->u.str16[i];
+ else
+ c = p->u.str8[i];
+ if (c == sep || c == '\\') {
+ putchar('\\');
+ putchar(c);
+ } else if (c >= ' ' && c <= 126) {
+ putchar(c);
+ } else if (c == '\n') {
+ putchar('\\');
+ putchar('n');
+ } else {
+ printf("\\u%04x", c);
+ }
+ }
+ 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:
+ switch(p->hash) {
+ case JS_ATOM_HASH_SYMBOL:
+ return JS_ATOM_KIND_SYMBOL;
+ case JS_ATOM_HASH_PRIVATE:
+ return JS_ATOM_KIND_PRIVATE;
+ default:
+ abort();
+ }
+ 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, str, 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 = JS_ATOM_HASH_SYMBOL;
+ } 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);
+}
+
+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
+ 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);
+}
+
+JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len)
+{
+ JSValue val;
+
+ if (len == 0 || !is_digit(*str)) {
+ 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;
+ snprintf(buf, sizeof(buf), "%u", n);
+ val = JS_NewString(ctx, buf);
+ 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;
+ snprintf(buf, sizeof(buf), "%" PRId64 , n);
+ val = JS_NewString(ctx, buf);
+ 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++) {
+ if (str->is_wide_char)
+ c = str->u.str16[i];
+ else
+ c = str->u.str8[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)) {
+ snprintf(buf, sizeof(buf), "%u", __JS_AtomToUInt32(atom));
+ return JS_NewString(ctx, buf);
+ } 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, len, 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;
+ p = p1;
+ len = p->len;
+ if (p->is_wide_char) {
+ const uint16_t *r = p->u.str16, *r_end = p->u.str16 + len;
+ if (r >= r_end)
+ return JS_UNDEFINED;
+ c = *r;
+ if (c == '-') {
+ if (r >= r_end)
+ return JS_UNDEFINED;
+ r++;
+ c = *r;
+ /* -0 case is specific */
+ if (c == '0' && len == 2)
+ goto minus_zero;
+ }
+ /* XXX: should test NaN, but the tests do not check it */
+ if (!is_num(c)) {
+ /* XXX: String should be normalized, therefore 8-bit only */
+ const uint16_t nfinity16[7] = { 'n', 'f', 'i', 'n', 'i', 't', 'y' };
+ if (!(c =='I' && (r_end - r) == 8 &&
+ !memcmp(r + 1, nfinity16, sizeof(nfinity16))))
+ return JS_UNDEFINED;
+ }
+ } else {
+ const uint8_t *r = p->u.str8, *r_end = p->u.str8 + len;
+ if (r >= r_end)
+ return JS_UNDEFINED;
+ c = *r;
+ if (c == '-') {
+ if (r >= r_end)
+ return JS_UNDEFINED;
+ r++;
+ c = *r;
+ /* -0 case is specific */
+ if (c == '0' && len == 2) {
+ minus_zero:
+ return __JS_NewFloat64(ctx, -0.0);
+ }
+ }
+ if (!is_num(c)) {
+ if (!(c =='I' && (r_end - r) == 8 &&
+ !memcmp(r + 1, "nfinity", 7)))
+ return JS_UNDEFINED;
+ }
+ }
+ /* XXX: bignum: would be better to only accept integer to avoid
+ relying on current floating point precision */
+ /* 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_SYMBOL) ||
+ p->atom_type == JS_ATOM_TYPE_GLOBAL_SYMBOL) &&
+ !(p->len == 0 && p->is_wide_char != 0));
+}
+
+static __maybe_unused void print_atom(JSContext *ctx, JSAtom atom)
+{
+ char buf[ATOM_GET_STR_BUF_SIZE];
+ const char *p;
+ int i;
+
+ /* XXX: should handle embedded null characters */
+ /* XXX: should move encoding code to JS_AtomGetStr */
+ p = JS_AtomGetStr(ctx, buf, sizeof(buf), atom);
+ for (i = 0; p[i]; i++) {
+ int c = (unsigned char)p[i];
+ if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+ (c == '_' || c == '$') || (c >= '0' && c <= '9' && i > 0)))
+ break;
+ }
+ if (i > 0 && p[i] == '\0') {
+ printf("%s", p);
+ } else {
+ putchar('"');
+ printf("%.*s", i, p);
+ for (; p[i]; i++) {
+ int c = (unsigned char)p[i];
+ if (c == '\"' || c == '\\') {
+ putchar('\\');
+ putchar(c);
+ } else if (c >= ' ' && c <= 126) {
+ putchar(c);
+ } else if (c == '\n') {
+ putchar('\\');
+ putchar('n');
+ } else {
+ printf("\\u%04x", c);
+ }
+ }
+ putchar('\"');
+ }
+}
+
+/* free with JS_FreeCString() */
+const char *JS_AtomToCString(JSContext *ctx, JSAtom atom)
+{
+ JSValue str;
+ const char *cstr;
+
+ str = JS_AtomToString(ctx, atom);
+ if (JS_IsException(str))
+ return NULL;
+ cstr = JS_ToCString(ctx, 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];
+ snprintf(buf, sizeof(buf), "%u", n);
+ 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 */
+
+/* a new class ID is allocated if *pclass_id != 0 */
+JSClassID JS_NewClassID(JSClassID *pclass_id)
+{
+ JSClassID class_id;
+ /* XXX: make it thread safe */
+ class_id = *pclass_id;
+ if (class_id == 0) {
+ class_id = js_class_id_alloc++;
+ *pclass_id = class_id;
+ }
+ return 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 < 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(JSContext *ctx, const uint8_t *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_string16(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(ctx, &ch8, 1);
+ } else {
+ uint16_t ch16 = c;
+ return js_new_string16(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(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(ctx, 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 */
+ c -= 0x10000;
+ if (string_buffer_putc16(s, (c >> 10) + 0xd800))
+ return -1;
+ c = (c & 0x3ff) + 0xdc00;
+ }
+ return string_buffer_putc16(s, c);
+}
+
+static int string_get(const JSString *p, int idx) {
+ return p->is_wide_char ? p->u.str16[idx] : p->u.str8[idx];
+}
+
+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 (c >= 0xd800 && c < 0xdc00 && idx < p->len) {
+ c1 = p->u.str16[idx];
+ if (c1 >= 0xdc00 && c1 < 0xe000) {
+ c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
+ 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)) {
+ 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;
+ p = p_start;
+ while (p < p_end && *p < 128)
+ p++;
+ len1 = p - p_start;
+ if (len1 > JS_STRING_LEN_MAX)
+ return JS_ThrowInternalError(ctx, "string too long");
+ if (p == p_end) {
+ /* ASCII string */
+ return js_new_string8(ctx, (const uint8_t *)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 */
+ c -= 0x10000;
+ string_buffer_putc16(b, (c >> 10) + 0xd800);
+ c = (c & 0x3ff) + 0xdc00;
+ } 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_NewString(JSContext *ctx, const char *str)
+{
+ return JS_NewStringLen(ctx, str, strlen(str));
+}
+
+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 (c >= 0xd800 && c < 0xdc00) {
+ if (pos < len && !cesu8) {
+ c1 = src[pos];
+ if (c1 >= 0xdc00 && c1 < 0xe000) {
+ pos++;
+ /* surrogate pair */
+ c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
+ } 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 = (JSString *)(void *)(ptr - offsetof(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, const JSString *p2, int len)
+{
+ int res;
+
+ if (likely(!p1->is_wide_char)) {
+ if (likely(!p2->is_wide_char))
+ res = memcmp(p1->u.str8, p2->u.str8, len);
+ else
+ res = -memcmp16_8(p2->u.str16, p1->u.str8, len);
+ } else {
+ if (!p2->is_wide_char)
+ res = memcmp16_8(p1->u.str16, p2->u.str8, len);
+ else
+ res = memcmp16(p1->u.str16, p2->u.str16, 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, p2, 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);
+}
+
+/* op1 and op2 are converted to strings. For convience, op1 or op2 =
+ JS_EXCEPTION are accepted and return JS_EXCEPTION. */
+static JSValue JS_ConcatString(JSContext *ctx, JSValue op1, JSValue op2)
+{
+ JSValue ret;
+ JSString *p1, *p2;
+
+ if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_STRING)) {
+ 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)) {
+ op2 = JS_ToStringFree(ctx, op2);
+ if (JS_IsException(op2)) {
+ JS_FreeValue(ctx, op1);
+ return JS_EXCEPTION;
+ }
+ }
+ p1 = JS_VALUE_GET_STRING(op1);
+ p2 = JS_VALUE_GET_STRING(op2);
+
+ /* XXX: could also check if p1 is empty */
+ if (p2->len == 0) {
+ goto ret_op1;
+ }
+ if (p1->header.ref_count == 1 && p1->is_wide_char == p2->is_wide_char
+ && js_malloc_usable_size(ctx, p1) >= sizeof(*p1) + ((p1->len + p2->len) << p2->is_wide_char) + 1 - p1->is_wide_char) {
+ /* Concatenate in place in available space at the end of p1 */
+ if (p1->is_wide_char) {
+ memcpy(p1->u.str16 + p1->len, p2->u.str16, p2->len << 1);
+ p1->len += p2->len;
+ } else {
+ memcpy(p1->u.str8 + p1->len, p2->u.str8, p2->len);
+ p1->len += p2->len;
+ p1->u.str8[p1->len] = '\0';
+ }
+ ret_op1:
+ JS_FreeValue(ctx, op2);
+ return op1;
+ }
+ ret = JS_ConcatString1(ctx, p1, p2);
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ return ret;
+}
+
+/* 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 void *get_alloc_from_shape(JSShape *sh)
+{
+ return sh->prop_hash_end - ((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(sh->prop_hash_end - hash_size, 0, sizeof(sh->prop_hash_end[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;
+
+ 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;
+ if (new_hash_size != (sh->prop_hash_mask + 1)) {
+ JSShape *old_sh;
+ /* 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);
+ /* copy all the fields and the 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);
+ new_hash_mask = new_hash_size - 1;
+ sh->prop_hash_mask = new_hash_mask;
+ memset(sh->prop_hash_end - new_hash_size, 0,
+ sizeof(sh->prop_hash_end[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 = sh->prop_hash_end[-h - 1];
+ sh->prop_hash_end[-h - 1] = i + 1;
+ }
+ }
+ js_free(ctx, get_alloc_from_shape(old_sh));
+ } else {
+ /* only resize the properties */
+ list_del(&sh->header.link);
+ sh_alloc = js_realloc(ctx, get_alloc_from_shape(sh),
+ get_shape_size(new_hash_size, new_size));
+ if (unlikely(!sh_alloc)) {
+ /* insert again in the GC list */
+ list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
+ return -1;
+ }
+ sh = get_shape_from_alloc(sh_alloc, new_hash_size);
+ list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
+ }
+ *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(sh->prop_hash_end - new_hash_size, 0,
+ sizeof(sh->prop_hash_end[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 = sh->prop_hash_end[-h - 1];
+ sh->prop_hash_end[-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 = sh->prop_hash_end[-h - 1];
+ sh->prop_hash_end[-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->is_uncatchable_error = 0;
+ p->tmp_mark = 0;
+ p->first_weak_ref = NULL;
+ 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 ... 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:
+#ifdef CONFIG_BIGNUM
+ case JS_CLASS_BIG_INT:
+ case JS_CLASS_BIG_FLOAT:
+ case JS_CLASS_BIG_DECIMAL:
+#endif
+ 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:
+#ifdef CONFIG_BIGNUM
+ case JS_CLASS_BIG_INT:
+ case JS_CLASS_BIG_FLOAT:
+ case JS_CLASS_BIG_DECIMAL:
+#endif
+ 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:
+#ifdef CONFIG_BIGNUM
+ case JS_CLASS_BIG_INT:
+ case JS_CLASS_BIG_FLOAT:
+ case JS_CLASS_BIG_DECIMAL:
+#endif
+ JS_FreeValue(ctx, p->u.object_data);
+ p->u.object_data = val;
+ 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);
+ 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 = sh->prop_hash_end[-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 = sh->prop_hash_end[-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);
+ remove_gc_object(&var_ref->header);
+ } else {
+ list_del(&var_ref->header.link); /* still on the stack */
+ }
+ 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 && var_ref->is_detached) {
+ 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;
+ JS_FreeValueRT(rt, it->obj);
+ 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;
+
+ if (unlikely(p->first_weak_ref)) {
+ reset_weak_ref(rt, p);
+ }
+
+ 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 && p->header.ref_count != 0) {
+ list_add_tail(&p->header.link, &rt->gc_zero_ref_count_list);
+ } else {
+ js_free_rt(rt, p);
+ }
+}
+
+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;
+ 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_OBJECT:
+ case JS_TAG_FUNCTION_BYTECODE:
+ {
+ 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);
+ if (rt->gc_phase == JS_GC_PHASE_NONE) {
+ free_zero_refcount(rt);
+ }
+ }
+ }
+ break;
+ case JS_TAG_MODULE:
+ abort(); /* never freed here */
+ break;
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_INT:
+ case JS_TAG_BIG_FLOAT:
+ {
+ JSBigFloat *bf = JS_VALUE_GET_PTR(v);
+ bf_delete(&bf->num);
+ js_free_rt(rt, bf);
+ }
+ break;
+ case JS_TAG_BIG_DECIMAL:
+ {
+ JSBigDecimal *bf = JS_VALUE_GET_PTR(v);
+ bfdec_delete(&bf->num);
+ js_free_rt(rt, bf);
+ }
+ break;
+#endif
+ case JS_TAG_SYMBOL:
+ {
+ JSAtomStruct *p = JS_VALUE_GET_PTR(v);
+ JS_FreeAtomStruct(rt, p);
+ }
+ break;
+ default:
+ printf("__JS_FreeValue: unknown tag=%d\n", tag);
+ abort();
+ }
+}
+
+void __JS_FreeValue(JSContext *ctx, JSValue v)
+{
+ __JS_FreeValueRT(ctx->rt, v);
+}
+
+/* garbage collection */
+
+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:
+ 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) {
+ if (pr->u.var_ref->is_detached) {
+ /* 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;
+ /* only detached variable referenced are taken into account */
+ assert(var_ref->is_detached);
+ JS_MarkValue(rt, *var_ref->pvalue, mark_func);
+ }
+ break;
+ case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
+ {
+ JSAsyncFunctionData *s = (JSAsyncFunctionData *)gp;
+ if (s->is_active)
+ async_func_mark(rt, &s->func_state, 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;
+ 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. 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:
+#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);
+ js_free_rt(rt, p);
+ }
+
+ init_list_head(&rt->gc_zero_ref_count_list);
+}
+
+void JS_RunGC(JSRuntime *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);
+}
+
+/* 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;
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_INT:
+ case JS_TAG_BIG_FLOAT:
+ case JS_TAG_BIG_DECIMAL:
+ /* should track JSBigFloat usage */
+ break;
+#endif
+ }
+}
+
+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 */
+#ifdef CONFIG_BIGNUM
+ case JS_CLASS_BIG_INT: /* u.object_data */
+ case JS_CLASS_BIG_FLOAT: /* u.object_data */
+ case JS_CLASS_BIG_DECIMAL: /* u.object_data */
+#endif
+ 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 */
+#ifdef CONFIG_BIGNUM
+ case JS_CLASS_BIG_INT64_ARRAY: /* u.typed_array / u.array */
+ case JS_CLASS_BIG_UINT64_ARRAY: /* u.typed_array / u.array */
+#endif
+ 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 */
+#ifdef CONFIG_BIGNUM
+ case JS_CLASS_FLOAT_ENV: /* u.float_env */
+#endif
+ 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 -- "
+#ifdef CONFIG_BIGNUM
+ "BigNum "
+#endif
+ CONFIG_VERSION " version, %d-bit, malloc limit: %"PRId64"\n\n",
+ (int)sizeof(void *) * 8, (int64_t)(ssize_t)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]) {
+ 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), js_std_class_def[class_id - 1].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;
+ 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_NULL;
+ return val;
+}
+
+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;
+}
+
+static int find_line_num(JSContext *ctx, JSFunctionBytecode *b,
+ uint32_t pc_value)
+{
+ const uint8_t *p_end, *p;
+ int new_line_num, line_num, pc, v, ret;
+ unsigned int op;
+
+ if (!b->has_debug || !b->debug.pc2line_buf) {
+ /* function was stripped */
+ return -1;
+ }
+
+ p = b->debug.pc2line_buf;
+ p_end = p + b->debug.pc2line_len;
+ pc = 0;
+ line_num = b->debug.line_num;
+ while (p < p_end) {
+ op = *p++;
+ if (op == 0) {
+ uint32_t val;
+ 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) {
+ fail:
+ /* should never happen */
+ return b->debug.line_num;
+ }
+ 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;
+ }
+ if (pc_value < pc)
+ return line_num;
+ line_num = new_line_num;
+ }
+ return line_num;
+}
+
+/* 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)
+/* only taken into account if filename is provided */
+#define JS_BACKTRACE_FLAG_SINGLE_LEVEL (1 << 1)
+
+/* 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 backtrace_flags)
+{
+ JSStackFrame *sf;
+ JSValue str;
+ DynBuf dbuf;
+ const char *func_name_str;
+ const char *str1;
+ JSObject *p;
+ BOOL backtrace_barrier;
+
+ js_dbuf_init(ctx, &dbuf);
+ if (filename) {
+ dbuf_printf(&dbuf, " at %s", filename);
+ if (line_num != -1)
+ dbuf_printf(&dbuf, ":%d", line_num);
+ dbuf_putc(&dbuf, '\n');
+ str = JS_NewString(ctx, filename);
+ JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, str,
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+ JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, JS_NewInt32(ctx, line_num),
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+ if (backtrace_flags & JS_BACKTRACE_FLAG_SINGLE_LEVEL)
+ goto done;
+ }
+ for(sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) {
+ 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);
+ backtrace_barrier = FALSE;
+ if (js_class_has_bytecode(p->class_id)) {
+ JSFunctionBytecode *b;
+ const char *atom_str;
+ int line_num1;
+
+ b = p->u.func.function_bytecode;
+ backtrace_barrier = b->backtrace_barrier;
+ if (b->has_debug) {
+ line_num1 = find_line_num(ctx, b,
+ sf->cur_pc - b->byte_code_buf - 1);
+ atom_str = JS_AtomToCString(ctx, b->debug.filename);
+ dbuf_printf(&dbuf, " (%s",
+ atom_str ? atom_str : "");
+ JS_FreeCString(ctx, atom_str);
+ if (line_num1 != -1)
+ dbuf_printf(&dbuf, ":%d", line_num1);
+ dbuf_putc(&dbuf, ')');
+ }
+ } else {
+ dbuf_printf(&dbuf, " (native)");
+ }
+ dbuf_putc(&dbuf, '\n');
+ /* stop backtrace if JS_EVAL_FLAG_BACKTRACE_BARRIER was used */
+ if (backtrace_barrier)
+ break;
+ }
+ done:
+ 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);
+ }
+ 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_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 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)) {
+ /* XXX: should set a specific flag to avoid catching */
+ JS_ThrowInternalError(ctx, "interrupted");
+ JS_SetUncatchableError(ctx, ctx->rt->current_exception, TRUE);
+ 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;
+ }
+}
+
+/* return -1 (exception) or TRUE/FALSE */
+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->class_id == JS_CLASS_PROXY))
+ return js_proxy_setPrototypeOf(ctx, obj, proto_val, throw_flag);
+ sh = p->shape;
+ if (sh->proto == proto)
+ return TRUE;
+ if (!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)) {
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_INT:
+ val = ctx->class_proto[JS_CLASS_BIG_INT];
+ break;
+ case JS_TAG_BIG_FLOAT:
+ val = ctx->class_proto[JS_CLASS_BIG_FLOAT];
+ break;
+ case JS_TAG_BIG_DECIMAL:
+ val = ctx->class_proto[JS_CLASS_BIG_DECIMAL];
+ break;
+#endif
+ 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:
+ 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 Proxy 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->class_id == JS_CLASS_PROXY)) {
+ val = js_proxy_getPrototypeOf(ctx, obj);
+ } else {
+ 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 proxy in the prototype chain */
+ if (unlikely(p->class_id == JS_CLASS_PROXY)) {
+ 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);
+}
+
+typedef int 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_InstantiateFunctionListItem, /* JS_AUTOINIT_ID_PROP */
+};
+
+static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop,
+ JSProperty *pr)
+{
+ int ret;
+ JSContext *realm;
+ JSAutoInitFunc *func;
+
+ realm = js_autoinit_get_realm(pr);
+ func = js_autoinit_func_table[js_autoinit_get_id(pr)];
+ ret = func(realm, p, prop, pr->u.init.opaque);
+ return ret;
+}
+
+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, ch;
+ idx = __JS_AtomToUInt32(prop);
+ if (idx < p1->len) {
+ if (p1->is_wide_char)
+ ch = p1->u.str16[idx];
+ else
+ ch = p1->u.str8[idx];
+ return js_new_string_char(ctx, ch);
+ }
+ } 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))
+ 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) {
+ goto typed_array_oob;
+ }
+ } 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;
+ typed_array_oob:
+ if (typed_array_is_detached(ctx, p))
+ return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+ 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;
+}
+
+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) {
+ brand = JS_NewSymbolFromAtom(ctx, JS_ATOM_brand, JS_ATOM_TYPE_PRIVATE);
+ if (JS_IsException(brand))
+ return -1;
+ /* if the brand is not present, add it */
+ 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 (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
+ JS_ThrowTypeErrorNotAnObject(ctx);
+ JS_FreeAtom(ctx, brand_atom);
+ return -1;
+ }
+ p1 = JS_VALUE_GET_OBJ(obj);
+ 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;
+ return 0;
+}
+
+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)) {
+ not_obj:
+ JS_ThrowTypeErrorNotAnObject(ctx);
+ return -1;
+ }
+ 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))
+ goto not_obj;
+ p = JS_VALUE_GET_OBJ(obj);
+ prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, (JSValue)brand));
+ if (!prs) {
+ JS_ThrowTypeError(ctx, "invalid brand on object");
+ return -1;
+ }
+ return 0;
+}
+
+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;
+}
+
+static void js_free_prop_enum(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;
+ 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_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) {
+ /* the implicit GetOwnProperty raises an exception if the
+ typed array is detached */
+ if ((flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY)) &&
+ (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
+ p->class_id <= JS_CLASS_FLOAT64_ARRAY) &&
+ typed_array_is_detached(ctx, p) &&
+ typed_array_get_length(ctx, p) != 0) {
+ JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+ return -1;
+ }
+ if (flags & JS_GPN_STRING_MASK) {
+ num_keys_count += p->u.array.count;
+ }
+ } 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_free_prop_enum(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) {
+ if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
+ num_keys_count++;
+ } else if (kind == JS_ATOM_KIND_STRING) {
+ str_keys_count++;
+ } else {
+ sym_keys_count++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* fill them */
+
+ atom_count = num_keys_count + str_keys_count + sym_keys_count;
+ /* avoid allocating 0 bytes */
+ tab_atom = js_malloc(ctx, sizeof(tab_atom[0]) * max_int(atom_count, 1));
+ if (!tab_atom) {
+ js_free_prop_enum(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) {
+ if (p->fast_array) {
+ if (flags & JS_GPN_STRING_MASK) {
+ for(i = 0; i < p->u.array.count; i++) {
+ tab_atom[num_index].atom = __JS_AtomFromUInt32(i);
+ if (tab_atom[num_index].atom == JS_ATOM_NULL) {
+ js_free_prop_enum(ctx, tab_exotic, exotic_count);
+ js_free_prop_enum(ctx, tab_atom, num_index);
+ return -1;
+ }
+ tab_atom[num_index].is_enumerable = TRUE;
+ num_index++;
+ }
+ }
+ }
+ if (exotic_count > 0) {
+ 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) {
+ 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 = atom;
+ tab_atom[j].is_enumerable = is_enumerable;
+ } 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))
+ 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;
+ if (p->class_id == JS_CLASS_ARRAY ||
+ p->class_id == JS_CLASS_ARGUMENTS)
+ desc->flags |= 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;
+ }
+ }
+ 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 -1;
+ if (typed_array_is_detached(ctx, p)) {
+ JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+ return -1;
+ }
+ }
+ }
+ } 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 (Proxy 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->class_id == JS_CLASS_PROXY))
+ return js_proxy_isExtensible(ctx, obj);
+ else
+ return p->extensible;
+}
+
+/* return -1 if exception (Proxy 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->class_id == JS_CLASS_PROXY))
+ return js_proxy_preventExtensions(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;
+ /* the detached array test was done in
+ JS_GetOwnPropertyInternal() */
+ 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, len;
+ /* fast path for array access */
+ p = JS_VALUE_GET_OBJ(this_obj);
+ idx = JS_VALUE_GET_INT(prop);
+ len = (uint32_t)p->u.array.count;
+ if (unlikely(idx >= len))
+ goto slow_path;
+ switch(p->class_id) {
+ case JS_CLASS_ARRAY:
+ case JS_CLASS_ARGUMENTS:
+ return JS_DupValue(ctx, p->u.array.u.values[idx]);
+ case JS_CLASS_INT8_ARRAY:
+ return JS_NewInt32(ctx, p->u.array.u.int8_ptr[idx]);
+ case JS_CLASS_UINT8C_ARRAY:
+ case JS_CLASS_UINT8_ARRAY:
+ return JS_NewInt32(ctx, p->u.array.u.uint8_ptr[idx]);
+ case JS_CLASS_INT16_ARRAY:
+ return JS_NewInt32(ctx, p->u.array.u.int16_ptr[idx]);
+ case JS_CLASS_UINT16_ARRAY:
+ return JS_NewInt32(ctx, p->u.array.u.uint16_ptr[idx]);
+ case JS_CLASS_INT32_ARRAY:
+ return JS_NewInt32(ctx, p->u.array.u.int32_ptr[idx]);
+ case JS_CLASS_UINT32_ARRAY:
+ return JS_NewUint32(ctx, p->u.array.u.uint32_ptr[idx]);
+#ifdef CONFIG_BIGNUM
+ case JS_CLASS_BIG_INT64_ARRAY:
+ return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]);
+ case JS_CLASS_BIG_UINT64_ARRAY:
+ return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]);
+#endif
+ case JS_CLASS_FLOAT32_ARRAY:
+ return __JS_NewFloat64(ctx, p->u.array.u.float_ptr[idx]);
+ case JS_CLASS_FLOAT64_ARRAY:
+ return __JS_NewFloat64(ctx, p->u.array.u.double_ptr[idx]);
+ default:
+ goto slow_path;
+ }
+ } else {
+ slow_path:
+ 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);
+ 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 = sh->prop_hash_end[-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 {
+ sh->prop_hash_end[-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; /* not configurable */
+ }
+ }
+ } 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, JSProperty *prop,
+ JSValue val, int flags)
+{
+ uint32_t len, idx, cur_len;
+ int i, ret;
+
+ ret = JS_ToArrayLengthFree(ctx, &len, val);
+ if (ret)
+ return -1;
+ 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;
+ }
+ prop->u.value = JS_NewUint32(ctx, len);
+ } else {
+ /* Note: length is always a uint32 because the object is an
+ array */
+ JS_ToUint32(ctx, &cur_len, prop->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;
+}
+
+/* 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)) {
+ 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) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ new_size += slack / sizeof(*new_array_prop);
+ p->u.array.u.values = new_array_prop;
+ p->u.array.u1.size = new_size;
+ }
+ p->u.array.u.values[new_len - 1] = val;
+ p->u.array.count = new_len;
+ return TRUE;
+}
+
+static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc)
+{
+ JS_FreeValue(ctx, desc->getter);
+ JS_FreeValue(ctx, desc->setter);
+ JS_FreeValue(ctx, desc->value);
+}
+
+/* generic (and slower) version of JS_SetProperty() for Reflect.set() */
+static int JS_SetPropertyGeneric(JSContext *ctx,
+ JSObject *p, JSAtom prop,
+ JSValue val, JSValueConst this_obj,
+ int flags)
+{
+ int ret;
+ JSPropertyDescriptor desc;
+
+ while (p != NULL) {
+ if (p->is_exotic) {
+ const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
+ if (em && em->set_property) {
+ JSValue obj1;
+ /* set_property can free the prototype */
+ obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+ ret = em->set_property(ctx, obj1, prop,
+ val, this_obj, flags);
+ JS_FreeValue(ctx, obj1);
+ JS_FreeValue(ctx, val);
+ return ret;
+ }
+ }
+
+ ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
+ if (ret < 0)
+ 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_error;
+ }
+ }
+ break;
+ }
+ p = p->shape->proto;
+ }
+
+ if (!JS_IsObject(this_obj))
+ return JS_ThrowTypeErrorOrFalse(ctx, flags, "receiver is not an object");
+
+ p = JS_VALUE_GET_OBJ(this_obj);
+
+ /* modify the property in this_obj if it already exists */
+ ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
+ if (ret < 0)
+ 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_error:
+ 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;
+ }
+
+ 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;
+}
+
+/* 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. */
+int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj,
+ JSAtom prop, JSValue val, 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)) {
+ 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, this_obj));
+ goto prototype_lookup;
+ }
+ }
+ p = JS_VALUE_GET_OBJ(this_obj);
+retry:
+ prs = find_own_property(&pr, p, 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 | JS_PROP_WRITABLE)) ==
+ (JS_PROP_LENGTH | JS_PROP_WRITABLE)) {
+ assert(p->class_id == JS_CLASS_ARRAY);
+ assert(prop == JS_ATOM_length);
+ return set_array_length(ctx, p, pr, 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)) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ goto retry;
+ } else {
+ goto read_only_prop;
+ }
+ }
+
+ p1 = p;
+ 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:
+ val = JS_ToNumberFree(ctx, val);
+ JS_FreeValue(ctx, val);
+ if (JS_IsException(val))
+ return -1;
+ if (typed_array_is_detached(ctx, p1)) {
+ JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+ return -1;
+ }
+ return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
+ }
+ }
+ } 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))
+ return -1;
+ goto retry2;
+ } else if (!(prs->flags & JS_PROP_WRITABLE)) {
+ read_only_prop:
+ JS_FreeValue(ctx, val);
+ return JS_ThrowTypeErrorReadOnly(ctx, flags, prop);
+ }
+ }
+ }
+
+ 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 (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 {
+ 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;
+ }
+ }
+
+ 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;
+}
+
+/* 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;
+#ifdef CONFIG_BIGNUM
+ 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;
+#endif
+ 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:
+ if (typed_array_is_detached(ctx, p)) {
+ JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+ return -1;
+ } else {
+ return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
+ }
+ }
+ 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, 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);
+ ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, 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)) {
+ if (!(prop_flags & JS_PROP_CONFIGURABLE)) {
+ 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 (!has_accessor && !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) {
+ /* property already exists */
+ if (!check_define_prop_flags(prs->flags, flags)) {
+ not_configurable:
+ return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
+ }
+
+ retry:
+ 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 if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
+ /* clear property and update */
+ if (js_shape_prepare_update(ctx, p, &prs))
+ return -1;
+ js_autoinit_free(ctx->rt, pr);
+ prs->flags &= ~JS_PROP_TMASK;
+ pr->u.value = JS_UNDEFINED;
+ goto retry;
+ } 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_TMASK) == JS_PROP_AUTOINIT) {
+ /* clear property and update */
+ if (js_shape_prepare_update(ctx, p, &prs))
+ return -1;
+ js_autoinit_free(ctx->rt, pr);
+ prs->flags &= ~JS_PROP_TMASK;
+ pr->u.value = JS_UNDEFINED;
+ } else {
+ if ((prs->flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 &&
+ (flags & JS_PROP_HAS_VALUE) &&
+ !js_same_value(ctx, val, pr->u.value)) {
+ goto not_configurable;
+ }
+ }
+ if (prs->flags & JS_PROP_LENGTH) {
+ if (flags & JS_PROP_HAS_VALUE) {
+ res = set_array_length(ctx, p, pr, JS_DupValue(ctx, val),
+ flags);
+ } else {
+ res = TRUE;
+ }
+ /* still need to reset the writable flag if needed.
+ The JS_PROP_LENGTH is reset to have the correct
+ read-only behavior in JS_SetProperty(). */
+ 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 | JS_PROP_LENGTH)))
+ return -1;
+ }
+ return res;
+ } else 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;
+ }
+ /* 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 (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_TMASK) == JS_PROP_AUTOINIT) {
+ /* XXX: should never happen, type was reset above */
+ abort();
+ } 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 >= typed_array_get_length(ctx, p)) {
+ 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);
+ if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET) ||
+ prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE)) {
+ 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);
+ 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;
+ }
+
+ flags = JS_PROP_THROW_STRICT;
+ if (flag != 2 && is_strict_mode(ctx))
+ flags |= JS_PROP_NO_ADD;
+ return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags);
+}
+
+/* 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);
+}
+
+/* used to avoid catching interrupt exceptions */
+BOOL JS_IsUncatchableError(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 && p->is_uncatchable_error;
+}
+
+void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag)
+{
+ JSObject *p;
+ if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
+ return;
+ p = JS_VALUE_GET_OBJ(val);
+ if (p->class_id == JS_CLASS_ERROR)
+ p->is_uncatchable_error = flag;
+}
+
+void JS_ResetUncatchableError(JSContext *ctx)
+{
+ JS_SetUncatchableError(ctx, ctx->rt->current_exception, FALSE);
+}
+
+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;
+}
+
+#define HINT_STRING 0
+#define HINT_NUMBER 1
+#define HINT_NONE 2
+/* don't try Symbol.toPrimitive */
+#define HINT_FORCE_ORDINARY (1 << 4)
+
+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);
+}
+
+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;
+ }
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_INT:
+ case JS_TAG_BIG_FLOAT:
+ {
+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ BOOL ret;
+ ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN;
+ JS_FreeValue(ctx, val);
+ return ret;
+ }
+ case JS_TAG_BIG_DECIMAL:
+ {
+ JSBigDecimal *p = JS_VALUE_GET_PTR(val);
+ BOOL ret;
+ ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN;
+ JS_FreeValue(ctx, val);
+ return ret;
+ }
+#endif
+ 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;
+}
+
+/* XXX: remove */
+static double js_strtod(const char *p, int radix, BOOL is_float)
+{
+ double d;
+ int c;
+
+ if (!is_float || radix != 10) {
+ uint64_t n_max, n;
+ int int_exp, is_neg;
+
+ is_neg = 0;
+ if (*p == '-') {
+ is_neg = 1;
+ p++;
+ }
+
+ /* skip leading zeros */
+ while (*p == '0')
+ p++;
+ n = 0;
+ if (radix == 10)
+ n_max = ((uint64_t)-1 - 9) / 10; /* most common case */
+ else
+ n_max = ((uint64_t)-1 - (radix - 1)) / radix;
+ /* XXX: could be more precise */
+ int_exp = 0;
+ while (*p != '\0') {
+ c = to_digit((uint8_t)*p);
+ if (c >= radix)
+ break;
+ if (n <= n_max) {
+ n = n * radix + c;
+ } else {
+ int_exp++;
+ }
+ p++;
+ }
+ d = n;
+ if (int_exp != 0) {
+ d *= pow(radix, int_exp);
+ }
+ if (is_neg)
+ d = -d;
+ } else {
+ d = strtod(p, NULL);
+ }
+ return d;
+}
+
+#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)
+#define ATOD_TYPE_BIG_FLOAT (2 << 7)
+#define ATOD_TYPE_BIG_DECIMAL (3 << 7)
+/* assume bigint mode: floats are parsed as integers if no decimal
+ point nor exponent */
+#define ATOD_MODE_BIGINT (1 << 9)
+/* accept -0x1 */
+#define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10)
+
+#ifdef CONFIG_BIGNUM
+static JSValue js_string_to_bigint(JSContext *ctx, const char *buf,
+ int radix, int flags, slimb_t *pexponent)
+{
+ bf_t a_s, *a = &a_s;
+ int ret;
+ JSValue val;
+ val = JS_NewBigInt(ctx);
+ if (JS_IsException(val))
+ return val;
+ a = JS_GetBigInt(val);
+ ret = bf_atof(a, buf, NULL, radix, BF_PREC_INF, BF_RNDZ);
+ if (ret & BF_ST_MEM_ERROR) {
+ JS_FreeValue(ctx, val);
+ return JS_ThrowOutOfMemory(ctx);
+ }
+ val = JS_CompactBigInt1(ctx, val, (flags & ATOD_MODE_BIGINT) != 0);
+ return val;
+}
+
+static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf,
+ int radix, int flags, slimb_t *pexponent)
+{
+ bf_t *a;
+ int ret;
+ JSValue val;
+
+ val = JS_NewBigFloat(ctx);
+ if (JS_IsException(val))
+ return val;
+ a = JS_GetBigFloat(val);
+ if (flags & ATOD_ACCEPT_SUFFIX) {
+ /* return the exponent to get infinite precision */
+ ret = bf_atof2(a, pexponent, buf, NULL, radix, BF_PREC_INF,
+ BF_RNDZ | BF_ATOF_EXPONENT);
+ } else {
+ ret = bf_atof(a, buf, NULL, radix, ctx->fp_env.prec,
+ ctx->fp_env.flags);
+ }
+ if (ret & BF_ST_MEM_ERROR) {
+ JS_FreeValue(ctx, val);
+ return JS_ThrowOutOfMemory(ctx);
+ }
+ return val;
+}
+
+static JSValue js_string_to_bigdecimal(JSContext *ctx, const char *buf,
+ int radix, int flags, slimb_t *pexponent)
+{
+ bfdec_t *a;
+ int ret;
+ JSValue val;
+
+ val = JS_NewBigDecimal(ctx);
+ if (JS_IsException(val))
+ return val;
+ a = JS_GetBigDecimal(val);
+ ret = bfdec_atof(a, buf, NULL, BF_PREC_INF,
+ BF_RNDZ | BF_ATOF_NO_NAN_INF);
+ if (ret & BF_ST_MEM_ERROR) {
+ JS_FreeValue(ctx, val);
+ return JS_ThrowOutOfMemory(ctx);
+ }
+ return val;
+}
+
+#endif
+
+/* return an exception in case of memory error. Return JS_NAN if
+ invalid syntax */
+#ifdef CONFIG_BIGNUM
+static JSValue js_atof2(JSContext *ctx, const char *str, const char **pp,
+ int radix, int flags, slimb_t *pexponent)
+#else
+static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
+ int radix, int flags)
+#endif
+{
+ 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;
+
+ /* 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 ||
+ atod_type == ATOD_TYPE_BIG_FLOAT) &&
+ strstart(p, "Infinity", &p)) {
+#ifdef CONFIG_BIGNUM
+ if (atod_type == ATOD_TYPE_BIG_FLOAT) {
+ bf_t *a;
+ val = JS_NewBigFloat(ctx);
+ if (JS_IsException(val))
+ goto done;
+ a = JS_GetBigFloat(val);
+ bf_set_inf(a, is_neg);
+ } else
+#endif
+ {
+ 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';
+
+#ifdef CONFIG_BIGNUM
+ if (flags & ATOD_ACCEPT_SUFFIX) {
+ if (*p == 'n') {
+ p++;
+ atod_type = ATOD_TYPE_BIG_INT;
+ } else if (*p == 'l') {
+ p++;
+ atod_type = ATOD_TYPE_BIG_FLOAT;
+ } else if (*p == 'm') {
+ p++;
+ atod_type = ATOD_TYPE_BIG_DECIMAL;
+ } else {
+ if (flags & ATOD_MODE_BIGINT) {
+ if (!is_float)
+ atod_type = ATOD_TYPE_BIG_INT;
+ if (has_legacy_octal)
+ goto fail;
+ } else {
+ if (is_float && radix != 10)
+ goto fail;
+ }
+ }
+ } else {
+ if (atod_type == ATOD_TYPE_FLOAT64) {
+ if (flags & ATOD_MODE_BIGINT) {
+ if (!is_float)
+ atod_type = ATOD_TYPE_BIG_INT;
+ if (has_legacy_octal)
+ goto fail;
+ } else {
+ if (is_float && radix != 10)
+ goto fail;
+ }
+ }
+ }
+
+ switch(atod_type) {
+ case ATOD_TYPE_FLOAT64:
+ {
+ double d;
+ d = js_strtod(buf, radix, is_float);
+ /* return int or float64 */
+ val = JS_NewFloat64(ctx, d);
+ }
+ break;
+ case ATOD_TYPE_BIG_INT:
+ if (has_legacy_octal || is_float)
+ goto fail;
+ val = ctx->rt->bigint_ops.from_string(ctx, buf, radix, flags, NULL);
+ break;
+ case ATOD_TYPE_BIG_FLOAT:
+ if (has_legacy_octal)
+ goto fail;
+ val = ctx->rt->bigfloat_ops.from_string(ctx, buf, radix, flags,
+ pexponent);
+ break;
+ case ATOD_TYPE_BIG_DECIMAL:
+ if (radix != 10)
+ goto fail;
+ val = ctx->rt->bigdecimal_ops.from_string(ctx, buf, radix, flags, NULL);
+ break;
+ default:
+ abort();
+ }
+#else
+ {
+ double d;
+ (void)has_legacy_octal;
+ if (is_float && radix != 10)
+ goto fail;
+ d = js_strtod(buf, radix, is_float);
+ val = JS_NewFloat64(ctx, d);
+ }
+#endif
+
+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;
+}
+
+#ifdef CONFIG_BIGNUM
+static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
+ int radix, int flags)
+{
+ return js_atof2(ctx, str, pp, radix, flags, NULL);
+}
+#endif
+
+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) {
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_DECIMAL:
+ if (flag != TON_FLAG_NUMERIC) {
+ JS_FreeValue(ctx, val);
+ return JS_ThrowTypeError(ctx, "cannot convert bigdecimal to number");
+ }
+ ret = val;
+ break;
+ case JS_TAG_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_BIG_FLOAT:
+ if (flag != TON_FLAG_NUMERIC) {
+ JS_FreeValue(ctx, val);
+ return JS_ThrowTypeError(ctx, "cannot convert bigfloat to number");
+ }
+ ret = val;
+ break;
+#endif
+ 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:
+ {
+ 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)) {
+ *pres = JS_FLOAT64_NAN;
+ return -1;
+ }
+ 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;
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_INT:
+ case JS_TAG_BIG_FLOAT:
+ {
+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ /* XXX: there can be a double rounding issue with some
+ primitives (such as JS_ToUint8ClampFree()), but it is
+ not critical to fix it. */
+ bf_get_float64(&p->num, &d, BF_RNDN);
+ JS_FreeValue(ctx, val);
+ }
+ break;
+#endif
+ default:
+ abort();
+ }
+ *pres = d;
+ return 0;
+}
+
+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;
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_FLOAT:
+ {
+ bf_t a_s, *a, r_s, *r = &r_s;
+ BOOL is_nan;
+
+ a = JS_ToBigFloat(ctx, &a_s, val);
+ if (!bf_is_finite(a)) {
+ is_nan = bf_is_nan(a);
+ if (is_nan)
+ ret = JS_NewInt32(ctx, 0);
+ else
+ ret = JS_DupValue(ctx, val);
+ } else {
+ ret = JS_NewBigInt(ctx);
+ if (!JS_IsException(ret)) {
+ r = JS_GetBigInt(ret);
+ bf_set(r, a);
+ bf_rint(r, BF_RNDZ);
+ ret = JS_CompactBigInt(ctx, ret);
+ }
+ }
+ if (a == &a_s)
+ bf_delete(a);
+ JS_FreeValue(ctx, val);
+ }
+ break;
+#endif
+ 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;
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_FLOAT:
+ {
+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ bf_get_int32(&ret, &p->num, 0);
+ JS_FreeValue(ctx, val);
+ }
+ break;
+#endif
+ 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 > INT64_MAX)
+ *pres = INT64_MAX;
+ else
+ *pres = (int64_t)d;
+ }
+ }
+ return 0;
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_FLOAT:
+ {
+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ bf_get_int64(pres, &p->num, 0);
+ JS_FreeValue(ctx, val);
+ }
+ return 0;
+#endif
+ 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;
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_FLOAT:
+ {
+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ bf_get_int64(&ret, &p->num, BF_GET_INT_MOD);
+ JS_FreeValue(ctx, val);
+ }
+ break;
+#endif
+ 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;
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_FLOAT:
+ {
+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ bf_get_int32(&ret, &p->num, BF_GET_INT_MOD);
+ JS_FreeValue(ctx, val);
+ }
+ break;
+#endif
+ 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);
+#ifdef CONFIG_BIGNUM
+ int_clamp:
+#endif
+ 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;
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_FLOAT:
+ {
+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ bf_t r_s, *r = &r_s;
+ bf_init(ctx->bf_ctx, r);
+ bf_set(r, &p->num);
+ bf_rint(r, BF_RNDN);
+ bf_get_int32(&res, r, 0);
+ bf_delete(r);
+ JS_FreeValue(ctx, val);
+ }
+ goto int_clamp;
+#endif
+ 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)
+{
+ uint32_t tag, len;
+
+ redo:
+ 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;
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_INT:
+ case JS_TAG_BIG_FLOAT:
+ {
+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ bf_t a;
+ BOOL res;
+ bf_get_int32((int32_t *)&len, &p->num, BF_GET_INT_MOD);
+ bf_init(ctx->bf_ctx, &a);
+ bf_set_ui(&a, len);
+ res = bf_cmp_eq(&a, &p->num);
+ bf_delete(&a);
+ JS_FreeValue(ctx, val);
+ if (!res)
+ goto fail;
+ }
+ break;
+#endif
+ default:
+ if (JS_TAG_IS_FLOAT64(tag)) {
+ double d;
+ d = JS_VALUE_GET_FLOAT64(val);
+ len = (uint32_t)d;
+ if (len != d) {
+ fail:
+ JS_ThrowRangeError(ctx, "invalid array length");
+ return -1;
+ }
+ } else {
+ val = JS_ToNumberFree(ctx, val);
+ if (JS_IsException(val))
+ return -1;
+ goto redo;
+ }
+ 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);
+ }
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_INT:
+ {
+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ /* Note: integer zeros are not necessarily positive */
+ return p->num.sign && !bf_is_zero(&p->num);
+ }
+ case JS_TAG_BIG_FLOAT:
+ {
+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ return p->num.sign;
+ }
+ break;
+ case JS_TAG_BIG_DECIMAL:
+ {
+ JSBigDecimal *p = JS_VALUE_GET_PTR(val);
+ return p->num.sign;
+ }
+ break;
+#endif
+ default:
+ return FALSE;
+ }
+}
+
+#ifdef CONFIG_BIGNUM
+
+static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix)
+{
+ JSValue ret;
+ bf_t a_s, *a;
+ char *str;
+ int saved_sign;
+
+ a = JS_ToBigInt(ctx, &a_s, val);
+ if (!a)
+ return JS_EXCEPTION;
+ saved_sign = a->sign;
+ if (a->expn == BF_EXP_ZERO)
+ a->sign = 0;
+ str = bf_ftoa(NULL, a, radix, 0, BF_RNDZ | BF_FTOA_FORMAT_FRAC |
+ BF_FTOA_JS_QUIRKS);
+ a->sign = saved_sign;
+ JS_FreeBigInt(ctx, a, &a_s);
+ if (!str)
+ return JS_ThrowOutOfMemory(ctx);
+ ret = JS_NewString(ctx, str);
+ bf_free(ctx->bf_ctx, str);
+ return ret;
+}
+
+static JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val)
+{
+ return js_bigint_to_string1(ctx, val, 10);
+}
+
+static JSValue js_ftoa(JSContext *ctx, JSValueConst val1, int radix,
+ limb_t prec, bf_flags_t flags)
+{
+ JSValue val, ret;
+ bf_t a_s, *a;
+ char *str;
+ int saved_sign;
+
+ val = JS_ToNumeric(ctx, val1);
+ if (JS_IsException(val))
+ return val;
+ a = JS_ToBigFloat(ctx, &a_s, val);
+ saved_sign = a->sign;
+ if (a->expn == BF_EXP_ZERO)
+ a->sign = 0;
+ flags |= BF_FTOA_JS_QUIRKS;
+ if ((flags & BF_FTOA_FORMAT_MASK) == BF_FTOA_FORMAT_FREE_MIN) {
+ /* Note: for floating point numbers with a radix which is not
+ a power of two, the current precision is used to compute
+ the number of digits. */
+ if ((radix & (radix - 1)) != 0) {
+ bf_t r_s, *r = &r_s;
+ int prec, flags1;
+ /* must round first */
+ if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {
+ prec = ctx->fp_env.prec;
+ flags1 = ctx->fp_env.flags &
+ (BF_FLAG_SUBNORMAL | (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT));
+ } else {
+ prec = 53;
+ flags1 = bf_set_exp_bits(11) | BF_FLAG_SUBNORMAL;
+ }
+ bf_init(ctx->bf_ctx, r);
+ bf_set(r, a);
+ bf_round(r, prec, flags1 | BF_RNDN);
+ str = bf_ftoa(NULL, r, radix, prec, flags1 | flags);
+ bf_delete(r);
+ } else {
+ str = bf_ftoa(NULL, a, radix, BF_PREC_INF, flags);
+ }
+ } else {
+ str = bf_ftoa(NULL, a, radix, prec, flags);
+ }
+ a->sign = saved_sign;
+ if (a == &a_s)
+ bf_delete(a);
+ JS_FreeValue(ctx, val);
+ if (!str)
+ return JS_ThrowOutOfMemory(ctx);
+ ret = JS_NewString(ctx, str);
+ bf_free(ctx->bf_ctx, str);
+ return ret;
+}
+
+static JSValue js_bigfloat_to_string(JSContext *ctx, JSValueConst val)
+{
+ return js_ftoa(ctx, val, 10, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);
+}
+
+static JSValue js_bigdecimal_to_string1(JSContext *ctx, JSValueConst val,
+ limb_t prec, int flags)
+{
+ JSValue ret;
+ bfdec_t *a;
+ char *str;
+ int saved_sign;
+
+ a = JS_ToBigDecimal(ctx, val);
+ saved_sign = a->sign;
+ if (a->expn == BF_EXP_ZERO)
+ a->sign = 0;
+ str = bfdec_ftoa(NULL, a, prec, flags | BF_FTOA_JS_QUIRKS);
+ a->sign = saved_sign;
+ if (!str)
+ return JS_ThrowOutOfMemory(ctx);
+ ret = JS_NewString(ctx, str);
+ bf_free(ctx->bf_ctx, str);
+ return ret;
+}
+
+static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val)
+{
+ return js_bigdecimal_to_string1(ctx, val, 0,
+ BF_RNDZ | BF_FTOA_FORMAT_FREE);
+}
+
+#endif /* CONFIG_BIGNUM */
+
+/* 2 <= base <= 36 */
+static char *i64toa(char *buf_end, int64_t n, unsigned int base)
+{
+ char *q = buf_end;
+ int digit, is_neg;
+
+ is_neg = 0;
+ if (n < 0) {
+ is_neg = 1;
+ n = -n;
+ }
+ *--q = '\0';
+ do {
+ digit = (uint64_t)n % base;
+ n = (uint64_t)n / base;
+ if (digit < 10)
+ digit += '0';
+ else
+ digit += 'a' - 10;
+ *--q = digit;
+ } while (n != 0);
+ if (is_neg)
+ *--q = '-';
+ return q;
+}
+
+/* buf1 contains the printf result */
+static void js_ecvt1(double d, int n_digits, int *decpt, int *sign, char *buf,
+ int rounding_mode, char *buf1, int buf1_size)
+{
+ if (rounding_mode != FE_TONEAREST)
+ fesetround(rounding_mode);
+ snprintf(buf1, buf1_size, "%+.*e", n_digits - 1, d);
+ if (rounding_mode != FE_TONEAREST)
+ fesetround(FE_TONEAREST);
+ *sign = (buf1[0] == '-');
+ /* mantissa */
+ buf[0] = buf1[1];
+ if (n_digits > 1)
+ memcpy(buf + 1, buf1 + 3, n_digits - 1);
+ buf[n_digits] = '\0';
+ /* exponent */
+ *decpt = atoi(buf1 + n_digits + 2 + (n_digits > 1)) + 1;
+}
+
+/* maximum buffer size for js_dtoa */
+#define JS_DTOA_BUF_SIZE 128
+
+/* needed because ecvt usually limits the number of digits to
+ 17. Return the number of digits. */
+static int js_ecvt(double d, int n_digits, int *decpt, int *sign, char *buf,
+ BOOL is_fixed)
+{
+ int rounding_mode;
+ char buf_tmp[JS_DTOA_BUF_SIZE];
+
+ if (!is_fixed) {
+ unsigned int n_digits_min, n_digits_max;
+ /* find the minimum amount of digits (XXX: inefficient but simple) */
+ n_digits_min = 1;
+ n_digits_max = 17;
+ while (n_digits_min < n_digits_max) {
+ n_digits = (n_digits_min + n_digits_max) / 2;
+ js_ecvt1(d, n_digits, decpt, sign, buf, FE_TONEAREST,
+ buf_tmp, sizeof(buf_tmp));
+ if (strtod(buf_tmp, NULL) == d) {
+ /* no need to keep the trailing zeros */
+ while (n_digits >= 2 && buf[n_digits - 1] == '0')
+ n_digits--;
+ n_digits_max = n_digits;
+ } else {
+ n_digits_min = n_digits + 1;
+ }
+ }
+ n_digits = n_digits_max;
+ rounding_mode = FE_TONEAREST;
+ } else {
+ rounding_mode = FE_TONEAREST;
+#ifdef CONFIG_PRINTF_RNDN
+ {
+ char buf1[JS_DTOA_BUF_SIZE], buf2[JS_DTOA_BUF_SIZE];
+ int decpt1, sign1, decpt2, sign2;
+ /* The JS rounding is specified as round to nearest ties away
+ from zero (RNDNA), but in printf the "ties" case is not
+ specified (for example it is RNDN for glibc, RNDNA for
+ Windows), so we must round manually. */
+ js_ecvt1(d, n_digits + 1, &decpt1, &sign1, buf1, FE_TONEAREST,
+ buf_tmp, sizeof(buf_tmp));
+ /* XXX: could use 2 digits to reduce the average running time */
+ if (buf1[n_digits] == '5') {
+ js_ecvt1(d, n_digits + 1, &decpt1, &sign1, buf1, FE_DOWNWARD,
+ buf_tmp, sizeof(buf_tmp));
+ js_ecvt1(d, n_digits + 1, &decpt2, &sign2, buf2, FE_UPWARD,
+ buf_tmp, sizeof(buf_tmp));
+ if (memcmp(buf1, buf2, n_digits + 1) == 0 && decpt1 == decpt2) {
+ /* exact result: round away from zero */
+ if (sign1)
+ rounding_mode = FE_DOWNWARD;
+ else
+ rounding_mode = FE_UPWARD;
+ }
+ }
+ }
+#endif /* CONFIG_PRINTF_RNDN */
+ }
+ js_ecvt1(d, n_digits, decpt, sign, buf, rounding_mode,
+ buf_tmp, sizeof(buf_tmp));
+ return n_digits;
+}
+
+static int js_fcvt1(char *buf, int buf_size, double d, int n_digits,
+ int rounding_mode)
+{
+ int n;
+ if (rounding_mode != FE_TONEAREST)
+ fesetround(rounding_mode);
+ n = snprintf(buf, buf_size, "%.*f", n_digits, d);
+ if (rounding_mode != FE_TONEAREST)
+ fesetround(FE_TONEAREST);
+ assert(n < buf_size);
+ return n;
+}
+
+static void js_fcvt(char *buf, int buf_size, double d, int n_digits)
+{
+ int rounding_mode;
+ rounding_mode = FE_TONEAREST;
+#ifdef CONFIG_PRINTF_RNDN
+ {
+ int n1, n2;
+ char buf1[JS_DTOA_BUF_SIZE];
+ char buf2[JS_DTOA_BUF_SIZE];
+
+ /* The JS rounding is specified as round to nearest ties away from
+ zero (RNDNA), but in printf the "ties" case is not specified
+ (for example it is RNDN for glibc, RNDNA for Windows), so we
+ must round manually. */
+ n1 = js_fcvt1(buf1, sizeof(buf1), d, n_digits + 1, FE_TONEAREST);
+ rounding_mode = FE_TONEAREST;
+ /* XXX: could use 2 digits to reduce the average running time */
+ if (buf1[n1 - 1] == '5') {
+ n1 = js_fcvt1(buf1, sizeof(buf1), d, n_digits + 1, FE_DOWNWARD);
+ n2 = js_fcvt1(buf2, sizeof(buf2), d, n_digits + 1, FE_UPWARD);
+ if (n1 == n2 && memcmp(buf1, buf2, n1) == 0) {
+ /* exact result: round away from zero */
+ if (buf1[0] == '-')
+ rounding_mode = FE_DOWNWARD;
+ else
+ rounding_mode = FE_UPWARD;
+ }
+ }
+ }
+#endif /* CONFIG_PRINTF_RNDN */
+ js_fcvt1(buf, buf_size, d, n_digits, rounding_mode);
+}
+
+/* radix != 10 is only supported with flags = JS_DTOA_VAR_FORMAT */
+/* use as many digits as necessary */
+#define JS_DTOA_VAR_FORMAT (0 << 0)
+/* use n_digits significant digits (1 <= n_digits <= 101) */
+#define JS_DTOA_FIXED_FORMAT (1 << 0)
+/* force fractional format: [-]dd.dd with n_digits fractional digits */
+#define JS_DTOA_FRAC_FORMAT (2 << 0)
+/* force exponential notation either in fixed or variable format */
+#define JS_DTOA_FORCE_EXP (1 << 2)
+
+/* XXX: slow and maybe not fully correct. Use libbf when it is fast enough.
+ XXX: radix != 10 is only supported for small integers
+*/
+static void js_dtoa1(char *buf, double d, int radix, int n_digits, int flags)
+{
+ char *q;
+
+ if (!isfinite(d)) {
+ if (isnan(d)) {
+ strcpy(buf, "NaN");
+ } else {
+ q = buf;
+ if (d < 0)
+ *q++ = '-';
+ strcpy(q, "Infinity");
+ }
+ } else if (flags == JS_DTOA_VAR_FORMAT) {
+ int64_t i64;
+ char buf1[70], *ptr;
+ i64 = (int64_t)d;
+ if (d != i64 || i64 > MAX_SAFE_INTEGER || i64 < -MAX_SAFE_INTEGER)
+ goto generic_conv;
+ /* fast path for integers */
+ ptr = i64toa(buf1 + sizeof(buf1), i64, radix);
+ strcpy(buf, ptr);
+ } else {
+ if (d == 0.0)
+ d = 0.0; /* convert -0 to 0 */
+ if (flags == JS_DTOA_FRAC_FORMAT) {
+ js_fcvt(buf, JS_DTOA_BUF_SIZE, d, n_digits);
+ } else {
+ char buf1[JS_DTOA_BUF_SIZE];
+ int sign, decpt, k, n, i, p, n_max;
+ BOOL is_fixed;
+ generic_conv:
+ is_fixed = ((flags & 3) == JS_DTOA_FIXED_FORMAT);
+ if (is_fixed) {
+ n_max = n_digits;
+ } else {
+ n_max = 21;
+ }
+ /* the number has k digits (k >= 1) */
+ k = js_ecvt(d, n_digits, &decpt, &sign, buf1, is_fixed);
+ n = decpt; /* d=10^(n-k)*(buf1) i.e. d= < x.yyyy 10^(n-1) */
+ q = buf;
+ if (sign)
+ *q++ = '-';
+ if (flags & JS_DTOA_FORCE_EXP)
+ goto force_exp;
+ if (n >= 1 && n <= n_max) {
+ if (k <= n) {
+ memcpy(q, buf1, k);
+ q += k;
+ for(i = 0; i < (n - k); i++)
+ *q++ = '0';
+ *q = '\0';
+ } else {
+ /* k > n */
+ memcpy(q, buf1, n);
+ q += n;
+ *q++ = '.';
+ for(i = 0; i < (k - n); i++)
+ *q++ = buf1[n + i];
+ *q = '\0';
+ }
+ } else if (n >= -5 && n <= 0) {
+ *q++ = '0';
+ *q++ = '.';
+ for(i = 0; i < -n; i++)
+ *q++ = '0';
+ memcpy(q, buf1, k);
+ q += k;
+ *q = '\0';
+ } else {
+ force_exp:
+ /* exponential notation */
+ *q++ = buf1[0];
+ if (k > 1) {
+ *q++ = '.';
+ for(i = 1; i < k; i++)
+ *q++ = buf1[i];
+ }
+ *q++ = 'e';
+ p = n - 1;
+ if (p >= 0)
+ *q++ = '+';
+ sprintf(q, "%d", p);
+ }
+ }
+ }
+}
+
+static JSValue js_dtoa(JSContext *ctx,
+ double d, int radix, int n_digits, int flags)
+{
+ char buf[JS_DTOA_BUF_SIZE];
+ js_dtoa1(buf, d, radix, n_digits, flags);
+ return JS_NewString(ctx, buf);
+}
+
+JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToPropertyKey)
+{
+ uint32_t tag;
+ const char *str;
+ char buf[32];
+
+ tag = JS_VALUE_GET_NORM_TAG(val);
+ switch(tag) {
+ case JS_TAG_STRING:
+ return JS_DupValue(ctx, val);
+ case JS_TAG_INT:
+ snprintf(buf, sizeof(buf), "%d", JS_VALUE_GET_INT(val));
+ str = buf;
+ goto new_string;
+ 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:
+ str = "[function bytecode]";
+ goto new_string;
+ 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_dtoa(ctx, JS_VALUE_GET_FLOAT64(val), 10, 0,
+ JS_DTOA_VAR_FORMAT);
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_INT:
+ return ctx->rt->bigint_ops.to_string(ctx, val);
+ case JS_TAG_BIG_FLOAT:
+ return ctx->rt->bigfloat_ops.to_string(ctx, val);
+ case JS_TAG_BIG_DECIMAL:
+ return ctx->rt->bigdecimal_ops.to_string(ctx, val);
+#endif
+ default:
+ str = "[unsupported type]";
+ new_string:
+ return JS_NewString(ctx, str);
+ }
+}
+
+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 || (c >= 0xd800 && c < 0xe000)) {
+ 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;
+}
+
+static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt)
+{
+ printf("%14s %4s %4s %14s %10s %s\n",
+ "ADDRESS", "REFS", "SHRF", "PROTO", "CLASS", "PROPS");
+}
+
+/* for debug only: dump an object without side effect */
+static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
+{
+ uint32_t i;
+ char atom_buf[ATOM_GET_STR_BUF_SIZE];
+ JSShape *sh;
+ JSShapeProperty *prs;
+ JSProperty *pr;
+ BOOL is_first = TRUE;
+
+ /* 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 ", "-", "-");
+ }
+ printf("%10s ",
+ JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), rt->class_array[p->class_id].class_name));
+ if (p->is_exotic && p->fast_array) {
+ printf("[ ");
+ for(i = 0; i < p->u.array.count; i++) {
+ if (i != 0)
+ printf(", ");
+ switch (p->class_id) {
+ case JS_CLASS_ARRAY:
+ case JS_CLASS_ARGUMENTS:
+ JS_DumpValueShort(rt, p->u.array.u.values[i]);
+ break;
+ case JS_CLASS_UINT8C_ARRAY ... JS_CLASS_FLOAT64_ARRAY:
+ {
+ int size = 1 << typed_array_size_log2(p->class_id);
+ const uint8_t *b = p->u.array.u.uint8_ptr + i * size;
+ while (size-- > 0)
+ printf("%02X", *b++);
+ }
+ break;
+ }
+ }
+ printf(" ] ");
+ }
+
+ if (sh) {
+ printf("{ ");
+ for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
+ if (prs->atom != JS_ATOM_NULL) {
+ pr = &p->prop[i];
+ if (!is_first)
+ printf(", ");
+ printf("%s: ",
+ JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), prs->atom));
+ if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
+ printf("[getset %p %p]", (void *)pr->u.getset.getter,
+ (void *)pr->u.getset.setter);
+ } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
+ printf("[varref %p]", (void *)pr->u.var_ref);
+ } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
+ printf("[autoinit %p %d %p]",
+ (void *)js_autoinit_get_realm(pr),
+ js_autoinit_get_id(pr),
+ (void *)pr->u.init.opaque);
+ } else {
+ JS_DumpValueShort(rt, pr->u.value);
+ }
+ is_first = FALSE;
+ }
+ }
+ printf(" }");
+ }
+
+ if (js_class_has_bytecode(p->class_id)) {
+ JSFunctionBytecode *b = p->u.func.function_bytecode;
+ JSVarRef **var_refs;
+ if (b->closure_var_count) {
+ var_refs = p->u.func.var_refs;
+ printf(" Closure:");
+ for(i = 0; i < b->closure_var_count; i++) {
+ printf(" ");
+ JS_DumpValueShort(rt, var_refs[i]->value);
+ }
+ if (p->u.func.home_object) {
+ printf(" HomeObject: ");
+ JS_DumpValueShort(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object));
+ }
+ }
+ }
+ 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;
+ default:
+ printf("[unknown %d]", p->gc_obj_type);
+ break;
+ }
+ printf("\n");
+ }
+}
+
+static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
+ JSValueConst val)
+{
+ uint32_t tag = JS_VALUE_GET_NORM_TAG(val);
+ const char *str;
+
+ switch(tag) {
+ case JS_TAG_INT:
+ printf("%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:
+ printf("%s", str);
+ break;
+ case JS_TAG_FLOAT64:
+ printf("%.14g", JS_VALUE_GET_FLOAT64(val));
+ break;
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_INT:
+ {
+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ char *str;
+ str = bf_ftoa(NULL, &p->num, 10, 0,
+ BF_RNDZ | BF_FTOA_FORMAT_FRAC);
+ printf("%sn", str);
+ bf_realloc(&rt->bf_ctx, str, 0);
+ }
+ break;
+ case JS_TAG_BIG_FLOAT:
+ {
+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ char *str;
+ str = bf_ftoa(NULL, &p->num, 16, BF_PREC_INF,
+ BF_RNDZ | BF_FTOA_FORMAT_FREE | BF_FTOA_ADD_PREFIX);
+ printf("%sl", str);
+ bf_free(&rt->bf_ctx, str);
+ }
+ break;
+ case JS_TAG_BIG_DECIMAL:
+ {
+ JSBigDecimal *p = JS_VALUE_GET_PTR(val);
+ char *str;
+ str = bfdec_ftoa(NULL, &p->num, BF_PREC_INF,
+ BF_RNDZ | BF_FTOA_FORMAT_FREE);
+ printf("%sm", str);
+ bf_free(&rt->bf_ctx, str);
+ }
+ break;
+#endif
+ case JS_TAG_STRING:
+ {
+ JSString *p;
+ p = JS_VALUE_GET_STRING(val);
+ JS_DumpString(rt, p);
+ }
+ break;
+ case JS_TAG_FUNCTION_BYTECODE:
+ {
+ JSFunctionBytecode *b = JS_VALUE_GET_PTR(val);
+ char buf[ATOM_GET_STR_BUF_SIZE];
+ printf("[bytecode %s]", JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
+ }
+ break;
+ case JS_TAG_OBJECT:
+ {
+ JSObject *p = JS_VALUE_GET_OBJ(val);
+ JSAtom atom = rt->class_array[p->class_id].class_name;
+ char atom_buf[ATOM_GET_STR_BUF_SIZE];
+ printf("[%s %p]",
+ JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), atom), (void *)p);
+ }
+ break;
+ case JS_TAG_SYMBOL:
+ {
+ JSAtomStruct *p = JS_VALUE_GET_PTR(val);
+ char atom_buf[ATOM_GET_STR_BUF_SIZE];
+ printf("Symbol(%s)",
+ JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), js_get_atom_index(rt, p)));
+ }
+ break;
+ case JS_TAG_MODULE:
+ printf("[module]");
+ break;
+ default:
+ printf("[unknown tag %d]", tag);
+ break;
+ }
+}
+
+static __maybe_unused void JS_DumpValue(JSContext *ctx,
+ JSValueConst val)
+{
+ JS_DumpValueShort(ctx->rt, val);
+}
+
+static __maybe_unused void JS_PrintValue(JSContext *ctx,
+ const char *str,
+ JSValueConst val)
+{
+ printf("%s=", str);
+ JS_DumpValueShort(ctx->rt, val);
+ printf("\n");
+}
+
+/* return -1 if exception (proxy case) or TRUE/FALSE */
+int JS_IsArray(JSContext *ctx, JSValueConst val)
+{
+ JSObject *p;
+ if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {
+ p = JS_VALUE_GET_OBJ(val);
+ if (unlikely(p->class_id == JS_CLASS_PROXY))
+ return js_proxy_isArray(ctx, val);
+ else
+ 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);
+ }
+}
+
+#ifdef CONFIG_BIGNUM
+
+JSValue JS_NewBigInt64_1(JSContext *ctx, int64_t v)
+{
+ JSValue val;
+ bf_t *a;
+ val = JS_NewBigInt(ctx);
+ if (JS_IsException(val))
+ return val;
+ a = JS_GetBigInt(val);
+ if (bf_set_si(a, v)) {
+ JS_FreeValue(ctx, val);
+ return JS_ThrowOutOfMemory(ctx);
+ }
+ return val;
+}
+
+JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
+{
+ if (is_math_mode(ctx) &&
+ v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
+ return JS_NewInt64(ctx, v);
+ } else {
+ return JS_NewBigInt64_1(ctx, v);
+ }
+}
+
+JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
+{
+ JSValue val;
+ if (is_math_mode(ctx) && v <= MAX_SAFE_INTEGER) {
+ val = JS_NewInt64(ctx, v);
+ } else {
+ bf_t *a;
+ val = JS_NewBigInt(ctx);
+ if (JS_IsException(val))
+ return val;
+ a = JS_GetBigInt(val);
+ if (bf_set_ui(a, v)) {
+ JS_FreeValue(ctx, val);
+ return JS_ThrowOutOfMemory(ctx);
+ }
+ }
+ return val;
+}
+
+/* if the returned bigfloat is allocated it is equal to
+ 'buf'. Otherwise it is a pointer to the bigfloat in 'val'. Return
+ NULL in case of error. */
+static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val)
+{
+ uint32_t tag;
+ bf_t *r;
+ JSBigFloat *p;
+
+ tag = JS_VALUE_GET_NORM_TAG(val);
+ switch(tag) {
+ case JS_TAG_INT:
+ case JS_TAG_BOOL:
+ case JS_TAG_NULL:
+ r = buf;
+ bf_init(ctx->bf_ctx, r);
+ if (bf_set_si(r, JS_VALUE_GET_INT(val)))
+ goto fail;
+ break;
+ case JS_TAG_FLOAT64:
+ r = buf;
+ bf_init(ctx->bf_ctx, r);
+ if (bf_set_float64(r, JS_VALUE_GET_FLOAT64(val))) {
+ fail:
+ bf_delete(r);
+ return NULL;
+ }
+ break;
+ case JS_TAG_BIG_INT:
+ case JS_TAG_BIG_FLOAT:
+ p = JS_VALUE_GET_PTR(val);
+ r = &p->num;
+ break;
+ case JS_TAG_UNDEFINED:
+ default:
+ r = buf;
+ bf_init(ctx->bf_ctx, r);
+ bf_set_nan(r);
+ break;
+ }
+ return r;
+}
+
+/* return NULL if invalid type */
+static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val)
+{
+ uint32_t tag;
+ JSBigDecimal *p;
+ bfdec_t *r;
+
+ tag = JS_VALUE_GET_NORM_TAG(val);
+ switch(tag) {
+ case JS_TAG_BIG_DECIMAL:
+ p = JS_VALUE_GET_PTR(val);
+ r = &p->num;
+ break;
+ default:
+ JS_ThrowTypeError(ctx, "bigdecimal expected");
+ r = NULL;
+ break;
+ }
+ return r;
+}
+
+/* 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;
+ if (is_math_mode(ctx))
+ flags |= ATOD_MODE_BIGINT;
+ 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;
+}
+
+/* if the returned bigfloat is allocated it is equal to
+ 'buf'. Otherwise it is a pointer to the bigfloat in 'val'. */
+static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val)
+{
+ uint32_t tag;
+ bf_t *r;
+ JSBigFloat *p;
+
+ redo:
+ tag = JS_VALUE_GET_NORM_TAG(val);
+ switch(tag) {
+ case JS_TAG_INT:
+ case JS_TAG_NULL:
+ case JS_TAG_UNDEFINED:
+ if (!is_math_mode(ctx))
+ goto fail;
+ /* fall tru */
+ case JS_TAG_BOOL:
+ r = buf;
+ bf_init(ctx->bf_ctx, r);
+ bf_set_si(r, JS_VALUE_GET_INT(val));
+ break;
+ case JS_TAG_FLOAT64:
+ {
+ double d = JS_VALUE_GET_FLOAT64(val);
+ if (!is_math_mode(ctx))
+ goto fail;
+ if (!isfinite(d))
+ goto fail;
+ r = buf;
+ bf_init(ctx->bf_ctx, r);
+ d = trunc(d);
+ bf_set_float64(r, d);
+ }
+ break;
+ case JS_TAG_BIG_INT:
+ p = JS_VALUE_GET_PTR(val);
+ r = &p->num;
+ break;
+ case JS_TAG_BIG_FLOAT:
+ if (!is_math_mode(ctx))
+ goto fail;
+ p = JS_VALUE_GET_PTR(val);
+ if (!bf_is_finite(&p->num))
+ goto fail;
+ r = buf;
+ bf_init(ctx->bf_ctx, r);
+ bf_set(r, &p->num);
+ bf_rint(r, BF_RNDZ);
+ JS_FreeValue(ctx, val);
+ break;
+ case JS_TAG_STRING:
+ val = JS_StringToBigIntErr(ctx, val);
+ if (JS_IsException(val))
+ return NULL;
+ goto redo;
+ case JS_TAG_OBJECT:
+ val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
+ if (JS_IsException(val))
+ return NULL;
+ goto redo;
+ default:
+ fail:
+ JS_FreeValue(ctx, val);
+ JS_ThrowTypeError(ctx, "cannot convert to bigint");
+ return NULL;
+ }
+ return r;
+}
+
+static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val)
+{
+ return JS_ToBigIntFree(ctx, buf, JS_DupValue(ctx, val));
+}
+
+static __maybe_unused JSValue JS_ToBigIntValueFree(JSContext *ctx, JSValue val)
+{
+ if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT) {
+ return val;
+ } else {
+ bf_t a_s, *a, *r;
+ int ret;
+ JSValue res;
+
+ res = JS_NewBigInt(ctx);
+ if (JS_IsException(res))
+ return JS_EXCEPTION;
+ a = JS_ToBigIntFree(ctx, &a_s, val);
+ if (!a) {
+ JS_FreeValue(ctx, res);
+ return JS_EXCEPTION;
+ }
+ r = JS_GetBigInt(res);
+ ret = bf_set(r, a);
+ JS_FreeBigInt(ctx, a, &a_s);
+ if (ret) {
+ JS_FreeValue(ctx, res);
+ return JS_ThrowOutOfMemory(ctx);
+ }
+ return JS_CompactBigInt(ctx, res);
+ }
+}
+
+/* free the bf_t allocated by JS_ToBigInt */
+static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf)
+{
+ if (a == buf) {
+ bf_delete(a);
+ } else {
+ JSBigFloat *p = (JSBigFloat *)((uint8_t *)a -
+ offsetof(JSBigFloat, num));
+ JS_FreeValue(ctx, JS_MKPTR(JS_TAG_BIG_FLOAT, p));
+ }
+}
+
+/* XXX: merge with JS_ToInt64Free with a specific flag */
+static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
+{
+ bf_t a_s, *a;
+
+ a = JS_ToBigIntFree(ctx, &a_s, val);
+ if (!a) {
+ *pres = 0;
+ return -1;
+ }
+ bf_get_int64(pres, a, BF_GET_INT_MOD);
+ JS_FreeBigInt(ctx, a, &a_s);
+ return 0;
+}
+
+int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
+{
+ return JS_ToBigInt64Free(ctx, pres, JS_DupValue(ctx, val));
+}
+
+static JSBigFloat *js_new_bf(JSContext *ctx)
+{
+ JSBigFloat *p;
+ p = js_malloc(ctx, sizeof(*p));
+ if (!p)
+ return NULL;
+ p->header.ref_count = 1;
+ bf_init(ctx->bf_ctx, &p->num);
+ return p;
+}
+
+static JSValue JS_NewBigFloat(JSContext *ctx)
+{
+ JSBigFloat *p;
+ p = js_malloc(ctx, sizeof(*p));
+ if (!p)
+ return JS_EXCEPTION;
+ p->header.ref_count = 1;
+ bf_init(ctx->bf_ctx, &p->num);
+ return JS_MKPTR(JS_TAG_BIG_FLOAT, p);
+}
+
+static JSValue JS_NewBigDecimal(JSContext *ctx)
+{
+ JSBigDecimal *p;
+ p = js_malloc(ctx, sizeof(*p));
+ if (!p)
+ return JS_EXCEPTION;
+ p->header.ref_count = 1;
+ bfdec_init(ctx->bf_ctx, &p->num);
+ return JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
+}
+
+static JSValue JS_NewBigInt(JSContext *ctx)
+{
+ JSBigFloat *p;
+ p = js_malloc(ctx, sizeof(*p));
+ if (!p)
+ return JS_EXCEPTION;
+ p->header.ref_count = 1;
+ bf_init(ctx->bf_ctx, &p->num);
+ return JS_MKPTR(JS_TAG_BIG_INT, p);
+}
+
+static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
+ BOOL convert_to_safe_integer)
+{
+ int64_t v;
+ bf_t *a;
+
+ if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT)
+ return val; /* fail safe */
+ a = JS_GetBigInt(val);
+ if (convert_to_safe_integer && bf_get_int64(&v, a, 0) == 0 &&
+ v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
+ JS_FreeValue(ctx, val);
+ return JS_NewInt64(ctx, v);
+ } else if (a->expn == BF_EXP_ZERO && a->sign) {
+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ assert(p->header.ref_count == 1);
+ a->sign = 0;
+ }
+ return val;
+}
+
+/* Convert the big int to a safe integer if in math mode. normalize
+ the zero representation. Could also be used to convert the bigint
+ to a short bigint value. The reference count of the value must be
+ 1. Cannot fail */
+static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val)
+{
+ return JS_CompactBigInt1(ctx, val, is_math_mode(ctx));
+}
+
+/* must be kept in sync with JSOverloadableOperatorEnum */
+/* XXX: use atoms ? */
+static const char js_overloadable_operator_names[JS_OVOP_COUNT][4] = {
+ "+",
+ "-",
+ "*",
+ "/",
+ "%",
+ "**",
+ "|",
+ "&",
+ "^",
+ "<<",
+ ">>",
+ ">>>",
+ "==",
+ "<",
+ "pos",
+ "neg",
+ "++",
+ "--",
+ "~",
+};
+
+static int get_ovop_from_opcode(OPCodeEnum op)
+{
+ switch(op) {
+ case OP_add:
+ return JS_OVOP_ADD;
+ case OP_sub:
+ return JS_OVOP_SUB;
+ case OP_mul:
+ return JS_OVOP_MUL;
+ case OP_div:
+ return JS_OVOP_DIV;
+ case OP_mod:
+ case OP_math_mod:
+ return JS_OVOP_MOD;
+ case OP_pow:
+ return JS_OVOP_POW;
+ case OP_or:
+ return JS_OVOP_OR;
+ case OP_and:
+ return JS_OVOP_AND;
+ case OP_xor:
+ return JS_OVOP_XOR;
+ case OP_shl:
+ return JS_OVOP_SHL;
+ case OP_sar:
+ return JS_OVOP_SAR;
+ case OP_shr:
+ return JS_OVOP_SHR;
+ case OP_eq:
+ case OP_neq:
+ return JS_OVOP_EQ;
+ case OP_lt:
+ case OP_lte:
+ case OP_gt:
+ case OP_gte:
+ return JS_OVOP_LESS;
+ case OP_plus:
+ return JS_OVOP_POS;
+ case OP_neg:
+ return JS_OVOP_NEG;
+ case OP_inc:
+ return JS_OVOP_INC;
+ case OP_dec:
+ return JS_OVOP_DEC;
+ default:
+ abort();
+ }
+}
+
+/* return NULL if not present */
+static JSObject *find_binary_op(JSBinaryOperatorDef *def,
+ uint32_t operator_index,
+ JSOverloadableOperatorEnum op)
+{
+ JSBinaryOperatorDefEntry *ent;
+ int i;
+ for(i = 0; i < def->count; i++) {
+ ent = &def->tab[i];
+ if (ent->operator_index == operator_index)
+ return ent->ops[op];
+ }
+ return NULL;
+}
+
+/* return -1 if exception, 0 if no operator overloading, 1 if
+ overloaded operator called */
+static __exception int js_call_binary_op_fallback(JSContext *ctx,
+ JSValue *pret,
+ JSValueConst op1,
+ JSValueConst op2,
+ OPCodeEnum op,
+ BOOL is_numeric,
+ int hint)
+{
+ JSValue opset1_obj, opset2_obj, method, ret, new_op1, new_op2;
+ JSOperatorSetData *opset1, *opset2;
+ JSOverloadableOperatorEnum ovop;
+ JSObject *p;
+ JSValueConst args[2];
+
+ if (!ctx->allow_operator_overloading)
+ return 0;
+
+ opset2_obj = JS_UNDEFINED;
+ opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
+ if (JS_IsException(opset1_obj))
+ goto exception;
+ if (JS_IsUndefined(opset1_obj))
+ return 0;
+ opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
+ if (!opset1)
+ goto exception;
+
+ opset2_obj = JS_GetProperty(ctx, op2, JS_ATOM_Symbol_operatorSet);
+ if (JS_IsException(opset2_obj))
+ goto exception;
+ if (JS_IsUndefined(opset2_obj)) {
+ JS_FreeValue(ctx, opset1_obj);
+ return 0;
+ }
+ opset2 = JS_GetOpaque2(ctx, opset2_obj, JS_CLASS_OPERATOR_SET);
+ if (!opset2)
+ goto exception;
+
+ if (opset1->is_primitive && opset2->is_primitive) {
+ JS_FreeValue(ctx, opset1_obj);
+ JS_FreeValue(ctx, opset2_obj);
+ return 0;
+ }
+
+ ovop = get_ovop_from_opcode(op);
+
+ if (opset1->operator_counter == opset2->operator_counter) {
+ p = opset1->self_ops[ovop];
+ } else if (opset1->operator_counter > opset2->operator_counter) {
+ p = find_binary_op(&opset1->left, opset2->operator_counter, ovop);
+ } else {
+ p = find_binary_op(&opset2->right, opset1->operator_counter, ovop);
+ }
+ if (!p) {
+ JS_ThrowTypeError(ctx, "operator %s: no function defined",
+ js_overloadable_operator_names[ovop]);
+ goto exception;
+ }
+
+ if (opset1->is_primitive) {
+ if (is_numeric) {
+ new_op1 = JS_ToNumeric(ctx, op1);
+ } else {
+ new_op1 = JS_ToPrimitive(ctx, op1, hint);
+ }
+ if (JS_IsException(new_op1))
+ goto exception;
+ } else {
+ new_op1 = JS_DupValue(ctx, op1);
+ }
+
+ if (opset2->is_primitive) {
+ if (is_numeric) {
+ new_op2 = JS_ToNumeric(ctx, op2);
+ } else {
+ new_op2 = JS_ToPrimitive(ctx, op2, hint);
+ }
+ if (JS_IsException(new_op2)) {
+ JS_FreeValue(ctx, new_op1);
+ goto exception;
+ }
+ } else {
+ new_op2 = JS_DupValue(ctx, op2);
+ }
+
+ /* XXX: could apply JS_ToPrimitive() if primitive type so that the
+ operator function does not get a value object */
+
+ method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+ if (ovop == JS_OVOP_LESS && (op == OP_lte || op == OP_gt)) {
+ args[0] = new_op2;
+ args[1] = new_op1;
+ } else {
+ args[0] = new_op1;
+ args[1] = new_op2;
+ }
+ ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
+ JS_FreeValue(ctx, new_op1);
+ JS_FreeValue(ctx, new_op2);
+ if (JS_IsException(ret))
+ goto exception;
+ if (ovop == JS_OVOP_EQ) {
+ BOOL res = JS_ToBoolFree(ctx, ret);
+ if (op == OP_neq)
+ res ^= 1;
+ ret = JS_NewBool(ctx, res);
+ } else if (ovop == JS_OVOP_LESS) {
+ if (JS_IsUndefined(ret)) {
+ ret = JS_FALSE;
+ } else {
+ BOOL res = JS_ToBoolFree(ctx, ret);
+ if (op == OP_lte || op == OP_gte)
+ res ^= 1;
+ ret = JS_NewBool(ctx, res);
+ }
+ }
+ JS_FreeValue(ctx, opset1_obj);
+ JS_FreeValue(ctx, opset2_obj);
+ *pret = ret;
+ return 1;
+ exception:
+ JS_FreeValue(ctx, opset1_obj);
+ JS_FreeValue(ctx, opset2_obj);
+ *pret = JS_UNDEFINED;
+ return -1;
+}
+
+/* try to call the operation on the operatorSet field of 'obj'. Only
+ used for "/" and "**" on the BigInt prototype in math mode */
+static __exception int js_call_binary_op_simple(JSContext *ctx,
+ JSValue *pret,
+ JSValueConst obj,
+ JSValueConst op1,
+ JSValueConst op2,
+ OPCodeEnum op)
+{
+ JSValue opset1_obj, method, ret, new_op1, new_op2;
+ JSOperatorSetData *opset1;
+ JSOverloadableOperatorEnum ovop;
+ JSObject *p;
+ JSValueConst args[2];
+
+ opset1_obj = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet);
+ if (JS_IsException(opset1_obj))
+ goto exception;
+ if (JS_IsUndefined(opset1_obj))
+ return 0;
+ opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
+ if (!opset1)
+ goto exception;
+ ovop = get_ovop_from_opcode(op);
+
+ p = opset1->self_ops[ovop];
+ if (!p) {
+ JS_FreeValue(ctx, opset1_obj);
+ return 0;
+ }
+
+ new_op1 = JS_ToNumeric(ctx, op1);
+ if (JS_IsException(new_op1))
+ goto exception;
+ new_op2 = JS_ToNumeric(ctx, op2);
+ if (JS_IsException(new_op2)) {
+ JS_FreeValue(ctx, new_op1);
+ goto exception;
+ }
+
+ method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+ args[0] = new_op1;
+ args[1] = new_op2;
+ ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
+ JS_FreeValue(ctx, new_op1);
+ JS_FreeValue(ctx, new_op2);
+ if (JS_IsException(ret))
+ goto exception;
+ JS_FreeValue(ctx, opset1_obj);
+ *pret = ret;
+ return 1;
+ exception:
+ JS_FreeValue(ctx, opset1_obj);
+ *pret = JS_UNDEFINED;
+ return -1;
+}
+
+/* return -1 if exception, 0 if no operator overloading, 1 if
+ overloaded operator called */
+static __exception int js_call_unary_op_fallback(JSContext *ctx,
+ JSValue *pret,
+ JSValueConst op1,
+ OPCodeEnum op)
+{
+ JSValue opset1_obj, method, ret;
+ JSOperatorSetData *opset1;
+ JSOverloadableOperatorEnum ovop;
+ JSObject *p;
+
+ if (!ctx->allow_operator_overloading)
+ return 0;
+
+ opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
+ if (JS_IsException(opset1_obj))
+ goto exception;
+ if (JS_IsUndefined(opset1_obj))
+ return 0;
+ opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
+ if (!opset1)
+ goto exception;
+ if (opset1->is_primitive) {
+ JS_FreeValue(ctx, opset1_obj);
+ return 0;
+ }
+
+ ovop = get_ovop_from_opcode(op);
+
+ p = opset1->self_ops[ovop];
+ if (!p) {
+ JS_ThrowTypeError(ctx, "no overloaded operator %s",
+ js_overloadable_operator_names[ovop]);
+ goto exception;
+ }
+ method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+ ret = JS_CallFree(ctx, method, JS_UNDEFINED, 1, &op1);
+ if (JS_IsException(ret))
+ goto exception;
+ JS_FreeValue(ctx, opset1_obj);
+ *pret = ret;
+ return 1;
+ exception:
+ JS_FreeValue(ctx, opset1_obj);
+ *pret = JS_UNDEFINED;
+ return -1;
+}
+
+static JSValue throw_bf_exception(JSContext *ctx, int status)
+{
+ const char *str;
+ if (status & BF_ST_MEM_ERROR)
+ return JS_ThrowOutOfMemory(ctx);
+ if (status & BF_ST_DIVIDE_ZERO) {
+ str = "division by zero";
+ } else if (status & BF_ST_INVALID_OP) {
+ str = "invalid operation";
+ } else {
+ str = "integer overflow";
+ }
+ return JS_ThrowRangeError(ctx, "%s", str);
+}
+
+static int js_unary_arith_bigint(JSContext *ctx,
+ JSValue *pres, OPCodeEnum op, JSValue op1)
+{
+ bf_t a_s, *r, *a;
+ int ret, v;
+ JSValue res;
+
+ if (op == OP_plus && !is_math_mode(ctx)) {
+ JS_ThrowTypeError(ctx, "bigint argument with unary +");
+ JS_FreeValue(ctx, op1);
+ return -1;
+ }
+ res = JS_NewBigInt(ctx);
+ if (JS_IsException(res)) {
+ JS_FreeValue(ctx, op1);
+ return -1;
+ }
+ r = JS_GetBigInt(res);
+ a = JS_ToBigInt(ctx, &a_s, op1);
+ ret = 0;
+ switch(op) {
+ case OP_inc:
+ case OP_dec:
+ v = 2 * (op - OP_dec) - 1;
+ ret = bf_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
+ break;
+ case OP_plus:
+ ret = bf_set(r, a);
+ break;
+ case OP_neg:
+ ret = bf_set(r, a);
+ bf_neg(r);
+ break;
+ case OP_not:
+ ret = bf_add_si(r, a, 1, BF_PREC_INF, BF_RNDZ);
+ bf_neg(r);
+ break;
+ default:
+ abort();
+ }
+ JS_FreeBigInt(ctx, a, &a_s);
+ JS_FreeValue(ctx, op1);
+ if (unlikely(ret)) {
+ JS_FreeValue(ctx, res);
+ throw_bf_exception(ctx, ret);
+ return -1;
+ }
+ res = JS_CompactBigInt(ctx, res);
+ *pres = res;
+ return 0;
+}
+
+static int js_unary_arith_bigfloat(JSContext *ctx,
+ JSValue *pres, OPCodeEnum op, JSValue op1)
+{
+ bf_t a_s, *r, *a;
+ int ret, v;
+ JSValue res;
+
+ if (op == OP_plus && !is_math_mode(ctx)) {
+ JS_ThrowTypeError(ctx, "bigfloat argument with unary +");
+ JS_FreeValue(ctx, op1);
+ return -1;
+ }
+
+ res = JS_NewBigFloat(ctx);
+ if (JS_IsException(res)) {
+ JS_FreeValue(ctx, op1);
+ return -1;
+ }
+ r = JS_GetBigFloat(res);
+ a = JS_ToBigFloat(ctx, &a_s, op1);
+ ret = 0;
+ switch(op) {
+ case OP_inc:
+ case OP_dec:
+ v = 2 * (op - OP_dec) - 1;
+ ret = bf_add_si(r, a, v, ctx->fp_env.prec, ctx->fp_env.flags);
+ break;
+ case OP_plus:
+ ret = bf_set(r, a);
+ break;
+ case OP_neg:
+ ret = bf_set(r, a);
+ bf_neg(r);
+ break;
+ default:
+ abort();
+ }
+ if (a == &a_s)
+ bf_delete(a);
+ JS_FreeValue(ctx, op1);
+ if (unlikely(ret & BF_ST_MEM_ERROR)) {
+ JS_FreeValue(ctx, res);
+ throw_bf_exception(ctx, ret);
+ return -1;
+ }
+ *pres = res;
+ return 0;
+}
+
+static int js_unary_arith_bigdecimal(JSContext *ctx,
+ JSValue *pres, OPCodeEnum op, JSValue op1)
+{
+ bfdec_t *r, *a;
+ int ret, v;
+ JSValue res;
+
+ if (op == OP_plus && !is_math_mode(ctx)) {
+ JS_ThrowTypeError(ctx, "bigdecimal argument with unary +");
+ JS_FreeValue(ctx, op1);
+ return -1;
+ }
+
+ res = JS_NewBigDecimal(ctx);
+ if (JS_IsException(res)) {
+ JS_FreeValue(ctx, op1);
+ return -1;
+ }
+ r = JS_GetBigDecimal(res);
+ a = JS_ToBigDecimal(ctx, op1);
+ ret = 0;
+ switch(op) {
+ case OP_inc:
+ case OP_dec:
+ v = 2 * (op - OP_dec) - 1;
+ ret = bfdec_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
+ break;
+ case OP_plus:
+ ret = bfdec_set(r, a);
+ break;
+ case OP_neg:
+ ret = bfdec_set(r, a);
+ bfdec_neg(r);
+ break;
+ default:
+ abort();
+ }
+ JS_FreeValue(ctx, op1);
+ if (unlikely(ret)) {
+ JS_FreeValue(ctx, res);
+ throw_bf_exception(ctx, ret);
+ return -1;
+ }
+ *pres = res;
+ return 0;
+}
+
+static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
+ JSValue *sp,
+ OPCodeEnum op)
+{
+ JSValue op1, val;
+ int v, ret;
+ uint32_t tag;
+
+ op1 = sp[-1];
+ /* fast path for float64 */
+ if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)))
+ goto handle_float64;
+ if (JS_IsObject(op1)) {
+ ret = js_call_unary_op_fallback(ctx, &val, op1, op);
+ if (ret < 0)
+ return -1;
+ if (ret) {
+ JS_FreeValue(ctx, op1);
+ sp[-1] = val;
+ return 0;
+ }
+ }
+
+ 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_BIG_INT:
+ handle_bigint:
+ if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, op, op1))
+ goto exception;
+ break;
+ case JS_TAG_BIG_FLOAT:
+ if (ctx->rt->bigfloat_ops.unary_arith(ctx, sp - 1, op, op1))
+ goto exception;
+ break;
+ case JS_TAG_BIG_DECIMAL:
+ if (ctx->rt->bigdecimal_ops.unary_arith(ctx, sp - 1, op, op1))
+ goto exception;
+ break;
+ default:
+ handle_float64:
+ {
+ double d;
+ if (is_math_mode(ctx))
+ goto handle_bigint;
+ 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, val;
+ int ret;
+
+ op1 = sp[-1];
+ if (JS_IsObject(op1)) {
+ ret = js_call_unary_op_fallback(ctx, &val, op1, OP_not);
+ if (ret < 0)
+ return -1;
+ if (ret) {
+ JS_FreeValue(ctx, op1);
+ sp[-1] = val;
+ return 0;
+ }
+ }
+
+ op1 = JS_ToNumericFree(ctx, op1);
+ if (JS_IsException(op1))
+ goto exception;
+ if (is_math_mode(ctx) || JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) {
+ if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, OP_not, op1))
+ goto exception;
+ } 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 int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op,
+ JSValue *pres, JSValue op1, JSValue op2)
+{
+ bf_t a_s, b_s, *r, *a, *b;
+ int ret;
+ JSValue res;
+
+ res = JS_NewBigFloat(ctx);
+ if (JS_IsException(res)) {
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ return -1;
+ }
+ r = JS_GetBigFloat(res);
+ a = JS_ToBigFloat(ctx, &a_s, op1);
+ b = JS_ToBigFloat(ctx, &b_s, op2);
+ bf_init(ctx->bf_ctx, r);
+ switch(op) {
+ case OP_add:
+ ret = bf_add(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
+ break;
+ case OP_sub:
+ ret = bf_sub(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
+ break;
+ case OP_mul:
+ ret = bf_mul(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
+ break;
+ case OP_div:
+ ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
+ break;
+ case OP_math_mod:
+ /* Euclidian remainder */
+ ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
+ BF_DIVREM_EUCLIDIAN);
+ break;
+ case OP_mod:
+ ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
+ BF_RNDZ);
+ break;
+ case OP_pow:
+ ret = bf_pow(r, a, b, ctx->fp_env.prec,
+ ctx->fp_env.flags | BF_POW_JS_QUIRKS);
+ break;
+ default:
+ abort();
+ }
+ if (a == &a_s)
+ bf_delete(a);
+ if (b == &b_s)
+ bf_delete(b);
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ if (unlikely(ret & BF_ST_MEM_ERROR)) {
+ JS_FreeValue(ctx, res);
+ throw_bf_exception(ctx, ret);
+ return -1;
+ }
+ *pres = res;
+ return 0;
+}
+
+static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
+ JSValue *pres, JSValue op1, JSValue op2)
+{
+ bf_t a_s, b_s, *r, *a, *b;
+ int ret;
+ JSValue res;
+
+ res = JS_NewBigInt(ctx);
+ if (JS_IsException(res))
+ goto fail;
+ a = JS_ToBigInt(ctx, &a_s, op1);
+ if (!a)
+ goto fail;
+ b = JS_ToBigInt(ctx, &b_s, op2);
+ if (!b) {
+ JS_FreeBigInt(ctx, a, &a_s);
+ goto fail;
+ }
+ r = JS_GetBigInt(res);
+ ret = 0;
+ switch(op) {
+ case OP_add:
+ ret = bf_add(r, a, b, BF_PREC_INF, BF_RNDZ);
+ break;
+ case OP_sub:
+ ret = bf_sub(r, a, b, BF_PREC_INF, BF_RNDZ);
+ break;
+ case OP_mul:
+ ret = bf_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
+ break;
+ case OP_div:
+ if (!is_math_mode(ctx)) {
+ bf_t rem_s, *rem = &rem_s;
+ bf_init(ctx->bf_ctx, rem);
+ ret = bf_divrem(r, rem, a, b, BF_PREC_INF, BF_RNDZ,
+ BF_RNDZ);
+ bf_delete(rem);
+ } else {
+ goto math_mode_div_pow;
+ }
+ break;
+ case OP_math_mod:
+ /* Euclidian remainder */
+ ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
+ BF_DIVREM_EUCLIDIAN) & BF_ST_INVALID_OP;
+ break;
+ case OP_mod:
+ ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
+ BF_RNDZ) & BF_ST_INVALID_OP;
+ break;
+ case OP_pow:
+ if (b->sign) {
+ if (!is_math_mode(ctx)) {
+ ret = BF_ST_INVALID_OP;
+ } else {
+ math_mode_div_pow:
+ JS_FreeValue(ctx, res);
+ ret = js_call_binary_op_simple(ctx, &res, ctx->class_proto[JS_CLASS_BIG_INT], op1, op2, op);
+ if (ret != 0) {
+ JS_FreeBigInt(ctx, a, &a_s);
+ JS_FreeBigInt(ctx, b, &b_s);
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ if (ret < 0) {
+ return -1;
+ } else {
+ *pres = res;
+ return 0;
+ }
+ }
+ /* if no BigInt power operator defined, return a
+ bigfloat */
+ res = JS_NewBigFloat(ctx);
+ if (JS_IsException(res)) {
+ JS_FreeBigInt(ctx, a, &a_s);
+ JS_FreeBigInt(ctx, b, &b_s);
+ goto fail;
+ }
+ r = JS_GetBigFloat(res);
+ if (op == OP_div) {
+ ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags) & BF_ST_MEM_ERROR;
+ } else {
+ ret = bf_pow(r, a, b, ctx->fp_env.prec,
+ ctx->fp_env.flags | BF_POW_JS_QUIRKS) & BF_ST_MEM_ERROR;
+ }
+ JS_FreeBigInt(ctx, a, &a_s);
+ JS_FreeBigInt(ctx, b, &b_s);
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ if (unlikely(ret)) {
+ JS_FreeValue(ctx, res);
+ throw_bf_exception(ctx, ret);
+ return -1;
+ }
+ *pres = res;
+ return 0;
+ }
+ } else {
+ ret = bf_pow(r, a, b, BF_PREC_INF, BF_RNDZ | BF_POW_JS_QUIRKS);
+ }
+ break;
+
+ /* logical operations */
+ case OP_shl:
+ case OP_sar:
+ {
+ slimb_t v2;
+#if LIMB_BITS == 32
+ bf_get_int32(&v2, b, 0);
+ if (v2 == INT32_MIN)
+ v2 = INT32_MIN + 1;
+#else
+ bf_get_int64(&v2, b, 0);
+ if (v2 == INT64_MIN)
+ v2 = INT64_MIN + 1;
+#endif
+ if (op == OP_sar)
+ v2 = -v2;
+ ret = bf_set(r, a);
+ ret |= bf_mul_2exp(r, v2, BF_PREC_INF, BF_RNDZ);
+ if (v2 < 0) {
+ ret |= bf_rint(r, BF_RNDD) & (BF_ST_OVERFLOW | BF_ST_MEM_ERROR);
+ }
+ }
+ break;
+ case OP_and:
+ ret = bf_logic_and(r, a, b);
+ break;
+ case OP_or:
+ ret = bf_logic_or(r, a, b);
+ break;
+ case OP_xor:
+ ret = bf_logic_xor(r, a, b);
+ break;
+ default:
+ abort();
+ }
+ JS_FreeBigInt(ctx, a, &a_s);
+ JS_FreeBigInt(ctx, b, &b_s);
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ if (unlikely(ret)) {
+ JS_FreeValue(ctx, res);
+ throw_bf_exception(ctx, ret);
+ return -1;
+ }
+ *pres = JS_CompactBigInt(ctx, res);
+ return 0;
+ fail:
+ JS_FreeValue(ctx, res);
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ return -1;
+}
+
+/* b must be a positive integer */
+static int js_bfdec_pow(bfdec_t *r, const bfdec_t *a, const bfdec_t *b)
+{
+ bfdec_t b1;
+ int32_t b2;
+ int ret;
+
+ bfdec_init(b->ctx, &b1);
+ ret = bfdec_set(&b1, b);
+ if (ret) {
+ bfdec_delete(&b1);
+ return ret;
+ }
+ ret = bfdec_rint(&b1, BF_RNDZ);
+ if (ret) {
+ bfdec_delete(&b1);
+ return BF_ST_INVALID_OP; /* must be an integer */
+ }
+ ret = bfdec_get_int32(&b2, &b1);
+ bfdec_delete(&b1);
+ if (ret)
+ return ret; /* overflow */
+ if (b2 < 0)
+ return BF_ST_INVALID_OP; /* must be positive */
+ return bfdec_pow_ui(r, a, b2);
+}
+
+static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op,
+ JSValue *pres, JSValue op1, JSValue op2)
+{
+ bfdec_t *r, *a, *b;
+ int ret;
+ JSValue res;
+
+ res = JS_NewBigDecimal(ctx);
+ if (JS_IsException(res))
+ goto fail;
+ r = JS_GetBigDecimal(res);
+
+ a = JS_ToBigDecimal(ctx, op1);
+ if (!a)
+ goto fail;
+ b = JS_ToBigDecimal(ctx, op2);
+ if (!b)
+ goto fail;
+ switch(op) {
+ case OP_add:
+ ret = bfdec_add(r, a, b, BF_PREC_INF, BF_RNDZ);
+ break;
+ case OP_sub:
+ ret = bfdec_sub(r, a, b, BF_PREC_INF, BF_RNDZ);
+ break;
+ case OP_mul:
+ ret = bfdec_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
+ break;
+ case OP_div:
+ ret = bfdec_div(r, a, b, BF_PREC_INF, BF_RNDZ);
+ break;
+ case OP_math_mod:
+ /* Euclidian remainder */
+ ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_DIVREM_EUCLIDIAN);
+ break;
+ case OP_mod:
+ ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ);
+ break;
+ case OP_pow:
+ ret = js_bfdec_pow(r, a, b);
+ break;
+ default:
+ abort();
+ }
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ if (unlikely(ret)) {
+ JS_FreeValue(ctx, res);
+ throw_bf_exception(ctx, ret);
+ return -1;
+ }
+ *pres = res;
+ return 0;
+ fail:
+ JS_FreeValue(ctx, res);
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ return -1;
+}
+
+static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
+ OPCodeEnum op)
+{
+ JSValue op1, op2, res;
+ uint32_t tag1, tag2;
+ int ret;
+ 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;
+ }
+
+ /* try to call an overloaded operator */
+ if ((tag1 == JS_TAG_OBJECT &&
+ (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
+ (tag2 == JS_TAG_OBJECT &&
+ (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
+ ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
+ if (ret != 0) {
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ if (ret < 0) {
+ goto exception;
+ } else {
+ sp[-2] = res;
+ 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 (is_math_mode(ctx) &&
+ (v < -MAX_SAFE_INTEGER || v > MAX_SAFE_INTEGER))
+ goto handle_bigint;
+ if (v == 0 && (v1 | v2) < 0) {
+ sp[-2] = __JS_NewFloat64(ctx, -0.0);
+ return 0;
+ }
+ break;
+ case OP_div:
+ if (is_math_mode(ctx))
+ goto handle_bigint;
+ sp[-2] = __JS_NewFloat64(ctx, (double)v1 / (double)v2);
+ return 0;
+ case OP_math_mod:
+ if (unlikely(v2 == 0)) {
+ throw_bf_exception(ctx, BF_ST_DIVIDE_ZERO);
+ goto exception;
+ }
+ v = (int64_t)v1 % (int64_t)v2;
+ if (v < 0) {
+ if (v2 < 0)
+ v -= v2;
+ else
+ v += v2;
+ }
+ break;
+ 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:
+ if (!is_math_mode(ctx)) {
+ sp[-2] = JS_NewFloat64(ctx, js_pow(v1, v2));
+ return 0;
+ } else {
+ goto handle_bigint;
+ }
+ break;
+ default:
+ abort();
+ }
+ sp[-2] = JS_NewInt64(ctx, v);
+ } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
+ if (ctx->rt->bigdecimal_ops.binary_arith(ctx, op, sp - 2, op1, op2))
+ goto exception;
+ } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
+ if (ctx->rt->bigfloat_ops.binary_arith(ctx, op, sp - 2, op1, op2))
+ goto exception;
+ } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
+ handle_bigint:
+ if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
+ goto exception;
+ } 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:
+ if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2))
+ goto handle_bigint;
+ 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_math_mod:
+ d2 = fabs(d2);
+ dr = fmod(d1, d2);
+ /* XXX: loss of accuracy if dr < 0 */
+ if (dr < 0)
+ dr += 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 no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
+{
+ JSValue op1, op2, res;
+ uint32_t tag1, tag2;
+ int ret;
+
+ 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;
+ }
+
+ if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) {
+ /* try to call an overloaded operator */
+ if ((tag1 == JS_TAG_OBJECT &&
+ (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED &&
+ tag2 != JS_TAG_STRING)) ||
+ (tag2 == JS_TAG_OBJECT &&
+ (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED &&
+ tag1 != JS_TAG_STRING))) {
+ ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add,
+ FALSE, HINT_NONE);
+ if (ret != 0) {
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ if (ret < 0) {
+ goto exception;
+ } else {
+ sp[-2] = res;
+ return 0;
+ }
+ }
+ }
+
+ 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 (tag1 == JS_TAG_STRING || tag2 == JS_TAG_STRING) {
+ 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_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
+ if (ctx->rt->bigdecimal_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
+ goto exception;
+ } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
+ if (ctx->rt->bigfloat_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
+ goto exception;
+ } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
+ handle_bigint:
+ if (ctx->rt->bigint_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
+ goto exception;
+ } 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;
+ if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2))
+ goto handle_bigint;
+ 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, res;
+ int ret;
+ 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);
+
+ /* try to call an overloaded operator */
+ if ((tag1 == JS_TAG_OBJECT &&
+ (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
+ (tag2 == JS_TAG_OBJECT &&
+ (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
+ ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
+ if (ret != 0) {
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ if (ret < 0) {
+ goto exception;
+ } else {
+ sp[-2] = res;
+ 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;
+ }
+
+ if (is_math_mode(ctx))
+ goto bigint_op;
+
+ tag1 = JS_VALUE_GET_TAG(op1);
+ tag2 = JS_VALUE_GET_TAG(op2);
+ if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
+ if (tag1 != tag2) {
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ JS_ThrowTypeError(ctx, "both operands must be bigint");
+ goto exception;
+ } else {
+ bigint_op:
+ if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
+ goto exception;
+ }
+ } 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;
+}
+
+/* Note: also used for bigint */
+static int js_compare_bigfloat(JSContext *ctx, OPCodeEnum op,
+ JSValue op1, JSValue op2)
+{
+ bf_t a_s, b_s, *a, *b;
+ int res;
+
+ a = JS_ToBigFloat(ctx, &a_s, op1);
+ if (!a) {
+ JS_FreeValue(ctx, op2);
+ return -1;
+ }
+ b = JS_ToBigFloat(ctx, &b_s, op2);
+ if (!b) {
+ if (a == &a_s)
+ bf_delete(a);
+ JS_FreeValue(ctx, op1);
+ return -1;
+ }
+ switch(op) {
+ case OP_lt:
+ res = bf_cmp_lt(a, b); /* if NaN return false */
+ break;
+ case OP_lte:
+ res = bf_cmp_le(a, b); /* if NaN return false */
+ break;
+ case OP_gt:
+ res = bf_cmp_lt(b, a); /* if NaN return false */
+ break;
+ case OP_gte:
+ res = bf_cmp_le(b, a); /* if NaN return false */
+ break;
+ case OP_eq:
+ res = bf_cmp_eq(a, b); /* if NaN return false */
+ break;
+ default:
+ abort();
+ }
+ if (a == &a_s)
+ bf_delete(a);
+ if (b == &b_s)
+ bf_delete(b);
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ return res;
+}
+
+static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op,
+ JSValue op1, JSValue op2)
+{
+ bfdec_t *a, *b;
+ int res;
+
+ /* Note: binary floats are converted to bigdecimal with
+ toString(). It is not mathematically correct but is consistent
+ with the BigDecimal() constructor behavior */
+ op1 = JS_ToBigDecimalFree(ctx, op1, TRUE);
+ if (JS_IsException(op1)) {
+ JS_FreeValue(ctx, op2);
+ return -1;
+ }
+ op2 = JS_ToBigDecimalFree(ctx, op2, TRUE);
+ if (JS_IsException(op2)) {
+ JS_FreeValue(ctx, op1);
+ return -1;
+ }
+ a = JS_ToBigDecimal(ctx, op1);
+ b = JS_ToBigDecimal(ctx, op2);
+
+ switch(op) {
+ case OP_lt:
+ res = bfdec_cmp_lt(a, b); /* if NaN return false */
+ break;
+ case OP_lte:
+ res = bfdec_cmp_le(a, b); /* if NaN return false */
+ break;
+ case OP_gt:
+ res = bfdec_cmp_lt(b, a); /* if NaN return false */
+ break;
+ case OP_gte:
+ res = bfdec_cmp_le(b, a); /* if NaN return false */
+ break;
+ case OP_eq:
+ res = bfdec_cmp_eq(a, b); /* if NaN return false */
+ break;
+ default:
+ abort();
+ }
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ return res;
+}
+
+static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
+ OPCodeEnum op)
+{
+ JSValue op1, op2, ret;
+ 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);
+ /* try to call an overloaded operator */
+ if ((tag1 == JS_TAG_OBJECT &&
+ (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
+ (tag2 == JS_TAG_OBJECT &&
+ (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
+ res = js_call_binary_op_fallback(ctx, &ret, op1, op2, op,
+ FALSE, HINT_NUMBER);
+ if (res != 0) {
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ if (res < 0) {
+ goto exception;
+ } else {
+ sp[-2] = ret;
+ return 0;
+ }
+ }
+ }
+ 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 (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) {
+ JSString *p1, *p2;
+ p1 = JS_VALUE_GET_STRING(op1);
+ p2 = JS_VALUE_GET_STRING(op2);
+ res = js_string_compare(ctx, p1, p2);
+ 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)) {
+ /* can use floating point comparison */
+ 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);
+ }
+ 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;
+ }
+ } else {
+ if (((tag1 == JS_TAG_BIG_INT && tag2 == JS_TAG_STRING) ||
+ (tag2 == JS_TAG_BIG_INT && tag1 == JS_TAG_STRING)) &&
+ !is_math_mode(ctx)) {
+ if (tag1 == JS_TAG_STRING) {
+ op1 = JS_StringToBigInt(ctx, op1);
+ if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
+ goto invalid_bigint_string;
+ }
+ if (tag2 == JS_TAG_STRING) {
+ op2 = JS_StringToBigInt(ctx, op2);
+ if (JS_VALUE_GET_TAG(op2) != JS_TAG_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;
+ }
+ }
+
+ if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_DECIMAL ||
+ JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_DECIMAL) {
+ res = ctx->rt->bigdecimal_ops.compare(ctx, op, op1, op2);
+ if (res < 0)
+ goto exception;
+ } else if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_FLOAT ||
+ JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_FLOAT) {
+ res = ctx->rt->bigfloat_ops.compare(ctx, op, op1, op2);
+ if (res < 0)
+ goto exception;
+ } else {
+ res = ctx->rt->bigint_ops.compare(ctx, op, op1, op2);
+ if (res < 0)
+ goto exception;
+ }
+ }
+ 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_BIG_INT ||
+ tag == JS_TAG_FLOAT64 || tag == JS_TAG_BIG_FLOAT ||
+ tag == JS_TAG_BIG_DECIMAL);
+}
+
+static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
+ BOOL is_neq)
+{
+ JSValue op1, op2, ret;
+ 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 if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
+ res = ctx->rt->bigdecimal_ops.compare(ctx, OP_eq, op1, op2);
+ if (res < 0)
+ goto exception;
+ } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
+ res = ctx->rt->bigfloat_ops.compare(ctx, OP_eq, op1, op2);
+ if (res < 0)
+ goto exception;
+ } else {
+ res = ctx->rt->bigint_ops.compare(ctx, OP_eq, op1, op2);
+ if (res < 0)
+ goto exception;
+ }
+ } else if (tag1 == tag2) {
+ if (tag1 == JS_TAG_OBJECT) {
+ /* try the fallback operator */
+ res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
+ is_neq ? OP_neq : OP_eq,
+ FALSE, HINT_NONE);
+ if (res != 0) {
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ if (res < 0) {
+ goto exception;
+ } else {
+ sp[-2] = ret;
+ return 0;
+ }
+ }
+ }
+ 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 ((tag1 == JS_TAG_STRING && tag_is_number(tag2)) ||
+ (tag2 == JS_TAG_STRING && tag_is_number(tag1))) {
+
+ if ((tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) &&
+ !is_math_mode(ctx)) {
+ if (tag1 == JS_TAG_STRING) {
+ op1 = JS_StringToBigInt(ctx, op1);
+ if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
+ goto invalid_bigint_string;
+ }
+ if (tag2 == JS_TAG_STRING) {
+ op2 = JS_StringToBigInt(ctx, op2);
+ if (JS_VALUE_GET_TAG(op2) != JS_TAG_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_eq(ctx, op1, op2);
+ } 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) || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) ||
+ (tag2 == JS_TAG_OBJECT &&
+ (tag_is_number(tag1) || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL))) {
+
+ /* try the fallback operator */
+ res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
+ is_neq ? OP_neq : OP_eq,
+ FALSE, HINT_NONE);
+ if (res != 0) {
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ if (res < 0) {
+ goto exception;
+ } else {
+ sp[-2] = ret;
+ return 0;
+ }
+ }
+
+ 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 {
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ res = FALSE;
+ }
+ 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;
+ }
+ /* XXX: could forbid >>> in bignum mode */
+ if (!is_math_mode(ctx) &&
+ (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT ||
+ JS_VALUE_GET_TAG(op2) == JS_TAG_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;
+}
+
+static JSValue js_mul_pow10_to_float64(JSContext *ctx, const bf_t *a,
+ int64_t exponent)
+{
+ bf_t r_s, *r = &r_s;
+ double d;
+ int ret;
+
+ /* always convert to Float64 */
+ bf_init(ctx->bf_ctx, r);
+ ret = bf_mul_pow_radix(r, a, 10, exponent,
+ 53, bf_set_exp_bits(11) | BF_RNDN |
+ BF_FLAG_SUBNORMAL);
+ bf_get_float64(r, &d, BF_RNDN);
+ bf_delete(r);
+ if (ret & BF_ST_MEM_ERROR)
+ return JS_ThrowOutOfMemory(ctx);
+ else
+ return __JS_NewFloat64(ctx, d);
+}
+
+static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp)
+{
+ bf_t a_s, *a, *r;
+ JSValue op1, op2, res;
+ int64_t e;
+ int ret;
+
+ res = JS_NewBigFloat(ctx);
+ if (JS_IsException(res))
+ return -1;
+ r = JS_GetBigFloat(res);
+ op1 = sp[-2];
+ op2 = sp[-1];
+ a = JS_ToBigFloat(ctx, &a_s, op1);
+ if (!a)
+ return -1;
+ if (JS_IsBigInt(ctx, op2)) {
+ ret = JS_ToBigInt64(ctx, &e, op2);
+ } else {
+ ret = JS_ToInt64(ctx, &e, op2);
+ }
+ if (ret) {
+ if (a == &a_s)
+ bf_delete(a);
+ JS_FreeValue(ctx, res);
+ return -1;
+ }
+
+ bf_mul_pow_radix(r, a, 10, e, ctx->fp_env.prec, ctx->fp_env.flags);
+ if (a == &a_s)
+ bf_delete(a);
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ sp[-2] = res;
+ return 0;
+}
+
+#else /* !CONFIG_BIGNUM */
+
+static JSValue JS_ThrowUnsupportedBigint(JSContext *ctx)
+{
+ return JS_ThrowTypeError(ctx, "bigint is not supported");
+}
+
+JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
+{
+ return JS_ThrowUnsupportedBigint(ctx);
+}
+
+JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
+{
+ return JS_ThrowUnsupportedBigint(ctx);
+}
+
+int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
+{
+ JS_ThrowUnsupportedBigint(ctx);
+ *pres = 0;
+ return -1;
+}
+
+static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
+ JSValue *sp,
+ OPCodeEnum op)
+{
+ JSValue op1;
+ double d;
+
+ op1 = sp[-1];
+ if (unlikely(JS_ToFloat64Free(ctx, &d, op1))) {
+ sp[-1] = JS_UNDEFINED;
+ return -1;
+ }
+ switch(op) {
+ case OP_inc:
+ d++;
+ break;
+ case OP_dec:
+ d--;
+ break;
+ case OP_plus:
+ break;
+ case OP_neg:
+ d = -d;
+ break;
+ default:
+ abort();
+ }
+ sp[-1] = JS_NewFloat64(ctx, d);
+ return 0;
+}
+
+/* specific case necessary for correct return value semantics */
+static __exception int js_post_inc_slow(JSContext *ctx,
+ JSValue *sp, OPCodeEnum op)
+{
+ JSValue op1;
+ double d, r;
+
+ op1 = sp[-1];
+ if (unlikely(JS_ToFloat64Free(ctx, &d, op1))) {
+ sp[-1] = JS_UNDEFINED;
+ return -1;
+ }
+ r = d + 2 * (op - OP_post_dec) - 1;
+ sp[0] = JS_NewFloat64(ctx, r);
+ sp[-1] = JS_NewFloat64(ctx, d);
+ return 0;
+}
+
+static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
+ OPCodeEnum op)
+{
+ JSValue op1, op2;
+ double d1, d2, r;
+
+ op1 = sp[-2];
+ op2 = sp[-1];
+ if (unlikely(JS_ToFloat64Free(ctx, &d1, op1))) {
+ JS_FreeValue(ctx, op2);
+ goto exception;
+ }
+ if (unlikely(JS_ToFloat64Free(ctx, &d2, op2))) {
+ goto exception;
+ }
+ switch(op) {
+ case OP_sub:
+ r = d1 - d2;
+ break;
+ case OP_mul:
+ r = d1 * d2;
+ break;
+ case OP_div:
+ r = d1 / d2;
+ break;
+ case OP_mod:
+ r = fmod(d1, d2);
+ break;
+ case OP_pow:
+ r = js_pow(d1, d2);
+ break;
+ default:
+ abort();
+ }
+ sp[-2] = JS_NewFloat64(ctx, r);
+ return 0;
+ exception:
+ sp[-2] = JS_UNDEFINED;
+ sp[-1] = JS_UNDEFINED;
+ return -1;
+}
+
+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_TAG(op1);
+ tag2 = JS_VALUE_GET_TAG(op2);
+ if ((tag1 == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag1)) &&
+ (tag2 == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag2))) {
+ goto add_numbers;
+ } else {
+ 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_TAG(op1);
+ tag2 = JS_VALUE_GET_TAG(op2);
+ if (tag1 == JS_TAG_STRING || tag2 == JS_TAG_STRING) {
+ sp[-2] = JS_ConcatString(ctx, op1, op2);
+ if (JS_IsException(sp[-2]))
+ goto exception;
+ } else {
+ double d1, d2;
+ add_numbers:
+ 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 v1, v2, r;
+
+ op1 = sp[-2];
+ op2 = sp[-1];
+ 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;
+}
+
+static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
+{
+ int32_t v1;
+
+ if (unlikely(JS_ToInt32Free(ctx, &v1, sp[-1]))) {
+ sp[-1] = JS_UNDEFINED;
+ return -1;
+ }
+ sp[-1] = JS_NewInt32(ctx, ~v1);
+ return 0;
+}
+
+static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
+ OPCodeEnum op)
+{
+ JSValue op1, op2;
+ int res;
+
+ op1 = sp[-2];
+ op2 = sp[-1];
+ 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;
+ }
+ if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING &&
+ JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {
+ JSString *p1, *p2;
+ p1 = JS_VALUE_GET_STRING(op1);
+ p2 = JS_VALUE_GET_STRING(op2);
+ res = js_string_compare(ctx, p1, p2);
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ 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;
+ }
+ } else {
+ double d1, d2;
+ if (JS_ToFloat64Free(ctx, &d1, op1)) {
+ JS_FreeValue(ctx, op2);
+ goto exception;
+ }
+ if (JS_ToFloat64Free(ctx, &d2, op2))
+ goto exception;
+ 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;
+ }
+ }
+ sp[-2] = JS_NewBool(ctx, res);
+ return 0;
+ exception:
+ sp[-2] = JS_UNDEFINED;
+ sp[-1] = JS_UNDEFINED;
+ return -1;
+}
+
+static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
+ BOOL is_neq)
+{
+ JSValue op1, op2;
+ int tag1, tag2;
+ BOOL res;
+
+ op1 = sp[-2];
+ op2 = sp[-1];
+ redo:
+ tag1 = JS_VALUE_GET_NORM_TAG(op1);
+ tag2 = JS_VALUE_GET_NORM_TAG(op2);
+ if (tag1 == tag2 ||
+ (tag1 == JS_TAG_INT && tag2 == JS_TAG_FLOAT64) ||
+ (tag2 == JS_TAG_INT && tag1 == JS_TAG_FLOAT64)) {
+ res = js_strict_eq(ctx, op1, op2);
+ } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) ||
+ (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) {
+ res = TRUE;
+ } else if ((tag1 == JS_TAG_STRING && (tag2 == JS_TAG_INT ||
+ tag2 == JS_TAG_FLOAT64)) ||
+ (tag2 == JS_TAG_STRING && (tag1 == JS_TAG_INT ||
+ tag1 == JS_TAG_FLOAT64))) {
+ double d1;
+ double d2;
+ if (JS_ToFloat64Free(ctx, &d1, op1)) {
+ JS_FreeValue(ctx, op2);
+ goto exception;
+ }
+ if (JS_ToFloat64Free(ctx, &d2, op2))
+ goto exception;
+ res = (d1 == d2);
+ } 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 &&
+ (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64 || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) {
+ op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
+ if (JS_IsException(op1)) {
+ JS_FreeValue(ctx, op2);
+ goto exception;
+ }
+ goto redo;
+ } else if (tag2 == JS_TAG_OBJECT &&
+ (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64 || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL)) {
+ op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
+ if (JS_IsException(op2)) {
+ JS_FreeValue(ctx, op1);
+ goto exception;
+ }
+ goto redo;
+ } else {
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ res = FALSE;
+ }
+ 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];
+ if (unlikely(JS_ToUint32Free(ctx, &v1, op1))) {
+ JS_FreeValue(ctx, op2);
+ goto exception;
+ }
+ if (unlikely(JS_ToUint32Free(ctx, &v2, op2)))
+ goto exception;
+ r = v1 >> (v2 & 0x1f);
+ sp[-2] = JS_NewUint32(ctx, r);
+ return 0;
+ exception:
+ sp[-2] = JS_UNDEFINED;
+ sp[-1] = JS_UNDEFINED;
+ return -1;
+}
+
+#endif /* !CONFIG_BIGNUM */
+
+/* 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:
+ {
+ JSString *p1, *p2;
+ if (tag1 != tag2) {
+ res = FALSE;
+ } else {
+ p1 = JS_VALUE_GET_STRING(op1);
+ p2 = JS_VALUE_GET_STRING(op2);
+ res = (js_string_compare(ctx, p1, p2) == 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;
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_INT:
+ {
+ bf_t a_s, *a, b_s, *b;
+ if (tag1 != tag2) {
+ res = FALSE;
+ break;
+ }
+ a = JS_ToBigFloat(ctx, &a_s, op1);
+ b = JS_ToBigFloat(ctx, &b_s, op2);
+ res = bf_cmp_eq(a, b);
+ if (a == &a_s)
+ bf_delete(a);
+ if (b == &b_s)
+ bf_delete(b);
+ }
+ break;
+ case JS_TAG_BIG_FLOAT:
+ {
+ JSBigFloat *p1, *p2;
+ const bf_t *a, *b;
+ if (tag1 != tag2) {
+ res = FALSE;
+ break;
+ }
+ p1 = JS_VALUE_GET_PTR(op1);
+ p2 = JS_VALUE_GET_PTR(op2);
+ a = &p1->num;
+ b = &p2->num;
+ if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) {
+ if (eq_mode == JS_EQ_SAME_VALUE_ZERO &&
+ a->expn == BF_EXP_ZERO && b->expn == BF_EXP_ZERO) {
+ res = TRUE;
+ } else {
+ res = (bf_cmp_full(a, b) == 0);
+ }
+ } else {
+ res = bf_cmp_eq(a, b);
+ }
+ }
+ break;
+ case JS_TAG_BIG_DECIMAL:
+ {
+ JSBigDecimal *p1, *p2;
+ const bfdec_t *a, *b;
+ if (tag1 != tag2) {
+ res = FALSE;
+ break;
+ }
+ p1 = JS_VALUE_GET_PTR(op1);
+ p2 = JS_VALUE_GET_PTR(op2);
+ a = &p1->num;
+ b = &p2->num;
+ res = bfdec_cmp_eq(a, b);
+ }
+ break;
+#endif
+ default:
+ res = FALSE;
+ break;
+ }
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ done_no_free:
+ return res;
+}
+
+static BOOL js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2)
+{
+ return js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
+}
+
+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);
+}
+
+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);
+}
+
+static no_inline int js_strict_eq_slow(JSContext *ctx, JSValue *sp,
+ BOOL is_neq)
+{
+ BOOL res;
+ res = js_strict_eq(ctx, sp[-2], sp[-1]);
+ 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_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, JSValue op1)
+{
+ JSAtom atom;
+ uint32_t tag;
+
+ tag = JS_VALUE_GET_NORM_TAG(op1);
+ switch(tag) {
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_INT:
+ atom = JS_ATOM_bigint;
+ break;
+ case JS_TAG_BIG_FLOAT:
+ atom = JS_ATOM_bigfloat;
+ break;
+ case JS_TAG_BIG_DECIMAL:
+ atom = JS_ATOM_bigdecimal;
+ break;
+#endif
+ 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:
+ atom = JS_ATOM_string;
+ break;
+ case JS_TAG_OBJECT:
+ 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;
+}
+
+static JSValue js_throw_type_error(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ return JS_ThrowTypeError(ctx, "invalid property access");
+}
+
+/* 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_function_proto_caller(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) {
+ return js_throw_type_error(ctx, this_val, 0, NULL);
+ }
+ 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)
+{
+ JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
+ if (b && b->has_debug) {
+ return JS_NewInt32(ctx, b->debug.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);
+ 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) {
+ JS_FreeValue(ctx, val);
+ return JS_EXCEPTION;
+ }
+ 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;
+}
+
+#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);
+ 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;
+ p = JS_VALUE_GET_OBJ(enum_obj);
+ p->u.for_in_iterator = it;
+
+ if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
+ return enum_obj;
+
+ p = JS_VALUE_GET_OBJ(obj);
+
+ /* fast path: assume no enumerable properties in the prototype chain */
+ p1 = p->shape->proto;
+ while (p1 != NULL) {
+ if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p1,
+ JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY))
+ goto fail;
+ js_free_prop_enum(ctx, tab_atom, tab_atom_count);
+ if (tab_atom_count != 0) {
+ goto slow_path;
+ }
+ p1 = p1->shape->proto;
+ }
+ 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;
+ }
+ /* the implicit GetOwnProperty raises an exception if the
+ typed array is detached */
+ if ((p->class_id >= JS_CLASS_UINT8C_ARRAY &&
+ p->class_id <= JS_CLASS_FLOAT64_ARRAY) &&
+ typed_array_is_detached(ctx, p) &&
+ typed_array_get_length(ctx, p) != 0) {
+ JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+ goto fail;
+ }
+ /* for fast arrays, we only store the number of elements */
+ it->is_array = TRUE;
+ it->array_length = p->u.array.count;
+ } else {
+ normal_case:
+ if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
+ JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY))
+ goto fail;
+ for(i = 0; i < tab_atom_count; i++) {
+ JS_SetPropertyInternal(ctx, enum_obj, tab_atom[i].atom, JS_NULL, 0);
+ }
+ js_free_prop_enum(ctx, tab_atom, tab_atom_count);
+ }
+ return enum_obj;
+
+ slow_path:
+ /* non enumerable properties hide the enumerables ones in the
+ prototype chain */
+ while (p != NULL) {
+ if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
+ JS_GPN_STRING_MASK | JS_GPN_SET_ENUM))
+ goto fail;
+ for(i = 0; i < tab_atom_count; i++) {
+ JS_DefinePropertyValue(ctx, enum_obj, tab_atom[i].atom, JS_NULL,
+ (tab_atom[i].is_enumerable ?
+ JS_PROP_ENUMERABLE : 0));
+ }
+ js_free_prop_enum(ctx, tab_atom, tab_atom_count);
+ p = p->shape->proto;
+ }
+ return enum_obj;
+
+ fail:
+ JS_FreeValue(ctx, enum_obj);
+ return JS_EXCEPTION;
+}
+
+/* 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;
+}
+
+/* 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;
+ 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->is_array) {
+ if (it->idx >= it->array_length)
+ goto done;
+ prop = __JS_AtomFromUInt32(it->idx);
+ it->idx++;
+ } else {
+ JSShape *sh = p->shape;
+ JSShapeProperty *prs;
+ if (it->idx >= sh->prop_count)
+ goto done;
+ prs = get_shape_prop(sh) + it->idx;
+ prop = prs->atom;
+ it->idx++;
+ if (prop == JS_ATOM_NULL || !(prs->flags & JS_PROP_ENUMERABLE))
+ continue;
+ }
+ /* check if the property was deleted */
+ ret = JS_HasProperty(ctx, 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;
+}
+
+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 (done != 2) {
+ *pdone = done;
+ return obj;
+ } 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_NULL;
+ 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 -> enum_rec value done */
+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;
+ }
+ }
+ sp[0] = value;
+ sp[1] = JS_NewBool(ctx, done);
+ return 0;
+}
+
+static __exception int js_for_await_of_next(JSContext *ctx, JSValue *sp)
+{
+ JSValue result;
+ result = JS_Call(ctx, sp[-2], sp[-3], 0, NULL);
+ if (JS_IsException(result))
+ return -1;
+ sp[0] = result;
+ 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);
+ 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 pos, is_array_iterator;
+ JSValue *arrp;
+ uint32_t i, count32;
+
+ 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)) {
+ int64_t len;
+ /* Handle fast arrays explicitly */
+ if (js_get_length64(ctx, &len, sp[-1]))
+ goto exception;
+ 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;
+ }
+ if (len > count32) {
+ /* This is not strictly correct because the trailing elements are
+ empty instead of undefined. Append undefined entries instead.
+ */
+ pos += len - count32;
+ if (JS_SetProperty(ctx, sp[-3], JS_ATOM_length, JS_NewUint32(ctx, pos)) < 0)
+ goto exception;
+ }
+ } else {
+ 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;
+ }
+ }
+ 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 = 0, flags;
+
+ 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);
+ if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
+ JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK |
+ JS_GPN_ENUM_ONLY))
+ return -1;
+
+ flags = JS_PROP_C_W_E;
+
+ 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)
+ break;
+ ret = 0;
+ continue;
+ }
+ }
+ ret = -1;
+ val = JS_GetProperty(ctx, source, tab_atom[i].atom);
+ if (JS_IsException(val))
+ break;
+ if (setprop)
+ ret = JS_SetProperty(ctx, target, tab_atom[i].atom, val);
+ else
+ ret = JS_DefinePropertyValue(ctx, target, tab_atom[i].atom, val, flags);
+ if (ret < 0)
+ break;
+ ret = 0;
+ }
+ js_free_prop_enum(ctx, tab_atom, tab_atom_count);
+ return ret;
+}
+
+/* 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;
+
+ list_for_each(el, &sf->var_ref_list) {
+ var_ref = list_entry(el, JSVarRef, header.link);
+ if (var_ref->var_idx == var_idx && var_ref->is_arg == is_arg) {
+ 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;
+ var_ref->is_detached = FALSE;
+ var_ref->is_arg = is_arg;
+ var_ref->var_idx = var_idx;
+ list_add_tail(&var_ref->header.link, &sf->var_ref_list);
+ if (is_arg)
+ var_ref->pvalue = &sf->arg_buf[var_idx];
+ else
+ var_ref->pvalue = &sf->var_buf[var_idx];
+ var_ref->value = JS_UNDEFINED;
+ 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 int 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 -1;
+ 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 (JS_DefinePropertyValue(ctx, this_val, atom, obj, JS_PROP_WRITABLE) < 0 || ret < 0)
+ return -1;
+ return 0;
+}
+
+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;
+ int var_idx;
+
+ list_for_each_safe(el, el1, &sf->var_ref_list) {
+ var_ref = list_entry(el, JSVarRef, header.link);
+ var_idx = var_ref->var_idx;
+ if (var_ref->is_arg)
+ var_ref->value = JS_DupValueRT(rt, sf->arg_buf[var_idx]);
+ else
+ var_ref->value = JS_DupValueRT(rt, sf->var_buf[var_idx]);
+ var_ref->pvalue = &var_ref->value;
+ /* the reference is no longer to a local variable */
+ var_ref->is_detached = TRUE;
+ add_gc_object(rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
+ }
+}
+
+static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int idx, int is_arg)
+{
+ struct list_head *el, *el1;
+ JSVarRef *var_ref;
+ int var_idx = idx;
+
+ list_for_each_safe(el, el1, &sf->var_ref_list) {
+ var_ref = list_entry(el, JSVarRef, header.link);
+ if (var_idx == var_ref->var_idx && var_ref->is_arg == is_arg) {
+ var_ref->value = JS_DupValue(ctx, sf->var_buf[var_idx]);
+ var_ref->pvalue = &var_ref->value;
+ list_del(&var_ref->header.link);
+ /* the reference is no longer to a local variable */
+ var_ref->is_detached = TRUE;
+ add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
+ }
+ }
+}
+
+#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 */
+
+#ifdef CONFIG_BIGNUM
+ /* we only propagate the bignum mode as some runtime functions
+ test it */
+ if (prev_sf)
+ sf->js_mode = prev_sf->js_mode & JS_MODE_MATH;
+ else
+ sf->js_mode = 0;
+#else
+ sf->js_mode = 0;
+#endif
+ 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
+
+/* 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_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;
+
+ 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;
+
+ 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)) {
+ JS_ThrowTypeError(caller_ctx, "class constructors must be invoked with 'new'");
+ goto exception;
+ }
+ BREAK;
+ CASE(OP_check_brand):
+ if (JS_CheckBrand(ctx, sp[-2], sp[-1]) < 0)
+ 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_var):
+#define JS_THROW_VAR_RO 0
+#define JS_THROW_VAR_REDECL 1
+#define JS_THROW_VAR_UNINITIALIZED 2
+#define JS_THROW_VAR_DELETE_SUPER 3
+ {
+ 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_VAR_DELETE_SUPER)
+ JS_ThrowReferenceError(ctx, "unsupported reference to 'super'");
+ 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) - 1;
+ 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) - 1;
+ pc += 2;
+ 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;
+ 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;
+ val = js_dynamic_import(ctx, sp[-1]);
+ if (JS_IsException(val))
+ goto exception;
+ JS_FreeValue(ctx, sp[-1]);
+ sp[-1] = val;
+ }
+ BREAK;
+
+ CASE(OP_check_var):
+ {
+ int ret;
+ JSAtom atom;
+ atom = get_u32(pc);
+ pc += 4;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ /* 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;
+ 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;
+ 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;
+ 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_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL);
+ 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_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL);
+ 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_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL);
+ 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_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL);
+ 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_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL);
+ 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, FALSE);
+ }
+ 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;
+
+ 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;
+ 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):
+ if (js_for_in_start(ctx, sp))
+ goto exception;
+ BREAK;
+ CASE(OP_for_in_next):
+ if (js_for_in_next(ctx, sp))
+ goto exception;
+ sp += 2;
+ BREAK;
+ CASE(OP_for_of_start):
+ 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;
+ if (js_for_of_next(ctx, sp, offset))
+ goto exception;
+ sp += 2;
+ }
+ BREAK;
+ CASE(OP_for_await_of_start):
+ if (js_for_of_start(ctx, sp, TRUE))
+ goto exception;
+ sp += 1;
+ *sp++ = JS_NewCatchOffset(ctx, 0);
+ BREAK;
+ CASE(OP_for_await_of_next):
+ if (js_for_await_of_next(ctx, sp))
+ goto exception;
+ sp += 1;
+ BREAK;
+ CASE(OP_iterator_get_value_done):
+ if (js_iterator_get_value_done(ctx, sp))
+ goto exception;
+ sp += 1;
+ 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])) {
+ if (JS_IteratorClose(ctx, sp[-1], FALSE))
+ goto exception;
+ JS_FreeValue(ctx, sp[-1]);
+ }
+ sp--;
+ BREAK;
+ CASE(OP_iterator_close_return):
+ {
+ JSValue ret_val;
+ /* iter_obj next catch_offset ... ret_val ->
+ ret_eval iter_obj next catch_offset */
+ 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 + 3)) {
+ JS_ThrowInternalError(ctx, "iterator_close_return");
+ JS_FreeValue(ctx, ret_val);
+ goto exception;
+ }
+ sp[0] = sp[-1];
+ sp[-1] = sp[-2];
+ sp[-2] = sp[-3];
+ sp[-3] = ret_val;
+ sp++;
+ }
+ BREAK;
+
+ CASE(OP_async_iterator_close):
+ /* iter_obj next catch_offset -> value flag */
+ {
+ JSValue ret, method;
+ int ret_flag;
+ sp--; /* remove the catch offset */
+ method = JS_GetProperty(ctx, sp[-2], JS_ATOM_return);
+ if (JS_IsException(method))
+ goto exception;
+ if (JS_IsUndefined(method) || JS_IsNull(method)) {
+ ret = JS_UNDEFINED;
+ ret_flag = TRUE;
+ } else {
+ ret = JS_CallFree(ctx, method, sp[-2], 0, NULL);
+ if (JS_IsException(ret))
+ goto exception;
+ if (!JS_IsObject(ret)) {
+ JS_FreeValue(ctx, ret);
+ JS_ThrowTypeErrorNotAnObject(ctx);
+ goto exception;
+ }
+ ret_flag = FALSE;
+ }
+ JS_FreeValue(ctx, sp[-2]);
+ JS_FreeValue(ctx, sp[-1]);
+ sp[-2] = ret;
+ sp[-1] = JS_NewBool(ctx, ret_flag);
+ }
+ BREAK;
+
+ CASE(OP_async_iterator_next):
+ /* stack: iter_obj next catch_offset val */
+ {
+ JSValue ret;
+ 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_async_iterator_get):
+ /* stack: iter_obj next catch_offset val */
+ {
+ JSValue method, ret;
+ BOOL ret_flag;
+ int flags;
+ flags = *pc++;
+ /* XXX: use another opcode such as OP_throw_var */
+ if (flags == 2) {
+ JS_ThrowTypeError(ctx, "iterator does not have a throw method");
+ goto exception;
+ }
+ method = JS_GetProperty(ctx, sp[-4], flags ? JS_ATOM_throw : JS_ATOM_return);
+ if (JS_IsException(method))
+ goto exception;
+ if (JS_IsUndefined(method) || JS_IsNull(method)) {
+ ret_flag = TRUE;
+ } 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;
+
+ 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;
+
+ 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;
+
+ ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1],
+ 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;
+ 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;
+
+ 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;
+
+ val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
+ sp[-1] = val;
+ if (unlikely(JS_IsException(val)))
+ goto exception;
+ }
+ BREAK;
+
+ CASE(OP_get_ref_value):
+ {
+ JSValue val;
+ if (unlikely(JS_IsUndefined(sp[-2]))) {
+ JSAtom atom = JS_ValueToAtom(ctx, sp[-1]);
+ if (atom != JS_ATOM_NULL) {
+ JS_ThrowReferenceErrorNotDefined(ctx, atom);
+ JS_FreeAtom(ctx, atom);
+ }
+ goto exception;
+ }
+ val = JS_GetPropertyValue(ctx, sp[-2],
+ JS_DupValue(ctx, sp[-1]));
+ if (unlikely(JS_IsException(val)))
+ goto exception;
+ sp[0] = val;
+ sp++;
+ }
+ BREAK;
+
+ CASE(OP_get_super_value):
+ {
+ JSValue val;
+ JSAtom atom;
+ 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;
+
+ 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;
+ if (unlikely(JS_IsUndefined(sp[-3]))) {
+ if (is_strict_mode(ctx)) {
+ JSAtom atom = JS_ValueToAtom(ctx, sp[-2]);
+ if (atom != JS_ATOM_NULL) {
+ JS_ThrowReferenceErrorNotDefined(ctx, atom);
+ JS_FreeAtom(ctx, atom);
+ }
+ goto exception;
+ } else {
+ sp[-3] = JS_DupValue(ctx, ctx->global_obj);
+ }
+ }
+ 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_super_value):
+ {
+ int ret;
+ JSAtom atom;
+ 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_SetPropertyGeneric(ctx, JS_VALUE_GET_OBJ(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 */
+ {
+ 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++;
+ 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 {
+ add_slow:
+ if (js_add_slow(ctx, sp))
+ goto exception;
+ sp--;
+ }
+ }
+ BREAK;
+ CASE(OP_add_loc):
+ {
+ JSValue ops[2];
+ int idx;
+ idx = *pc;
+ pc += 1;
+
+ ops[0] = var_buf[idx];
+ ops[1] = sp[-1];
+ if (likely(JS_VALUE_IS_BOTH_INT(ops[0], ops[1]))) {
+ int64_t r;
+ r = (int64_t)JS_VALUE_GET_INT(ops[0]) + JS_VALUE_GET_INT(ops[1]);
+ if (unlikely((int)r != r))
+ goto add_loc_slow;
+ var_buf[idx] = JS_NewInt32(ctx, r);
+ sp--;
+ } else if (JS_VALUE_GET_TAG(ops[0]) == JS_TAG_STRING) {
+ sp--;
+ ops[1] = JS_ToPrimitiveFree(ctx, ops[1], HINT_NONE);
+ if (JS_IsException(ops[1])) {
+ goto exception;
+ }
+ /* XXX: should not modify the variable in case of
+ exception */
+ ops[0] = JS_ConcatString(ctx, ops[0], ops[1]);
+ if (JS_IsException(ops[0])) {
+ var_buf[idx] = JS_UNDEFINED;
+ goto exception;
+ }
+ var_buf[idx] = ops[0];
+ } else {
+ add_loc_slow:
+ /* XXX: should not modify the variable in case of
+ exception */
+ sp--;
+ /* In case of exception, js_add_slow frees ops[0]
+ and ops[1]. */
+ /* XXX: change API */
+ if (js_add_slow(ctx, ops + 2)) {
+ var_buf[idx] = JS_UNDEFINED;
+ goto exception;
+ }
+ var_buf[idx] = 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)) {
+#ifdef CONFIG_BIGNUM
+ if (unlikely(sf->js_mode & JS_MODE_MATH) &&
+ (r < -MAX_SAFE_INTEGER || r > MAX_SAFE_INTEGER))
+ goto binary_arith_slow;
+#endif
+ 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)) {
+#ifdef CONFIG_BIGNUM
+ if (unlikely(sf->js_mode & JS_MODE_MATH))
+ goto binary_arith_slow;
+#endif
+ 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;
+ if (unlikely(sf->js_mode & JS_MODE_MATH))
+ goto binary_arith_slow;
+ 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):
+#ifdef CONFIG_BIGNUM
+ CASE(OP_math_mod):
+#endif
+ {
+ 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:
+ 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 {
+ 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 {
+ 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:
+ 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:
+ if (js_unary_arith_slow(ctx, sp, opcode))
+ goto exception;
+ }
+ }
+ BREAK;
+ CASE(OP_post_inc):
+ CASE(OP_post_dec):
+ 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:
+ if (js_unary_arith_slow(ctx, var_buf + idx + 1, OP_inc))
+ goto exception;
+ }
+ }
+ 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:
+ if (js_unary_arith_slow(ctx, var_buf + idx + 1, OP_dec))
+ goto exception;
+ }
+ }
+ 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 {
+ 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);
+#ifdef CONFIG_BIGNUM
+ {
+ int64_t r;
+ if (unlikely(sf->js_mode & JS_MODE_MATH)) {
+ if (v2 > 0x1f)
+ goto shl_slow;
+ r = (int64_t)v1 << v2;
+ if ((int)r != r)
+ goto shl_slow;
+ } else {
+ v2 &= 0x1f;
+ }
+ }
+#else
+ v2 &= 0x1f;
+#endif
+ sp[-2] = JS_NewInt32(ctx, v1 << v2);
+ sp--;
+ } else {
+#ifdef CONFIG_BIGNUM
+ shl_slow:
+#endif
+ 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);
+ /* v1 >>> v2 retains its JS semantics if CONFIG_BIGNUM */
+ v2 &= 0x1f;
+ sp[-2] = JS_NewUint32(ctx,
+ (uint32_t)JS_VALUE_GET_INT(op1) >>
+ v2);
+ sp--;
+ } else {
+ 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);
+#ifdef CONFIG_BIGNUM
+ if (unlikely(v2 > 0x1f)) {
+ if (unlikely(sf->js_mode & JS_MODE_MATH))
+ goto sar_slow;
+ else
+ v2 &= 0x1f;
+ }
+#else
+ v2 &= 0x1f;
+#endif
+ sp[-2] = JS_NewInt32(ctx,
+ (int)JS_VALUE_GET_INT(op1) >> v2);
+ sp--;
+ } else {
+#ifdef CONFIG_BIGNUM
+ sar_slow:
+#endif
+ 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 {
+ 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 {
+ 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 {
+ 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 { \
+ 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));
+
+#ifdef CONFIG_BIGNUM
+ CASE(OP_mul_pow10):
+ if (rt->bigfloat_ops.mul_pow10(ctx, sp))
+ goto exception;
+ sp--;
+ BREAK;
+#endif
+ CASE(OP_in):
+ if (js_operator_in(ctx, sp))
+ goto exception;
+ sp--;
+ BREAK;
+ CASE(OP_instanceof):
+ 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):
+ if (js_operator_delete(ctx, sp))
+ goto exception;
+ sp--;
+ BREAK;
+ CASE(OP_delete_var):
+ {
+ JSAtom atom;
+ int ret;
+
+ atom = get_u32(pc);
+ pc += 4;
+
+ ret = JS_DeleteProperty(ctx, ctx->global_obj, atom, 0);
+ 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) {
+ 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:
+ 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;
+
+ CASE(OP_to_propkey2):
+ /* must be tested first */
+ if (unlikely(JS_IsUndefined(sp[-2]) || JS_IsNull(sp[-2]))) {
+ JS_ThrowTypeError(ctx, "value has no property");
+ goto exception;
+ }
+ switch (JS_VALUE_GET_TAG(sp[-1])) {
+ case JS_TAG_INT:
+ case JS_TAG_STRING:
+ case JS_TAG_SYMBOL:
+ break;
+ default:
+ 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):
+ CASE(OP_with_get_ref_undef):
+ {
+ 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;
+
+ 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:
+ 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:
+ ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2],
+ 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 */
+ val = JS_GetProperty(ctx, obj, atom);
+ if (unlikely(JS_IsException(val)))
+ goto exception;
+ *sp++ = val;
+ break;
+ case OP_with_get_ref_undef:
+ /* produce a pair undefined/function on the stack */
+ val = JS_GetProperty(ctx, obj, atom);
+ if (unlikely(JS_IsException(val)))
+ goto exception;
+ JS_FreeValue(ctx, sp[-1]);
+ sp[-1] = JS_UNDEFINED;
+ *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):
+ CASE(OP_initial_yield):
+ ret_val = JS_UNDEFINED;
+ 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;
+ }
+ CASE(OP_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);
+ }
+ if (!JS_IsUncatchableError(ctx, rt->current_exception)) {
+ 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_NULL;
+ 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 __exception int async_func_init(JSContext *ctx, JSAsyncFunctionState *s,
+ JSValueConst func_obj, JSValueConst this_obj,
+ int argc, JSValueConst *argv)
+{
+ JSObject *p;
+ JSFunctionBytecode *b;
+ JSStackFrame *sf;
+ int local_count, i, arg_buf_len, n;
+
+ 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;
+ 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)
+ return -1;
+ 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;
+ return 0;
+}
+
+static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s,
+ JS_MarkFunc *mark_func)
+{
+ JSStackFrame *sf;
+ JSValue *sp;
+
+ sf = &s->frame;
+ JS_MarkValue(rt, sf->cur_func, mark_func);
+ JS_MarkValue(rt, s->this_val, mark_func);
+ 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);
+ }
+}
+
+static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
+{
+ JSStackFrame *sf;
+ JSValue *sp;
+
+ sf = &s->frame;
+
+ /* close the closure variables. */
+ close_var_refs(rt, sf);
+
+ 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);
+ }
+ JS_FreeValueRT(rt, sf->cur_func);
+ JS_FreeValueRT(rt, s->this_val);
+}
+
+static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s)
+{
+ JSValue func_obj;
+
+ if (js_check_stack_overflow(ctx->rt, 0))
+ return JS_ThrowStackOverflow(ctx);
+
+ /* the tag does not matter provided it is not an object */
+ func_obj = JS_MKPTR(JS_TAG_INT, s);
+ return JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED,
+ s->argc, s->frame.arg_buf, JS_CALL_FLAG_GENERATOR);
+}
+
+
+/* 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;
+ async_func_free(rt, &s->func_state);
+ 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->state == JS_GENERATOR_STATE_COMPLETED)
+ return;
+ async_func_mark(rt, &s->func_state, mark_func);
+}
+
+/* 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;
+ JSValueConst iter_args[1];
+
+ *pdone = TRUE;
+ if (!s)
+ return JS_ThrowTypeError(ctx, "not a generator");
+ sf = &s->func_state.frame;
+ redo:
+ switch(s->state) {
+ default:
+ case JS_GENERATOR_STATE_SUSPENDED_START:
+ 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:
+ {
+ int done;
+ JSValue method, iter_obj;
+
+ iter_obj = sf->cur_sp[-2];
+ if (magic == GEN_MAGIC_NEXT) {
+ method = JS_DupValue(ctx, sf->cur_sp[-1]);
+ } else {
+ method = JS_GetProperty(ctx, iter_obj,
+ magic == GEN_MAGIC_RETURN ?
+ JS_ATOM_return : JS_ATOM_throw);
+ if (JS_IsException(method))
+ goto iter_exception;
+ }
+ if (magic != GEN_MAGIC_NEXT &&
+ (JS_IsUndefined(method) || JS_IsNull(method))) {
+ /* default action */
+ if (magic == GEN_MAGIC_RETURN) {
+ ret = JS_DupValue(ctx, argv[0]);
+ goto iter_done;
+ } else {
+ if (JS_IteratorClose(ctx, iter_obj, FALSE))
+ goto iter_exception;
+ JS_ThrowTypeError(ctx, "iterator does not have a throw method");
+ goto iter_exception;
+ }
+ }
+ ret = JS_IteratorNext2(ctx, iter_obj, method, argc, argv, &done);
+ JS_FreeValue(ctx, method);
+ if (JS_IsException(ret)) {
+ iter_exception:
+ goto exec_throw;
+ }
+ /* if not done, the iterator returns the exact object
+ returned by 'method' */
+ if (done == 2) {
+ JSValue done_val, value;
+ done_val = JS_GetProperty(ctx, ret, JS_ATOM_done);
+ if (JS_IsException(done_val)) {
+ JS_FreeValue(ctx, ret);
+ goto iter_exception;
+ }
+ done = JS_ToBoolFree(ctx, done_val);
+ if (done) {
+ value = JS_GetProperty(ctx, ret, JS_ATOM_value);
+ JS_FreeValue(ctx, ret);
+ if (JS_IsException(value))
+ goto iter_exception;
+ ret = value;
+ goto iter_done;
+ } else {
+ *pdone = 2;
+ }
+ } else {
+ if (done) {
+ /* 'yield *' returns the value associated to done = true */
+ iter_done:
+ JS_FreeValue(ctx, sf->cur_sp[-2]);
+ JS_FreeValue(ctx, sf->cur_sp[-1]);
+ sf->cur_sp--;
+ goto exec_arg;
+ } else {
+ *pdone = FALSE;
+ }
+ }
+ break;
+ }
+ break;
+ case JS_GENERATOR_STATE_SUSPENDED_YIELD:
+ /* cur_sp[-1] was set to JS_UNDEFINED in the previous call */
+ ret = JS_DupValue(ctx, argv[0]);
+ if (magic == GEN_MAGIC_THROW) {
+ JS_Throw(ctx, ret);
+ exec_throw:
+ s->func_state.throw_flag = TRUE;
+ } else {
+ exec_arg:
+ sf->cur_sp[-1] = ret;
+ sf->cur_sp[0] = JS_NewBool(ctx, (magic == GEN_MAGIC_RETURN));
+ 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 (JS_IsException(func_ret)) {
+ /* finalize the execution in case of exception */
+ free_generator_stack(ctx, s);
+ return func_ret;
+ }
+ if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) {
+ if (JS_VALUE_GET_INT(func_ret) == FUNC_RET_YIELD_STAR) {
+ /* 'yield *' */
+ s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
+ iter_args[0] = JS_UNDEFINED;
+ argc = 1;
+ argv = iter_args;
+ goto redo;
+ } else {
+ /* get the return the yield value at the top of the stack */
+ ret = sf->cur_sp[-1];
+ sf->cur_sp[-1] = JS_UNDEFINED;
+ *pdone = FALSE;
+ }
+ } else {
+ /* end of iterator */
+ ret = sf->cur_sp[-1];
+ sf->cur_sp[-1] = JS_UNDEFINED;
+ JS_FreeValue(ctx, func_ret);
+ free_generator_stack(ctx, s);
+ }
+ 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;
+ if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
+ 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_terminate(JSRuntime *rt, JSAsyncFunctionData *s)
+{
+ if (s->is_active) {
+ async_func_free(rt, &s->func_state);
+ s->is_active = FALSE;
+ }
+}
+
+static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s)
+{
+ js_async_function_terminate(rt, s);
+ JS_FreeValueRT(rt, s->resolving_funcs[0]);
+ JS_FreeValueRT(rt, s->resolving_funcs[1]);
+ remove_gc_object(&s->header);
+ js_free_rt(rt, s);
+}
+
+static void js_async_function_free(JSRuntime *rt, JSAsyncFunctionData *s)
+{
+ if (--s->header.ref_count == 0) {
+ js_async_function_free0(rt, s);
+ }
+}
+
+static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSObject *p = JS_VALUE_GET_OBJ(val);
+ JSAsyncFunctionData *s = p->u.async_function_data;
+ if (s) {
+ js_async_function_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);
+ JSAsyncFunctionData *s = p->u.async_function_data;
+ if (s) {
+ mark_func(rt, &s->header);
+ }
+}
+
+static int js_async_function_resolve_create(JSContext *ctx,
+ JSAsyncFunctionData *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, JSAsyncFunctionData *s)
+{
+ JSValue func_ret, ret2;
+
+ func_ret = async_func_resume(ctx, &s->func_state);
+ 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_async_function_terminate(ctx->rt, s);
+ JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
+ } else {
+ JSValue value;
+ value = s->func_state.frame.cur_sp[-1];
+ s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
+ if (JS_IsUndefined(func_ret)) {
+ /* function returned */
+ ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED,
+ 1, (JSValueConst *)&value);
+ JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
+ JS_FreeValue(ctx, value);
+ js_async_function_terminate(ctx->rt, s);
+ } else {
+ JSValue promise, resolving_funcs[2], resolving_funcs1[2];
+ int i, res;
+
+ /* 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);
+ JSAsyncFunctionData *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->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_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;
+ JSAsyncFunctionData *s;
+
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return JS_EXCEPTION;
+ s->header.ref_count = 1;
+ add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION);
+ s->is_active = FALSE;
+ s->resolving_funcs[0] = JS_UNDEFINED;
+ s->resolving_funcs[1] = JS_UNDEFINED;
+
+ promise = JS_NewPromiseCapability(ctx, s->resolving_funcs);
+ if (JS_IsException(promise))
+ goto fail;
+
+ if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
+ fail:
+ JS_FreeValue(ctx, promise);
+ js_async_function_free(ctx->rt, s);
+ return JS_EXCEPTION;
+ }
+ s->is_active = TRUE;
+
+ js_async_function_resume(ctx, s);
+
+ js_async_function_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;
+ 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->state != JS_ASYNC_GENERATOR_STATE_COMPLETED &&
+ s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) {
+ 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->state != JS_ASYNC_GENERATOR_STATE_COMPLETED &&
+ s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) {
+ async_func_mark(rt, &s->func_state, mark_func);
+ }
+ }
+}
+
+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);
+ }
+}
+
+static int js_async_generator_completed_return(JSContext *ctx,
+ JSAsyncGeneratorData *s,
+ JSValueConst value)
+{
+ JSValue promise, resolving_funcs[2], resolving_funcs1[2];
+ int res;
+
+ promise = js_promise_resolve(ctx, ctx->promise_ctor,
+ 1, (JSValueConst *)&value, 0);
+ 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);
+ goto done;
+ } 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 (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 if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) {
+ int func_ret_code;
+ value = s->func_state.frame.cur_sp[-1];
+ s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
+ func_ret_code = JS_VALUE_GET_INT(func_ret);
+ 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:
+ js_async_generator_await(ctx, s, value);
+ JS_FreeValue(ctx, value);
+ goto done;
+ default:
+ abort();
+ }
+ } else {
+ assert(JS_IsUndefined(func_ret));
+ /* end of function */
+ value = s->func_state.frame.cur_sp[-1];
+ s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
+ js_async_generator_complete(ctx, s);
+ js_async_generator_resolve(ctx, s, value, TRUE);
+ JS_FreeValue(ctx, value);
+ }
+ 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);
+ if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
+ s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
+ 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,
+#ifdef CONFIG_BIGNUM
+ TOK_MATH_POW_ASSIGN,
+#endif
+ TOK_POW_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,
+#ifdef CONFIG_BIGNUM
+ TOK_MATH_POW,
+#endif
+ 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;
+ int has_iterator;
+} BlockEnv;
+
+typedef struct JSHoistedDef {
+ int cpool_idx; /* -1 means variable global definition */
+ uint8_t force_init : 1; /* initialize to undefined */
+ uint8_t is_lexical : 1; /* global let/const definition */
+ uint8_t is_const : 1; /* const definition */
+ int var_idx; /* function object index if cpool_idx >= 0 */
+ int scope_level; /* scope of definition */
+ JSAtom var_name; /* variable name if cpool_idx < 0 */
+} JSHoistedDef;
+
+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;
+ int line_num;
+} LineNumberSlot;
+
+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_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_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;
+ BOOL backtrace_barrier;
+ 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 arguments_var_idx; /* -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 hoisted_def_count;
+ int hoisted_def_size;
+ JSHoistedDef *hoisted_def;
+
+ DynBuf byte_code;
+ int last_opcode_pos; /* -1 if no last opcode */
+ int last_opcode_line_num;
+ 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 */
+ JSAtom filename;
+ int line_num;
+ DynBuf pc2line;
+
+ char *source; /* raw source, utf-8 encoded */
+ int source_len;
+
+ JSModuleDef *module; /* != NULL when parsing a module */
+} JSFunctionDef;
+
+typedef struct JSToken {
+ int val;
+ int line_num; /* line number of token start */
+ const uint8_t *ptr;
+ union {
+ struct {
+ JSValue str;
+ int sep;
+ } str;
+ struct {
+ JSValue val;
+#ifdef CONFIG_BIGNUM
+ slimb_t exponent; /* may be != 0 only if val is a float */
+#endif
+ } num;
+ struct {
+ JSAtom atom;
+ BOOL has_escape;
+ BOOL is_reserved;
+ } ident;
+ struct {
+ JSValue body;
+ JSValue flags;
+ } regexp;
+ } u;
+} JSToken;
+
+typedef struct JSParseState {
+ JSContext *ctx;
+ int last_line_num; /* line number of last token */
+ int line_num; /* line number of current offset */
+ 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_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 */
+} 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) {
+#ifdef CONFIG_BIGNUM
+ case TOK_NUMBER:
+ JS_FreeValue(s->ctx, token->u.num.val);
+ break;
+#endif
+ 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_FIRST_KEYWORD ... TOK_LAST_KEYWORD:
+ case TOK_PRIVATE_NAME:
+ JS_FreeAtom(s->ctx, token->u.ident.atom);
+ break;
+ default:
+ 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;
+ }
+}
+
+int __attribute__((format(printf, 2, 3))) js_parse_error(JSParseState *s, const char *fmt, ...)
+{
+ JSContext *ctx = s->ctx;
+ va_list ap;
+ int backtrace_flags;
+
+ va_start(ap, fmt);
+ JS_ThrowError2(ctx, JS_SYNTAX_ERROR, fmt, ap, FALSE);
+ va_end(ap);
+ backtrace_flags = 0;
+ if (s->cur_func && s->cur_func->backtrace_barrier)
+ backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL;
+ build_backtrace(ctx, ctx->rt->current_exception, s->filename, s->line_num,
+ backtrace_flags);
+ return -1;
+}
+
+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;
+
+ /* 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 == '\n') {
+ s->line_num++;
+ } else 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(s, "invalid UTF-8 sequence");
+ goto fail;
+ }
+ p = p_next;
+ }
+ if (string_buffer_putc(b, c))
+ goto fail;
+ }
+ s->token.val = TOK_TEMPLATE;
+ s->token.u.str.sep = c;
+ s->token.u.str.str = string_buffer_end(b);
+ 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;
+
+ /* 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 (!s->cur_func) {
+ if (do_throw)
+ js_parse_error(s, "invalid character in a JSON string");
+ goto fail;
+ }
+ 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 == '\\') {
+ c = *p;
+ 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++;
+ if (sep != '`')
+ s->line_num++;
+ continue;
+ default:
+ if (c >= '0' && c <= '7') {
+ if (!s->cur_func)
+ goto invalid_octal; /* JSON case */
+ 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 {
+ invalid_octal:
+ if (do_throw)
+ js_parse_error(s, "invalid octal syntax 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) {
+ if (do_throw)
+ js_parse_error(s, "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;
+ }
+ token->val = TOK_STRING;
+ token->u.str.sep = c;
+ token->u.str.str = string_buffer_end(b);
+ *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;
+
+ 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(s, "invalid UTF-8 sequence");
+ goto fail;
+ }
+ p = p_next;
+ /* LS or PS are considered as line terminator */
+ if (c == CP_LS || c == CP_PS) {
+ eol_error:
+ js_parse_error(s, "unexpected line terminator in regexp");
+ goto fail;
+ }
+ }
+ 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) {
+ goto invalid_utf8;
+ }
+ }
+ if (!lre_js_is_ident_next(c))
+ break;
+ if (string_buffer_putc(b2, c))
+ goto fail;
+ p = p_next;
+ }
+
+ s->token.val = TOK_REGEXP;
+ s->token.u.regexp.body = string_buffer_end(b);
+ s->token.u.regexp.flags = string_buffer_end(b2);
+ 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;
+}
+
+/* '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;
+ s->last_line_num = s->token.line_num;
+ redo:
+ s->token.line_num = s->line_num;
+ 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;
+ s->line_num++;
+ 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') {
+ s->line_num++;
+ s->got_lf = TRUE; /* considered as LF for ASI */
+ p++;
+ } else if (*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' ... 'z':
+ case 'A' ... '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;
+ 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_ARROW &&
+ !s->cur_func->in_function_body && s->cur_func->parent &&
+ (s->cur_func->parent->func_kind & JS_FUNC_ASYNC))))))) {
+ if (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;
+ }
+ } else {
+ s->token.val = TOK_IDENT;
+ }
+ 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' ... '9':
+ /* number */
+ parse_number:
+ {
+ JSValue ret;
+ const uint8_t *p1;
+ int flags, radix;
+ flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL |
+ ATOD_ACCEPT_UNDERSCORES;
+#ifdef CONFIG_BIGNUM
+ flags |= ATOD_ACCEPT_SUFFIX;
+ if (s->cur_func->js_mode & JS_MODE_MATH) {
+ flags |= ATOD_MODE_BIGINT;
+ if (s->cur_func->js_mode & JS_MODE_MATH)
+ flags |= ATOD_TYPE_BIG_FLOAT;
+ }
+#endif
+ radix = 0;
+#ifdef CONFIG_BIGNUM
+ s->token.u.num.exponent = 0;
+ ret = js_atof2(s->ctx, (const char *)p, (const char **)&p, radix,
+ flags, &s->token.u.num.exponent);
+#else
+ ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix,
+ flags);
+#endif
+ 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->last_line_num != s->line_num) {
+ /* 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 `
+
+
diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..b775178
--- /dev/null
+++ b/example/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/android/app/src/main/kotlin/soko/ekibun/example/MainActivity.kt b/example/android/app/src/main/kotlin/soko/ekibun/example/MainActivity.kt
new file mode 100644
index 0000000..5d6e9bd
--- /dev/null
+++ b/example/android/app/src/main/kotlin/soko/ekibun/example/MainActivity.kt
@@ -0,0 +1,6 @@
+package soko.ekibun.example
+
+import io.flutter.embedding.android.FlutterActivity
+
+class MainActivity: FlutterActivity() {
+}
diff --git a/example/android/app/src/main/kotlin/soko/ekibun/flutter_qjs_example/MainActivity.kt b/example/android/app/src/main/kotlin/soko/ekibun/flutter_qjs_example/MainActivity.kt
new file mode 100644
index 0000000..1449f1f
--- /dev/null
+++ b/example/android/app/src/main/kotlin/soko/ekibun/flutter_qjs_example/MainActivity.kt
@@ -0,0 +1,6 @@
+package soko.ekibun.flutter_qjs_example
+
+import io.flutter.embedding.android.FlutterActivity
+
+class MainActivity: FlutterActivity() {
+}
diff --git a/example/android/app/src/main/res/drawable/launch_background.xml b/example/android/app/src/main/res/drawable/launch_background.xml
new file mode 100644
index 0000000..304732f
--- /dev/null
+++ b/example/android/app/src/main/res/drawable/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..db77bb4
Binary files /dev/null and b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..17987b7
Binary files /dev/null and b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..09d4391
Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..d5f1c8d
Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..4d6372e
Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..1f83a33
--- /dev/null
+++ b/example/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml
new file mode 100644
index 0000000..dd00848
--- /dev/null
+++ b/example/android/app/src/profile/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/example/android/build.gradle b/example/android/build.gradle
new file mode 100644
index 0000000..3100ad2
--- /dev/null
+++ b/example/android/build.gradle
@@ -0,0 +1,31 @@
+buildscript {
+ ext.kotlin_version = '1.3.50'
+ repositories {
+ google()
+ jcenter()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.5.0'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+rootProject.buildDir = '../build'
+subprojects {
+ project.buildDir = "${rootProject.buildDir}/${project.name}"
+}
+subprojects {
+ project.evaluationDependsOn(':app')
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/example/android/gradle.properties b/example/android/gradle.properties
new file mode 100644
index 0000000..38c8d45
--- /dev/null
+++ b/example/android/gradle.properties
@@ -0,0 +1,4 @@
+org.gradle.jvmargs=-Xmx1536M
+android.enableR8=true
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..296b146
--- /dev/null
+++ b/example/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Fri Jun 23 08:50:38 CEST 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
diff --git a/example/android/settings.gradle b/example/android/settings.gradle
new file mode 100644
index 0000000..44e62bc
--- /dev/null
+++ b/example/android/settings.gradle
@@ -0,0 +1,11 @@
+include ':app'
+
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
+
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
+
+def flutterSdkPath = properties.getProperty("flutter.sdk")
+assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
+apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
diff --git a/flutter_qjs.iml b/flutter_qjs.iml
index 429df7d..f3b36a2 100644
--- a/flutter_qjs.iml
+++ b/flutter_qjs.iml
@@ -8,11 +8,12 @@
+
+
-
diff --git a/pubspec.yaml b/pubspec.yaml
index 03e9cea..18017a7 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -34,6 +34,9 @@ flutter:
# -------------------
windows:
pluginClass: FlutterQjsPlugin
+ android:
+ pluginClass: FlutterQjsPlugin
+ package: soko.ekibun.flutter_qjs
# -------------------
# To add assets to your plugin package, add an assets section, like this:
diff --git a/windows/flutter_qjs_plugin.cpp b/windows/flutter_qjs_plugin.cpp
index b5ef743..37b5f22 100644
--- a/windows/flutter_qjs_plugin.cpp
+++ b/windows/flutter_qjs_plugin.cpp
@@ -87,7 +87,7 @@ namespace
}
else if (method_call.method_name().compare("evaluate") == 0)
{
- flutter::EncodableMap args = *((flutter::EncodableMap *)method_call.arguments());
+ flutter::EncodableMap args = *std::get_if(method_call.arguments());
std::string script = std::get(ValueOrNull(args, "script"));
std::string name = std::get(ValueOrNull(args, "name"));
auto presult = result.release();