diff --git a/Makefile b/Makefile index 0f29afafc..ad265cd28 100644 --- a/Makefile +++ b/Makefile @@ -319,7 +319,6 @@ include third_party/argon2/BUILD.mk include third_party/smallz4/BUILD.mk include third_party/sqlite3/BUILD.mk include third_party/mbedtls/test/BUILD.mk -include third_party/quickjs/BUILD.mk include third_party/lz4cli/BUILD.mk include third_party/zip/BUILD.mk include third_party/xxhash/BUILD.mk diff --git a/examples/BUILD.mk b/examples/BUILD.mk index 4b839fdaf..ffe8625d2 100644 --- a/examples/BUILD.mk +++ b/examples/BUILD.mk @@ -85,7 +85,6 @@ EXAMPLES_DIRECTDEPS = \ THIRD_PARTY_MUSL \ THIRD_PARTY_NSYNC \ THIRD_PARTY_NSYNC_MEM \ - THIRD_PARTY_QUICKJS \ THIRD_PARTY_SED \ THIRD_PARTY_STB \ THIRD_PARTY_TR \ diff --git a/test/net/https/mbedtls_test.c b/test/net/https/mbedtls_test.c index fa355e5f2..821e83eb4 100644 --- a/test/net/https/mbedtls_test.c +++ b/test/net/https/mbedtls_test.c @@ -59,7 +59,6 @@ #include "third_party/mbedtls/sha256.h" #include "third_party/mbedtls/sha512.h" #include "third_party/mbedtls/x509.h" -#include "third_party/quickjs/libbf.h" #include "third_party/zlib/zlib.h" uint64_t rng[12]; diff --git a/third_party/BUILD.mk b/third_party/BUILD.mk index be22c9d2a..72b213b9f 100644 --- a/third_party/BUILD.mk +++ b/third_party/BUILD.mk @@ -31,7 +31,6 @@ o/$(MODE)/third_party: \ o/$(MODE)/third_party/pcre \ o/$(MODE)/third_party/puff \ o/$(MODE)/third_party/python \ - o/$(MODE)/third_party/quickjs \ o/$(MODE)/third_party/readline \ o/$(MODE)/third_party/regex \ o/$(MODE)/third_party/sed \ diff --git a/third_party/python/Modules/_pickle.c b/third_party/python/Modules/_pickle.c index 6a15d8ce2..ae6f64d5e 100644 --- a/third_party/python/Modules/_pickle.c +++ b/third_party/python/Modules/_pickle.c @@ -30,7 +30,6 @@ #include "third_party/python/Include/structmember.h" #include "third_party/python/Include/sysmodule.h" #include "third_party/python/Include/yoink.h" -#include "third_party/quickjs/internal.h" PYTHON_PROVIDE("_pickle"); PYTHON_PROVIDE("_pickle.PickleError"); diff --git a/third_party/python/Objects/weakrefobject.c b/third_party/python/Objects/weakrefobject.c index 4eca28c1d..1ef3863ea 100644 --- a/third_party/python/Objects/weakrefobject.c +++ b/third_party/python/Objects/weakrefobject.c @@ -11,7 +11,6 @@ #include "third_party/python/Include/objimpl.h" #include "third_party/python/Include/structmember.h" #include "third_party/python/Include/weakrefobject.h" -#include "third_party/quickjs/quickjs.h" #define GET_WEAKREFS_LISTPTR(o) \ ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o)) diff --git a/third_party/python/Python/peephole.c b/third_party/python/Python/peephole.c index 3da80aa66..a75e327f8 100644 --- a/third_party/python/Python/peephole.c +++ b/third_party/python/Python/peephole.c @@ -20,7 +20,6 @@ #include "third_party/python/Include/tupleobject.h" #include "third_party/python/Include/unicodeobject.h" #include "third_party/python/Python/wordcode_helpers.inc" -#include "third_party/quickjs/internal.h" /* Peephole optimizations for bytecode compiler. */ diff --git a/third_party/quickjs/BUILD.mk b/third_party/quickjs/BUILD.mk deleted file mode 100644 index 845af3160..000000000 --- a/third_party/quickjs/BUILD.mk +++ /dev/null @@ -1,216 +0,0 @@ -#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ -#── vi: set noet ft=make ts=8 sw=8 fenc=utf-8 :vi ────────────────────┘ - -PKGS += THIRD_PARTY_QUICKJS - -THIRD_PARTY_QUICKJS_ARTIFACTS += THIRD_PARTY_QUICKJS_A -THIRD_PARTY_QUICKJS_BINS = $(THIRD_PARTY_QUICKJS_COMS) $(THIRD_PARTY_QUICKJS_COMS:%=%.dbg) -THIRD_PARTY_QUICKJS = $(THIRD_PARTY_QUICKJS_A_DEPS) $(THIRD_PARTY_QUICKJS_A) -THIRD_PARTY_QUICKJS_A = o/$(MODE)/third_party/quickjs/quickjs.a -THIRD_PARTY_QUICKJS_HDRS = $(foreach x,$(THIRD_PARTY_QUICKJS_ARTIFACTS),$($(x)_HDRS)) -THIRD_PARTY_QUICKJS_INCS = $(foreach x,$(THIRD_PARTY_QUICKJS_ARTIFACTS),$($(x)_INCS)) - -THIRD_PARTY_QUICKJS_A_SRCS = \ - third_party/quickjs/array.c \ - third_party/quickjs/atof.c \ - third_party/quickjs/atom.c \ - third_party/quickjs/atomics.c \ - third_party/quickjs/bigdecimal.c \ - third_party/quickjs/bigint.c \ - third_party/quickjs/byte.c \ - third_party/quickjs/call.c \ - third_party/quickjs/cutils.c \ - third_party/quickjs/date.c \ - third_party/quickjs/dbuf.c \ - third_party/quickjs/dbuf.c \ - third_party/quickjs/diglet.c \ - third_party/quickjs/eq.c \ - third_party/quickjs/err.c \ - third_party/quickjs/float.c \ - third_party/quickjs/gc.c \ - third_party/quickjs/gen.c \ - third_party/quickjs/iter.c \ - third_party/quickjs/json.c \ - third_party/quickjs/leb128.c \ - third_party/quickjs/libbf.c \ - third_party/quickjs/libregexp.c \ - third_party/quickjs/libunicode.c \ - third_party/quickjs/map.c \ - third_party/quickjs/math.c \ - third_party/quickjs/mem.c \ - third_party/quickjs/object.c \ - third_party/quickjs/parse.c \ - third_party/quickjs/prim.c \ - third_party/quickjs/promise.c \ - third_party/quickjs/proxy.c \ - third_party/quickjs/quickjs-libc.c \ - third_party/quickjs/quickjs.c \ - third_party/quickjs/reflect.c \ - third_party/quickjs/regexp.c \ - third_party/quickjs/shape.c \ - third_party/quickjs/str.c \ - third_party/quickjs/strbuf.c \ - third_party/quickjs/tok.c \ - third_party/quickjs/typedarray.c \ - third_party/quickjs/uri.c \ - third_party/quickjs/usage.c - -THIRD_PARTY_QUICKJS_A_HDRS = \ - third_party/quickjs/cutils.h \ - third_party/quickjs/diglet.h \ - third_party/quickjs/internal.h \ - third_party/quickjs/leb128.h \ - third_party/quickjs/libbf.h \ - third_party/quickjs/libregexp.h \ - third_party/quickjs/libunicode.h \ - third_party/quickjs/list.h \ - third_party/quickjs/quickjs-libc.h \ - third_party/quickjs/quickjs.h - -THIRD_PARTY_QUICKJS_A_INCS = \ - third_party/quickjs/libregexp-opcode.inc \ - third_party/quickjs/libunicode-table.inc \ - third_party/quickjs/quickjs-atom.inc \ - third_party/quickjs/quickjs-opcode.inc \ - third_party/quickjs/unicode_gen_def.inc - -THIRD_PARTY_QUICKJS_A_OBJS = \ - $(THIRD_PARTY_QUICKJS_A_SRCS:%.c=o/$(MODE)/%.o) - -THIRD_PARTY_QUICKJS_A_DIRECTDEPS = \ - LIBC_CALLS \ - LIBC_DLOPEN \ - LIBC_FMT \ - LIBC_INTRIN \ - LIBC_LOG \ - LIBC_MEM \ - LIBC_NEXGEN32E \ - LIBC_NT_KERNEL32 \ - LIBC_PROC \ - LIBC_RUNTIME \ - LIBC_SOCK \ - LIBC_STDIO \ - LIBC_STR \ - LIBC_SYSV \ - LIBC_SYSV_CALLS \ - LIBC_TIME \ - LIBC_TINYMATH \ - LIBC_X \ - THIRD_PARTY_COMPILER_RT \ - THIRD_PARTY_GDTOA \ - THIRD_PARTY_GETOPT \ - THIRD_PARTY_MUSL \ - TOOL_ARGS - -THIRD_PARTY_QUICKJS_A_DEPS := \ - $(call uniq,$(foreach x,$(THIRD_PARTY_QUICKJS_A_DIRECTDEPS),$($(x)))) - -$(THIRD_PARTY_QUICKJS_A): \ - third_party/quickjs/ \ - $(THIRD_PARTY_QUICKJS_A).pkg \ - $(THIRD_PARTY_QUICKJS_A_OBJS) - -$(THIRD_PARTY_QUICKJS_A).pkg: \ - $(THIRD_PARTY_QUICKJS_A_OBJS) \ - $(foreach x,$(THIRD_PARTY_QUICKJS_A_DIRECTDEPS),$($(x)_A).pkg) - -THIRD_PARTY_QUICKJS_SRCS = \ - third_party/quickjs/qjs.c \ - third_party/quickjs/qjsc.c \ - third_party/quickjs/run-test262.c \ - third_party/quickjs/unicode_gen.c \ - $(foreach x,$(THIRD_PARTY_QUICKJS_ARTIFACTS),$($(x)_SRCS)) - -THIRD_PARTY_QUICKJS_OBJS = \ - o/$(MODE)/third_party/quickjs/qjs.o \ - o/$(MODE)/third_party/quickjs/qjsc.o \ - o/$(MODE)/third_party/quickjs/run-test262.o \ - $(THIRD_PARTY_QUICKJS_A_OBJS) - -THIRD_PARTY_QUICKJS_COMS = \ - o/$(MODE)/third_party/quickjs/qjs.com \ - o/$(MODE)/third_party/quickjs/qjsc.com \ - o/$(MODE)/third_party/quickjs/run-test262.com \ - o/$(MODE)/third_party/quickjs/unicode_gen.com - -THIRD_PARTY_QUICKJS_CHECKS = \ - $(THIRD_PARTY_QUICKJS_A).pkg \ - $(THIRD_PARTY_QUICKJS_A_HDRS:%=o/$(MODE)/%.ok) - -o/$(MODE)/third_party/quickjs/qjscalc.c: \ - third_party/quickjs/qjscalc.js \ - o/$(MODE)/third_party/quickjs/qjsc.com - @$(COMPILE) -wAQJSC o/$(MODE)/third_party/quickjs/qjsc.com -fbignum -o $@ -c $< - -o/$(MODE)/third_party/quickjs/repl.c: \ - third_party/quickjs/repl.js \ - o/$(MODE)/third_party/quickjs/qjsc.com - @$(COMPILE) -wAQJSC o/$(MODE)/third_party/quickjs/qjsc.com -o $@ -m -c $< - -o/$(MODE)/third_party/quickjs/qjs.com.dbg: \ - $(THIRD_PARTY_QUICKJS) \ - o/$(MODE)/third_party/quickjs/qjs.o \ - o/$(MODE)/third_party/quickjs/repl.o \ - o/$(MODE)/third_party/quickjs/qjscalc.o \ - $(CRT) \ - $(APE_NO_MODIFY_SELF) - @$(APELINK) - -o/$(MODE)/third_party/quickjs/qjs.com: \ - o/$(MODE)/third_party/quickjs/qjs.com.dbg \ - o/$(MODE)/third_party/zip/zip.com \ - o/$(MODE)/tool/build/symtab.com - @$(MAKE_OBJCOPY) - @$(MAKE_SYMTAB_CREATE) - @$(MAKE_SYMTAB_ZIP) - -o/$(MODE)/third_party/quickjs/qjsc.com.dbg: \ - $(THIRD_PARTY_QUICKJS) \ - o/$(MODE)/third_party/quickjs/qjsc.o \ - $(CRT) \ - $(APE_NO_MODIFY_SELF) - @$(APELINK) - -# git clone git@github.com:tc39/test262 /opt/test262 -# make -j8 MODE=dbg o/dbg/third_party/quickjs/run-test262.com -# o/dbg/third_party/quickjs/run-test262.com -m -c third_party/quickjs/test262.conf -a -o/$(MODE)/third_party/quickjs/run-test262.com.dbg: \ - $(THIRD_PARTY_QUICKJS_A_DEPS) \ - $(THIRD_PARTY_QUICKJS_A) \ - $(THIRD_PARTY_QUICKJS_A).pkg \ - o/$(MODE)/third_party/quickjs/run-test262.o \ - $(CRT) \ - $(APE_NO_MODIFY_SELF) - @$(APELINK) - -o/$(MODE)/third_party/quickjs/unicode_gen.com.dbg: \ - $(THIRD_PARTY_QUICKJS_A_DEPS) \ - $(THIRD_PARTY_QUICKJS_A) \ - $(THIRD_PARTY_QUICKJS_A).pkg \ - o/$(MODE)/third_party/quickjs/unicode_gen.o \ - $(CRT) \ - $(APE_NO_MODIFY_SELF) - @$(APELINK) - -$(THIRD_PARTY_QUICKJS_OBJS): private \ - CPPFLAGS += \ - -DCONFIG_BIGNUM \ - -DCONFIG_VERSION=\"2021-03-27\" - -o/tiny/third_party/quickjs/call.o: private \ - CFLAGS += \ - -O2 - -# TODO(jart): Replace alloca() calls with malloc(). -o/$(MODE)/third_party/quickjs/libregexp.o \ -o/$(MODE)/third_party/quickjs/quickjs.o: private \ - CPPFLAGS += \ - -DSTACK_FRAME_UNLIMITED - -o/$(MODE)/third_party/quickjs/call.o: private QUOTA = -M1024m -C32 -L180 -o/$(MODE)/third_party/quickjs/quickjs.o: private QUOTA = -M512m -C32 -L180 - -.PHONY: o/$(MODE)/third_party/quickjs -o/$(MODE)/third_party/quickjs: \ - $(THIRD_PARTY_QUICKJS_BINS) \ - $(THIRD_PARTY_QUICKJS_CHECKS) diff --git a/third_party/quickjs/Changelog b/third_party/quickjs/Changelog deleted file mode 100644 index c09af91cb..000000000 --- a/third_party/quickjs/Changelog +++ /dev/null @@ -1,148 +0,0 @@ -2021-03-27: - -- faster Array.prototype.push and Array.prototype.unshift -- added JS_UpdateStackTop() -- fixed Windows console -- misc bug fixes - -2020-11-08: - -- improved function parameter initializers -- added std.setenv(), std.unsetenv() and std.getenviron() -- added JS_EvalThis() -- misc bug fixes - -2020-09-06: - -- added logical assignment operators -- added IsHTMLDDA support -- faster for-of loops -- os.Worker now takes a module filename as parameter -- qjsc: added -D option to compile dynamically loaded modules or workers -- misc bug fixes - -2020-07-05: - -- modified JS_GetPrototype() to return a live value -- REPL: support unicode characters larger than 16 bits -- added os.Worker -- improved object serialization -- added std.parseExtJSON -- misc bug fixes - -2020-04-12: - -- added cross realm support -- added AggregateError and Promise.any -- added env, uid and gid options in os.exec() -- misc bug fixes - -2020-03-16: - -- reworked error handling in std and os libraries: suppressed I/O - exceptions in std FILE functions and return a positive errno value - when it is explicit -- output exception messages to stderr -- added std.loadFile(), std.strerror(), std.FILE.prototype.tello() -- added JS_GetRuntimeOpaque(), JS_SetRuntimeOpaque(), JS_NewUint32() -- updated to Unicode 13.0.0 -- misc bug fixes - -2020-01-19: - -- keep CONFIG_BIGNUM in the makefile -- added os.chdir() -- qjs: added -I option -- more memory checks in the bignum operations -- modified operator overloading semantics to be closer to the TC39 - proposal -- suppressed "use bigint" mode. Simplified "use math" mode -- BigDecimal: changed suffix from 'd' to 'm' -- misc bug fixes - -2020-01-05: - -- always compile the bignum code. Added '--bignum' option to qjs. -- added BigDecimal -- added String.prototype.replaceAll -- misc bug fixes - -2019-12-21: - -- added nullish coalescing operator (ES2020) -- added optional chaining (ES2020) -- removed recursions in garbage collector -- test stack overflow in the parser -- improved backtrace logic -- added JS_SetHostPromiseRejectionTracker() -- allow exotic constructors -- improved c++ compatibility -- misc bug fixes - -2019-10-27: - -- added example of C class in a module (examples/test_point.js) -- added JS_GetTypedArrayBuffer() -- misc bug fixes - -2019-09-18: - -- added os.exec and other system calls -- exported JS_ValueToAtom() -- qjsc: added 'qjsc_' prefix to the generated C identifiers -- added cross-compilation support -- misc bug fixes - -2019-09-01: - -- added globalThis -- documented JS_EVAL_FLAG_COMPILE_ONLY -- added import.meta.url and import.meta.main -- added 'debugger' statement -- misc bug fixes - -2019-08-18: - -- added os.realpath, os.getcwd, os.mkdir, os.stat, os.lstat, - os.readlink, os.readdir, os.utimes, std.popen -- module autodetection -- added import.meta -- misc bug fixes - -2019-08-10: - -- added public class fields and private class fields, methods and - accessors (TC39 proposal) -- changed JS_ToCStringLen() prototype -- qjsc: handle '-' in module names and modules with the same filename -- added std.urlGet -- exported JS_GetOwnPropertyNames() and JS_GetOwnProperty() -- exported some bigint C functions -- added support for eshost in run-test262 -- misc bug fixes - -2019-07-28: - -- added dynamic import -- added Promise.allSettled -- added String.prototype.matchAll -- added Object.fromEntries -- reduced number of ticks in await -- added BigInt support in Atomics -- exported JS_NewPromiseCapability() -- misc async function and async generator fixes -- enabled hashbang support by default - -2019-07-21: - -- updated test262 tests -- updated to Unicode version 12.1.0 -- fixed missing Date object in qjsc -- fixed multi-context creation -- misc ES2020 related fixes -- simplified power and division operators in bignum extension -- fixed several crash conditions - -2019-07-09: - -- first public release diff --git a/third_party/quickjs/LICENSE b/third_party/quickjs/LICENSE deleted file mode 100644 index 2c8fdebaf..000000000 --- a/third_party/quickjs/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -QuickJS Javascript Engine - -Copyright (c) 2017-2021 Fabrice Bellard -Copyright (c) 2017-2021 Charlie Gordon - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/third_party/quickjs/README.cosmo b/third_party/quickjs/README.cosmo deleted file mode 100644 index 1f9dfd2bd..000000000 --- a/third_party/quickjs/README.cosmo +++ /dev/null @@ -1,16 +0,0 @@ -LOCAL CHANGES - - - Replace snprintf with xasprintf in find_unique_cname - - Squash uninitialized read of harnessbuf in run-test262.c - - Change run-test262.c to not rebase configured paths - - https://github.com/bellard/quickjs/pull/132 - - https://github.com/bellard/quickjs/pull/171 - - https://github.com/bellard/quickjs/pull/182 - -SYNCHRONIZATION POINT (`--date=format:"%a %b %d %H:%M:%S %Y %z"`) - - commit 2788d71e823b522b178db3b3660ce93689534e6d - Author: bellard <6490144+bellard@users.noreply.github.com> - Date: Sun Mar 06 19:00:24 2022 +0100 - - updated to Unicode 14.0.0 diff --git a/third_party/quickjs/TODO b/third_party/quickjs/TODO deleted file mode 100644 index 2a3b3c311..000000000 --- a/third_party/quickjs/TODO +++ /dev/null @@ -1,70 +0,0 @@ -Bugs: -- modules: better error handling with cyclic module references - -Misc ideas: -- use custom printf to avoid compatibility issues with floating point numbers -- consistent naming for preprocessor defines -- unify coding style and naming conventions -- use names from the ECMA spec in library implementation -- use byte code emitters with typed arguments (for clarity) -- use 2 bytecode DynBufs in JSFunctionDef, one for reading, one for writing - and use the same wrappers in all phases -- use more generic method for line numbers in resolve_variables and resolve_labels -- use custom timezone support to avoid C library compatibility issues - -Memory: -- use memory pools for objects, etc? -- test border cases for max number of atoms, object properties, string length -- add emergency malloc mode for out of memory exceptions. -- test all DynBuf memory errors -- test all js_realloc memory errors -- improve JS_ComputeMemoryUsage() with more info - -Built-in standard library: -- BSD sockets -- modules: use realpath in module name normalizer and put it in quickjs-libc -- modules: if no ".", use a well known module loading path ? -- get rid of __loadScript, use more common name - -REPL: -- debugger -- readline: support MS Windows terminal -- readline: handle dynamic terminal resizing -- readline: handle double width unicode characters -- multiline editing -- runtime object and function inspectors -- interactive object browser -- use more generic approach to display evaluation results -- improve directive handling: dispatch, colorize, completion... -- save history -- close all predefined methods in repl.js and jscalc.js - -Optimization ideas: -- 64-bit atoms in 64-bit mode ? -- 64-bit small bigint in 64-bit mode ? -- reuse stack slots for disjoint scopes, if strip -- add heuristic to avoid some cycles in closures -- small String (0-2 charcodes) with immediate storage -- perform static string concatenation at compile time -- optimize string concatenation with ropes or miniropes? -- add implicit numeric strings for Uint32 numbers? -- optimize `s += a + b`, `s += a.b` and similar simple expressions -- ensure string canonical representation and optimise comparisons and hashes? -- remove JSObject.first_weak_ref, use bit+context based hashed array for weak references -- property access optimization on the global object, functions, - prototypes and special non extensible objects. -- create object literals with the correct length by backpatching length argument -- remove redundant set_loc_uninitialized/check_uninitialized opcodes -- peephole optim: push_atom_value, to_propkey -> push_atom_value -- peephole optim: put_loc x, get_loc_check x -> set_loc x -- convert slow array to fast array when all properties != length are numeric -- optimize destructuring assignments for global and local variables -- implement some form of tail-call-optimization -- optimize OP_apply -- optimize f(...b) - -Test262o: 0/11262 errors, 463 excluded -Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch) - -Result: 35/75280 errors, 909 excluded, 585 skipped -Test262 commit: 31126581e7290f9233c29cefd93f66c6ac78f1c9 diff --git a/third_party/quickjs/array.c b/third_party/quickjs/array.c deleted file mode 100644 index 50fd7c285..000000000 --- a/third_party/quickjs/array.c +++ /dev/null @@ -1,1951 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/str/str.h" -#include "third_party/quickjs/internal.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -/* 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 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; -} - -static int JS_CopySubArray(JSContext *ctx, - JSValueConst obj, int64_t to_pos, - int64_t from_pos, int64_t count, int dir) -{ - JSObject *p; - int64_t i, from, to, len; - JSValue val; - int fromPresent; - p = NULL; - if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { - p = JS_VALUE_GET_OBJ(obj); - if (p->class_id != JS_CLASS_ARRAY || !p->fast_array) { - p = NULL; - } - } - - for(i = 0; i < count; ) { - if (dir < 0) { - from = from_pos + count - i - 1; - to = to_pos + count - i - 1; - } else { - from = from_pos + i; - to = to_pos + i; - } - if (p && p->fast_array && - from >= 0 && from < (len = p->u.array.count) && - to >= 0 && to < len) { - int64_t l, j; - /* Fast path for fast arrays. Since we don't look at the - prototype chain, we can optimize only the cases where - all the elements are present in the array. */ - l = count - i; - if (dir < 0) { - l = min_int64(l, from + 1); - l = min_int64(l, to + 1); - for(j = 0; j < l; j++) { - set_value(ctx, &p->u.array.u.values[to - j], - JS_DupValue(ctx, p->u.array.u.values[from - j])); - } - } else { - l = min_int64(l, len - from); - l = min_int64(l, len - to); - for(j = 0; j < l; j++) { - set_value(ctx, &p->u.array.u.values[to + j], - JS_DupValue(ctx, p->u.array.u.values[from + j])); - } - } - i += l; - } else { - fromPresent = JS_TryGetPropertyInt64(ctx, obj, from, &val); - if (fromPresent < 0) - goto exception; - - if (fromPresent) { - if (JS_SetPropertyInt64(ctx, obj, to, val) < 0) - goto exception; - } else { - if (JS_DeletePropertyInt64(ctx, obj, to, JS_PROP_THROW) < 0) - goto exception; - } - i++; - } - } - return 0; - exception: - return -1; -} - -JSValue js_array_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) -{ - JSValue obj; - int i; - obj = js_create_from_ctor(ctx, new_target, JS_CLASS_ARRAY); - if (JS_IsException(obj)) - return obj; - if (argc == 1 && JS_IsNumber(argv[0])) { - uint32_t len; - if (JS_ToArrayLengthFree(ctx, &len, JS_DupValue(ctx, argv[0]), TRUE)) - goto fail; - if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, len)) < 0) - goto fail; - } else { - for(i = 0; i < argc; i++) { - if (JS_SetPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i])) < 0) - goto fail; - } - } - return obj; -fail: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -JSValue js_array_from(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // from(items, mapfn = void 0, this_arg = void 0) - JSValueConst items = argv[0], mapfn, this_arg; - JSValueConst args[2]; - JSValue stack[2]; - JSValue iter, r, v, v2, arrayLike; - int64_t k, len; - int done, mapping; - mapping = FALSE; - mapfn = JS_UNDEFINED; - this_arg = JS_UNDEFINED; - r = JS_UNDEFINED; - arrayLike = JS_UNDEFINED; - stack[0] = JS_UNDEFINED; - stack[1] = JS_UNDEFINED; - if (argc > 1) { - mapfn = argv[1]; - if (!JS_IsUndefined(mapfn)) { - if (check_function(ctx, mapfn)) - goto exception; - mapping = 1; - if (argc > 2) - this_arg = argv[2]; - } - } - iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator); - if (JS_IsException(iter)) - goto exception; - if (!JS_IsUndefined(iter)) { - JS_FreeValue(ctx, iter); - if (JS_IsConstructor(ctx, this_val)) - r = JS_CallConstructor(ctx, this_val, 0, NULL); - else - r = JS_NewArray(ctx); - if (JS_IsException(r)) - goto exception; - stack[0] = JS_DupValue(ctx, items); - if (js_for_of_start(ctx, &stack[1], FALSE)) - goto exception; - for (k = 0;; k++) { - v = JS_IteratorNext(ctx, stack[0], stack[1], 0, NULL, &done); - if (JS_IsException(v)) - goto exception_close; - if (done) - break; - if (mapping) { - args[0] = v; - args[1] = JS_NewInt32(ctx, k); - v2 = JS_Call(ctx, mapfn, this_arg, 2, args); - JS_FreeValue(ctx, v); - v = v2; - if (JS_IsException(v)) - goto exception_close; - } - if (JS_DefinePropertyValueInt64(ctx, r, k, v, - JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception_close; - } - } else { - arrayLike = JS_ToObject(ctx, items); - if (JS_IsException(arrayLike)) - goto exception; - if (js_get_length64(ctx, &len, arrayLike) < 0) - goto exception; - v = JS_NewInt64(ctx, len); - args[0] = v; - if (JS_IsConstructor(ctx, this_val)) { - r = JS_CallConstructor(ctx, this_val, 1, args); - } else { - r = js_array_constructor(ctx, JS_UNDEFINED, 1, args); - } - JS_FreeValue(ctx, v); - if (JS_IsException(r)) - goto exception; - for(k = 0; k < len; k++) { - v = JS_GetPropertyInt64(ctx, arrayLike, k); - if (JS_IsException(v)) - goto exception; - if (mapping) { - args[0] = v; - args[1] = JS_NewInt32(ctx, k); - v2 = JS_Call(ctx, mapfn, this_arg, 2, args); - JS_FreeValue(ctx, v); - v = v2; - if (JS_IsException(v)) - goto exception; - } - if (JS_DefinePropertyValueInt64(ctx, r, k, v, - JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - } - } - if (JS_SetProperty(ctx, r, JS_ATOM_length, JS_NewUint32(ctx, k)) < 0) - goto exception; - goto done; - exception_close: - if (!JS_IsUndefined(stack[0])) - JS_IteratorClose(ctx, stack[0], TRUE); - exception: - JS_FreeValue(ctx, r); - r = JS_EXCEPTION; - done: - JS_FreeValue(ctx, arrayLike); - JS_FreeValue(ctx, stack[0]); - JS_FreeValue(ctx, stack[1]); - return r; -} - -static JSValue js_array_of(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj, args[1]; - int i; - if (JS_IsConstructor(ctx, this_val)) { - args[0] = JS_NewInt32(ctx, argc); - obj = JS_CallConstructor(ctx, this_val, 1, (JSValueConst *)args); - } else { - obj = JS_NewArray(ctx); - } - if (JS_IsException(obj)) - return JS_EXCEPTION; - for(i = 0; i < argc; i++) { - if (JS_CreateDataPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i]), - JS_PROP_THROW) < 0) { - goto fail; - } - } - if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, argc)) < 0) { - fail: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - return obj; -} - -static JSValue js_array_isArray(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int ret; - ret = JS_IsArray(ctx, argv[0]); - if (ret < 0) - return JS_EXCEPTION; - else - return JS_NewBool(ctx, ret); -} - -static JSValue JS_ArraySpeciesCreate(JSContext *ctx, JSValueConst obj, - JSValueConst len_val) -{ - JSValue ctor, ret, species; - int res; - JSContext *realm; - res = JS_IsArray(ctx, obj); - if (res < 0) - return JS_EXCEPTION; - if (!res) - return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val); - ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor); - if (JS_IsException(ctor)) - return ctor; - if (JS_IsConstructor(ctx, ctor)) { - /* legacy web compatibility */ - realm = JS_GetFunctionRealm(ctx, ctor); - if (!realm) { - JS_FreeValue(ctx, ctor); - return JS_EXCEPTION; - } - if (realm != ctx && - js_same_value(ctx, ctor, realm->array_ctor)) { - JS_FreeValue(ctx, ctor); - ctor = JS_UNDEFINED; - } - } - if (JS_IsObject(ctor)) { - species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species); - JS_FreeValue(ctx, ctor); - if (JS_IsException(species)) - return species; - ctor = species; - if (JS_IsNull(ctor)) - ctor = JS_UNDEFINED; - } - if (JS_IsUndefined(ctor)) { - return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val); - } else { - ret = JS_CallConstructor(ctx, ctor, 1, &len_val); - JS_FreeValue(ctx, ctor); - return ret; - } -} - -static const JSCFunctionListEntry js_array_funcs[] = { - JS_CFUNC_DEF("isArray", 1, js_array_isArray ), - JS_CFUNC_DEF("from", 1, js_array_from ), - JS_CFUNC_DEF("of", 0, js_array_of ), - JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ), -}; - -static int JS_isConcatSpreadable(JSContext *ctx, JSValueConst obj) -{ - JSValue val; - if (!JS_IsObject(obj)) - return FALSE; - val = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_isConcatSpreadable); - if (JS_IsException(val)) - return -1; - if (!JS_IsUndefined(val)) - return JS_ToBoolFree(ctx, val); - return JS_IsArray(ctx, obj); -} - -static JSValue js_array_concat(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj, arr, val; - JSValueConst e; - int64_t len, k, n; - int i, res; - arr = JS_UNDEFINED; - obj = JS_ToObject(ctx, this_val); - if (JS_IsException(obj)) - goto exception; - arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0)); - if (JS_IsException(arr)) - goto exception; - n = 0; - for (i = -1; i < argc; i++) { - if (i < 0) - e = obj; - else - e = argv[i]; - res = JS_isConcatSpreadable(ctx, e); - if (res < 0) - goto exception; - if (res) { - if (js_get_length64(ctx, &len, e)) - goto exception; - if (n + len > MAX_SAFE_INTEGER) { - JS_ThrowTypeError(ctx, "Array loo long"); - goto exception; - } - for (k = 0; k < len; k++, n++) { - res = JS_TryGetPropertyInt64(ctx, e, k, &val); - if (res < 0) - goto exception; - if (res) { - if (JS_DefinePropertyValueInt64(ctx, arr, n, val, - JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - } - } - } else { - if (n >= MAX_SAFE_INTEGER) { - JS_ThrowTypeError(ctx, "Array loo long"); - goto exception; - } - if (JS_DefinePropertyValueInt64(ctx, arr, n, JS_DupValue(ctx, e), - JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - n++; - } - } - if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0) - goto exception; - JS_FreeValue(ctx, obj); - return arr; -exception: - JS_FreeValue(ctx, arr); - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -JSValue js_array_every(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int special) -{ - JSValue obj, val, index_val, res, ret; - JSValueConst args[3]; - JSValueConst func, this_arg; - int64_t len, k, n; - int present; - ret = JS_UNDEFINED; - val = JS_UNDEFINED; - if (special & special_TA) { - obj = JS_DupValue(ctx, this_val); - len = js_typed_array_get_length_internal(ctx, obj); - if (len < 0) - goto exception; - } else { - obj = JS_ToObject(ctx, this_val); - if (js_get_length64(ctx, &len, obj)) - goto exception; - } - func = argv[0]; - this_arg = JS_UNDEFINED; - if (argc > 1) - this_arg = argv[1]; - if (check_function(ctx, func)) - goto exception; - switch (special) { - case special_every: - case special_every | special_TA: - ret = JS_TRUE; - break; - case special_some: - case special_some | special_TA: - ret = JS_FALSE; - break; - case special_map: - /* XXX: JS_ArraySpeciesCreate should take int64_t */ - ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt64(ctx, len)); - if (JS_IsException(ret)) - goto exception; - break; - case special_filter: - ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0)); - if (JS_IsException(ret)) - goto exception; - break; - case special_map | special_TA: - args[0] = obj; - args[1] = JS_NewInt32(ctx, len); - ret = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args); - if (JS_IsException(ret)) - goto exception; - break; - case special_filter | special_TA: - ret = JS_NewArray(ctx); - if (JS_IsException(ret)) - goto exception; - break; - } - n = 0; - for(k = 0; k < len; k++) { - if (special & special_TA) { - val = JS_GetPropertyInt64(ctx, obj, k); - if (JS_IsException(val)) - goto exception; - present = TRUE; - } else { - present = JS_TryGetPropertyInt64(ctx, obj, k, &val); - if (present < 0) - goto exception; - } - if (present) { - index_val = JS_NewInt64(ctx, k); - if (JS_IsException(index_val)) - goto exception; - args[0] = val; - args[1] = index_val; - args[2] = obj; - res = JS_Call(ctx, func, this_arg, 3, args); - JS_FreeValue(ctx, index_val); - if (JS_IsException(res)) - goto exception; - switch (special) { - case special_every: - case special_every | special_TA: - if (!JS_ToBoolFree(ctx, res)) { - ret = JS_FALSE; - goto done; - } - break; - case special_some: - case special_some | special_TA: - if (JS_ToBoolFree(ctx, res)) { - ret = JS_TRUE; - goto done; - } - break; - case special_map: - if (JS_DefinePropertyValueInt64(ctx, ret, k, res, - JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - break; - case special_map | special_TA: - if (JS_SetPropertyValue(ctx, ret, JS_NewInt32(ctx, k), res, JS_PROP_THROW) < 0) - goto exception; - break; - case special_filter: - case special_filter | special_TA: - if (JS_ToBoolFree(ctx, res)) { - if (JS_DefinePropertyValueInt64(ctx, ret, n++, JS_DupValue(ctx, val), - JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - } - break; - default: - JS_FreeValue(ctx, res); - break; - } - JS_FreeValue(ctx, val); - val = JS_UNDEFINED; - } - } -done: - if (special == (special_filter | special_TA)) { - JSValue arr; - args[0] = obj; - args[1] = JS_NewInt32(ctx, n); - arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args); - if (JS_IsException(arr)) - goto exception; - args[0] = ret; - res = JS_Invoke(ctx, arr, JS_ATOM_set, 1, args); - if (check_exception_free(ctx, res)) - goto exception; - JS_FreeValue(ctx, ret); - ret = arr; - } - JS_FreeValue(ctx, val); - JS_FreeValue(ctx, obj); - return ret; -exception: - JS_FreeValue(ctx, ret); - JS_FreeValue(ctx, val); - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int special) -{ - JSValue obj, val, index_val, acc, acc1; - JSValueConst args[4]; - JSValueConst func; - int64_t len, k, k1; - int present; - acc = JS_UNDEFINED; - val = JS_UNDEFINED; - if (special & special_TA) { - obj = JS_DupValue(ctx, this_val); - len = js_typed_array_get_length_internal(ctx, obj); - if (len < 0) - goto exception; - } else { - obj = JS_ToObject(ctx, this_val); - if (js_get_length64(ctx, &len, obj)) - goto exception; - } - func = argv[0]; - if (check_function(ctx, func)) - goto exception; - k = 0; - if (argc > 1) { - acc = JS_DupValue(ctx, argv[1]); - } else { - for(;;) { - if (k >= len) { - JS_ThrowTypeError(ctx, "empty array"); - goto exception; - } - k1 = (special & special_reduceRight) ? len - k - 1 : k; - k++; - if (special & special_TA) { - acc = JS_GetPropertyInt64(ctx, obj, k1); - if (JS_IsException(acc)) - goto exception; - break; - } else { - present = JS_TryGetPropertyInt64(ctx, obj, k1, &acc); - if (present < 0) - goto exception; - if (present) - break; - } - } - } - for (; k < len; k++) { - k1 = (special & special_reduceRight) ? len - k - 1 : k; - if (special & special_TA) { - val = JS_GetPropertyInt64(ctx, obj, k1); - if (JS_IsException(val)) - goto exception; - present = TRUE; - } else { - present = JS_TryGetPropertyInt64(ctx, obj, k1, &val); - if (present < 0) - goto exception; - } - if (present) { - index_val = JS_NewInt64(ctx, k1); - if (JS_IsException(index_val)) - goto exception; - args[0] = acc; - args[1] = val; - args[2] = index_val; - args[3] = obj; - acc1 = JS_Call(ctx, func, JS_UNDEFINED, 4, args); - JS_FreeValue(ctx, index_val); - JS_FreeValue(ctx, val); - val = JS_UNDEFINED; - if (JS_IsException(acc1)) - goto exception; - JS_FreeValue(ctx, acc); - acc = acc1; - } - } - JS_FreeValue(ctx, obj); - return acc; -exception: - JS_FreeValue(ctx, acc); - JS_FreeValue(ctx, val); - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue js_array_fill(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj; - int64_t len, start, end; - obj = JS_ToObject(ctx, this_val); - if (js_get_length64(ctx, &len, obj)) - goto exception; - start = 0; - if (argc > 1 && !JS_IsUndefined(argv[1])) { - if (JS_ToInt64Clamp(ctx, &start, argv[1], 0, len, len)) - goto exception; - } - end = len; - if (argc > 2 && !JS_IsUndefined(argv[2])) { - if (JS_ToInt64Clamp(ctx, &end, argv[2], 0, len, len)) - goto exception; - } - /* XXX: should special case fast arrays */ - while (start < end) { - if (JS_SetPropertyInt64(ctx, obj, start, - JS_DupValue(ctx, argv[0])) < 0) - goto exception; - start++; - } - return obj; - exception: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -/* Access an Array's internal JSValue array if available */ -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; -} - -JSValue js_array_includes(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj, val; - int64_t len, n, res; - JSValue *arrp; - uint32_t count; - obj = JS_ToObject(ctx, this_val); - if (js_get_length64(ctx, &len, obj)) - goto exception; - res = FALSE; - if (len > 0) { - n = 0; - if (argc > 1) { - if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len)) - goto exception; - } - if (js_get_fast_array(ctx, obj, &arrp, &count)) { - for (; n < count; n++) { - if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), - JS_DupValue(ctx, arrp[n]), - JS_EQ_SAME_VALUE_ZERO)) { - res = TRUE; - goto done; - } - } - } - for (; n < len; n++) { - val = JS_GetPropertyInt64(ctx, obj, n); - if (JS_IsException(val)) - goto exception; - if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, - JS_EQ_SAME_VALUE_ZERO)) { - res = TRUE; - break; - } - } - } - done: - JS_FreeValue(ctx, obj); - return JS_NewBool(ctx, res); - exception: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue js_array_indexOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj, val; - int64_t len, n, res; - JSValue *arrp; - uint32_t count; - obj = JS_ToObject(ctx, this_val); - if (js_get_length64(ctx, &len, obj)) - goto exception; - res = -1; - if (len > 0) { - n = 0; - if (argc > 1) { - if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len)) - goto exception; - } - if (js_get_fast_array(ctx, obj, &arrp, &count)) { - for (; n < count; n++) { - if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), - JS_DupValue(ctx, arrp[n]), JS_EQ_STRICT)) { - res = n; - goto done; - } - } - } - for (; n < len; n++) { - int present = JS_TryGetPropertyInt64(ctx, obj, n, &val); - if (present < 0) - goto exception; - if (present) { - if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) { - res = n; - break; - } - } - } - } - done: - JS_FreeValue(ctx, obj); - return JS_NewInt64(ctx, res); - exception: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue js_array_lastIndexOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj, val; - int64_t len, n, res; - int present; - obj = JS_ToObject(ctx, this_val); - if (js_get_length64(ctx, &len, obj)) - goto exception; - res = -1; - if (len > 0) { - n = len - 1; - if (argc > 1) { - if (JS_ToInt64Clamp(ctx, &n, argv[1], -1, len - 1, len)) - goto exception; - } - /* XXX: should special case fast arrays */ - for (; n >= 0; n--) { - present = JS_TryGetPropertyInt64(ctx, obj, n, &val); - if (present < 0) - goto exception; - if (present) { - if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) { - res = n; - break; - } - } - } - } - JS_FreeValue(ctx, obj); - return JS_NewInt64(ctx, res); - exception: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int findIndex) -{ - JSValueConst func, this_arg; - JSValueConst args[3]; - JSValue obj, val, index_val, res; - int64_t len, k; - index_val = JS_UNDEFINED; - val = JS_UNDEFINED; - obj = JS_ToObject(ctx, this_val); - if (js_get_length64(ctx, &len, obj)) - goto exception; - func = argv[0]; - if (check_function(ctx, func)) - goto exception; - this_arg = JS_UNDEFINED; - if (argc > 1) - this_arg = argv[1]; - for(k = 0; k < len; k++) { - index_val = JS_NewInt64(ctx, k); - if (JS_IsException(index_val)) - goto exception; - val = JS_GetPropertyValue(ctx, obj, index_val); - if (JS_IsException(val)) - goto exception; - args[0] = val; - args[1] = index_val; - args[2] = this_val; - res = JS_Call(ctx, func, this_arg, 3, args); - if (JS_IsException(res)) - goto exception; - if (JS_ToBoolFree(ctx, res)) { - if (findIndex) { - JS_FreeValue(ctx, val); - JS_FreeValue(ctx, obj); - return index_val; - } else { - JS_FreeValue(ctx, index_val); - JS_FreeValue(ctx, obj); - return val; - } - } - JS_FreeValue(ctx, val); - JS_FreeValue(ctx, index_val); - } - JS_FreeValue(ctx, obj); - if (findIndex) - return JS_NewInt32(ctx, -1); - else - return JS_UNDEFINED; -exception: - JS_FreeValue(ctx, index_val); - JS_FreeValue(ctx, val); - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue js_array_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj, method, ret; - obj = JS_ToObject(ctx, this_val); - if (JS_IsException(obj)) - return JS_EXCEPTION; - method = JS_GetProperty(ctx, obj, JS_ATOM_join); - if (JS_IsException(method)) { - ret = JS_EXCEPTION; - } else - if (!JS_IsFunction(ctx, method)) { - /* Use intrinsic Object.prototype.toString */ - JS_FreeValue(ctx, method); - ret = js_object_toString(ctx, obj, 0, NULL); - } else { - ret = JS_CallFree(ctx, method, obj, 0, NULL); - } - JS_FreeValue(ctx, obj); - return ret; -} - -static JSValue js_array_join(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int toLocaleString) -{ - JSValue obj, sep = JS_UNDEFINED, el; - StringBuffer b_s, *b = &b_s; - JSString *p = NULL; - int64_t i, n; - int c; - obj = JS_ToObject(ctx, this_val); - if (js_get_length64(ctx, &n, obj)) - goto exception; - c = ','; /* default separator */ - if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) { - sep = JS_ToString(ctx, argv[0]); - if (JS_IsException(sep)) - goto exception; - p = JS_VALUE_GET_STRING(sep); - if (p->len == 1 && !p->is_wide_char) - c = p->u.str8[0]; - else - c = -1; - } - string_buffer_init(ctx, b, 0); - for(i = 0; i < n; i++) { - if (i > 0) { - if (c >= 0) { - string_buffer_putc8(b, c); - } else { - string_buffer_concat(b, p, 0, p->len); - } - } - el = JS_GetPropertyUint32(ctx, obj, i); - if (JS_IsException(el)) - goto fail; - if (!JS_IsNull(el) && !JS_IsUndefined(el)) { - if (toLocaleString) { - el = JS_ToLocaleStringFree(ctx, el); - } - if (string_buffer_concat_value_free(b, el)) - goto fail; - } - } - JS_FreeValue(ctx, sep); - JS_FreeValue(ctx, obj); - return string_buffer_end(b); -fail: - string_buffer_free(b); - JS_FreeValue(ctx, sep); -exception: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -JSValue js_array_pop(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int shift) -{ - JSValue obj, res = JS_UNDEFINED; - int64_t len, newLen; - JSValue *arrp; - uint32_t count32; - obj = JS_ToObject(ctx, this_val); - if (js_get_length64(ctx, &len, obj)) - goto exception; - newLen = 0; - if (len > 0) { - newLen = len - 1; - /* Special case fast arrays */ - if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) { - JSObject *p = JS_VALUE_GET_OBJ(obj); - if (shift) { - res = arrp[0]; - memmove(arrp, arrp + 1, (count32 - 1) * sizeof(*arrp)); - p->u.array.count--; - } else { - res = arrp[count32 - 1]; - p->u.array.count--; - } - } else { - if (shift) { - res = JS_GetPropertyInt64(ctx, obj, 0); - if (JS_IsException(res)) - goto exception; - if (JS_CopySubArray(ctx, obj, 0, 1, len - 1, +1)) - goto exception; - } else { - res = JS_GetPropertyInt64(ctx, obj, newLen); - if (JS_IsException(res)) - goto exception; - } - if (JS_DeletePropertyInt64(ctx, obj, newLen, JS_PROP_THROW) < 0) - goto exception; - } - } - if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0) - goto exception; - JS_FreeValue(ctx, obj); - return res; - exception: - JS_FreeValue(ctx, res); - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -/* return -1 if exception */ -static int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len) -{ - uint32_t new_size; - size_t slack; - JSValue *new_array_prop; - /* XXX: potential arithmetic overflow */ - new_size = max_int(new_len, p->u.array.u1.size * 3 / 2); - new_array_prop = js_realloc2(ctx, p->u.array.u.values, sizeof(JSValue) * new_size, &slack); - if (!new_array_prop) - return -1; - new_size += slack / sizeof(*new_array_prop); - p->u.array.u.values = new_array_prop; - p->u.array.u1.size = new_size; - return 0; -} - -/* Preconditions: 'p' must be of class JS_CLASS_ARRAY, p->fast_array = - TRUE and p->extensible = TRUE */ -int add_fast_array_element(JSContext *ctx, JSObject *p, JSValue val, int flags) -{ - uint32_t new_len, array_len; - /* extend the array by one */ - /* XXX: convert to slow array if new_len > 2^31-1 elements */ - new_len = p->u.array.count + 1; - /* update the length if necessary. We assume that if the length is - not an integer, then if it >= 2^31. */ - if (LIKELY(JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT)) { - array_len = JS_VALUE_GET_INT(p->prop[0].u.value); - if (new_len > array_len) { - if (UNLIKELY(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE))) { - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length); - } - p->prop[0].u.value = JS_NewInt32(ctx, new_len); - } - } - if (UNLIKELY(new_len > p->u.array.u1.size)) { - if (expand_fast_array(ctx, p, new_len)) { - JS_FreeValue(ctx, val); - return -1; - } - } - p->u.array.u.values[new_len - 1] = val; - p->u.array.count = new_len; - return TRUE; -} - -JSValue js_array_push(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int unshift) -{ - JSValue obj; - int i; - int64_t len, from, newLen; - obj = JS_ToObject(ctx, this_val); - if (js_get_length64(ctx, &len, obj)) - goto exception; - newLen = len + argc; - if (newLen > MAX_SAFE_INTEGER) { - JS_ThrowTypeError(ctx, "Array loo long"); - goto exception; - } - from = len; - if (unshift && argc > 0) { - if (JS_CopySubArray(ctx, obj, argc, 0, len, -1)) - goto exception; - from = 0; - } - for(i = 0; i < argc; i++) { - if (JS_SetPropertyInt64(ctx, obj, from + i, JS_DupValue(ctx, argv[i])) < 0) - goto exception; - } - if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0) - goto exception; - - JS_FreeValue(ctx, obj); - return JS_NewInt64(ctx, newLen); - exception: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue js_array_reverse(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj, lval, hval; - JSValue *arrp; - int64_t len, l, h; - int l_present, h_present; - uint32_t count32; - lval = JS_UNDEFINED; - obj = JS_ToObject(ctx, this_val); - if (js_get_length64(ctx, &len, obj)) - goto exception; - /* Special case fast arrays */ - if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) { - uint32_t ll, hh; - if (count32 > 1) { - for (ll = 0, hh = count32 - 1; ll < hh; ll++, hh--) { - lval = arrp[ll]; - arrp[ll] = arrp[hh]; - arrp[hh] = lval; - } - } - return obj; - } - for (l = 0, h = len - 1; l < h; l++, h--) { - l_present = JS_TryGetPropertyInt64(ctx, obj, l, &lval); - if (l_present < 0) - goto exception; - h_present = JS_TryGetPropertyInt64(ctx, obj, h, &hval); - if (h_present < 0) - goto exception; - if (h_present) { - if (JS_SetPropertyInt64(ctx, obj, l, hval) < 0) - goto exception; - if (l_present) { - if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) { - lval = JS_UNDEFINED; - goto exception; - } - lval = JS_UNDEFINED; - } else { - if (JS_DeletePropertyInt64(ctx, obj, h, JS_PROP_THROW) < 0) - goto exception; - } - } else { - if (l_present) { - if (JS_DeletePropertyInt64(ctx, obj, l, JS_PROP_THROW) < 0) - goto exception; - if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) { - lval = JS_UNDEFINED; - goto exception; - } - lval = JS_UNDEFINED; - } - } - } - return obj; - exception: - JS_FreeValue(ctx, lval); - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -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; -} - -static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int splice) -{ - JSValue obj, arr, val, len_val; - int64_t len, start, k, final, n, count, del_count, new_len; - int kPresent; - JSValue *arrp; - uint32_t count32, i, item_count; - arr = JS_UNDEFINED; - obj = JS_ToObject(ctx, this_val); - if (js_get_length64(ctx, &len, obj)) - goto exception; - if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len)) - goto exception; - if (splice) { - if (argc == 0) { - item_count = 0; - del_count = 0; - } else - if (argc == 1) { - item_count = 0; - del_count = len - start; - } else { - item_count = argc - 2; - if (JS_ToInt64Clamp(ctx, &del_count, argv[1], 0, len - start, 0)) - goto exception; - } - if (len + item_count - del_count > MAX_SAFE_INTEGER) { - JS_ThrowTypeError(ctx, "Array loo long"); - goto exception; - } - count = del_count; - } else { - item_count = 0; /* avoid warning */ - final = len; - if (!JS_IsUndefined(argv[1])) { - if (JS_ToInt64Clamp(ctx, &final, argv[1], 0, len, len)) - goto exception; - } - count = max_int64(final - start, 0); - } - len_val = JS_NewInt64(ctx, count); - arr = JS_ArraySpeciesCreate(ctx, obj, len_val); - JS_FreeValue(ctx, len_val); - if (JS_IsException(arr)) - goto exception; - k = start; - final = start + count; - n = 0; - /* The fast array test on arr ensures that - JS_CreateDataPropertyUint32() won't modify obj in case arr is - an exotic object */ - /* Special case fast arrays */ - if (js_get_fast_array(ctx, obj, &arrp, &count32) && - js_is_fast_array(ctx, arr)) { - /* XXX: should share code with fast array constructor */ - for (; k < final && k < count32; k++, n++) { - if (JS_CreateDataPropertyUint32(ctx, arr, n, JS_DupValue(ctx, arrp[k]), JS_PROP_THROW) < 0) - goto exception; - } - } - /* Copy the remaining elements if any (handle case of inherited properties) */ - for (; k < final; k++, n++) { - kPresent = JS_TryGetPropertyInt64(ctx, obj, k, &val); - if (kPresent < 0) - goto exception; - if (kPresent) { - if (JS_CreateDataPropertyUint32(ctx, arr, n, val, JS_PROP_THROW) < 0) - goto exception; - } - } - if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0) - goto exception; - if (splice) { - new_len = len + item_count - del_count; - if (item_count != del_count) { - if (JS_CopySubArray(ctx, obj, start + item_count, - start + del_count, len - (start + del_count), - item_count <= del_count ? +1 : -1) < 0) - goto exception; - for (k = len; k-- > new_len; ) { - if (JS_DeletePropertyInt64(ctx, obj, k, JS_PROP_THROW) < 0) - goto exception; - } - } - for (i = 0; i < item_count; i++) { - if (JS_SetPropertyInt64(ctx, obj, start + i, JS_DupValue(ctx, argv[i + 2])) < 0) - goto exception; - } - if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, new_len)) < 0) - goto exception; - } - JS_FreeValue(ctx, obj); - return arr; - exception: - JS_FreeValue(ctx, obj); - JS_FreeValue(ctx, arr); - return JS_EXCEPTION; -} - -static JSValue js_array_copyWithin(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj; - int64_t len, from, to, final, count; - obj = JS_ToObject(ctx, this_val); - if (js_get_length64(ctx, &len, obj)) - goto exception; - if (JS_ToInt64Clamp(ctx, &to, argv[0], 0, len, len)) - goto exception; - if (JS_ToInt64Clamp(ctx, &from, argv[1], 0, len, len)) - goto exception; - final = len; - if (argc > 2 && !JS_IsUndefined(argv[2])) { - if (JS_ToInt64Clamp(ctx, &final, argv[2], 0, len, len)) - goto exception; - } - count = min_int64(final - from, len - to); - if (JS_CopySubArray(ctx, obj, to, from, count, - (from < to && to < from + count) ? -1 : +1)) - goto exception; - return obj; - exception: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target, - JSValueConst source, int64_t sourceLen, - int64_t targetIndex, int depth, - JSValueConst mapperFunction, - JSValueConst thisArg) -{ - JSValue element; - int64_t sourceIndex, elementLen; - int present, is_array; - if (js_check_stack_overflow(ctx->rt, 0)) { - JS_ThrowStackOverflow(ctx); - return -1; - } - for (sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) { - present = JS_TryGetPropertyInt64(ctx, source, sourceIndex, &element); - if (present < 0) - return -1; - if (!present) - continue; - if (!JS_IsUndefined(mapperFunction)) { - JSValueConst args[3] = { element, JS_NewInt64(ctx, sourceIndex), source }; - element = JS_Call(ctx, mapperFunction, thisArg, 3, args); - JS_FreeValue(ctx, (JSValue)args[0]); - JS_FreeValue(ctx, (JSValue)args[1]); - if (JS_IsException(element)) - return -1; - } - if (depth > 0) { - is_array = JS_IsArray(ctx, element); - if (is_array < 0) - goto fail; - if (is_array) { - if (js_get_length64(ctx, &elementLen, element) < 0) - goto fail; - targetIndex = JS_FlattenIntoArray(ctx, target, element, - elementLen, targetIndex, - depth - 1, - JS_UNDEFINED, JS_UNDEFINED); - if (targetIndex < 0) - goto fail; - JS_FreeValue(ctx, element); - continue; - } - } - if (targetIndex >= MAX_SAFE_INTEGER) { - JS_ThrowTypeError(ctx, "Array too long"); - goto fail; - } - if (JS_DefinePropertyValueInt64(ctx, target, targetIndex, element, - JS_PROP_C_W_E | JS_PROP_THROW) < 0) - return -1; - targetIndex++; - } - return targetIndex; -fail: - JS_FreeValue(ctx, element); - return -1; -} - -static JSValue js_array_flatten(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int map) -{ - JSValue obj, arr; - JSValueConst mapperFunction, thisArg; - int64_t sourceLen; - int depthNum; - arr = JS_UNDEFINED; - obj = JS_ToObject(ctx, this_val); - if (js_get_length64(ctx, &sourceLen, obj)) - goto exception; - depthNum = 1; - mapperFunction = JS_UNDEFINED; - thisArg = JS_UNDEFINED; - if (map) { - mapperFunction = argv[0]; - if (argc > 1) { - thisArg = argv[1]; - } - if (check_function(ctx, mapperFunction)) - goto exception; - } else { - if (argc > 0 && !JS_IsUndefined(argv[0])) { - if (JS_ToInt32Sat(ctx, &depthNum, argv[0]) < 0) - goto exception; - } - } - arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0)); - if (JS_IsException(arr)) - goto exception; - if (JS_FlattenIntoArray(ctx, arr, obj, sourceLen, 0, depthNum, - mapperFunction, thisArg) < 0) - goto exception; - JS_FreeValue(ctx, obj); - return arr; -exception: - JS_FreeValue(ctx, obj); - JS_FreeValue(ctx, arr); - return JS_EXCEPTION; -} - -typedef struct ValueSlot { - JSValue val; - JSString *str; - int64_t pos; -} ValueSlot; - -struct array_sort_context { - JSContext *ctx; - int exception; - int has_method; - JSValueConst method; -}; - -static int js_array_cmp_generic(const void *a, const void *b, void *opaque) { - struct array_sort_context *psc = opaque; - JSContext *ctx = psc->ctx; - JSValueConst argv[2]; - JSValue res; - ValueSlot *ap = (ValueSlot *)(void *)a; - ValueSlot *bp = (ValueSlot *)(void *)b; - int cmp; - if (psc->exception) - return 0; - if (psc->has_method) { - /* custom sort function is specified as returning 0 for identical - * objects: avoid method call overhead. - */ - if (!memcmp(&ap->val, &bp->val, sizeof(ap->val))) - goto cmp_same; - argv[0] = ap->val; - argv[1] = bp->val; - res = JS_Call(ctx, psc->method, JS_UNDEFINED, 2, argv); - if (JS_IsException(res)) - goto exception; - if (JS_VALUE_GET_TAG(res) == JS_TAG_INT) { - int val = JS_VALUE_GET_INT(res); - cmp = (val > 0) - (val < 0); - } else { - double val; - if (JS_ToFloat64Free(ctx, &val, res) < 0) - goto exception; - cmp = (val > 0) - (val < 0); - } - } else { - /* Not supposed to bypass ToString even for identical objects as - * tested in test262/test/built-ins/Array/prototype/sort/bug_596_1.js - */ - if (!ap->str) { - JSValue str = JS_ToString(ctx, ap->val); - if (JS_IsException(str)) - goto exception; - ap->str = JS_VALUE_GET_STRING(str); - } - if (!bp->str) { - JSValue str = JS_ToString(ctx, bp->val); - if (JS_IsException(str)) - goto exception; - bp->str = JS_VALUE_GET_STRING(str); - } - cmp = js_string_compare(ctx, ap->str, bp->str); - } - if (cmp != 0) - return cmp; -cmp_same: - /* make sort stable: compare array offsets */ - return (ap->pos > bp->pos) - (ap->pos < bp->pos); -exception: - psc->exception = 1; - return 0; -} - -static JSValue js_array_sort(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - struct array_sort_context asc = { ctx, 0, 0, argv[0] }; - JSValue obj = JS_UNDEFINED; - ValueSlot *array = NULL; - size_t array_size = 0, pos = 0, n = 0; - int64_t i, len, undefined_count = 0; - int present; - if (!JS_IsUndefined(asc.method)) { - if (check_function(ctx, asc.method)) - goto exception; - asc.has_method = 1; - } - obj = JS_ToObject(ctx, this_val); - if (js_get_length64(ctx, &len, obj)) - goto exception; - /* XXX: should special case fast arrays */ - for (i = 0; i < len; i++) { - if (pos >= array_size) { - size_t new_size, slack; - ValueSlot *new_array; - new_size = (array_size + (array_size >> 1) + 31) & ~15; - new_array = js_realloc2(ctx, array, new_size * sizeof(*array), &slack); - if (new_array == NULL) - goto exception; - new_size += slack / sizeof(*new_array); - array = new_array; - array_size = new_size; - } - present = JS_TryGetPropertyInt64(ctx, obj, i, &array[pos].val); - if (present < 0) - goto exception; - if (present == 0) - continue; - if (JS_IsUndefined(array[pos].val)) { - undefined_count++; - continue; - } - array[pos].str = NULL; - array[pos].pos = i; - pos++; - } - rqsort(array, pos, sizeof(*array), js_array_cmp_generic, &asc); - if (asc.exception) - goto exception; - /* XXX: should special case fast arrays */ - while (n < pos) { - if (array[n].str) - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str)); - if (array[n].pos == n) { - JS_FreeValue(ctx, array[n].val); - } else { - if (JS_SetPropertyInt64(ctx, obj, n, array[n].val) < 0) { - n++; - goto exception; - } - } - n++; - } - js_free(ctx, array); - for (i = n; undefined_count-- > 0; i++) { - if (JS_SetPropertyInt64(ctx, obj, i, JS_UNDEFINED) < 0) - goto fail; - } - for (; i < len; i++) { - if (JS_DeletePropertyInt64(ctx, obj, i, JS_PROP_THROW) < 0) - goto fail; - } - return obj; -exception: - for (; n < pos; n++) { - JS_FreeValue(ctx, array[n].val); - if (array[n].str) - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str)); - } - js_free(ctx, array); -fail: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -void js_array_iterator_finalizer(JSRuntime *rt, JSValue val) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JSArrayIteratorData *it = p->u.array_iterator_data; - if (it) { - JS_FreeValueRT(rt, it->obj); - js_free_rt(rt, it); - } -} - -void js_array_iterator_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JSArrayIteratorData *it = p->u.array_iterator_data; - if (it) { - JS_MarkValue(rt, it->obj, mark_func); - } -} - -JSValue js_create_array(JSContext *ctx, int len, JSValueConst *tab) -{ - JSValue obj; - int i; - obj = JS_NewArray(ctx); - if (JS_IsException(obj)) - return JS_EXCEPTION; - for(i = 0; i < len; i++) { - if (JS_CreateDataPropertyUint32(ctx, obj, i, JS_DupValue(ctx, tab[i]), 0) < 0) { - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - } - return obj; -} - -JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSValue enum_obj, arr; - JSArrayIteratorData *it; - JSIteratorKindEnum kind; - int class_id; - - kind = magic & 3; - if (magic & 4) { - /* string iterator case */ - arr = JS_ToStringCheckObject(ctx, this_val); - class_id = JS_CLASS_STRING_ITERATOR; - } else { - arr = JS_ToObject(ctx, this_val); - class_id = JS_CLASS_ARRAY_ITERATOR; - } - if (JS_IsException(arr)) - goto fail; - enum_obj = JS_NewObjectClass(ctx, class_id); - if (JS_IsException(enum_obj)) - goto fail; - it = js_malloc(ctx, sizeof(*it)); - if (!it) - goto fail1; - it->obj = arr; - it->kind = kind; - it->idx = 0; - JS_SetOpaque(enum_obj, it); - return enum_obj; - fail1: - JS_FreeValue(ctx, enum_obj); - fail: - JS_FreeValue(ctx, arr); - return JS_EXCEPTION; -} - -JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - BOOL *pdone, int magic) -{ - JSArrayIteratorData *it; - uint32_t len, idx; - JSValue val, obj; - JSObject *p; - it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_ITERATOR); - if (!it) - goto fail1; - if (JS_IsUndefined(it->obj)) - goto done; - p = JS_VALUE_GET_OBJ(it->obj); - if (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) { - if (typed_array_is_detached(ctx, p)) { - JS_ThrowTypeErrorDetachedArrayBuffer(ctx); - goto fail1; - } - len = p->u.array.count; - } else { - if (js_get_length32(ctx, &len, it->obj)) { - fail1: - *pdone = FALSE; - return JS_EXCEPTION; - } - } - idx = it->idx; - if (idx >= len) { - JS_FreeValue(ctx, it->obj); - it->obj = JS_UNDEFINED; - done: - *pdone = TRUE; - return JS_UNDEFINED; - } - it->idx = idx + 1; - *pdone = FALSE; - if (it->kind == JS_ITERATOR_KIND_KEY) { - return JS_NewUint32(ctx, idx); - } else { - val = JS_GetPropertyUint32(ctx, it->obj, idx); - if (JS_IsException(val)) - return JS_EXCEPTION; - if (it->kind == JS_ITERATOR_KIND_VALUE) { - return val; - } else { - JSValueConst args[2]; - JSValue num; - num = JS_NewUint32(ctx, idx); - args[0] = num; - args[1] = val; - obj = js_create_array(ctx, 2, args); - JS_FreeValue(ctx, val); - JS_FreeValue(ctx, num); - return obj; - } - } -} - -static const JSCFunctionListEntry js_array_proto_funcs[] = { - JS_CFUNC_DEF("concat", 1, js_array_concat ), - JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every ), - JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some ), - JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, special_forEach ), - JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, special_map ), - JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, special_filter ), - JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce ), - JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight ), - JS_CFUNC_DEF("fill", 1, js_array_fill ), - JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, 0 ), - JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, 1 ), - JS_CFUNC_DEF("indexOf", 1, js_array_indexOf ), - JS_CFUNC_DEF("lastIndexOf", 1, js_array_lastIndexOf ), - JS_CFUNC_DEF("includes", 1, js_array_includes ), - JS_CFUNC_MAGIC_DEF("join", 1, js_array_join, 0 ), - JS_CFUNC_DEF("toString", 0, js_array_toString ), - JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_array_join, 1 ), - JS_CFUNC_MAGIC_DEF("pop", 0, js_array_pop, 0 ), - JS_CFUNC_MAGIC_DEF("push", 1, js_array_push, 0 ), - JS_CFUNC_MAGIC_DEF("shift", 0, js_array_pop, 1 ), - JS_CFUNC_MAGIC_DEF("unshift", 1, js_array_push, 1 ), - JS_CFUNC_DEF("reverse", 0, js_array_reverse ), - JS_CFUNC_DEF("sort", 1, js_array_sort ), - JS_CFUNC_MAGIC_DEF("slice", 2, js_array_slice, 0 ), - JS_CFUNC_MAGIC_DEF("splice", 2, js_array_slice, 1 ), - JS_CFUNC_DEF("copyWithin", 2, js_array_copyWithin ), - JS_CFUNC_MAGIC_DEF("flatMap", 1, js_array_flatten, 1 ), - JS_CFUNC_MAGIC_DEF("flat", 0, js_array_flatten, 0 ), - JS_CFUNC_MAGIC_DEF("values", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE ), - JS_ALIAS_DEF("[Symbol.iterator]", "values" ), - JS_CFUNC_MAGIC_DEF("keys", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY ), - JS_CFUNC_MAGIC_DEF("entries", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ), -}; - -void JS_AddIntrinsicArray(JSContext *ctx) { - JSValueConst obj; - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY], - js_array_proto_funcs, - countof(js_array_proto_funcs)); - obj = JS_NewGlobalCConstructor(ctx, "Array", js_array_constructor, 1, - ctx->class_proto[JS_CLASS_ARRAY]); - ctx->array_ctor = JS_DupValue(ctx, obj); - JS_SetPropertyFunctionList(ctx, obj, js_array_funcs, - countof(js_array_funcs)); -} - -static const JSCFunctionListEntry js_array_iterator_proto_funcs[] = { - JS_ITERATOR_NEXT_DEF("next", 0, js_array_iterator_next, 0 ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Array Iterator", JS_PROP_CONFIGURABLE ), -}; - -void JS_AddArrayIteratorProto(JSContext *ctx) { - /* needed to initialize arguments[Symbol.iterator] */ - ctx->array_proto_values = - JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_values); - ctx->class_proto[JS_CLASS_ARRAY_ITERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY_ITERATOR], - js_array_iterator_proto_funcs, - countof(js_array_iterator_proto_funcs)); -} - -int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, JSValue val, BOOL is_array_ctor) -{ - uint32_t tag, len; - tag = JS_VALUE_GET_TAG(val); - switch(tag) { - case JS_TAG_INT: - case JS_TAG_BOOL: - case JS_TAG_NULL: - { - int v; - v = JS_VALUE_GET_INT(val); - if (v < 0) - goto fail; - len = v; - } - break; -#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) - goto fail; - } else { - uint32_t len1; - if (is_array_ctor) { - val = JS_ToNumberFree(ctx, val); - if (JS_IsException(val)) - return -1; - /* cannot recurse because val is a number */ - if (JS_ToArrayLengthFree(ctx, &len, val, TRUE)) - return -1; - } else { - /* legacy behavior: must do the conversion twice and compare */ - if (JS_ToUint32(ctx, &len, val)) { - JS_FreeValue(ctx, val); - return -1; - } - val = JS_ToNumberFree(ctx, val); - if (JS_IsException(val)) - return -1; - /* cannot recurse because val is a number */ - if (JS_ToArrayLengthFree(ctx, &len1, val, FALSE)) - return -1; - if (len1 != len) { - fail: - JS_ThrowRangeError(ctx, "invalid array length"); - return -1; - } - } - } - break; - } - *plen = len; - return 0; -} - -/* set the array length and remove the array elements if necessary. */ -int set_array_length(JSContext *ctx, JSObject *p, JSValue val, int flags) -{ - uint32_t len, idx, cur_len; - int i, ret; - /* Note: this call can reallocate the properties of 'p' */ - ret = JS_ToArrayLengthFree(ctx, &len, val, FALSE); - if (ret) - return -1; - /* JS_ToArrayLengthFree() must be done before the read-only test */ - if (UNLIKELY(!(p->shape->prop[0].flags & JS_PROP_WRITABLE))) - return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length); - if (LIKELY(p->fast_array)) { - uint32_t old_len = p->u.array.count; - if (len < old_len) { - for(i = len; i < old_len; i++) { - JS_FreeValue(ctx, p->u.array.u.values[i]); - } - p->u.array.count = len; - } - p->prop[0].u.value = JS_NewUint32(ctx, len); - } else { - /* Note: length is always a uint32 because the object is an - array */ - JS_ToUint32(ctx, &cur_len, p->prop[0].u.value); - if (len < cur_len) { - uint32_t d; - JSShape *sh; - JSShapeProperty *pr; - d = cur_len - len; - sh = p->shape; - if (d <= sh->prop_count) { - JSAtom atom; - /* faster to iterate */ - while (cur_len > len) { - atom = JS_NewAtomUInt32(ctx, cur_len - 1); - ret = delete_property(ctx, p, atom); - JS_FreeAtom(ctx, atom); - if (UNLIKELY(!ret)) { - /* UNLIKELY case: property is not - configurable */ - break; - } - cur_len--; - } - } else { - /* faster to iterate thru all the properties. Need two - passes in case one of the property is not - configurable */ - cur_len = len; - for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; - i++, pr++) { - if (pr->atom != JS_ATOM_NULL && - JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) { - if (idx >= cur_len && - !(pr->flags & JS_PROP_CONFIGURABLE)) { - cur_len = idx + 1; - } - } - } - for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; - i++, pr++) { - if (pr->atom != JS_ATOM_NULL && - JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) { - if (idx >= cur_len) { - /* remove the property */ - delete_property(ctx, p, pr->atom); - /* WARNING: the shape may have been modified */ - sh = p->shape; - pr = get_shape_prop(sh) + i; - } - } - } - } - } else { - cur_len = len; - } - set_value(ctx, &p->prop[0].u.value, JS_NewUint32(ctx, cur_len)); - if (UNLIKELY(cur_len > len)) { - return JS_ThrowTypeErrorOrFalse(ctx, flags, "not configurable"); - } - } - return TRUE; -} - -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); -} - -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); - } -} diff --git a/third_party/quickjs/atof.c b/third_party/quickjs/atof.c deleted file mode 100644 index 39a75d13c..000000000 --- a/third_party/quickjs/atof.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/assert.h" -#include "libc/fmt/conv.h" -#include "libc/runtime/runtime.h" -#include "libc/str/str.h" -#include "third_party/quickjs/internal.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -/* 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; -} - -/* return an exception in case of memory error. Return JS_NAN if - invalid syntax */ -#ifdef CONFIG_BIGNUM -JSValue js_atof2(JSContext *ctx, const char *str, const char **pp, int radix, int flags, slimb_t *pexponent) -#else -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 (isdigit((uint8_t)*p1)) { - p = p1 + 1; - while (isdigit((uint8_t)*p) || (*p == sep && isdigit((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 -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 diff --git a/third_party/quickjs/atom.c b/third_party/quickjs/atom.c deleted file mode 100644 index 314e62925..000000000 --- a/third_party/quickjs/atom.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/assert.h" -#include "libc/str/str.h" -#include "third_party/quickjs/internal.h" -#include "third_party/quickjs/libregexp.h" -#include "third_party/quickjs/quickjs.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -/* Should only be used for debug. */ -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; -} - -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 */ -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; - } - } -} - -/* return TRUE if the string is a number n with 0 <= n <= 2^32-1 */ -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 (isdigit(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 (!isdigit(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; - } -} - -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; -} - -/* val must be a symbol */ -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 a string atom containing name concatenated with str1 */ -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; -} diff --git a/third_party/quickjs/atomics.c b/third_party/quickjs/atomics.c deleted file mode 100644 index bf486522e..000000000 --- a/third_party/quickjs/atomics.c +++ /dev/null @@ -1,520 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/assert.h" -#include "third_party/quickjs/internal.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -#ifdef CONFIG_ATOMICS - -typedef enum AtomicsOpEnum { - ATOMICS_OP_ADD, - ATOMICS_OP_AND, - ATOMICS_OP_OR, - ATOMICS_OP_SUB, - ATOMICS_OP_XOR, - ATOMICS_OP_EXCHANGE, - ATOMICS_OP_COMPARE_EXCHANGE, - ATOMICS_OP_LOAD, -} AtomicsOpEnum; - -static void *js_atomics_get_ptr(JSContext *ctx, - JSArrayBuffer **pabuf, - int *psize_log2, JSClassID *pclass_id, - JSValueConst obj, JSValueConst idx_val, - int is_waitable) -{ - JSObject *p; - JSTypedArray *ta; - JSArrayBuffer *abuf; - void *ptr; - uint64_t idx; - BOOL err; - int size_log2; - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - goto fail; - p = JS_VALUE_GET_OBJ(obj); -#ifdef CONFIG_BIGNUM - if (is_waitable) - err = (p->class_id != JS_CLASS_INT32_ARRAY && - p->class_id != JS_CLASS_BIG_INT64_ARRAY); - else - err = !(p->class_id >= JS_CLASS_INT8_ARRAY && - p->class_id <= JS_CLASS_BIG_UINT64_ARRAY); -#else - if (is_waitable) - err = (p->class_id != JS_CLASS_INT32_ARRAY); - else - err = !(p->class_id >= JS_CLASS_INT8_ARRAY && - p->class_id <= JS_CLASS_UINT32_ARRAY); -#endif - if (err) { - fail: - JS_ThrowTypeError(ctx, "integer TypedArray expected"); - return NULL; - } - ta = p->u.typed_array; - abuf = ta->buffer->u.array_buffer; - if (!abuf->shared) { - if (is_waitable == 2) { - JS_ThrowTypeError(ctx, "not a SharedArrayBuffer TypedArray"); - return NULL; - } - if (abuf->detached) { - JS_ThrowTypeErrorDetachedArrayBuffer(ctx); - return NULL; - } - } - if (JS_ToIndex(ctx, &idx, idx_val)) { - return NULL; - } - /* if the array buffer is detached, p->u.array.count = 0 */ - if (idx >= p->u.array.count) { - JS_ThrowRangeError(ctx, "out-of-bound access"); - return NULL; - } - size_log2 = typed_array_size_log2(p->class_id); - ptr = p->u.array.u.uint8_ptr + ((uintptr_t)idx << size_log2); - if (pabuf) - *pabuf = abuf; - if (psize_log2) - *psize_log2 = size_log2; - if (pclass_id) - *pclass_id = p->class_id; - return ptr; -} - -static JSValue js_atomics_op(JSContext *ctx, - JSValueConst this_obj, - int argc, JSValueConst *argv, int op) -{ - int size_log2; -#ifdef CONFIG_BIGNUM - uint64_t v, a, rep_val; -#else - uint32_t v, a, rep_val; -#endif - void *ptr; - JSValue ret; - JSClassID class_id; - JSArrayBuffer *abuf; - - ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, &class_id, - argv[0], argv[1], 0); - if (!ptr) - return JS_EXCEPTION; - rep_val = 0; - if (op == ATOMICS_OP_LOAD) { - v = 0; - } else { -#ifdef CONFIG_BIGNUM - if (size_log2 == 3) { - int64_t v64; - if (JS_ToBigInt64(ctx, &v64, argv[2])) - return JS_EXCEPTION; - v = v64; - if (op == ATOMICS_OP_COMPARE_EXCHANGE) { - if (JS_ToBigInt64(ctx, &v64, argv[3])) - return JS_EXCEPTION; - rep_val = v64; - } - } else -#endif - { - uint32_t v32; - if (JS_ToUint32(ctx, &v32, argv[2])) - return JS_EXCEPTION; - v = v32; - if (op == ATOMICS_OP_COMPARE_EXCHANGE) { - if (JS_ToUint32(ctx, &v32, argv[3])) - return JS_EXCEPTION; - rep_val = v32; - } - } - if (abuf->detached) - return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); - } - - switch(op | (size_log2 << 3)) { - -#ifdef CONFIG_BIGNUM -#define OP(op_name, func_name) \ - case ATOMICS_OP_ ## op_name | (0 << 3): \ - a = func_name((_Atomic(uint8_t) *)ptr, v); \ - break; \ - case ATOMICS_OP_ ## op_name | (1 << 3): \ - a = func_name((_Atomic(uint16_t) *)ptr, v); \ - break; \ - case ATOMICS_OP_ ## op_name | (2 << 3): \ - a = func_name((_Atomic(uint32_t) *)ptr, v); \ - break; \ - case ATOMICS_OP_ ## op_name | (3 << 3): \ - a = func_name((_Atomic(uint64_t) *)ptr, v); \ - break; -#else -#define OP(op_name, func_name) \ - case ATOMICS_OP_ ## op_name | (0 << 3): \ - a = func_name((_Atomic(uint8_t) *)ptr, v); \ - break; \ - case ATOMICS_OP_ ## op_name | (1 << 3): \ - a = func_name((_Atomic(uint16_t) *)ptr, v); \ - break; \ - case ATOMICS_OP_ ## op_name | (2 << 3): \ - a = func_name((_Atomic(uint32_t) *)ptr, v); \ - break; -#endif - OP(ADD, atomic_fetch_add) - OP(AND, atomic_fetch_and) - OP(OR, atomic_fetch_or) - OP(SUB, atomic_fetch_sub) - OP(XOR, atomic_fetch_xor) - OP(EXCHANGE, atomic_exchange) -#undef OP - - case ATOMICS_OP_LOAD | (0 << 3): - a = atomic_load((_Atomic(uint8_t) *)ptr); - break; - case ATOMICS_OP_LOAD | (1 << 3): - a = atomic_load((_Atomic(uint16_t) *)ptr); - break; - case ATOMICS_OP_LOAD | (2 << 3): - a = atomic_load((_Atomic(uint32_t) *)ptr); - break; -#ifdef CONFIG_BIGNUM - case ATOMICS_OP_LOAD | (3 << 3): - a = atomic_load((_Atomic(uint64_t) *)ptr); - break; -#endif - - case ATOMICS_OP_COMPARE_EXCHANGE | (0 << 3): - { - uint8_t v1 = v; - atomic_compare_exchange_strong((_Atomic(uint8_t) *)ptr, &v1, rep_val); - a = v1; - } - break; - case ATOMICS_OP_COMPARE_EXCHANGE | (1 << 3): - { - uint16_t v1 = v; - atomic_compare_exchange_strong((_Atomic(uint16_t) *)ptr, &v1, rep_val); - a = v1; - } - break; - case ATOMICS_OP_COMPARE_EXCHANGE | (2 << 3): - { - uint32_t v1 = v; - atomic_compare_exchange_strong((_Atomic(uint32_t) *)ptr, &v1, rep_val); - a = v1; - } - break; -#ifdef CONFIG_BIGNUM - case ATOMICS_OP_COMPARE_EXCHANGE | (3 << 3): - { - uint64_t v1 = v; - atomic_compare_exchange_strong((_Atomic(uint64_t) *)ptr, &v1, rep_val); - a = v1; - } - break; -#endif - default: - abort(); - } - - switch(class_id) { - case JS_CLASS_INT8_ARRAY: - a = (int8_t)a; - goto done; - case JS_CLASS_UINT8_ARRAY: - a = (uint8_t)a; - goto done; - case JS_CLASS_INT16_ARRAY: - a = (int16_t)a; - goto done; - case JS_CLASS_UINT16_ARRAY: - a = (uint16_t)a; - goto done; - case JS_CLASS_INT32_ARRAY: - done: - ret = JS_NewInt32(ctx, a); - break; - case JS_CLASS_UINT32_ARRAY: - ret = JS_NewUint32(ctx, a); - break; -#ifdef CONFIG_BIGNUM - case JS_CLASS_BIG_INT64_ARRAY: - ret = JS_NewBigInt64(ctx, a); - break; - case JS_CLASS_BIG_UINT64_ARRAY: - ret = JS_NewBigUint64(ctx, a); - break; -#endif - default: - abort(); - } - return ret; -} - -static JSValue js_atomics_store(JSContext *ctx, - JSValueConst this_obj, - int argc, JSValueConst *argv) -{ - int size_log2; - void *ptr; - JSValue ret; - JSArrayBuffer *abuf; - - ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, NULL, - argv[0], argv[1], 0); - if (!ptr) - return JS_EXCEPTION; -#ifdef CONFIG_BIGNUM - if (size_log2 == 3) { - int64_t v64; - ret = JS_ToBigIntValueFree(ctx, JS_DupValue(ctx, argv[2])); - if (JS_IsException(ret)) - return ret; - if (JS_ToBigInt64(ctx, &v64, ret)) { - JS_FreeValue(ctx, ret); - return JS_EXCEPTION; - } - if (abuf->detached) - return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); - atomic_store((_Atomic(uint64_t) *)ptr, v64); - } else -#endif - { - uint32_t v; - /* XXX: spec, would be simpler to return the written value */ - ret = JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[2])); - if (JS_IsException(ret)) - return ret; - if (JS_ToUint32(ctx, &v, ret)) { - JS_FreeValue(ctx, ret); - return JS_EXCEPTION; - } - if (abuf->detached) - return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); - switch(size_log2) { - case 0: - atomic_store((_Atomic(uint8_t) *)ptr, v); - break; - case 1: - atomic_store((_Atomic(uint16_t) *)ptr, v); - break; - case 2: - atomic_store((_Atomic(uint32_t) *)ptr, v); - break; - default: - abort(); - } - } - return ret; -} - -static JSValue js_atomics_isLockFree(JSContext *ctx, - JSValueConst this_obj, - int argc, JSValueConst *argv) -{ - int v, ret; - if (JS_ToInt32Sat(ctx, &v, argv[0])) - return JS_EXCEPTION; - ret = (v == 1 || v == 2 || v == 4 -#ifdef CONFIG_BIGNUM - || v == 8 -#endif - ); - return JS_NewBool(ctx, ret); -} - -typedef struct JSAtomicsWaiter { - struct list_head link; - BOOL linked; - pthread_cond_t cond; - int32_t *ptr; -} JSAtomicsWaiter; - -static pthread_mutex_t js_atomics_mutex = PTHREAD_MUTEX_INITIALIZER; -static struct list_head js_atomics_waiter_list = - LIST_HEAD_INIT(js_atomics_waiter_list); - -static JSValue js_atomics_wait(JSContext *ctx, - JSValueConst this_obj, - int argc, JSValueConst *argv) -{ - int64_t v; - int32_t v32; - void *ptr; - int64_t timeout; - struct timespec ts; - JSAtomicsWaiter waiter_s, *waiter; - int ret, size_log2, res; - double d; - ptr = js_atomics_get_ptr(ctx, NULL, &size_log2, NULL, - argv[0], argv[1], 2); - if (!ptr) - return JS_EXCEPTION; -#ifdef CONFIG_BIGNUM - if (size_log2 == 3) { - if (JS_ToBigInt64(ctx, &v, argv[2])) - return JS_EXCEPTION; - } else -#endif - { - if (JS_ToInt32(ctx, &v32, argv[2])) - return JS_EXCEPTION; - v = v32; - } - if (JS_ToFloat64(ctx, &d, argv[3])) - return JS_EXCEPTION; - if (isnan(d) || d > INT64_MAX) - timeout = INT64_MAX; - else if (d < 0) - timeout = 0; - else - timeout = (int64_t)d; - if (!ctx->rt->can_block) - return JS_ThrowTypeError(ctx, "cannot block in this thread"); - /* XXX: inefficient if large number of waiters, should hash on - 'ptr' value */ - /* XXX: use Linux futexes when available ? */ - pthread_mutex_lock(&js_atomics_mutex); - if (size_log2 == 3) { - res = *(int64_t *)ptr != v; - } else { - res = *(int32_t *)ptr != v; - } - if (res) { - pthread_mutex_unlock(&js_atomics_mutex); - return JS_AtomToString(ctx, JS_ATOM_not_equal); - } - waiter = &waiter_s; - waiter->ptr = ptr; - pthread_cond_init(&waiter->cond, NULL); - waiter->linked = TRUE; - list_add_tail(&waiter->link, &js_atomics_waiter_list); - if (timeout == INT64_MAX) { - pthread_cond_wait(&waiter->cond, &js_atomics_mutex); - ret = 0; - } else { - /* XXX: use clock monotonic */ - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += timeout / 1000; - ts.tv_nsec += (timeout % 1000) * 1000000; - if (ts.tv_nsec >= 1000000000) { - ts.tv_nsec -= 1000000000; - ts.tv_sec++; - } - ret = pthread_cond_timedwait(&waiter->cond, &js_atomics_mutex, - &ts); - } - if (waiter->linked) - list_del(&waiter->link); - pthread_mutex_unlock(&js_atomics_mutex); - pthread_cond_destroy(&waiter->cond); - if (ret == ETIMEDOUT) { - return JS_AtomToString(ctx, JS_ATOM_timed_out); - } else { - return JS_AtomToString(ctx, JS_ATOM_ok); - } -} - -static JSValue js_atomics_notify(JSContext *ctx, - JSValueConst this_obj, - int argc, JSValueConst *argv) -{ - struct list_head *el, *el1, waiter_list; - int32_t count, n; - void *ptr; - JSAtomicsWaiter *waiter; - JSArrayBuffer *abuf; - - ptr = js_atomics_get_ptr(ctx, &abuf, NULL, NULL, argv[0], argv[1], 1); - if (!ptr) - return JS_EXCEPTION; - - if (JS_IsUndefined(argv[2])) { - count = INT32_MAX; - } else { - if (JS_ToInt32Clamp(ctx, &count, argv[2], 0, INT32_MAX, 0)) - return JS_EXCEPTION; - } - if (abuf->detached) - return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); - - n = 0; - if (abuf->shared && count > 0) { - pthread_mutex_lock(&js_atomics_mutex); - init_list_head(&waiter_list); - list_for_each_safe(el, el1, &js_atomics_waiter_list) { - waiter = list_entry(el, JSAtomicsWaiter, link); - if (waiter->ptr == ptr) { - list_del(&waiter->link); - waiter->linked = FALSE; - list_add_tail(&waiter->link, &waiter_list); - n++; - if (n >= count) - break; - } - } - list_for_each(el, &waiter_list) { - waiter = list_entry(el, JSAtomicsWaiter, link); - pthread_cond_signal(&waiter->cond); - } - pthread_mutex_unlock(&js_atomics_mutex); - } - return JS_NewInt32(ctx, n); -} - -static const JSCFunctionListEntry js_atomics_funcs[] = { - JS_CFUNC_MAGIC_DEF("add", 3, js_atomics_op, ATOMICS_OP_ADD ), - JS_CFUNC_MAGIC_DEF("and", 3, js_atomics_op, ATOMICS_OP_AND ), - JS_CFUNC_MAGIC_DEF("or", 3, js_atomics_op, ATOMICS_OP_OR ), - JS_CFUNC_MAGIC_DEF("sub", 3, js_atomics_op, ATOMICS_OP_SUB ), - JS_CFUNC_MAGIC_DEF("xor", 3, js_atomics_op, ATOMICS_OP_XOR ), - JS_CFUNC_MAGIC_DEF("exchange", 3, js_atomics_op, ATOMICS_OP_EXCHANGE ), - JS_CFUNC_MAGIC_DEF("compareExchange", 4, js_atomics_op, ATOMICS_OP_COMPARE_EXCHANGE ), - JS_CFUNC_MAGIC_DEF("load", 2, js_atomics_op, ATOMICS_OP_LOAD ), - JS_CFUNC_DEF("store", 3, js_atomics_store ), - JS_CFUNC_DEF("isLockFree", 1, js_atomics_isLockFree ), - JS_CFUNC_DEF("wait", 4, js_atomics_wait ), - JS_CFUNC_DEF("notify", 3, js_atomics_notify ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Atomics", JS_PROP_CONFIGURABLE ), -}; - -static const JSCFunctionListEntry js_atomics_obj[] = { - JS_OBJECT_DEF("Atomics", js_atomics_funcs, countof(js_atomics_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ), -}; - -void JS_AddIntrinsicAtomics(JSContext *ctx) -{ - /* add Atomics as autoinit object */ - JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_atomics_obj, countof(js_atomics_obj)); -} - -#endif /* CONFIG_ATOMICS */ diff --git a/third_party/quickjs/bigdecimal.c b/third_party/quickjs/bigdecimal.c deleted file mode 100644 index 07b072c64..000000000 --- a/third_party/quickjs/bigdecimal.c +++ /dev/null @@ -1,724 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/runtime/runtime.h" -#include "libc/str/str.h" -#include "third_party/quickjs/internal.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -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); -} - -/* return NULL if invalid type */ -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; -} - -static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val, - BOOL allow_null_or_undefined) -{ - redo: - switch(JS_VALUE_GET_NORM_TAG(val)) { - case JS_TAG_BIG_DECIMAL: - break; - case JS_TAG_NULL: - if (!allow_null_or_undefined) - goto fail; - /* fall thru */ - case JS_TAG_BOOL: - case JS_TAG_INT: - { - bfdec_t *r; - int32_t v = JS_VALUE_GET_INT(val); - val = JS_NewBigDecimal(ctx); - if (JS_IsException(val)) - break; - r = JS_GetBigDecimal(val); - if (bfdec_set_si(r, v)) { - JS_FreeValue(ctx, val); - val = JS_EXCEPTION; - break; - } - } - break; - case JS_TAG_FLOAT64: - case JS_TAG_BIG_INT: - case JS_TAG_BIG_FLOAT: - val = JS_ToStringFree(ctx, val); - if (JS_IsException(val)) - break; - goto redo; - case JS_TAG_STRING: - { - const char *str, *p; - size_t len; - int err; - 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) { - bfdec_t *r; - val = JS_NewBigDecimal(ctx); - if (JS_IsException(val)) - break; - r = JS_GetBigDecimal(val); - bfdec_set_zero(r, 0); - err = 0; - } else { - val = js_atof(ctx, p, &p, 0, ATOD_TYPE_BIG_DECIMAL); - if (JS_IsException(val)) { - JS_FreeCString(ctx, str); - return JS_EXCEPTION; - } - p += skip_spaces(p); - err = ((p - str) != len); - } - JS_FreeCString(ctx, str); - if (err) { - JS_FreeValue(ctx, val); - return JS_ThrowSyntaxError(ctx, "invalid bigdecimal literal"); - } - } - break; - case JS_TAG_OBJECT: - val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER); - if (JS_IsException(val)) - break; - goto redo; - case JS_TAG_UNDEFINED: - { - bfdec_t *r; - if (!allow_null_or_undefined) - goto fail; - val = JS_NewBigDecimal(ctx); - if (JS_IsException(val)) - break; - r = JS_GetBigDecimal(val); - bfdec_set_nan(r); - } - break; - default: - fail: - JS_FreeValue(ctx, val); - return JS_ThrowTypeError(ctx, "cannot convert to bigdecimal"); - } - return val; -} - -static JSValue js_bigdecimal_constructor(JSContext *ctx, - JSValueConst new_target, - int argc, JSValueConst *argv) -{ - JSValue val; - if (!JS_IsUndefined(new_target)) - return JS_ThrowTypeError(ctx, "not a constructor"); - if (argc == 0) { - bfdec_t *r; - val = JS_NewBigDecimal(ctx); - if (JS_IsException(val)) - return val; - r = JS_GetBigDecimal(val); - bfdec_set_zero(r, 0); - } else { - val = JS_ToBigDecimalFree(ctx, JS_DupValue(ctx, argv[0]), FALSE); - } - return val; -} - -static JSValue js_thisBigDecimalValue(JSContext *ctx, JSValueConst this_val) -{ - if (JS_IsBigDecimal(this_val)) - return JS_DupValue(ctx, this_val); - - if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(this_val); - if (p->class_id == JS_CLASS_BIG_DECIMAL) { - if (JS_IsBigDecimal(p->u.object_data)) - return JS_DupValue(ctx, p->u.object_data); - } - } - return JS_ThrowTypeError(ctx, "not a bigdecimal"); -} - -static JSValue js_bigdecimal_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val; - - val = js_thisBigDecimalValue(ctx, this_val); - if (JS_IsException(val)) - return val; - return JS_ToStringFree(ctx, val); -} - -static JSValue js_bigdecimal_valueOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return js_thisBigDecimalValue(ctx, this_val); -} - -static int js_bigdecimal_get_rnd_mode(JSContext *ctx, JSValueConst obj) -{ - const char *str; - size_t size; - int rnd_mode; - - str = JS_ToCStringLen(ctx, &size, obj); - if (!str) - return -1; - if (strlen(str) != size) - goto invalid_rounding_mode; - if (!strcmp(str, "floor")) { - rnd_mode = BF_RNDD; - } else if (!strcmp(str, "ceiling")) { - rnd_mode = BF_RNDU; - } else if (!strcmp(str, "down")) { - rnd_mode = BF_RNDZ; - } else if (!strcmp(str, "up")) { - rnd_mode = BF_RNDA; - } else if (!strcmp(str, "half-even")) { - rnd_mode = BF_RNDN; - } else if (!strcmp(str, "half-up")) { - rnd_mode = BF_RNDNA; - } else { - invalid_rounding_mode: - JS_FreeCString(ctx, str); - JS_ThrowTypeError(ctx, "invalid rounding mode"); - return -1; - } - JS_FreeCString(ctx, str); - return rnd_mode; -} - -typedef struct { - int64_t prec; - bf_flags_t flags; -} BigDecimalEnv; - -static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe, - JSValueConst obj) -{ - JSValue prop; - int64_t val; - BOOL has_prec; - int rnd_mode; - if (!JS_IsObject(obj)) { - JS_ThrowTypeErrorNotAnObject(ctx); - return -1; - } - prop = JS_GetProperty(ctx, obj, JS_ATOM_roundingMode); - if (JS_IsException(prop)) - return -1; - rnd_mode = js_bigdecimal_get_rnd_mode(ctx, prop); - JS_FreeValue(ctx, prop); - if (rnd_mode < 0) - return -1; - fe->flags = rnd_mode; - prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumSignificantDigits); - if (JS_IsException(prop)) - return -1; - has_prec = FALSE; - if (!JS_IsUndefined(prop)) { - if (JS_ToInt64SatFree(ctx, &val, prop)) - return -1; - if (val < 1 || val > BF_PREC_MAX) - goto invalid_precision; - fe->prec = val; - has_prec = TRUE; - } - prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumFractionDigits); - if (JS_IsException(prop)) - return -1; - if (!JS_IsUndefined(prop)) { - if (has_prec) { - JS_FreeValue(ctx, prop); - JS_ThrowTypeError(ctx, "cannot provide both maximumSignificantDigits and maximumFractionDigits"); - return -1; - } - if (JS_ToInt64SatFree(ctx, &val, prop)) - return -1; - if (val < 0 || val > BF_PREC_MAX) { - invalid_precision: - JS_ThrowTypeError(ctx, "invalid precision"); - return -1; - } - fe->prec = val; - fe->flags |= BF_FLAG_RADPNT_PREC; - has_prec = TRUE; - } - if (!has_prec) { - JS_ThrowTypeError(ctx, "precision must be present"); - return -1; - } - return 0; -} - -static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - bfdec_t *a, *b, r_s, *r = &r_s; - JSValue op1, op2, res; - BigDecimalEnv fe_s, *fe = &fe_s; - int op_count, ret; - if (magic == MATH_OP_SQRT || - magic == MATH_OP_ROUND) - op_count = 1; - else - op_count = 2; - op1 = JS_ToNumeric(ctx, argv[0]); - if (JS_IsException(op1)) - return op1; - a = JS_ToBigDecimal(ctx, op1); - if (!a) { - JS_FreeValue(ctx, op1); - return JS_EXCEPTION; - } - if (op_count >= 2) { - op2 = JS_ToNumeric(ctx, argv[1]); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - return op2; - } - b = JS_ToBigDecimal(ctx, op2); - if (!b) - goto fail; - } else { - op2 = JS_UNDEFINED; - b = NULL; - } - fe->flags = BF_RNDZ; - fe->prec = BF_PREC_INF; - if (op_count < argc) { - if (js_bigdecimal_get_env(ctx, fe, argv[op_count])) - goto fail; - } - res = JS_NewBigDecimal(ctx); - if (JS_IsException(res)) { - fail: - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - return JS_EXCEPTION; - } - r = JS_GetBigDecimal(res); - switch (magic) { - case MATH_OP_ADD: - ret = bfdec_add(r, a, b, fe->prec, fe->flags); - break; - case MATH_OP_SUB: - ret = bfdec_sub(r, a, b, fe->prec, fe->flags); - break; - case MATH_OP_MUL: - ret = bfdec_mul(r, a, b, fe->prec, fe->flags); - break; - case MATH_OP_DIV: - ret = bfdec_div(r, a, b, fe->prec, fe->flags); - break; - case MATH_OP_FMOD: - ret = bfdec_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ); - break; - case MATH_OP_SQRT: - ret = bfdec_sqrt(r, a, fe->prec, fe->flags); - break; - case MATH_OP_ROUND: - ret = bfdec_set(r, a); - if (!(ret & BF_ST_MEM_ERROR)) - ret = bfdec_round(r, fe->prec, fe->flags); - break; - default: - abort(); - } - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - ret &= BF_ST_MEM_ERROR | BF_ST_DIVIDE_ZERO | BF_ST_INVALID_OP | - BF_ST_OVERFLOW; - if (ret != 0) { - JS_FreeValue(ctx, res); - return throw_bf_exception(ctx, ret); - } else { - return res; - } -} - -static JSValue js_bigdecimal_toFixed(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val, ret; - int64_t f; - int rnd_mode; - val = js_thisBigDecimalValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (JS_ToInt64Sat(ctx, &f, argv[0])) - goto fail; - if (f < 0 || f > BF_PREC_MAX) { - JS_ThrowRangeError(ctx, "invalid number of digits"); - goto fail; - } - rnd_mode = BF_RNDNA; - if (argc > 1) { - rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]); - if (rnd_mode < 0) - goto fail; - } - ret = js_bigdecimal_to_string1(ctx, val, f, rnd_mode | BF_FTOA_FORMAT_FRAC); - JS_FreeValue(ctx, val); - return ret; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static JSValue js_bigdecimal_toExponential(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val, ret; - int64_t f; - int rnd_mode; - val = js_thisBigDecimalValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (JS_ToInt64Sat(ctx, &f, argv[0])) - goto fail; - if (JS_IsUndefined(argv[0])) { - ret = js_bigdecimal_to_string1(ctx, val, 0, - BF_RNDN | BF_FTOA_FORMAT_FREE_MIN | BF_FTOA_FORCE_EXP); - } else { - if (f < 0 || f > BF_PREC_MAX) { - JS_ThrowRangeError(ctx, "invalid number of digits"); - goto fail; - } - rnd_mode = BF_RNDNA; - if (argc > 1) { - rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]); - if (rnd_mode < 0) - goto fail; - } - ret = js_bigdecimal_to_string1(ctx, val, f + 1, - rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP); - } - JS_FreeValue(ctx, val); - return ret; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static JSValue js_bigdecimal_toPrecision(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val, ret; - int64_t p; - int rnd_mode; - val = js_thisBigDecimalValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (JS_IsUndefined(argv[0])) { - return JS_ToStringFree(ctx, val); - } - if (JS_ToInt64Sat(ctx, &p, argv[0])) - goto fail; - if (p < 1 || p > BF_PREC_MAX) { - JS_ThrowRangeError(ctx, "invalid number of digits"); - goto fail; - } - rnd_mode = BF_RNDNA; - if (argc > 1) { - rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]); - if (rnd_mode < 0) - goto fail; - } - ret = js_bigdecimal_to_string1(ctx, val, p, - rnd_mode | BF_FTOA_FORMAT_FIXED); - JS_FreeValue(ctx, val); - return ret; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static const JSCFunctionListEntry js_bigdecimal_proto_funcs[] = { - JS_CFUNC_DEF("toString", 0, js_bigdecimal_toString ), - JS_CFUNC_DEF("valueOf", 0, js_bigdecimal_valueOf ), - JS_CFUNC_DEF("toPrecision", 1, js_bigdecimal_toPrecision ), - JS_CFUNC_DEF("toFixed", 1, js_bigdecimal_toFixed ), - JS_CFUNC_DEF("toExponential", 1, js_bigdecimal_toExponential ), -}; - -static const JSCFunctionListEntry js_bigdecimal_funcs[] = { - JS_CFUNC_MAGIC_DEF("add", 2, js_bigdecimal_fop, MATH_OP_ADD ), - JS_CFUNC_MAGIC_DEF("sub", 2, js_bigdecimal_fop, MATH_OP_SUB ), - JS_CFUNC_MAGIC_DEF("mul", 2, js_bigdecimal_fop, MATH_OP_MUL ), - JS_CFUNC_MAGIC_DEF("div", 2, js_bigdecimal_fop, MATH_OP_DIV ), - JS_CFUNC_MAGIC_DEF("mod", 2, js_bigdecimal_fop, MATH_OP_FMOD ), - JS_CFUNC_MAGIC_DEF("round", 1, js_bigdecimal_fop, MATH_OP_ROUND ), - JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigdecimal_fop, MATH_OP_SQRT ), -}; - -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; -} - -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; -} - -/* 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_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 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; -} - -void JS_AddIntrinsicBigDecimal(JSContext *ctx) -{ - JSRuntime *rt = ctx->rt; - JSValueConst obj1; - rt->bigdecimal_ops.to_string = js_bigdecimal_to_string; - rt->bigdecimal_ops.from_string = js_string_to_bigdecimal; - rt->bigdecimal_ops.unary_arith = js_unary_arith_bigdecimal; - rt->bigdecimal_ops.binary_arith = js_binary_arith_bigdecimal; - rt->bigdecimal_ops.compare = js_compare_bigdecimal; - ctx->class_proto[JS_CLASS_BIG_DECIMAL] = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL], - js_bigdecimal_proto_funcs, - countof(js_bigdecimal_proto_funcs)); - obj1 = JS_NewGlobalCConstructor(ctx, "BigDecimal", - js_bigdecimal_constructor, 1, - ctx->class_proto[JS_CLASS_BIG_DECIMAL]); - JS_SetPropertyFunctionList(ctx, obj1, js_bigdecimal_funcs, - countof(js_bigdecimal_funcs)); -} - -void JS_EnableBignumExt(JSContext *ctx, BOOL enable) -{ - ctx->bignum_ext = enable; -} diff --git a/third_party/quickjs/bigint.c b/third_party/quickjs/bigint.c deleted file mode 100644 index 48931a1bf..000000000 --- a/third_party/quickjs/bigint.c +++ /dev/null @@ -1,851 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/assert.h" -#include "libc/runtime/runtime.h" -#include "third_party/quickjs/internal.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -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); - (void)p; - 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 */ -JSValue JS_CompactBigInt(JSContext *ctx, JSValue val) -{ - return JS_CompactBigInt1(ctx, val, is_math_mode(ctx)); -} - -/* return NaN if bad bigint literal */ -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; -} - -static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val) -{ - uint32_t tag; - redo: - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_INT: - case JS_TAG_BOOL: - val = JS_NewBigInt64(ctx, JS_VALUE_GET_INT(val)); - break; - case JS_TAG_BIG_INT: - break; - case JS_TAG_FLOAT64: - case JS_TAG_BIG_FLOAT: - { - bf_t *a, a_s; - a = JS_ToBigFloat(ctx, &a_s, val); - if (!bf_is_finite(a)) { - JS_FreeValue(ctx, val); - val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to bigint"); - } else { - JSValue val1 = JS_NewBigInt(ctx); - bf_t *r; - int ret; - if (JS_IsException(val1)) { - JS_FreeValue(ctx, val); - return JS_EXCEPTION; - } - r = JS_GetBigInt(val1); - ret = bf_set(r, a); - ret |= bf_rint(r, BF_RNDZ); - JS_FreeValue(ctx, val); - if (ret & BF_ST_MEM_ERROR) { - JS_FreeValue(ctx, val1); - val = JS_ThrowOutOfMemory(ctx); - } else if (ret & BF_ST_INEXACT) { - JS_FreeValue(ctx, val1); - val = JS_ThrowRangeError(ctx, "cannot convert to bigint: not an integer"); - } else { - val = JS_CompactBigInt(ctx, val1); - } - } - if (a == &a_s) - bf_delete(a); - } - break; - case JS_TAG_BIG_DECIMAL: - val = JS_ToStringFree(ctx, val); - if (JS_IsException(val)) - break; - goto redo; - case JS_TAG_STRING: - val = JS_StringToBigIntErr(ctx, val); - break; - case JS_TAG_OBJECT: - val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER); - if (JS_IsException(val)) - break; - goto redo; - case JS_TAG_NULL: - case JS_TAG_UNDEFINED: - default: - JS_FreeValue(ctx, val); - return JS_ThrowTypeError(ctx, "cannot convert to bigint"); - } - return val; -} - -static JSValue js_bigint_constructor(JSContext *ctx, - JSValueConst new_target, - int argc, JSValueConst *argv) -{ - if (!JS_IsUndefined(new_target)) - return JS_ThrowTypeError(ctx, "not a constructor"); - return JS_ToBigIntCtorFree(ctx, JS_DupValue(ctx, argv[0])); -} - -static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val) -{ - if (JS_IsBigInt(ctx, this_val)) - return JS_DupValue(ctx, this_val); - if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(this_val); - if (p->class_id == JS_CLASS_BIG_INT) { - if (JS_IsBigInt(ctx, p->u.object_data)) - return JS_DupValue(ctx, p->u.object_data); - } - } - return JS_ThrowTypeError(ctx, "not a bigint"); -} - -static JSValue js_bigint_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val; - int base; - JSValue ret; - val = js_thisBigIntValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (argc == 0 || JS_IsUndefined(argv[0])) { - base = 10; - } else { - base = js_get_radix(ctx, argv[0]); - if (base < 0) - goto fail; - } - ret = js_bigint_to_string1(ctx, val, base); - JS_FreeValue(ctx, val); - return ret; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static JSValue js_bigint_valueOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return js_thisBigIntValue(ctx, this_val); -} - -static JSValue js_bigint_div(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - bf_t a_s, b_s, *a, *b, *r, *q; - int status; - JSValue q_val, r_val; - q_val = JS_NewBigInt(ctx); - if (JS_IsException(q_val)) - return JS_EXCEPTION; - r_val = JS_NewBigInt(ctx); - if (JS_IsException(r_val)) - goto fail; - b = NULL; - a = JS_ToBigInt(ctx, &a_s, argv[0]); - if (!a) - goto fail; - b = JS_ToBigInt(ctx, &b_s, argv[1]); - if (!b) { - JS_FreeBigInt(ctx, a, &a_s); - goto fail; - } - q = JS_GetBigInt(q_val); - r = JS_GetBigInt(r_val); - status = bf_divrem(q, r, a, b, BF_PREC_INF, BF_RNDZ, magic & 0xf); - JS_FreeBigInt(ctx, a, &a_s); - JS_FreeBigInt(ctx, b, &b_s); - if (UNLIKELY(status)) { - throw_bf_exception(ctx, status); - goto fail; - } - q_val = JS_CompactBigInt(ctx, q_val); - if (magic & 0x10) { - JSValue ret; - ret = JS_NewArray(ctx); - if (JS_IsException(ret)) - goto fail; - JS_SetPropertyUint32(ctx, ret, 0, q_val); - JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, r_val)); - return ret; - } else { - JS_FreeValue(ctx, r_val); - return q_val; - } - fail: - JS_FreeValue(ctx, q_val); - JS_FreeValue(ctx, r_val); - return JS_EXCEPTION; -} - -static JSValue js_bigint_sqrt(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - bf_t a_s, *a, *r, *rem; - int status; - JSValue r_val, rem_val; - r_val = JS_NewBigInt(ctx); - if (JS_IsException(r_val)) - return JS_EXCEPTION; - rem_val = JS_NewBigInt(ctx); - if (JS_IsException(rem_val)) - return JS_EXCEPTION; - r = JS_GetBigInt(r_val); - rem = JS_GetBigInt(rem_val); - a = JS_ToBigInt(ctx, &a_s, argv[0]); - if (!a) - goto fail; - status = bf_sqrtrem(r, rem, a); - JS_FreeBigInt(ctx, a, &a_s); - if (UNLIKELY(status & ~BF_ST_INEXACT)) { - throw_bf_exception(ctx, status); - goto fail; - } - r_val = JS_CompactBigInt(ctx, r_val); - if (magic) { - JSValue ret; - ret = JS_NewArray(ctx); - if (JS_IsException(ret)) - goto fail; - JS_SetPropertyUint32(ctx, ret, 0, r_val); - JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, rem_val)); - return ret; - } else { - JS_FreeValue(ctx, rem_val); - return r_val; - } - fail: - JS_FreeValue(ctx, r_val); - JS_FreeValue(ctx, rem_val); - return JS_EXCEPTION; -} - -static JSValue js_bigint_op1(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, - int magic) -{ - bf_t a_s, *a; - int64_t res; - a = JS_ToBigInt(ctx, &a_s, argv[0]); - if (!a) - return JS_EXCEPTION; - switch(magic) { - case 0: /* floorLog2 */ - if (a->sign || a->expn <= 0) { - res = -1; - } else { - res = a->expn - 1; - } - break; - case 1: /* ctz */ - if (bf_is_zero(a)) { - res = -1; - } else { - res = bf_get_exp_min(a); - } - break; - default: - abort(); - } - JS_FreeBigInt(ctx, a, &a_s); - return JS_NewBigInt64(ctx, res); -} - -static JSValue js_bigint_asUintN(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, int asIntN) -{ - uint64_t bits; - bf_t a_s, *a = &a_s, *r, mask_s, *mask = &mask_s; - JSValue res; - if (JS_ToIndex(ctx, &bits, argv[0])) - return JS_EXCEPTION; - res = JS_NewBigInt(ctx); - if (JS_IsException(res)) - return JS_EXCEPTION; - r = JS_GetBigInt(res); - a = JS_ToBigInt(ctx, &a_s, argv[1]); - if (!a) { - JS_FreeValue(ctx, res); - return JS_EXCEPTION; - } - /* XXX: optimize */ - r = JS_GetBigInt(res); - bf_init(ctx->bf_ctx, mask); - bf_set_ui(mask, 1); - bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ); - bf_add_si(mask, mask, -1, BF_PREC_INF, BF_RNDZ); - bf_logic_and(r, a, mask); - if (asIntN && bits != 0) { - bf_set_ui(mask, 1); - bf_mul_2exp(mask, bits - 1, BF_PREC_INF, BF_RNDZ); - if (bf_cmpu(r, mask) >= 0) { - bf_set_ui(mask, 1); - bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ); - bf_sub(r, r, mask, BF_PREC_INF, BF_RNDZ); - } - } - bf_delete(mask); - JS_FreeBigInt(ctx, a, &a_s); - return JS_CompactBigInt(ctx, res); -} - -static const JSCFunctionListEntry js_bigint_funcs[] = { - JS_CFUNC_MAGIC_DEF("asUintN", 2, js_bigint_asUintN, 0 ), - JS_CFUNC_MAGIC_DEF("asIntN", 2, js_bigint_asUintN, 1 ), - /* QuickJS extensions */ - JS_CFUNC_MAGIC_DEF("tdiv", 2, js_bigint_div, BF_RNDZ ), - JS_CFUNC_MAGIC_DEF("fdiv", 2, js_bigint_div, BF_RNDD ), - JS_CFUNC_MAGIC_DEF("cdiv", 2, js_bigint_div, BF_RNDU ), - JS_CFUNC_MAGIC_DEF("ediv", 2, js_bigint_div, BF_DIVREM_EUCLIDIAN ), - JS_CFUNC_MAGIC_DEF("tdivrem", 2, js_bigint_div, BF_RNDZ | 0x10 ), - JS_CFUNC_MAGIC_DEF("fdivrem", 2, js_bigint_div, BF_RNDD | 0x10 ), - JS_CFUNC_MAGIC_DEF("cdivrem", 2, js_bigint_div, BF_RNDU | 0x10 ), - JS_CFUNC_MAGIC_DEF("edivrem", 2, js_bigint_div, BF_DIVREM_EUCLIDIAN | 0x10 ), - JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigint_sqrt, 0 ), - JS_CFUNC_MAGIC_DEF("sqrtrem", 1, js_bigint_sqrt, 1 ), - JS_CFUNC_MAGIC_DEF("floorLog2", 1, js_bigint_op1, 0 ), - JS_CFUNC_MAGIC_DEF("ctz", 1, js_bigint_op1, 1 ), -}; - -static const JSCFunctionListEntry js_bigint_proto_funcs[] = { - JS_CFUNC_DEF("toString", 0, js_bigint_toString ), - JS_CFUNC_DEF("valueOf", 0, js_bigint_valueOf ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "BigInt", JS_PROP_CONFIGURABLE ), -}; - -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 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; -} - -/* 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; -} - -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; -} - -void JS_AddIntrinsicBigInt(JSContext *ctx) -{ - JSRuntime *rt = ctx->rt; - JSValueConst obj1; - rt->bigint_ops.to_string = js_bigint_to_string; - rt->bigint_ops.from_string = js_string_to_bigint; - rt->bigint_ops.unary_arith = js_unary_arith_bigint; - rt->bigint_ops.binary_arith = js_binary_arith_bigint; - rt->bigint_ops.compare = js_compare_bigfloat; - ctx->class_proto[JS_CLASS_BIG_INT] = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_INT], - js_bigint_proto_funcs, - countof(js_bigint_proto_funcs)); - obj1 = JS_NewGlobalCConstructor(ctx, "BigInt", js_bigint_constructor, 1, - ctx->class_proto[JS_CLASS_BIG_INT]); - JS_SetPropertyFunctionList(ctx, obj1, js_bigint_funcs, - countof(js_bigint_funcs)); -} - -/* 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; -} - -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 */ -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 */ -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)); -} diff --git a/third_party/quickjs/byte.c b/third_party/quickjs/byte.c deleted file mode 100644 index 9a10644f0..000000000 --- a/third_party/quickjs/byte.c +++ /dev/null @@ -1,2239 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/assert.h" -#include "libc/runtime/runtime.h" -#include "libc/str/str.h" -#include "third_party/quickjs/internal.h" -#include "third_party/quickjs/leb128.h" -#include "third_party/quickjs/libregexp.h" -#include "third_party/quickjs/quickjs.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -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 */ -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; -} - -void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b) -{ - int i; -#if 0 - { - char buf[ATOM_GET_STR_BUF_SIZE]; - printf("freeing %s\n", - JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name)); - } -#endif - free_bytecode_atoms(rt, b->byte_code_buf, b->byte_code_len, TRUE); - if (b->vardefs) { - for(i = 0; i < b->arg_count + b->var_count; i++) { - JS_FreeAtomRT(rt, b->vardefs[i].var_name); - } - } - for(i = 0; i < b->cpool_count; i++) - JS_FreeValueRT(rt, b->cpool[i]); - for(i = 0; i < b->closure_var_count; i++) { - JSClosureVar *cv = &b->closure_var[i]; - JS_FreeAtomRT(rt, cv->var_name); - } - if (b->realm) - JS_FreeContext(b->realm); - JS_FreeAtomRT(rt, b->func_name); - if (b->has_debug) { - JS_FreeAtomRT(rt, b->debug.filename); - js_free_rt(rt, b->debug.pc2line_buf); - js_free_rt(rt, b->debug.source); - } - remove_gc_object(&b->header); - if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && b->header.ref_count != 0) { - list_add_tail(&b->header.link, &rt->gc_zero_ref_count_list); - } else { - js_free_rt(rt, b); - } -} - -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)); - } -} - -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); - } -} - -int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b, - int byte_code_offset, uint32_t bc_len) -{ - uint8_t *bc_buf; - int pos, len, op; - JSAtom atom; - uint32_t idx; - if (s->is_rom_data) { - /* directly use the input buffer */ - if (UNLIKELY(s->buf_end - s->ptr < bc_len)) - return bc_read_error_end(s); - bc_buf = (uint8_t *)s->ptr; - s->ptr += bc_len; - } else { - bc_buf = (void *)((uint8_t*)b + byte_code_offset); - if (bc_get_buf(s, bc_buf, bc_len)) - return -1; - } - b->byte_code_buf = bc_buf; - pos = 0; - while (pos < bc_len) { - op = bc_buf[pos]; - len = short_opcode_info(op).size; - switch(short_opcode_info(op).fmt) { - case OP_FMT_atom: - case OP_FMT_atom_u8: - case OP_FMT_atom_u16: - case OP_FMT_atom_label_u8: - case OP_FMT_atom_label_u16: - idx = get_u32(bc_buf + pos + 1); - if (s->is_rom_data) { - /* just increment the reference count of the atom */ - JS_DupAtom(s->ctx, (JSAtom)idx); - } else { - if (bc_idx_to_atom(s, &atom, idx)) { - /* Note: the atoms will be freed up to this position */ - b->byte_code_len = pos; - return -1; - } - put_u32(bc_buf + pos + 1, atom); -#ifdef DUMP_READ_OBJECT - bc_read_trace(s, "at %d, fixup atom: ", pos + 1); print_atom(s->ctx, atom); printf("\n"); -#endif - } - break; - default: - break; - } - pos += len; - } - return 0; -} - -typedef enum BCTagEnum { - BC_TAG_NULL = 1, - BC_TAG_UNDEFINED, - BC_TAG_BOOL_FALSE, - BC_TAG_BOOL_TRUE, - BC_TAG_INT32, - BC_TAG_FLOAT64, - BC_TAG_STRING, - BC_TAG_OBJECT, - BC_TAG_ARRAY, - BC_TAG_BIG_INT, - BC_TAG_BIG_FLOAT, - BC_TAG_BIG_DECIMAL, - BC_TAG_TEMPLATE_OBJECT, - BC_TAG_FUNCTION_BYTECODE, - BC_TAG_MODULE, - BC_TAG_TYPED_ARRAY, - BC_TAG_ARRAY_BUFFER, - BC_TAG_SHARED_ARRAY_BUFFER, - BC_TAG_DATE, - BC_TAG_OBJECT_VALUE, - BC_TAG_OBJECT_REFERENCE, -} BCTagEnum; - -#ifdef CONFIG_BIGNUM -#define BC_BASE_VERSION 2 -#else -#define BC_BASE_VERSION 1 -#endif -#define BC_BE_VERSION 0x40 -#ifdef WORDS_BIGENDIAN -#define BC_VERSION (BC_BASE_VERSION | BC_BE_VERSION) -#else -#define BC_VERSION BC_BASE_VERSION -#endif - -typedef struct { - JSObject *obj; - uint32_t hash_next; /* -1 if no next entry */ -} JSObjectListEntry; - -/* XXX: reuse it to optimize weak references */ -typedef struct { - JSObjectListEntry *object_tab; - int object_count; - int object_size; - uint32_t *hash_table; - uint32_t hash_size; -} JSObjectList; - -static void js_object_list_init(JSObjectList *s) -{ - bzero(s, sizeof(*s)); -} - -static uint32_t js_object_list_get_hash(JSObject *p, uint32_t hash_size) -{ - return ((uintptr_t)p * 3163) & (hash_size - 1); -} - -static int js_object_list_resize_hash(JSContext *ctx, JSObjectList *s, - uint32_t new_hash_size) -{ - JSObjectListEntry *e; - uint32_t i, h, *new_hash_table; - new_hash_table = js_malloc(ctx, sizeof(new_hash_table[0]) * new_hash_size); - if (!new_hash_table) - return -1; - js_free(ctx, s->hash_table); - s->hash_table = new_hash_table; - s->hash_size = new_hash_size; - for(i = 0; i < s->hash_size; i++) { - s->hash_table[i] = -1; - } - for(i = 0; i < s->object_count; i++) { - e = &s->object_tab[i]; - h = js_object_list_get_hash(e->obj, s->hash_size); - e->hash_next = s->hash_table[h]; - s->hash_table[h] = i; - } - return 0; -} - -/* the reference count of 'obj' is not modified. Return 0 if OK, -1 if - memory error */ -static int js_object_list_add(JSContext *ctx, JSObjectList *s, JSObject *obj) -{ - JSObjectListEntry *e; - uint32_t h, new_hash_size; - if (js_resize_array(ctx, (void *)&s->object_tab, - sizeof(s->object_tab[0]), - &s->object_size, s->object_count + 1)) - return -1; - if (UNLIKELY((s->object_count + 1) >= s->hash_size)) { - new_hash_size = max_uint32(s->hash_size, 4); - while (new_hash_size <= s->object_count) - new_hash_size *= 2; - if (js_object_list_resize_hash(ctx, s, new_hash_size)) - return -1; - } - e = &s->object_tab[s->object_count++]; - h = js_object_list_get_hash(obj, s->hash_size); - e->obj = obj; - e->hash_next = s->hash_table[h]; - s->hash_table[h] = s->object_count - 1; - return 0; -} - -/* return -1 if not present or the object index */ -static int js_object_list_find(JSContext *ctx, JSObjectList *s, JSObject *obj) -{ - JSObjectListEntry *e; - uint32_t h, p; - /* must test empty size because there is no hash table */ - if (s->object_count == 0) - return -1; - h = js_object_list_get_hash(obj, s->hash_size); - p = s->hash_table[h]; - while (p != -1) { - e = &s->object_tab[p]; - if (e->obj == obj) - return p; - p = e->hash_next; - } - return -1; -} - -static void js_object_list_end(JSContext *ctx, JSObjectList *s) -{ - js_free(ctx, s->object_tab); - js_free(ctx, s->hash_table); -} - -typedef struct BCWriterState { - JSContext *ctx; - DynBuf dbuf; - BOOL byte_swap : 8; - BOOL allow_bytecode : 8; - BOOL allow_sab : 8; - BOOL allow_reference : 8; - uint32_t first_atom; - uint32_t *atom_to_idx; - int atom_to_idx_size; - JSAtom *idx_to_atom; - int idx_to_atom_count; - int idx_to_atom_size; - uint8_t **sab_tab; - int sab_tab_len; - int sab_tab_size; - /* list of referenced objects (used if allow_reference = TRUE) */ - JSObjectList object_list; -} BCWriterState; - -#ifdef DUMP_READ_OBJECT -static const char * const bc_tag_str[] = { - "invalid", - "null", - "undefined", - "false", - "true", - "int32", - "float64", - "string", - "object", - "array", - "bigint", - "bigfloat", - "bigdecimal", - "template", - "function", - "module", - "TypedArray", - "ArrayBuffer", - "SharedArrayBuffer", - "Date", - "ObjectValue", - "ObjectReference", -}; -#endif - -static void bc_put_u8(BCWriterState *s, uint8_t v) -{ - dbuf_putc(&s->dbuf, v); -} - -static void bc_put_u16(BCWriterState *s, uint16_t v) -{ - if (s->byte_swap) - v = bswap16(v); - dbuf_put_u16(&s->dbuf, v); -} - -static __maybe_unused void bc_put_u32(BCWriterState *s, uint32_t v) -{ - if (s->byte_swap) - v = bswap32(v); - dbuf_put_u32(&s->dbuf, v); -} - -static void bc_put_u64(BCWriterState *s, uint64_t v) -{ - if (s->byte_swap) - v = bswap64(v); - dbuf_put(&s->dbuf, (uint8_t *)&v, sizeof(v)); -} - -static void bc_put_leb128(BCWriterState *s, uint32_t v) -{ - dbuf_put_leb128(&s->dbuf, v); -} - -static void bc_put_sleb128(BCWriterState *s, int32_t v) -{ - dbuf_put_sleb128(&s->dbuf, v); -} - -static void bc_set_flags(uint32_t *pflags, int *pidx, uint32_t val, int n) -{ - *pflags = *pflags | (val << *pidx); - *pidx += n; -} - -static int bc_atom_to_idx(BCWriterState *s, uint32_t *pres, JSAtom atom) -{ - uint32_t v; - if (atom < s->first_atom || __JS_AtomIsTaggedInt(atom)) { - *pres = atom; - return 0; - } - atom -= s->first_atom; - if (atom < s->atom_to_idx_size && s->atom_to_idx[atom] != 0) { - *pres = s->atom_to_idx[atom]; - return 0; - } - if (atom >= s->atom_to_idx_size) { - int old_size, i; - old_size = s->atom_to_idx_size; - if (js_resize_array(s->ctx, (void **)&s->atom_to_idx, - sizeof(s->atom_to_idx[0]), &s->atom_to_idx_size, - atom + 1)) - return -1; - /* XXX: could add a specific js_resize_array() function to do it */ - for(i = old_size; i < s->atom_to_idx_size; i++) - s->atom_to_idx[i] = 0; - } - if (js_resize_array(s->ctx, (void **)&s->idx_to_atom, - sizeof(s->idx_to_atom[0]), - &s->idx_to_atom_size, s->idx_to_atom_count + 1)) - goto fail; - v = s->idx_to_atom_count++; - s->idx_to_atom[v] = atom + s->first_atom; - v += s->first_atom; - s->atom_to_idx[atom] = v; - *pres = v; - return 0; - fail: - *pres = 0; - return -1; -} - -static int bc_put_atom(BCWriterState *s, JSAtom atom) -{ - uint32_t v; - if (__JS_AtomIsTaggedInt(atom)) { - v = (__JS_AtomToUInt32(atom) << 1) | 1; - } else { - if (bc_atom_to_idx(s, &v, atom)) - return -1; - v <<= 1; - } - bc_put_leb128(s, v); - return 0; -} - -static void bc_byte_swap(uint8_t *bc_buf, int bc_len) -{ - int pos, len, op, fmt; - pos = 0; - while (pos < bc_len) { - op = bc_buf[pos]; - len = short_opcode_info(op).size; - fmt = short_opcode_info(op).fmt; - switch(fmt) { - case OP_FMT_u16: - case OP_FMT_i16: - case OP_FMT_label16: - case OP_FMT_npop: - case OP_FMT_loc: - case OP_FMT_arg: - case OP_FMT_var_ref: - put_u16(bc_buf + pos + 1, - bswap16(get_u16(bc_buf + pos + 1))); - break; - case OP_FMT_i32: - case OP_FMT_u32: - case OP_FMT_const: - case OP_FMT_label: - case OP_FMT_atom: - case OP_FMT_atom_u8: - put_u32(bc_buf + pos + 1, - bswap32(get_u32(bc_buf + pos + 1))); - break; - case OP_FMT_atom_u16: - case OP_FMT_label_u16: - put_u32(bc_buf + pos + 1, - bswap32(get_u32(bc_buf + pos + 1))); - put_u16(bc_buf + pos + 1 + 4, - bswap16(get_u16(bc_buf + pos + 1 + 4))); - break; - case OP_FMT_atom_label_u8: - case OP_FMT_atom_label_u16: - put_u32(bc_buf + pos + 1, - bswap32(get_u32(bc_buf + pos + 1))); - put_u32(bc_buf + pos + 1 + 4, - bswap32(get_u32(bc_buf + pos + 1 + 4))); - if (fmt == OP_FMT_atom_label_u16) { - put_u16(bc_buf + pos + 1 + 4 + 4, - bswap16(get_u16(bc_buf + pos + 1 + 4 + 4))); - } - break; - case OP_FMT_npop_u16: - put_u16(bc_buf + pos + 1, - bswap16(get_u16(bc_buf + pos + 1))); - put_u16(bc_buf + pos + 1 + 2, - bswap16(get_u16(bc_buf + pos + 1 + 2))); - break; - default: - break; - } - pos += len; - } -} - -static int JS_WriteFunctionBytecode(BCWriterState *s, - const uint8_t *bc_buf1, int bc_len) -{ - int pos, len, op; - JSAtom atom; - uint8_t *bc_buf; - uint32_t val; - bc_buf = js_malloc(s->ctx, bc_len); - if (!bc_buf) - return -1; - memcpy(bc_buf, bc_buf1, bc_len); - pos = 0; - while (pos < bc_len) { - op = bc_buf[pos]; - len = short_opcode_info(op).size; - switch(short_opcode_info(op).fmt) { - case OP_FMT_atom: - case OP_FMT_atom_u8: - case OP_FMT_atom_u16: - case OP_FMT_atom_label_u8: - case OP_FMT_atom_label_u16: - atom = get_u32(bc_buf + pos + 1); - if (bc_atom_to_idx(s, &val, atom)) - goto fail; - put_u32(bc_buf + pos + 1, val); - break; - default: - break; - } - pos += len; - } - if (s->byte_swap) - bc_byte_swap(bc_buf, bc_len); - dbuf_put(&s->dbuf, bc_buf, bc_len); - js_free(s->ctx, bc_buf); - return 0; - fail: - js_free(s->ctx, bc_buf); - return -1; -} - -static void JS_WriteString(BCWriterState *s, JSString *p) -{ - int i; - bc_put_leb128(s, ((uint32_t)p->len << 1) | p->is_wide_char); - if (p->is_wide_char) { - for(i = 0; i < p->len; i++) - bc_put_u16(s, p->u.str16[i]); - } else { - dbuf_put(&s->dbuf, p->u.str8, p->len); - } -} - -#ifdef CONFIG_BIGNUM -static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj) -{ - uint32_t tag, tag1; - int64_t e; - JSBigFloat *bf = JS_VALUE_GET_PTR(obj); - bf_t *a = &bf->num; - size_t len, i, n1, j; - limb_t v; - tag = JS_VALUE_GET_TAG(obj); - switch(tag) { - case JS_TAG_BIG_INT: - tag1 = BC_TAG_BIG_INT; - break; - case JS_TAG_BIG_FLOAT: - tag1 = BC_TAG_BIG_FLOAT; - break; - case JS_TAG_BIG_DECIMAL: - tag1 = BC_TAG_BIG_DECIMAL; - break; - default: - abort(); - } - bc_put_u8(s, tag1); - /* sign + exponent */ - if (a->expn == BF_EXP_ZERO) - e = 0; - else if (a->expn == BF_EXP_INF) - e = 1; - else if (a->expn == BF_EXP_NAN) - e = 2; - else if (a->expn >= 0) - e = a->expn + 3; - else - e = a->expn; - e = (e << 1) | a->sign; - if (e < INT32_MIN || e > INT32_MAX) { - JS_ThrowInternalError(s->ctx, "bignum exponent is too large"); - return -1; - } - bc_put_sleb128(s, e); - /* mantissa */ - if (a->len != 0) { - if (tag != JS_TAG_BIG_DECIMAL) { - i = 0; - while (i < a->len && a->tab[i] == 0) - i++; - assert(i < a->len); - v = a->tab[i]; - n1 = sizeof(limb_t); - while ((v & 0xff) == 0) { - n1--; - v >>= 8; - } - i++; - len = (a->len - i) * sizeof(limb_t) + n1; - if (len > INT32_MAX) { - JS_ThrowInternalError(s->ctx, "bignum is too large"); - return -1; - } - bc_put_leb128(s, len); - /* always saved in byte based little endian representation */ - for(j = 0; j < n1; j++) { - dbuf_putc(&s->dbuf, v >> (j * 8)); - } - for(; i < a->len; i++) { - limb_t v = a->tab[i]; -#if LIMB_BITS == 32 -#ifdef WORDS_BIGENDIAN - v = bswap32(v); -#endif - dbuf_put_u32(&s->dbuf, v); -#else -#ifdef WORDS_BIGENDIAN - v = bswap64(v); -#endif - dbuf_put_u64(&s->dbuf, v); -#endif - } - } else { - int bpos, d; - uint8_t v8; - size_t i0; - /* little endian BCD */ - i = 0; - while (i < a->len && a->tab[i] == 0) - i++; - assert(i < a->len); - len = a->len * LIMB_DIGITS; - v = a->tab[i]; - j = 0; - while ((v % 10) == 0) { - j++; - v /= 10; - } - len -= j; - assert(len > 0); - if (len > INT32_MAX) { - JS_ThrowInternalError(s->ctx, "bignum is too large"); - return -1; - } - bc_put_leb128(s, len); - bpos = 0; - v8 = 0; - i0 = i; - for(; i < a->len; i++) { - if (i != i0) { - v = a->tab[i]; - j = 0; - } - for(; j < LIMB_DIGITS; j++) { - d = v % 10; - v /= 10; - if (bpos == 0) { - v8 = d; - bpos = 1; - } else { - dbuf_putc(&s->dbuf, v8 | (d << 4)); - bpos = 0; - } - } - } - /* flush the last digit */ - if (bpos) { - dbuf_putc(&s->dbuf, v8); - } - } - } - return 0; -} -#endif /* CONFIG_BIGNUM */ - -static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj); - -static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj) -{ - JSFunctionBytecode *b = JS_VALUE_GET_PTR(obj); - uint32_t flags; - int idx, i; - bc_put_u8(s, BC_TAG_FUNCTION_BYTECODE); - flags = idx = 0; - bc_set_flags(&flags, &idx, b->has_prototype, 1); - bc_set_flags(&flags, &idx, b->has_simple_parameter_list, 1); - bc_set_flags(&flags, &idx, b->is_derived_class_constructor, 1); - bc_set_flags(&flags, &idx, b->need_home_object, 1); - bc_set_flags(&flags, &idx, b->func_kind, 2); - bc_set_flags(&flags, &idx, b->new_target_allowed, 1); - bc_set_flags(&flags, &idx, b->super_call_allowed, 1); - bc_set_flags(&flags, &idx, b->super_allowed, 1); - bc_set_flags(&flags, &idx, b->arguments_allowed, 1); - bc_set_flags(&flags, &idx, b->has_debug, 1); - bc_set_flags(&flags, &idx, b->backtrace_barrier, 1); - assert(idx <= 16); - bc_put_u16(s, flags); - bc_put_u8(s, b->js_mode); - bc_put_atom(s, b->func_name); - bc_put_leb128(s, b->arg_count); - bc_put_leb128(s, b->var_count); - bc_put_leb128(s, b->defined_arg_count); - bc_put_leb128(s, b->stack_size); - bc_put_leb128(s, b->closure_var_count); - bc_put_leb128(s, b->cpool_count); - bc_put_leb128(s, b->byte_code_len); - if (b->vardefs) { - /* XXX: this field is redundant */ - bc_put_leb128(s, b->arg_count + b->var_count); - for(i = 0; i < b->arg_count + b->var_count; i++) { - JSVarDef *vd = &b->vardefs[i]; - bc_put_atom(s, vd->var_name); - bc_put_leb128(s, vd->scope_level); - bc_put_leb128(s, vd->scope_next + 1); - flags = idx = 0; - bc_set_flags(&flags, &idx, vd->var_kind, 4); - bc_set_flags(&flags, &idx, vd->is_const, 1); - bc_set_flags(&flags, &idx, vd->is_lexical, 1); - bc_set_flags(&flags, &idx, vd->is_captured, 1); - assert(idx <= 8); - bc_put_u8(s, flags); - } - } else { - bc_put_leb128(s, 0); - } - for(i = 0; i < b->closure_var_count; i++) { - JSClosureVar *cv = &b->closure_var[i]; - bc_put_atom(s, cv->var_name); - bc_put_leb128(s, cv->var_idx); - flags = idx = 0; - bc_set_flags(&flags, &idx, cv->is_local, 1); - bc_set_flags(&flags, &idx, cv->is_arg, 1); - bc_set_flags(&flags, &idx, cv->is_const, 1); - bc_set_flags(&flags, &idx, cv->is_lexical, 1); - bc_set_flags(&flags, &idx, cv->var_kind, 4); - assert(idx <= 8); - bc_put_u8(s, flags); - } - if (JS_WriteFunctionBytecode(s, b->byte_code_buf, b->byte_code_len)) - goto fail; - if (b->has_debug) { - bc_put_atom(s, b->debug.filename); - bc_put_leb128(s, b->debug.line_num); - bc_put_leb128(s, b->debug.pc2line_len); - dbuf_put(&s->dbuf, b->debug.pc2line_buf, b->debug.pc2line_len); - } - for(i = 0; i < b->cpool_count; i++) { - if (JS_WriteObjectRec(s, b->cpool[i])) - goto fail; - } - return 0; - fail: - return -1; -} - -static int JS_WriteModule(BCWriterState *s, JSValueConst obj) -{ - JSModuleDef *m = JS_VALUE_GET_PTR(obj); - int i; - bc_put_u8(s, BC_TAG_MODULE); - bc_put_atom(s, m->module_name); - bc_put_leb128(s, m->req_module_entries_count); - for(i = 0; i < m->req_module_entries_count; i++) { - JSReqModuleEntry *rme = &m->req_module_entries[i]; - bc_put_atom(s, rme->module_name); - } - bc_put_leb128(s, m->export_entries_count); - for(i = 0; i < m->export_entries_count; i++) { - JSExportEntry *me = &m->export_entries[i]; - bc_put_u8(s, me->export_type); - if (me->export_type == JS_EXPORT_TYPE_LOCAL) { - bc_put_leb128(s, me->u.local.var_idx); - } else { - bc_put_leb128(s, me->u.req_module_idx); - bc_put_atom(s, me->local_name); - } - bc_put_atom(s, me->export_name); - } - bc_put_leb128(s, m->star_export_entries_count); - for(i = 0; i < m->star_export_entries_count; i++) { - JSStarExportEntry *se = &m->star_export_entries[i]; - bc_put_leb128(s, se->req_module_idx); - } - bc_put_leb128(s, m->import_entries_count); - for(i = 0; i < m->import_entries_count; i++) { - JSImportEntry *mi = &m->import_entries[i]; - bc_put_leb128(s, mi->var_idx); - bc_put_atom(s, mi->import_name); - bc_put_leb128(s, mi->req_module_idx); - } - if (JS_WriteObjectRec(s, m->func_obj)) - goto fail; - return 0; - fail: - return -1; -} - -static int JS_WriteArray(BCWriterState *s, JSValueConst obj) -{ - JSObject *p = JS_VALUE_GET_OBJ(obj); - uint32_t i, len; - JSValue val; - int ret; - BOOL is_template; - if (s->allow_bytecode && !p->extensible) { - /* not extensible array: we consider it is a - template when we are saving bytecode */ - bc_put_u8(s, BC_TAG_TEMPLATE_OBJECT); - is_template = TRUE; - } else { - bc_put_u8(s, BC_TAG_ARRAY); - is_template = FALSE; - } - if (js_get_length32(s->ctx, &len, obj)) - goto fail1; - bc_put_leb128(s, len); - for(i = 0; i < len; i++) { - val = JS_GetPropertyUint32(s->ctx, obj, i); - if (JS_IsException(val)) - goto fail1; - ret = JS_WriteObjectRec(s, val); - JS_FreeValue(s->ctx, val); - if (ret) - goto fail1; - } - if (is_template) { - val = JS_GetProperty(s->ctx, obj, JS_ATOM_raw); - if (JS_IsException(val)) - goto fail1; - ret = JS_WriteObjectRec(s, val); - JS_FreeValue(s->ctx, val); - if (ret) - goto fail1; - } - return 0; - fail1: - return -1; -} - -static BOOL JS_AtomIsString(JSContext *ctx, JSAtom v) -{ - return JS_AtomGetKind(ctx, v) == JS_ATOM_KIND_STRING; -} - -static int JS_WriteObjectTag(BCWriterState *s, JSValueConst obj) -{ - JSObject *p = JS_VALUE_GET_OBJ(obj); - uint32_t i, prop_count; - JSShape *sh; - JSShapeProperty *pr; - int pass; - JSAtom atom; - bc_put_u8(s, BC_TAG_OBJECT); - prop_count = 0; - sh = p->shape; - for(pass = 0; pass < 2; pass++) { - if (pass == 1) - bc_put_leb128(s, prop_count); - for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) { - atom = pr->atom; - if (atom != JS_ATOM_NULL && - JS_AtomIsString(s->ctx, atom) && - (pr->flags & JS_PROP_ENUMERABLE)) { - if (pr->flags & JS_PROP_TMASK) { - JS_ThrowTypeError(s->ctx, "only value properties are supported"); - goto fail; - } - if (pass == 0) { - prop_count++; - } else { - bc_put_atom(s, atom); - if (JS_WriteObjectRec(s, p->prop[i].u.value)) - goto fail; - } - } - } - } - return 0; - fail: - return -1; -} - -static int JS_WriteTypedArray(BCWriterState *s, JSValueConst obj) -{ - JSObject *p = JS_VALUE_GET_OBJ(obj); - JSTypedArray *ta = p->u.typed_array; - bc_put_u8(s, BC_TAG_TYPED_ARRAY); - bc_put_u8(s, p->class_id - JS_CLASS_UINT8C_ARRAY); - bc_put_leb128(s, p->u.array.count); - bc_put_leb128(s, ta->offset); - if (JS_WriteObjectRec(s, JS_MKPTR(JS_TAG_OBJECT, ta->buffer))) - return -1; - return 0; -} - -static int JS_WriteArrayBuffer(BCWriterState *s, JSValueConst obj) -{ - JSObject *p = JS_VALUE_GET_OBJ(obj); - JSArrayBuffer *abuf = p->u.array_buffer; - if (abuf->detached) { - JS_ThrowTypeErrorDetachedArrayBuffer(s->ctx); - return -1; - } - bc_put_u8(s, BC_TAG_ARRAY_BUFFER); - bc_put_leb128(s, abuf->byte_length); - dbuf_put(&s->dbuf, abuf->data, abuf->byte_length); - return 0; -} - -static int JS_WriteSharedArrayBuffer(BCWriterState *s, JSValueConst obj) -{ - JSObject *p = JS_VALUE_GET_OBJ(obj); - JSArrayBuffer *abuf = p->u.array_buffer; - assert(!abuf->detached); /* SharedArrayBuffer are never detached */ - bc_put_u8(s, BC_TAG_SHARED_ARRAY_BUFFER); - bc_put_leb128(s, abuf->byte_length); - bc_put_u64(s, (uintptr_t)abuf->data); - if (js_resize_array(s->ctx, (void **)&s->sab_tab, sizeof(s->sab_tab[0]), - &s->sab_tab_size, s->sab_tab_len + 1)) - return -1; - /* keep the SAB pointer so that the user can clone it or free it */ - s->sab_tab[s->sab_tab_len++] = abuf->data; - return 0; -} - -static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj) -{ - uint32_t tag; - if (js_check_stack_overflow(s->ctx->rt, 0)) { - JS_ThrowStackOverflow(s->ctx); - return -1; - } - tag = JS_VALUE_GET_NORM_TAG(obj); - switch(tag) { - case JS_TAG_NULL: - bc_put_u8(s, BC_TAG_NULL); - break; - case JS_TAG_UNDEFINED: - bc_put_u8(s, BC_TAG_UNDEFINED); - break; - case JS_TAG_BOOL: - bc_put_u8(s, BC_TAG_BOOL_FALSE + JS_VALUE_GET_INT(obj)); - break; - case JS_TAG_INT: - bc_put_u8(s, BC_TAG_INT32); - bc_put_sleb128(s, JS_VALUE_GET_INT(obj)); - break; - case JS_TAG_FLOAT64: - { - JSFloat64Union u; - bc_put_u8(s, BC_TAG_FLOAT64); - u.d = JS_VALUE_GET_FLOAT64(obj); - bc_put_u64(s, u.u64); - } - break; - case JS_TAG_STRING: - { - JSString *p = JS_VALUE_GET_STRING(obj); - bc_put_u8(s, BC_TAG_STRING); - JS_WriteString(s, p); - } - break; - case JS_TAG_FUNCTION_BYTECODE: - if (!s->allow_bytecode) - goto invalid_tag; - if (JS_WriteFunctionTag(s, obj)) - goto fail; - break; - case JS_TAG_MODULE: - if (!s->allow_bytecode) - goto invalid_tag; - if (JS_WriteModule(s, obj)) - goto fail; - break; - case JS_TAG_OBJECT: - { - JSObject *p = JS_VALUE_GET_OBJ(obj); - int ret, idx; - if (s->allow_reference) { - idx = js_object_list_find(s->ctx, &s->object_list, p); - if (idx >= 0) { - bc_put_u8(s, BC_TAG_OBJECT_REFERENCE); - bc_put_leb128(s, idx); - break; - } else { - if (js_object_list_add(s->ctx, &s->object_list, p)) - goto fail; - } - } else { - if (p->tmp_mark) { - JS_ThrowTypeError(s->ctx, "circular reference"); - goto fail; - } - p->tmp_mark = 1; - } - switch(p->class_id) { - case JS_CLASS_ARRAY: - ret = JS_WriteArray(s, obj); - break; - case JS_CLASS_OBJECT: - ret = JS_WriteObjectTag(s, obj); - break; - case JS_CLASS_ARRAY_BUFFER: - ret = JS_WriteArrayBuffer(s, obj); - break; - case JS_CLASS_SHARED_ARRAY_BUFFER: - if (!s->allow_sab) - goto invalid_tag; - ret = JS_WriteSharedArrayBuffer(s, obj); - break; - case JS_CLASS_DATE: - bc_put_u8(s, BC_TAG_DATE); - ret = JS_WriteObjectRec(s, p->u.object_data); - break; - case JS_CLASS_NUMBER: - case JS_CLASS_STRING: - case JS_CLASS_BOOLEAN: -#ifdef CONFIG_BIGNUM - case JS_CLASS_BIG_INT: - case JS_CLASS_BIG_FLOAT: - case JS_CLASS_BIG_DECIMAL: -#endif - bc_put_u8(s, BC_TAG_OBJECT_VALUE); - ret = JS_WriteObjectRec(s, p->u.object_data); - break; - default: - if (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) { - ret = JS_WriteTypedArray(s, obj); - } else { - JS_ThrowTypeError(s->ctx, "unsupported object class"); - ret = -1; - } - break; - } - p->tmp_mark = 0; - if (ret) - goto fail; - } - break; -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_INT: - case JS_TAG_BIG_FLOAT: - case JS_TAG_BIG_DECIMAL: - if (JS_WriteBigNum(s, obj)) - goto fail; - break; -#endif - default: - invalid_tag: - JS_ThrowInternalError(s->ctx, "unsupported tag (%d)", tag); - goto fail; - } - return 0; - fail: - return -1; -} - -/* create the atom table */ -static int JS_WriteObjectAtoms(BCWriterState *s) -{ - JSRuntime *rt = s->ctx->rt; - DynBuf dbuf1; - int i, atoms_size; - uint8_t version; - dbuf1 = s->dbuf; - js_dbuf_init(s->ctx, &s->dbuf); - version = BC_VERSION; - if (s->byte_swap) - version ^= BC_BE_VERSION; - bc_put_u8(s, version); - bc_put_leb128(s, s->idx_to_atom_count); - for(i = 0; i < s->idx_to_atom_count; i++) { - JSAtomStruct *p = rt->atom_array[s->idx_to_atom[i]]; - JS_WriteString(s, p); - } - /* XXX: should check for OOM in above phase */ - /* move the atoms at the start */ - /* XXX: could just append dbuf1 data, but it uses more memory if - dbuf1 is larger than dbuf */ - atoms_size = s->dbuf.size; - if (dbuf_realloc(&dbuf1, dbuf1.size + atoms_size)) - goto fail; - memmove(dbuf1.buf + atoms_size, dbuf1.buf, dbuf1.size); - memcpy(dbuf1.buf, s->dbuf.buf, atoms_size); - dbuf1.size += atoms_size; - dbuf_free(&s->dbuf); - s->dbuf = dbuf1; - return 0; - fail: - dbuf_free(&dbuf1); - return -1; -} - -uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj, - int flags, uint8_t ***psab_tab, size_t *psab_tab_len) -{ - BCWriterState ss, *s = &ss; - bzero(s, sizeof(*s)); - s->ctx = ctx; - /* XXX: byte swapped output is untested */ - s->byte_swap = ((flags & JS_WRITE_OBJ_BSWAP) != 0); - s->allow_bytecode = ((flags & JS_WRITE_OBJ_BYTECODE) != 0); - s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0); - s->allow_reference = ((flags & JS_WRITE_OBJ_REFERENCE) != 0); - /* XXX: could use a different version when bytecode is included */ - if (s->allow_bytecode) - s->first_atom = JS_ATOM_END; - else - s->first_atom = 1; - js_dbuf_init(ctx, &s->dbuf); - js_object_list_init(&s->object_list); - if (JS_WriteObjectRec(s, obj)) - goto fail; - if (JS_WriteObjectAtoms(s)) - goto fail; - js_object_list_end(ctx, &s->object_list); - js_free(ctx, s->atom_to_idx); - js_free(ctx, s->idx_to_atom); - *psize = s->dbuf.size; - if (psab_tab) - *psab_tab = s->sab_tab; - if (psab_tab_len) - *psab_tab_len = s->sab_tab_len; - return s->dbuf.buf; - fail: - js_object_list_end(ctx, &s->object_list); - js_free(ctx, s->atom_to_idx); - js_free(ctx, s->idx_to_atom); - dbuf_free(&s->dbuf); - *psize = 0; - if (psab_tab) - *psab_tab = NULL; - if (psab_tab_len) - *psab_tab_len = 0; - return NULL; -} - -uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj, - int flags) -{ - return JS_WriteObject2(ctx, psize, obj, flags, NULL, NULL); -} - -#ifdef DUMP_READ_OBJECT -static void printfesque(2) bc_read_trace(BCReaderState *s, const char *fmt, ...) { - va_list ap; - int i, n, n0; - if (!s->ptr_last) - s->ptr_last = s->buf_start; - n = n0 = 0; - if (s->ptr > s->ptr_last || s->ptr == s->buf_start) { - n0 = printf("%04x: ", (int)(s->ptr_last - s->buf_start)); - n += n0; - } - for (i = 0; s->ptr_last < s->ptr; i++) { - if ((i & 7) == 0 && i > 0) { - printf("\n%*s", n0, ""); - n = n0; - } - n += printf(" %02x", *s->ptr_last++); - } - if (*fmt == '}') - s->level--; - if (n < 32 + s->level * 2) { - printf("%*s", 32 + s->level * 2 - n, ""); - } - va_start(ap, fmt); - vfprintf(stdout, fmt, ap); - va_end(ap); - if (strchr(fmt, '{')) - s->level++; -} -#else -#define bc_read_trace(...) -#endif - -int bc_read_error_end(BCReaderState *s) -{ - if (!s->error_state) { - JS_ThrowSyntaxError(s->ctx, "read after the end of the buffer"); - } - return s->error_state = -1; -} - -static int bc_get_u8(BCReaderState *s, uint8_t *pval) -{ - if (UNLIKELY(s->buf_end - s->ptr < 1)) { - *pval = 0; /* avoid warning */ - return bc_read_error_end(s); - } - *pval = *s->ptr++; - return 0; -} - -static int bc_get_u16(BCReaderState *s, uint16_t *pval) -{ - if (UNLIKELY(s->buf_end - s->ptr < 2)) { - *pval = 0; /* avoid warning */ - return bc_read_error_end(s); - } - *pval = get_u16(s->ptr); - s->ptr += 2; - return 0; -} - -static __maybe_unused int bc_get_u32(BCReaderState *s, uint32_t *pval) -{ - if (UNLIKELY(s->buf_end - s->ptr < 4)) { - *pval = 0; /* avoid warning */ - return bc_read_error_end(s); - } - *pval = get_u32(s->ptr); - s->ptr += 4; - return 0; -} - -static int bc_get_u64(BCReaderState *s, uint64_t *pval) -{ - if (UNLIKELY(s->buf_end - s->ptr < 8)) { - *pval = 0; /* avoid warning */ - return bc_read_error_end(s); - } - *pval = get_u64(s->ptr); - s->ptr += 8; - return 0; -} - -static int bc_get_leb128(BCReaderState *s, uint32_t *pval) -{ - int ret; - ret = get_leb128(pval, s->ptr, s->buf_end); - if (UNLIKELY(ret < 0)) - return bc_read_error_end(s); - s->ptr += ret; - return 0; -} - -static int bc_get_sleb128(BCReaderState *s, int32_t *pval) -{ - int ret; - ret = get_sleb128(pval, s->ptr, s->buf_end); - if (UNLIKELY(ret < 0)) - return bc_read_error_end(s); - s->ptr += ret; - return 0; -} - -/* XXX: used to read an `int` with a positive value */ -static int bc_get_leb128_int(BCReaderState *s, int *pval) -{ - return bc_get_leb128(s, (uint32_t *)pval); -} - -static int bc_get_leb128_u16(BCReaderState *s, uint16_t *pval) -{ - uint32_t val; - if (bc_get_leb128(s, &val)) { - *pval = 0; - return -1; - } - *pval = val; - return 0; -} - -int bc_get_buf(BCReaderState *s, uint8_t *buf, uint32_t buf_len) -{ - if (buf_len != 0) { - if (UNLIKELY(!buf || s->buf_end - s->ptr < buf_len)) - return bc_read_error_end(s); - memcpy(buf, s->ptr, buf_len); - s->ptr += buf_len; - } - return 0; -} - -int bc_idx_to_atom(BCReaderState *s, JSAtom *patom, uint32_t idx) -{ - JSAtom atom; - if (__JS_AtomIsTaggedInt(idx)) { - atom = idx; - } else if (idx < s->first_atom) { - atom = JS_DupAtom(s->ctx, idx); - } else { - idx -= s->first_atom; - if (idx >= s->idx_to_atom_count) { - JS_ThrowSyntaxError(s->ctx, "invalid atom index (pos=%u)", - (unsigned int)(s->ptr - s->buf_start)); - *patom = JS_ATOM_NULL; - return s->error_state = -1; - } - atom = JS_DupAtom(s->ctx, s->idx_to_atom[idx]); - } - *patom = atom; - return 0; -} - -static int bc_get_atom(BCReaderState *s, JSAtom *patom) -{ - uint32_t v; - if (bc_get_leb128(s, &v)) - return -1; - if (v & 1) { - *patom = __JS_AtomFromUInt32(v >> 1); - return 0; - } else { - return bc_idx_to_atom(s, patom, v >> 1); - } -} - -static JSString *JS_ReadString(BCReaderState *s) -{ - uint32_t len; - size_t size; - BOOL is_wide_char; - JSString *p; - if (bc_get_leb128(s, &len)) - return NULL; - is_wide_char = len & 1; - len >>= 1; - p = js_alloc_string(s->ctx, len, is_wide_char); - if (!p) { - s->error_state = -1; - return NULL; - } - size = (size_t)len << is_wide_char; - if ((s->buf_end - s->ptr) < size) { - bc_read_error_end(s); - js_free_string(s->ctx->rt, p); - return NULL; - } - memcpy(p->u.str8, s->ptr, size); - s->ptr += size; - if (!is_wide_char) { - p->u.str8[size] = '\0'; /* add the trailing zero for 8 bit strings */ - } -#ifdef DUMP_READ_OBJECT - JS_DumpString(s->ctx->rt, p); printf("\n"); -#endif - return p; -} - -static uint32_t bc_get_flags(uint32_t flags, int *pidx, int n) -{ - uint32_t val; - /* XXX: this does not work for n == 32 */ - val = (flags >> *pidx) & ((1U << n) - 1); - *pidx += n; - return 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; -} - -#ifdef CONFIG_BIGNUM -static JSValue JS_ReadBigNum(BCReaderState *s, int tag) -{ - JSValue obj = JS_UNDEFINED; - uint8_t v8; - int32_t e; - uint32_t len; - limb_t l, i, n, j; - JSBigFloat *p; - limb_t v; - bf_t *a; - int bpos, d; - p = js_new_bf(s->ctx); - if (!p) - goto fail; - switch(tag) { - case BC_TAG_BIG_INT: - obj = JS_MKPTR(JS_TAG_BIG_INT, p); - break; - case BC_TAG_BIG_FLOAT: - obj = JS_MKPTR(JS_TAG_BIG_FLOAT, p); - break; - case BC_TAG_BIG_DECIMAL: - obj = JS_MKPTR(JS_TAG_BIG_DECIMAL, p); - break; - default: - abort(); - } - /* sign + exponent */ - if (bc_get_sleb128(s, &e)) - goto fail; - a = &p->num; - a->sign = e & 1; - e >>= 1; - if (e == 0) - a->expn = BF_EXP_ZERO; - else if (e == 1) - a->expn = BF_EXP_INF; - else if (e == 2) - a->expn = BF_EXP_NAN; - else if (e >= 3) - a->expn = e - 3; - else - a->expn = e; - /* mantissa */ - if (a->expn != BF_EXP_ZERO && - a->expn != BF_EXP_INF && - a->expn != BF_EXP_NAN) { - if (bc_get_leb128(s, &len)) - goto fail; - bc_read_trace(s, "len=%" PRId64 "\n", (int64_t)len); - if (len == 0) { - JS_ThrowInternalError(s->ctx, "invalid bignum length"); - goto fail; - } - if (tag != BC_TAG_BIG_DECIMAL) - l = (len + sizeof(limb_t) - 1) / sizeof(limb_t); - else - l = (len + LIMB_DIGITS - 1) / LIMB_DIGITS; - if (bf_resize(a, l)) { - JS_ThrowOutOfMemory(s->ctx); - goto fail; - } - if (tag != BC_TAG_BIG_DECIMAL) { - n = len & (sizeof(limb_t) - 1); - if (n != 0) { - v = 0; - for(i = 0; i < n; i++) { - if (bc_get_u8(s, &v8)) - goto fail; - v |= (limb_t)v8 << ((sizeof(limb_t) - n + i) * 8); - } - a->tab[0] = v; - i = 1; - } else { - i = 0; - } - for(; i < l; i++) { -#if LIMB_BITS == 32 - if (bc_get_u32(s, &v)) - goto fail; -#ifdef WORDS_BIGENDIAN - v = bswap32(v); -#endif -#else - if (bc_get_u64(s, &v)) - goto fail; -#ifdef WORDS_BIGENDIAN - v = bswap64(v); -#endif -#endif - a->tab[i] = v; - } - } else { - bpos = 0; - for(i = 0; i < l; i++) { - if (i == 0 && (n = len % LIMB_DIGITS) != 0) { - j = LIMB_DIGITS - n; - } else { - j = 0; - } - v = 0; - for(; j < LIMB_DIGITS; j++) { - if (bpos == 0) { - if (bc_get_u8(s, &v8)) - goto fail; - d = v8 & 0xf; - bpos = 1; - } else { - d = v8 >> 4; - bpos = 0; - } - if (d >= 10) { - JS_ThrowInternalError(s->ctx, "invalid digit"); - goto fail; - } - v += mp_pow_dec[j] * d; - } - a->tab[i] = v; - } - } - } - bc_read_trace(s, "}\n"); - return obj; - fail: - JS_FreeValue(s->ctx, obj); - return JS_EXCEPTION; -} -#endif /* CONFIG_BIGNUM */ - -static JSValue JS_ReadObjectRec(BCReaderState *s); - -static int BC_add_object_ref1(BCReaderState *s, JSObject *p) -{ - if (s->allow_reference) { - if (js_resize_array(s->ctx, (void *)&s->objects, - sizeof(s->objects[0]), - &s->objects_size, s->objects_count + 1)) - return -1; - s->objects[s->objects_count++] = p; - } - return 0; -} - -static int BC_add_object_ref(BCReaderState *s, JSValueConst obj) -{ - return BC_add_object_ref1(s, JS_VALUE_GET_OBJ(obj)); -} - -static JSValue JS_ReadFunctionTag(BCReaderState *s) -{ - JSContext *ctx = s->ctx; - JSFunctionBytecode bc, *b; - JSValue obj = JS_UNDEFINED; - uint16_t v16; - uint8_t v8; - int idx, i, local_count; - int function_size, cpool_offset, byte_code_offset; - int closure_var_offset, vardefs_offset; - bzero(&bc, sizeof(bc)); - bc.header.ref_count = 1; - //bc.gc_header.mark = 0; - if (bc_get_u16(s, &v16)) - goto fail; - idx = 0; - bc.has_prototype = bc_get_flags(v16, &idx, 1); - bc.has_simple_parameter_list = bc_get_flags(v16, &idx, 1); - bc.is_derived_class_constructor = bc_get_flags(v16, &idx, 1); - bc.need_home_object = bc_get_flags(v16, &idx, 1); - bc.func_kind = bc_get_flags(v16, &idx, 2); - bc.new_target_allowed = bc_get_flags(v16, &idx, 1); - bc.super_call_allowed = bc_get_flags(v16, &idx, 1); - bc.super_allowed = bc_get_flags(v16, &idx, 1); - bc.arguments_allowed = bc_get_flags(v16, &idx, 1); - bc.has_debug = bc_get_flags(v16, &idx, 1); - bc.backtrace_barrier = bc_get_flags(v16, &idx, 1); - bc.read_only_bytecode = s->is_rom_data; - if (bc_get_u8(s, &v8)) - goto fail; - bc.js_mode = v8; - if (bc_get_atom(s, &bc.func_name)) //@ atom leak if failure - goto fail; - if (bc_get_leb128_u16(s, &bc.arg_count)) - goto fail; - if (bc_get_leb128_u16(s, &bc.var_count)) - goto fail; - if (bc_get_leb128_u16(s, &bc.defined_arg_count)) - goto fail; - if (bc_get_leb128_u16(s, &bc.stack_size)) - goto fail; - if (bc_get_leb128_int(s, &bc.closure_var_count)) - goto fail; - if (bc_get_leb128_int(s, &bc.cpool_count)) - goto fail; - if (bc_get_leb128_int(s, &bc.byte_code_len)) - goto fail; - if (bc_get_leb128_int(s, &local_count)) - goto fail; - if (bc.has_debug) { - function_size = sizeof(*b); - } else { - function_size = offsetof(JSFunctionBytecode, debug); - } - cpool_offset = function_size; - function_size += bc.cpool_count * sizeof(*bc.cpool); - vardefs_offset = function_size; - function_size += local_count * sizeof(*bc.vardefs); - closure_var_offset = function_size; - function_size += bc.closure_var_count * sizeof(*bc.closure_var); - byte_code_offset = function_size; - if (!bc.read_only_bytecode) { - function_size += bc.byte_code_len; - } - b = js_mallocz(ctx, function_size); - if (!b) - return JS_EXCEPTION; - memcpy(b, &bc, offsetof(JSFunctionBytecode, debug)); - b->header.ref_count = 1; - if (local_count != 0) { - b->vardefs = (void *)((uint8_t*)b + vardefs_offset); - } - if (b->closure_var_count != 0) { - b->closure_var = (void *)((uint8_t*)b + closure_var_offset); - } - if (b->cpool_count != 0) { - b->cpool = (void *)((uint8_t*)b + cpool_offset); - } - add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE); - obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b); -#ifdef DUMP_READ_OBJECT - bc_read_trace(s, "name: "); print_atom(s->ctx, b->func_name); printf("\n"); -#endif - bc_read_trace(s, "args=%d vars=%d defargs=%d closures=%d cpool=%d\n", - b->arg_count, b->var_count, b->defined_arg_count, - b->closure_var_count, b->cpool_count); - bc_read_trace(s, "stack=%d bclen=%d locals=%d\n", - b->stack_size, b->byte_code_len, local_count); - if (local_count != 0) { - bc_read_trace(s, "vars {\n"); - for(i = 0; i < local_count; i++) { - JSVarDef *vd = &b->vardefs[i]; - if (bc_get_atom(s, &vd->var_name)) - goto fail; - if (bc_get_leb128_int(s, &vd->scope_level)) - goto fail; - if (bc_get_leb128_int(s, &vd->scope_next)) - goto fail; - vd->scope_next--; - if (bc_get_u8(s, &v8)) - goto fail; - idx = 0; - vd->var_kind = bc_get_flags(v8, &idx, 4); - vd->is_const = bc_get_flags(v8, &idx, 1); - vd->is_lexical = bc_get_flags(v8, &idx, 1); - vd->is_captured = bc_get_flags(v8, &idx, 1); -#ifdef DUMP_READ_OBJECT - bc_read_trace(s, "name: "); print_atom(s->ctx, vd->var_name); printf("\n"); -#endif - } - bc_read_trace(s, "}\n"); - } - if (b->closure_var_count != 0) { - bc_read_trace(s, "closure vars {\n"); - for(i = 0; i < b->closure_var_count; i++) { - JSClosureVar *cv = &b->closure_var[i]; - int var_idx; - if (bc_get_atom(s, &cv->var_name)) - goto fail; - if (bc_get_leb128_int(s, &var_idx)) - goto fail; - cv->var_idx = var_idx; - if (bc_get_u8(s, &v8)) - goto fail; - idx = 0; - cv->is_local = bc_get_flags(v8, &idx, 1); - cv->is_arg = bc_get_flags(v8, &idx, 1); - cv->is_const = bc_get_flags(v8, &idx, 1); - cv->is_lexical = bc_get_flags(v8, &idx, 1); - cv->var_kind = bc_get_flags(v8, &idx, 4); -#ifdef DUMP_READ_OBJECT - bc_read_trace(s, "name: "); print_atom(s->ctx, cv->var_name); printf("\n"); -#endif - } - bc_read_trace(s, "}\n"); - } - { - bc_read_trace(s, "bytecode {\n"); - if (JS_ReadFunctionBytecode(s, b, byte_code_offset, b->byte_code_len)) - goto fail; - bc_read_trace(s, "}\n"); - } - if (b->has_debug) { - /* read optional debug information */ - bc_read_trace(s, "debug {\n"); - if (bc_get_atom(s, &b->debug.filename)) - goto fail; - if (bc_get_leb128_int(s, &b->debug.line_num)) - goto fail; - if (bc_get_leb128_int(s, &b->debug.pc2line_len)) - goto fail; - if (b->debug.pc2line_len) { - b->debug.pc2line_buf = js_mallocz(ctx, b->debug.pc2line_len); - if (!b->debug.pc2line_buf) - goto fail; - if (bc_get_buf(s, b->debug.pc2line_buf, b->debug.pc2line_len)) - goto fail; - } -#ifdef DUMP_READ_OBJECT - bc_read_trace(s, "filename: "); print_atom(s->ctx, b->debug.filename); printf("\n"); -#endif - bc_read_trace(s, "}\n"); - } - if (b->cpool_count != 0) { - bc_read_trace(s, "cpool {\n"); - for(i = 0; i < b->cpool_count; i++) { - JSValue val; - val = JS_ReadObjectRec(s); - if (JS_IsException(val)) - goto fail; - b->cpool[i] = val; - } - bc_read_trace(s, "}\n"); - } - b->realm = JS_DupContext(ctx); - return obj; - fail: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue JS_ReadModule(BCReaderState *s) -{ - JSContext *ctx = s->ctx; - JSValue obj; - JSModuleDef *m = NULL; - JSAtom module_name; - int i; - uint8_t v8; - if (bc_get_atom(s, &module_name)) - goto fail; -#ifdef DUMP_READ_OBJECT - bc_read_trace(s, "name: "); print_atom(s->ctx, module_name); printf("\n"); -#endif - m = js_new_module_def(ctx, module_name); - if (!m) - goto fail; - obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); - if (bc_get_leb128_int(s, &m->req_module_entries_count)) - goto fail; - if (m->req_module_entries_count != 0) { - m->req_module_entries_size = m->req_module_entries_count; - m->req_module_entries = js_mallocz(ctx, sizeof(m->req_module_entries[0]) * m->req_module_entries_size); - if (!m->req_module_entries) - goto fail; - for(i = 0; i < m->req_module_entries_count; i++) { - JSReqModuleEntry *rme = &m->req_module_entries[i]; - if (bc_get_atom(s, &rme->module_name)) - goto fail; - } - } - if (bc_get_leb128_int(s, &m->export_entries_count)) - goto fail; - if (m->export_entries_count != 0) { - m->export_entries_size = m->export_entries_count; - m->export_entries = js_mallocz(ctx, sizeof(m->export_entries[0]) * m->export_entries_size); - if (!m->export_entries) - goto fail; - for(i = 0; i < m->export_entries_count; i++) { - JSExportEntry *me = &m->export_entries[i]; - if (bc_get_u8(s, &v8)) - goto fail; - me->export_type = v8; - if (me->export_type == JS_EXPORT_TYPE_LOCAL) { - if (bc_get_leb128_int(s, &me->u.local.var_idx)) - goto fail; - } else { - if (bc_get_leb128_int(s, &me->u.req_module_idx)) - goto fail; - if (bc_get_atom(s, &me->local_name)) - goto fail; - } - if (bc_get_atom(s, &me->export_name)) - goto fail; - } - } - if (bc_get_leb128_int(s, &m->star_export_entries_count)) - goto fail; - if (m->star_export_entries_count != 0) { - m->star_export_entries_size = m->star_export_entries_count; - m->star_export_entries = js_mallocz(ctx, sizeof(m->star_export_entries[0]) * m->star_export_entries_size); - if (!m->star_export_entries) - goto fail; - for(i = 0; i < m->star_export_entries_count; i++) { - JSStarExportEntry *se = &m->star_export_entries[i]; - if (bc_get_leb128_int(s, &se->req_module_idx)) - goto fail; - } - } - if (bc_get_leb128_int(s, &m->import_entries_count)) - goto fail; - if (m->import_entries_count != 0) { - m->import_entries_size = m->import_entries_count; - m->import_entries = js_mallocz(ctx, sizeof(m->import_entries[0]) * m->import_entries_size); - if (!m->import_entries) - goto fail; - for(i = 0; i < m->import_entries_count; i++) { - JSImportEntry *mi = &m->import_entries[i]; - if (bc_get_leb128_int(s, &mi->var_idx)) - goto fail; - if (bc_get_atom(s, &mi->import_name)) - goto fail; - if (bc_get_leb128_int(s, &mi->req_module_idx)) - goto fail; - } - } - m->func_obj = JS_ReadObjectRec(s); - if (JS_IsException(m->func_obj)) - goto fail; - return obj; - fail: - if (m) { - js_free_module_def(ctx, m); - } - return JS_EXCEPTION; -} - -static JSValue JS_ReadObjectTag(BCReaderState *s) -{ - JSContext *ctx = s->ctx; - JSValue obj; - uint32_t prop_count, i; - JSAtom atom; - JSValue val; - int ret; - obj = JS_NewObject(ctx); - if (BC_add_object_ref(s, obj)) - goto fail; - if (bc_get_leb128(s, &prop_count)) - goto fail; - for(i = 0; i < prop_count; i++) { - if (bc_get_atom(s, &atom)) - goto fail; -#ifdef DUMP_READ_OBJECT - bc_read_trace(s, "propname: "); print_atom(s->ctx, atom); printf("\n"); -#endif - val = JS_ReadObjectRec(s); - if (JS_IsException(val)) { - JS_FreeAtom(ctx, atom); - goto fail; - } - ret = JS_DefinePropertyValue(ctx, obj, atom, val, JS_PROP_C_W_E); - JS_FreeAtom(ctx, atom); - if (ret < 0) - goto fail; - } - return obj; - fail: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue JS_ReadArray(BCReaderState *s, int tag) -{ - JSContext *ctx = s->ctx; - JSValue obj; - uint32_t len, i; - JSValue val; - int ret, prop_flags; - BOOL is_template; - obj = JS_NewArray(ctx); - if (BC_add_object_ref(s, obj)) - goto fail; - is_template = (tag == BC_TAG_TEMPLATE_OBJECT); - if (bc_get_leb128(s, &len)) - goto fail; - for(i = 0; i < len; i++) { - val = JS_ReadObjectRec(s); - if (JS_IsException(val)) - goto fail; - if (is_template) - prop_flags = JS_PROP_ENUMERABLE; - else - prop_flags = JS_PROP_C_W_E; - ret = JS_DefinePropertyValueUint32(ctx, obj, i, val, - prop_flags); - if (ret < 0) - goto fail; - } - if (is_template) { - val = JS_ReadObjectRec(s); - if (JS_IsException(val)) - goto fail; - if (!JS_IsUndefined(val)) { - ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_raw, val, 0); - if (ret < 0) - goto fail; - } - JS_PreventExtensions(ctx, obj); - } - return obj; - fail: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue JS_ReadTypedArray(BCReaderState *s) -{ - JSContext *ctx = s->ctx; - JSValue obj = JS_UNDEFINED, array_buffer = JS_UNDEFINED; - uint8_t array_tag; - JSValueConst args[3]; - uint32_t offset, len, idx; - if (bc_get_u8(s, &array_tag)) - return JS_EXCEPTION; - if (array_tag >= JS_TYPED_ARRAY_COUNT) - return JS_ThrowTypeError(ctx, "invalid typed array"); - if (bc_get_leb128(s, &len)) - return JS_EXCEPTION; - if (bc_get_leb128(s, &offset)) - return JS_EXCEPTION; - /* XXX: this hack could be avoided if the typed array could be - created before the array buffer */ - idx = s->objects_count; - if (BC_add_object_ref1(s, NULL)) - goto fail; - array_buffer = JS_ReadObjectRec(s); - if (JS_IsException(array_buffer)) - return JS_EXCEPTION; - if (!js_get_array_buffer(ctx, array_buffer)) { - JS_FreeValue(ctx, array_buffer); - return JS_EXCEPTION; - } - args[0] = array_buffer; - args[1] = JS_NewInt64(ctx, offset); - args[2] = JS_NewInt64(ctx, len); - obj = js_typed_array_constructor(ctx, JS_UNDEFINED, - 3, args, - JS_CLASS_UINT8C_ARRAY + array_tag); - if (JS_IsException(obj)) - goto fail; - if (s->allow_reference) { - s->objects[idx] = JS_VALUE_GET_OBJ(obj); - } - JS_FreeValue(ctx, array_buffer); - return obj; - fail: - JS_FreeValue(ctx, array_buffer); - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue JS_ReadArrayBuffer(BCReaderState *s) -{ - JSContext *ctx = s->ctx; - uint32_t byte_length; - JSValue obj; - - if (bc_get_leb128(s, &byte_length)) - return JS_EXCEPTION; - if (UNLIKELY(s->buf_end - s->ptr < byte_length)) { - bc_read_error_end(s); - return JS_EXCEPTION; - } - obj = JS_NewArrayBufferCopy(ctx, s->ptr, byte_length); - if (JS_IsException(obj)) - goto fail; - if (BC_add_object_ref(s, obj)) - goto fail; - s->ptr += byte_length; - return obj; - fail: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue JS_ReadSharedArrayBuffer(BCReaderState *s) -{ - JSContext *ctx = s->ctx; - uint32_t byte_length; - uint8_t *data_ptr; - JSValue obj; - uint64_t u64; - if (bc_get_leb128(s, &byte_length)) - return JS_EXCEPTION; - if (bc_get_u64(s, &u64)) - return JS_EXCEPTION; - data_ptr = (uint8_t *)(uintptr_t)u64; - /* the SharedArrayBuffer is cloned */ - obj = js_array_buffer_constructor3(ctx, JS_UNDEFINED, byte_length, - JS_CLASS_SHARED_ARRAY_BUFFER, - data_ptr, - NULL, NULL, FALSE); - if (JS_IsException(obj)) - goto fail; - if (BC_add_object_ref(s, obj)) - goto fail; - return obj; - fail: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue JS_ReadDate(BCReaderState *s) -{ - JSContext *ctx = s->ctx; - JSValue val, obj = JS_UNDEFINED; - val = JS_ReadObjectRec(s); - if (JS_IsException(val)) - goto fail; - if (!JS_IsNumber(val)) { - JS_ThrowTypeError(ctx, "Number tag expected for date"); - goto fail; - } - obj = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_DATE], - JS_CLASS_DATE); - if (JS_IsException(obj)) - goto fail; - if (BC_add_object_ref(s, obj)) - goto fail; - JS_SetObjectData(ctx, obj, val); - return obj; - fail: - JS_FreeValue(ctx, val); - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue JS_ReadObjectValue(BCReaderState *s) -{ - JSContext *ctx = s->ctx; - JSValue val, obj = JS_UNDEFINED; - val = JS_ReadObjectRec(s); - if (JS_IsException(val)) - goto fail; - obj = JS_ToObject(ctx, val); - if (JS_IsException(obj)) - goto fail; - if (BC_add_object_ref(s, obj)) - goto fail; - JS_FreeValue(ctx, val); - return obj; - fail: - JS_FreeValue(ctx, val); - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue JS_ReadObjectRec(BCReaderState *s) -{ - JSContext *ctx = s->ctx; - uint8_t tag; - JSValue obj = JS_UNDEFINED; - if (js_check_stack_overflow(ctx->rt, 0)) - return JS_ThrowStackOverflow(ctx); - if (bc_get_u8(s, &tag)) - return JS_EXCEPTION; - bc_read_trace(s, "%s {\n", bc_tag_str[tag]); - switch(tag) { - case BC_TAG_NULL: - obj = JS_NULL; - break; - case BC_TAG_UNDEFINED: - obj = JS_UNDEFINED; - break; - case BC_TAG_BOOL_FALSE: - case BC_TAG_BOOL_TRUE: - obj = JS_NewBool(ctx, tag - BC_TAG_BOOL_FALSE); - break; - case BC_TAG_INT32: - { - int32_t val; - if (bc_get_sleb128(s, &val)) - return JS_EXCEPTION; - bc_read_trace(s, "%d\n", val); - obj = JS_NewInt32(ctx, val); - } - break; - case BC_TAG_FLOAT64: - { - JSFloat64Union u; - if (bc_get_u64(s, &u.u64)) - return JS_EXCEPTION; - bc_read_trace(s, "%g\n", u.d); - obj = __JS_NewFloat64(ctx, u.d); - } - break; - case BC_TAG_STRING: - { - JSString *p; - p = JS_ReadString(s); - if (!p) - return JS_EXCEPTION; - obj = JS_MKPTR(JS_TAG_STRING, p); - } - break; - case BC_TAG_FUNCTION_BYTECODE: - if (!s->allow_bytecode) - goto invalid_tag; - obj = JS_ReadFunctionTag(s); - break; - case BC_TAG_MODULE: - if (!s->allow_bytecode) - goto invalid_tag; - obj = JS_ReadModule(s); - break; - case BC_TAG_OBJECT: - obj = JS_ReadObjectTag(s); - break; - case BC_TAG_ARRAY: - case BC_TAG_TEMPLATE_OBJECT: - obj = JS_ReadArray(s, tag); - break; - case BC_TAG_TYPED_ARRAY: - obj = JS_ReadTypedArray(s); - break; - case BC_TAG_ARRAY_BUFFER: - obj = JS_ReadArrayBuffer(s); - break; - case BC_TAG_SHARED_ARRAY_BUFFER: - if (!s->allow_sab || !ctx->rt->sab_funcs.sab_dup) - goto invalid_tag; - obj = JS_ReadSharedArrayBuffer(s); - break; - case BC_TAG_DATE: - obj = JS_ReadDate(s); - break; - case BC_TAG_OBJECT_VALUE: - obj = JS_ReadObjectValue(s); - break; -#ifdef CONFIG_BIGNUM - case BC_TAG_BIG_INT: - case BC_TAG_BIG_FLOAT: - case BC_TAG_BIG_DECIMAL: - obj = JS_ReadBigNum(s, tag); - break; -#endif - case BC_TAG_OBJECT_REFERENCE: - { - uint32_t val; - if (!s->allow_reference) - return JS_ThrowSyntaxError(ctx, "object references are not allowed"); - if (bc_get_leb128(s, &val)) - return JS_EXCEPTION; - bc_read_trace(s, "%u\n", val); - if (val >= s->objects_count) { - return JS_ThrowSyntaxError(ctx, "invalid object reference (%u >= %u)", - val, s->objects_count); - } - obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, s->objects[val])); - } - break; - default: - invalid_tag: - return JS_ThrowSyntaxError(ctx, "invalid tag (tag=%d pos=%u)", - tag, (unsigned int)(s->ptr - s->buf_start)); - } - bc_read_trace(s, "}\n"); - return obj; -} - -static int JS_ReadObjectAtoms(BCReaderState *s) -{ - uint8_t v8; - JSString *p; - int i; - JSAtom atom; - if (bc_get_u8(s, &v8)) - return -1; - /* XXX: could support byte swapped input */ - if (v8 != BC_VERSION) { - JS_ThrowSyntaxError(s->ctx, "invalid version (%d expected=%d)", - v8, BC_VERSION); - return -1; - } - if (bc_get_leb128(s, &s->idx_to_atom_count)) - return -1; - bc_read_trace(s, "%d atom indexes {\n", s->idx_to_atom_count); - if (s->idx_to_atom_count != 0) { - s->idx_to_atom = js_mallocz(s->ctx, s->idx_to_atom_count * - sizeof(s->idx_to_atom[0])); - if (!s->idx_to_atom) - return s->error_state = -1; - } - for(i = 0; i < s->idx_to_atom_count; i++) { - p = JS_ReadString(s); - if (!p) - return -1; - atom = JS_NewAtomStr(s->ctx, p); - if (atom == JS_ATOM_NULL) - return s->error_state = -1; - s->idx_to_atom[i] = atom; - if (s->is_rom_data && (atom != (i + s->first_atom))) - s->is_rom_data = FALSE; /* atoms must be relocated */ - } - bc_read_trace(s, "}\n"); - return 0; -} - -static void bc_reader_free(BCReaderState *s) -{ - int i; - if (s->idx_to_atom) { - for(i = 0; i < s->idx_to_atom_count; i++) { - JS_FreeAtom(s->ctx, s->idx_to_atom[i]); - } - js_free(s->ctx, s->idx_to_atom); - } - js_free(s->ctx, s->objects); -} - -JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, - int flags) -{ - BCReaderState ss, *s = &ss; - JSValue obj; - ctx->binary_object_count += 1; - ctx->binary_object_size += buf_len; - bzero(s, sizeof(*s)); - s->ctx = ctx; - s->buf_start = buf; - s->buf_end = buf + buf_len; - s->ptr = buf; - s->allow_bytecode = ((flags & JS_READ_OBJ_BYTECODE) != 0); - s->is_rom_data = ((flags & JS_READ_OBJ_ROM_DATA) != 0); - s->allow_sab = ((flags & JS_READ_OBJ_SAB) != 0); - s->allow_reference = ((flags & JS_READ_OBJ_REFERENCE) != 0); - if (s->allow_bytecode) - s->first_atom = JS_ATOM_END; - else - s->first_atom = 1; - if (JS_ReadObjectAtoms(s)) { - obj = JS_EXCEPTION; - } else { - obj = JS_ReadObjectRec(s); - } - bc_reader_free(s); - return obj; -} diff --git a/third_party/quickjs/call.c b/third_party/quickjs/call.c deleted file mode 100644 index bdca43a6b..000000000 --- a/third_party/quickjs/call.c +++ /dev/null @@ -1,4107 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/assert.h" -#include "libc/mem/gc.h" -#include "libc/mem/mem.h" -#include "libc/runtime/runtime.h" -#include "third_party/quickjs/internal.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -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_CallConstructorInternal(JSContext *, - JSValueConst, - JSValueConst, - int, JSValue *, int); - -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; -} - -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; -} - -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 = gc(malloc(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; -} - -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 = gc(malloc(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); - } -} - -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); -} - -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; -} - -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; -} - -/* 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_import_meta(JSContext *ctx) -{ - JSAtom filename; - JSModuleDef *m; - filename = JS_GetScriptOrModuleName(ctx, 0); - if (filename == JS_ATOM_NULL) - goto fail; - /* XXX: inefficient, need to add a module or script pointer in - JSFunctionBytecode */ - m = js_find_loaded_module(ctx, filename); - JS_FreeAtom(ctx, filename); - if (!m) { - fail: - JS_ThrowTypeError(ctx, "import.meta not supported in this context"); - return JS_EXCEPTION; - } - return JS_GetImportMeta(ctx, m); -} - -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 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; -} - -/* 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); -} - -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 JSValue js_dynamic_import_job(JSContext *ctx, - int argc, JSValueConst *argv) -{ - JSValueConst *resolving_funcs = argv; - JSValueConst basename_val = argv[2]; - JSValueConst specifier = argv[3]; - JSModuleDef *m; - const char *basename = NULL, *filename; - JSValue ret, err, ns; - if (!JS_IsString(basename_val)) { - JS_ThrowTypeError(ctx, "no function filename for import()"); - goto exception; - } - basename = JS_ToCString(ctx, basename_val); - if (!basename) - goto exception; - filename = JS_ToCString(ctx, specifier); - if (!filename) - goto exception; - m = JS_RunModule(ctx, basename, filename); - JS_FreeCString(ctx, filename); - if (!m) - goto exception; - /* return the module namespace */ - ns = js_get_module_ns(ctx, m); - if (JS_IsException(ns)) - goto exception; - ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, - 1, (JSValueConst *)&ns); - JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */ - JS_FreeValue(ctx, ns); - JS_FreeCString(ctx, basename); - return JS_UNDEFINED; - exception: - err = JS_GetException(ctx); - ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, - 1, (JSValueConst *)&err); - JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */ - JS_FreeValue(ctx, err); - JS_FreeCString(ctx, basename); - return JS_UNDEFINED; -} - -static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier) -{ - JSAtom basename; - JSValue promise, resolving_funcs[2], basename_val; - JSValueConst args[4]; - basename = JS_GetScriptOrModuleName(ctx, 0); - if (basename == JS_ATOM_NULL) - basename_val = JS_NULL; - else - basename_val = JS_AtomToValue(ctx, basename); - JS_FreeAtom(ctx, basename); - if (JS_IsException(basename_val)) - return basename_val; - promise = JS_NewPromiseCapability(ctx, resolving_funcs); - if (JS_IsException(promise)) { - JS_FreeValue(ctx, basename_val); - return promise; - } - args[0] = resolving_funcs[0]; - args[1] = resolving_funcs[1]; - args[2] = basename_val; - args[3] = specifier; - JS_EnqueueJob(ctx, js_dynamic_import_job, 4, args); - JS_FreeValue(ctx, basename_val); - JS_FreeValue(ctx, resolving_funcs[0]); - JS_FreeValue(ctx, resolving_funcs[1]); - return promise; -} - -/* 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; -} - -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); -} - -/* 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 (is_strict_mode(ctx)) - flags |= JS_PROP_NO_ADD; - return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags); -} - -/* 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 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); - } - } -} - -/* 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; -} - -static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj) -{ - JSObject *p; - JSPropertyEnum *tab_atom; - int i; - JSValue enum_obj, obj1; - 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; - /* fast path: assume no enumerable properties in the prototype chain */ - obj1 = JS_DupValue(ctx, obj); - for(;;) { - obj1 = JS_GetPrototypeFree(ctx, obj1); - if (JS_IsNull(obj1)) - break; - if (JS_IsException(obj1)) - goto fail; - if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, - JS_VALUE_GET_OBJ(obj1), - JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) { - JS_FreeValue(ctx, obj1); - goto fail; - } - js_free_prop_enum(ctx, tab_atom, tab_atom_count); - if (tab_atom_count != 0) { - JS_FreeValue(ctx, obj1); - goto slow_path; - } - /* must check for timeout to avoid infinite loop */ - if (js_poll_interrupts(ctx)) { - JS_FreeValue(ctx, obj1); - goto fail; - } - } - p = JS_VALUE_GET_OBJ(obj); - if (p->fast_array) { - JSShape *sh; - JSShapeProperty *prs; - /* check that there are no enumerable normal fields */ - sh = p->shape; - for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { - if (prs->flags & JS_PROP_ENUMERABLE) - goto normal_case; - } - /* for fast arrays, we only store the number of elements */ - it->is_array = TRUE; - it->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 */ - obj1 = JS_DupValue(ctx, obj); - for(;;) { - if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, - JS_VALUE_GET_OBJ(obj1), - JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { - JS_FreeValue(ctx, obj1); - 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); - obj1 = JS_GetPrototypeFree(ctx, obj1); - if (JS_IsNull(obj1)) - break; - if (JS_IsException(obj1)) - goto fail; - /* must check for timeout to avoid infinite loop */ - if (js_poll_interrupts(ctx)) { - JS_FreeValue(ctx, obj1); - goto fail; - } - } - 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; -} - -/* enum_rec [objs] -> enum_rec [objs] value done. There are 'offset' - objs. If 'done' is true or in case of exception, 'enum_rec' is set - to undefined. If 'done' is true, 'value' is always set to - undefined. */ -static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset) -{ - JSValue value = JS_UNDEFINED; - int done = 1; - if (LIKELY(!JS_IsUndefined(sp[offset]))) { - value = JS_IteratorNext(ctx, sp[offset], sp[offset + 1], 0, NULL, &done); - if (JS_IsException(value)) - done = -1; - if (done) { - /* value is JS_UNDEFINED or JS_EXCEPTION */ - /* replace the iteration object with undefined */ - JS_FreeValue(ctx, sp[offset]); - sp[offset] = JS_UNDEFINED; - if (done < 0) { - return -1; - } else { - JS_FreeValue(ctx, value); - value = JS_UNDEFINED; - } - } - } - sp[0] = value; - sp[1] = JS_NewBool(ctx, done); - return 0; -} - -static __exception int js_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_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; -} - -/* 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; -} - -/* 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; -} - -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 __exception int js_append_enumerate(JSContext *ctx, JSValue *sp) -{ - JSValue iterator, enumobj, method, value; - int is_array_iterator; - JSValue *arrp; - uint32_t i, count32, pos; - if (JS_VALUE_GET_TAG(sp[-2]) != JS_TAG_INT) { - JS_ThrowInternalError(ctx, "invalid index for append"); - return -1; - } - pos = JS_VALUE_GET_INT(sp[-2]); - /* XXX: further optimisations: - - use ctx->array_proto_values? - - check if array_iterator_prototype next method is built-in and - avoid constructing actual iterator object? - - build this into js_for_of_start and use in all `for (x of o)` loops - */ - iterator = JS_GetProperty(ctx, sp[-1], JS_ATOM_Symbol_iterator); - if (JS_IsException(iterator)) - return -1; - is_array_iterator = JS_IsCFunction(ctx, iterator, - (JSCFunction *)js_create_array_iterator, - JS_ITERATOR_KIND_VALUE); - JS_FreeValue(ctx, iterator); - enumobj = JS_GetIterator(ctx, sp[-1], FALSE); - if (JS_IsException(enumobj)) - return -1; - method = JS_GetProperty(ctx, enumobj, JS_ATOM_next); - if (JS_IsException(method)) { - JS_FreeValue(ctx, enumobj); - return -1; - } - if (is_array_iterator - && JS_IsCFunction(ctx, method, (JSCFunction *)js_array_iterator_next, 0) - && js_get_fast_array(ctx, sp[-1], &arrp, &count32)) { - uint32_t len; - if (js_get_length32(ctx, &len, sp[-1])) - goto exception; - /* if len > count32, the elements >= count32 might be read in - the prototypes and might have side effects */ - if (len != count32) - goto general_case; - /* Handle fast arrays explicitly */ - for (i = 0; i < count32; i++) { - if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, - JS_DupValue(ctx, arrp[i]), JS_PROP_C_W_E) < 0) - goto exception; - } - } else { - general_case: - for (;;) { - BOOL done; - value = JS_IteratorNext(ctx, enumobj, method, 0, NULL, &done); - if (JS_IsException(value)) - goto exception; - if (done) { - /* value is JS_UNDEFINED */ - break; - } - if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, value, JS_PROP_C_W_E) < 0) - goto exception; - } - } - /* Note: could raise an error if too many elements */ - sp[-2] = JS_NewInt32(ctx, pos); - JS_FreeValue(ctx, enumobj); - JS_FreeValue(ctx, method); - return 0; -exception: - JS_IteratorClose(ctx, enumobj, TRUE); - JS_FreeValue(ctx, enumobj); - JS_FreeValue(ctx, method); - return -1; -} - -static __wur 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 __wur int js_operator_typeof(JSContext *ctx, JSValueConst 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: - { - JSObject *p; - p = JS_VALUE_GET_OBJ(op1); - if (UNLIKELY(p->is_HTMLDDA)) - atom = JS_ATOM_undefined; - else if (JS_IsFunction(ctx, op1)) - atom = JS_ATOM_function; - else - goto obj_type; - } - break; - case JS_TAG_NULL: - obj_type: - atom = JS_ATOM_object; - break; - case JS_TAG_SYMBOL: - atom = JS_ATOM_symbol; - break; - default: - atom = JS_ATOM_unknown; - break; - } - return atom; -} - -static __wur 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 __wur 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; -} - -/* 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; -} - -/* used to avoid catching interrupt exceptions */ -static 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; -} - -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); - } -} - -/* 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 "third_party/quickjs/quickjs-opcode.inc" - [ 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 = gc(malloc(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(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_error): - { - JSAtom atom; - int type; - atom = get_u32(pc); - type = pc[4]; - pc += 5; - if (type == JS_THROW_VAR_RO) - JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, atom); - else - if (type == JS_THROW_VAR_REDECL) - JS_ThrowSyntaxErrorVarRedeclaration(ctx, atom); - else - if (type == JS_THROW_VAR_UNINITIALIZED) - JS_ThrowReferenceErrorUninitialized(ctx, atom); - else - if (type == JS_THROW_ERROR_DELETE_SUPER) - JS_ThrowReferenceError(ctx, "unsupported reference to 'super'"); - else - if (type == JS_THROW_ERROR_ITERATOR_THROW) - JS_ThrowTypeError(ctx, "iterator does not have a throw method"); - else - JS_ThrowInternalError(ctx, "invalid throw var type %d", type); - } - goto exception; - CASE(OP_eval): - { - JSValueConst obj; - int scope_idx; - call_argc = get_u16(pc); - scope_idx = get_u16(pc + 2) - 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_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE); - goto exception; - } - sp[0] = JS_DupValue(ctx, val); - sp++; - } - BREAK; - CASE(OP_put_var_ref_check): - { - int idx; - idx = get_u16(pc); - pc += 2; - if (UNLIKELY(JS_IsUninitialized(*var_refs[idx]->pvalue))) { - JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE); - goto exception; - } - set_value(ctx, var_refs[idx]->pvalue, sp[-1]); - sp--; - } - BREAK; - CASE(OP_put_var_ref_check_init): - { - int idx; - idx = get_u16(pc); - pc += 2; - if (UNLIKELY(!JS_IsUninitialized(*var_refs[idx]->pvalue))) { - JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE); - goto exception; - } - set_value(ctx, var_refs[idx]->pvalue, sp[-1]); - sp--; - } - BREAK; - CASE(OP_set_loc_uninitialized): - { - int idx; - idx = get_u16(pc); - pc += 2; - set_value(ctx, &var_buf[idx], JS_UNINITIALIZED); - } - BREAK; - CASE(OP_get_loc_check): - { - int idx; - idx = get_u16(pc); - pc += 2; - if (UNLIKELY(JS_IsUninitialized(var_buf[idx]))) { - JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE); - goto exception; - } - sp[0] = JS_DupValue(ctx, var_buf[idx]); - sp++; - } - BREAK; - CASE(OP_put_loc_check): - { - int idx; - idx = get_u16(pc); - pc += 2; - if (UNLIKELY(JS_IsUninitialized(var_buf[idx]))) { - JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE); - goto exception; - } - set_value(ctx, &var_buf[idx], sp[-1]); - sp--; - } - BREAK; - CASE(OP_put_loc_check_init): - { - int idx; - idx = get_u16(pc); - pc += 2; - if (UNLIKELY(!JS_IsUninitialized(var_buf[idx]))) { - JS_ThrowReferenceError(ctx, "'this' can be initialized only once"); - goto exception; - } - set_value(ctx, &var_buf[idx], sp[-1]); - sp--; - } - BREAK; - CASE(OP_close_loc): - { - int idx; - idx = get_u16(pc); - pc += 2; - close_lexical_var(ctx, sf, idx, 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_iterator_get_value_done): - if (js_iterator_get_value_done(ctx, sp)) - goto exception; - sp += 1; - BREAK; - CASE(OP_iterator_check_object): - if (UNLIKELY(!JS_IsObject(sp[-1]))) { - JS_ThrowTypeError(ctx, "iterator must return an object"); - goto exception; - } - BREAK; - CASE(OP_iterator_close): - /* iter_obj next catch_offset -> */ - sp--; /* drop the catch offset to avoid getting caught by exception */ - JS_FreeValue(ctx, sp[-1]); /* drop the next method */ - sp--; - if (!JS_IsUndefined(sp[-1])) { - 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_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_iterator_call): - /* stack: iter_obj next catch_offset val */ - { - JSValue method, ret; - BOOL ret_flag; - int flags; - flags = *pc++; - method = JS_GetProperty(ctx, sp[-4], (flags & 1) ? - JS_ATOM_throw : JS_ATOM_return); - if (JS_IsException(method)) - goto exception; - if (JS_IsUndefined(method) || JS_IsNull(method)) { - ret_flag = TRUE; - } else { - if (flags & 2) { - /* no argument */ - ret = JS_CallFree(ctx, method, sp[-4], - 0, NULL); - } else { - ret = JS_CallFree(ctx, method, sp[-4], - 1, (JSValueConst *)(sp - 1)); - } - if (JS_IsException(ret)) - goto exception; - JS_FreeValue(ctx, sp[-1]); - sp[-1] = ret; - ret_flag = FALSE; - } - sp[0] = JS_NewBool(ctx, ret_flag); - sp += 1; - } - BREAK; - CASE(OP_lnot): - { - int res; - JSValue op1; - op1 = sp[-1]; - if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) { - res = JS_VALUE_GET_INT(op1) != 0; - } else { - res = JS_ToBoolFree(ctx, op1); - } - sp[-1] = JS_NewBool(ctx, !res); - } - BREAK; - CASE(OP_get_field): - { - JSValue val; - JSAtom atom; - atom = get_u32(pc); - pc += 4; - 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; - 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, flags; - flags = JS_PROP_THROW_STRICT; - 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); - } - } else { - if (is_strict_mode(ctx)) - flags |= JS_PROP_NO_ADD; - } - ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], flags); - 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, 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 *pv; - int idx; - idx = *pc; - pc += 1; - pv = &var_buf[idx]; - if (LIKELY(JS_VALUE_IS_BOTH_INT(*pv, sp[-1]))) { - int64_t r; - r = (int64_t)JS_VALUE_GET_INT(*pv) + - JS_VALUE_GET_INT(sp[-1]); - if (UNLIKELY((int)r != r)) - goto add_loc_slow; - *pv = JS_NewInt32(ctx, r); - sp--; - } else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING) { - JSValue op1; - op1 = sp[-1]; - sp--; - op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); - if (JS_IsException(op1)) - goto exception; - op1 = JS_ConcatString(ctx, JS_DupValue(ctx, *pv), op1); - if (JS_IsException(op1)) - goto exception; - set_value(ctx, pv, op1); - } else { - JSValue ops[2]; - add_loc_slow: - /* In case of exception, js_add_slow frees ops[0] - and ops[1], so we must duplicate *pv */ - ops[0] = JS_DupValue(ctx, *pv); - ops[1] = sp[-1]; - sp--; - if (js_add_slow(ctx, ops + 2)) - goto exception; - set_value(ctx, pv, ops[0]); - } - } - BREAK; - CASE(OP_sub): - { - JSValue op1, op2; - op1 = sp[-2]; - op2 = sp[-1]; - if (LIKELY(JS_VALUE_IS_BOTH_INT(op1, op2))) { - int64_t r; - r = (int64_t)JS_VALUE_GET_INT(op1) - JS_VALUE_GET_INT(op2); - if (UNLIKELY((int)r != r)) - goto binary_arith_slow; - sp[-2] = JS_NewInt32(ctx, r); - sp--; - } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) { - sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) - - JS_VALUE_GET_FLOAT64(op2)); - sp--; - } else { - goto binary_arith_slow; - } - } - BREAK; - CASE(OP_mul): - { - JSValue op1, op2; - double d; - op1 = sp[-2]; - op2 = sp[-1]; - if (LIKELY(JS_VALUE_IS_BOTH_INT(op1, op2))) { - int32_t v1, v2; - int64_t r; - v1 = JS_VALUE_GET_INT(op1); - v2 = JS_VALUE_GET_INT(op2); - r = (int64_t)v1 * v2; - if (UNLIKELY((int)r != r)) { -#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: - /* must duplicate otherwise the variable value may - be destroyed before JS code accesses it */ - op1 = JS_DupValue(ctx, op1); - if (js_unary_arith_slow(ctx, &op1 + 1, OP_inc)) - goto exception; - set_value(ctx, &var_buf[idx], op1); - } - } - BREAK; - CASE(OP_dec_loc): - { - JSValue op1; - int val; - int idx; - idx = *pc; - pc += 1; - op1 = var_buf[idx]; - if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) { - val = JS_VALUE_GET_INT(op1); - if (UNLIKELY(val == INT32_MIN)) - goto dec_loc_slow; - var_buf[idx] = JS_NewInt32(ctx, val - 1); - } else { - dec_loc_slow: - /* must duplicate otherwise the variable value may - be destroyed before JS code accesses it */ - op1 = JS_DupValue(ctx, op1); - if (js_unary_arith_slow(ctx, &op1 + 1, OP_dec)) - goto exception; - set_value(ctx, &var_buf[idx], op1); - } - } - BREAK; - CASE(OP_not): - { - JSValue op1; - op1 = sp[-1]; - if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) { - sp[-1] = JS_NewInt32(ctx, ~JS_VALUE_GET_INT(op1)); - } else { - 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: - /* XXX: check if strict mode */ - 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; - } - /* XXX: could merge to a single opcode */ - CASE(OP_typeof_is_undefined): - /* different from OP_is_undefined because of isHTMLDDA */ - if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_undefined) { - goto free_and_set_true; - } else { - goto free_and_set_false; - } - CASE(OP_typeof_is_function): - if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_function) { - goto free_and_set_true; - } else { - goto free_and_set_false; - } - free_and_set_true: - JS_FreeValue(ctx, sp[-1]); -#endif - set_true: - sp[-1] = JS_TRUE; - BREAK; - free_and_set_false: - JS_FreeValue(ctx, sp[-1]); - sp[-1] = JS_FALSE; - BREAK; - CASE(OP_invalid): - DEFAULT: - JS_ThrowInternalError(ctx, "invalid opcode: pc=%u opcode=0x%02x", - (int)(pc - b->byte_code_buf - 1), opcode); - goto exception; - } - } - exception: - if (is_backtrace_needed(ctx, rt->current_exception)) { - /* add the backtrace information now (it is not done - before if the exception happens in a bytecode - operation */ - sf->cur_pc = pc; - build_backtrace(ctx, rt->current_exception, NULL, 0, 0); - } - 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); -} - -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; -} - -/* 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; - } - } -} - -/* XXX: add a specific eval mode so that Function("}), ({") is rejected */ -JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv, int magic) -{ - JSFunctionKindEnum func_kind = magic; - int i, n, ret; - JSValue s, proto, obj = JS_UNDEFINED; - StringBuffer b_s, *b = &b_s; - string_buffer_init(ctx, b, 0); - string_buffer_putc8(b, '('); - if (func_kind == JS_FUNC_ASYNC || func_kind == JS_FUNC_ASYNC_GENERATOR) { - string_buffer_puts8(b, "async "); - } - string_buffer_puts8(b, "function"); - if (func_kind == JS_FUNC_GENERATOR || func_kind == JS_FUNC_ASYNC_GENERATOR) { - string_buffer_putc8(b, '*'); - } - string_buffer_puts8(b, " anonymous("); - n = argc - 1; - for(i = 0; i < n; i++) { - if (i != 0) { - string_buffer_putc8(b, ','); - } - if (string_buffer_concat_value(b, argv[i])) - goto fail; - } - string_buffer_puts8(b, "\n) {\n"); - if (n >= 0) { - if (string_buffer_concat_value(b, argv[n])) - goto fail; - } - string_buffer_puts8(b, "\n})"); - s = string_buffer_end(b); - if (JS_IsException(s)) - goto fail1; - obj = JS_EvalObject(ctx, ctx->global_obj, s, JS_EVAL_TYPE_INDIRECT, -1); - JS_FreeValue(ctx, s); - if (JS_IsException(obj)) - goto fail1; - if (!JS_IsUndefined(new_target)) { - /* set the prototype */ - proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype); - if (JS_IsException(proto)) - goto fail1; - if (!JS_IsObject(proto)) { - JSContext *realm; - JS_FreeValue(ctx, proto); - realm = JS_GetFunctionRealm(ctx, new_target); - if (!realm) - goto fail1; - proto = JS_DupValue(ctx, realm->class_proto[func_kind_to_class_id[func_kind]]); - } - ret = JS_SetPrototypeInternal(ctx, obj, proto, TRUE); - JS_FreeValue(ctx, proto); - if (ret < 0) - goto fail1; - } - return obj; - fail: - string_buffer_free(b); - fail1: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -/* JSAsyncFunctionState (used by generator and async functions) */ -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; -} - -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); - } -} - -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); -} - -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); -} diff --git a/third_party/quickjs/cutils.c b/third_party/quickjs/cutils.c deleted file mode 100644 index 65415593b..000000000 --- a/third_party/quickjs/cutils.c +++ /dev/null @@ -1,515 +0,0 @@ -/* - * C utilities - * - * Copyright (c) 2017 Fabrice Bellard - * Copyright (c) 2018 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/mem/mem.h" -#include "libc/str/str.h" -#include "third_party/quickjs/cutils.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - - -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 */ - -/* Note: at most 31 bits are encoded. At most UTF8_CHAR_LEN_MAX bytes - are output. */ -int unicode_to_utf8(uint8_t *buf, unsigned int c) -{ - uint8_t *q = buf; - - if (c < 0x80) { - *q++ = c; - } else { - if (c < 0x800) { - *q++ = (c >> 6) | 0xc0; - } else { - if (c < 0x10000) { - *q++ = (c >> 12) | 0xe0; - } else { - if (c < 0x00200000) { - *q++ = (c >> 18) | 0xf0; - } else { - if (c < 0x04000000) { - *q++ = (c >> 24) | 0xf8; - } else if (c < 0x80000000) { - *q++ = (c >> 30) | 0xfc; - *q++ = ((c >> 24) & 0x3f) | 0x80; - } else { - return 0; - } - *q++ = ((c >> 18) & 0x3f) | 0x80; - } - *q++ = ((c >> 12) & 0x3f) | 0x80; - } - *q++ = ((c >> 6) & 0x3f) | 0x80; - } - *q++ = (c & 0x3f) | 0x80; - } - return q - buf; -} - -static const unsigned int utf8_min_code[5] = { - 0x80, 0x800, 0x10000, 0x00200000, 0x04000000, -}; - -static const unsigned char utf8_first_code_mask[5] = { - 0x1f, 0xf, 0x7, 0x3, 0x1, -}; - -/* return -1 if error. *pp is not updated in this case. max_len must - be >= 1. The maximum length for a UTF8 byte sequence is 6 bytes. */ -int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp) -{ - int l, c, b, i; - - c = *p++; - if (c < 0x80) { - *pp = p; - return c; - } - switch(c) { - case 0xc0: case 0xc1: case 0xc2: case 0xc3: - case 0xc4: case 0xc5: case 0xc6: case 0xc7: - case 0xc8: case 0xc9: case 0xca: case 0xcb: - case 0xcc: case 0xcd: case 0xce: case 0xcf: - case 0xd0: case 0xd1: case 0xd2: case 0xd3: - case 0xd4: case 0xd5: case 0xd6: case 0xd7: - case 0xd8: case 0xd9: case 0xda: case 0xdb: - case 0xdc: case 0xdd: case 0xde: case 0xdf: - l = 1; - break; - case 0xe0: case 0xe1: case 0xe2: case 0xe3: - case 0xe4: case 0xe5: case 0xe6: case 0xe7: - case 0xe8: case 0xe9: case 0xea: case 0xeb: - case 0xec: case 0xed: case 0xee: case 0xef: - l = 2; - break; - case 0xf0: case 0xf1: case 0xf2: case 0xf3: - case 0xf4: case 0xf5: case 0xf6: case 0xf7: - l = 3; - break; - case 0xf8: case 0xf9: case 0xfa: case 0xfb: - l = 4; - break; - case 0xfc: case 0xfd: - l = 5; - break; - default: - return -1; - } - /* check that we have enough characters */ - if (l > (max_len - 1)) - return -1; - c &= utf8_first_code_mask[l - 1]; - for(i = 0; i < l; i++) { - b = *p++; - if (b < 0x80 || b >= 0xc0) - return -1; - c = (c << 6) | (b & 0x3f); - } - if (c < utf8_min_code[l - 1]) - return -1; - *pp = p; - return c; -} - -#if 0 - -#if defined(EMSCRIPTEN) || defined(__ANDROID__) - -static void *rqsort_arg; -static int (*rqsort_cmp)(const void *, const void *, void *); - -static int rqsort_cmp2(const void *p1, const void *p2) -{ - return rqsort_cmp(p1, p2, rqsort_arg); -} - -/* not reentrant, but not needed with emscripten */ -void rqsort(void *base, size_t nmemb, size_t size, - int (*cmp)(const void *, const void *, void *), - void *arg) -{ - rqsort_arg = arg; - rqsort_cmp = cmp; - qsort(base, nmemb, size, rqsort_cmp2); -} - -#endif - -#else - -typedef void (*exchange_f)(void *a, void *b, size_t size); -typedef int (*cmp_f)(const void *, const void *, void *opaque); - -static void exchange_bytes(void *a, void *b, size_t size) { - uint8_t *ap = (uint8_t *)a; - uint8_t *bp = (uint8_t *)b; - - while (size-- != 0) { - uint8_t t = *ap; - *ap++ = *bp; - *bp++ = t; - } -} - -static void exchange_one_byte(void *a, void *b, size_t size) { - uint8_t *ap = (uint8_t *)a; - uint8_t *bp = (uint8_t *)b; - uint8_t t = *ap; - *ap = *bp; - *bp = t; -} - -static void exchange_int16s(void *a, void *b, size_t size) { - uint16_t *ap = (uint16_t *)a; - uint16_t *bp = (uint16_t *)b; - - for (size /= sizeof(uint16_t); size-- != 0;) { - uint16_t t = *ap; - *ap++ = *bp; - *bp++ = t; - } -} - -static void exchange_one_int16(void *a, void *b, size_t size) { - uint16_t *ap = (uint16_t *)a; - uint16_t *bp = (uint16_t *)b; - uint16_t t = *ap; - *ap = *bp; - *bp = t; -} - -static void exchange_int32s(void *a, void *b, size_t size) { - uint32_t *ap = (uint32_t *)a; - uint32_t *bp = (uint32_t *)b; - - for (size /= sizeof(uint32_t); size-- != 0;) { - uint32_t t = *ap; - *ap++ = *bp; - *bp++ = t; - } -} - -static void exchange_one_int32(void *a, void *b, size_t size) { - uint32_t *ap = (uint32_t *)a; - uint32_t *bp = (uint32_t *)b; - uint32_t t = *ap; - *ap = *bp; - *bp = t; -} - -static void exchange_int64s(void *a, void *b, size_t size) { - uint64_t *ap = (uint64_t *)a; - uint64_t *bp = (uint64_t *)b; - - for (size /= sizeof(uint64_t); size-- != 0;) { - uint64_t t = *ap; - *ap++ = *bp; - *bp++ = t; - } -} - -static void exchange_one_int64(void *a, void *b, size_t size) { - uint64_t *ap = (uint64_t *)a; - uint64_t *bp = (uint64_t *)b; - uint64_t t = *ap; - *ap = *bp; - *bp = t; -} - -static void exchange_int128s(void *a, void *b, size_t size) { - uint64_t *ap = (uint64_t *)a; - uint64_t *bp = (uint64_t *)b; - - for (size /= sizeof(uint64_t) * 2; size-- != 0; ap += 2, bp += 2) { - uint64_t t = ap[0]; - uint64_t u = ap[1]; - ap[0] = bp[0]; - ap[1] = bp[1]; - bp[0] = t; - bp[1] = u; - } -} - -static void exchange_one_int128(void *a, void *b, size_t size) { - uint64_t *ap = (uint64_t *)a; - uint64_t *bp = (uint64_t *)b; - uint64_t t = ap[0]; - uint64_t u = ap[1]; - ap[0] = bp[0]; - ap[1] = bp[1]; - bp[0] = t; - bp[1] = u; -} - -static inline exchange_f exchange_func(const void *base, size_t size) { - switch (((uintptr_t)base | (uintptr_t)size) & 15) { - case 0: - if (size == sizeof(uint64_t) * 2) - return exchange_one_int128; - else - return exchange_int128s; - case 8: - if (size == sizeof(uint64_t)) - return exchange_one_int64; - else - return exchange_int64s; - case 4: - case 12: - if (size == sizeof(uint32_t)) - return exchange_one_int32; - else - return exchange_int32s; - case 2: - case 6: - case 10: - case 14: - if (size == sizeof(uint16_t)) - return exchange_one_int16; - else - return exchange_int16s; - default: - if (size == 1) - return exchange_one_byte; - else - return exchange_bytes; - } -} - -static void heapsortx(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque) -{ - uint8_t *basep = (uint8_t *)base; - size_t i, n, c, r; - exchange_f swap = exchange_func(base, size); - - if (nmemb > 1) { - i = (nmemb / 2) * size; - n = nmemb * size; - - while (i > 0) { - i -= size; - for (r = i; (c = r * 2 + size) < n; r = c) { - if (c < n - size && cmp(basep + c, basep + c + size, opaque) <= 0) - c += size; - if (cmp(basep + r, basep + c, opaque) > 0) - break; - swap(basep + r, basep + c, size); - } - } - for (i = n - size; i > 0; i -= size) { - swap(basep, basep + i, size); - - for (r = 0; (c = r * 2 + size) < i; r = c) { - if (c < i - size && cmp(basep + c, basep + c + size, opaque) <= 0) - c += size; - if (cmp(basep + r, basep + c, opaque) > 0) - break; - swap(basep + r, basep + c, size); - } - } - } -} - -static inline void *med3(void *a, void *b, void *c, cmp_f cmp, void *opaque) -{ - return cmp(a, b, opaque) < 0 ? - (cmp(b, c, opaque) < 0 ? b : (cmp(a, c, opaque) < 0 ? c : a )) : - (cmp(b, c, opaque) > 0 ? b : (cmp(a, c, opaque) < 0 ? a : c )); -} - -/* pointer based version with local stack and insertion sort threshhold */ -void rqsort(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque) -{ - struct { uint8_t *base; size_t count; int depth; } stack[50], *sp = stack; - uint8_t *ptr, *pi, *pj, *plt, *pgt, *top, *m; - size_t m4, i, lt, gt, span, span2; - int c, depth; - exchange_f swap = exchange_func(base, size); - exchange_f swap_block = exchange_func(base, size | 128); - - if (nmemb < 2 || size <= 0) - return; - - sp->base = (uint8_t *)base; - sp->count = nmemb; - sp->depth = 0; - sp++; - - while (sp > stack) { - sp--; - ptr = sp->base; - nmemb = sp->count; - depth = sp->depth; - - while (nmemb > 6) { - if (++depth > 50) { - /* depth check to ensure worst case logarithmic time */ - heapsortx(ptr, nmemb, size, cmp, opaque); - nmemb = 0; - break; - } - /* select median of 3 from 1/4, 1/2, 3/4 positions */ - /* should use median of 5 or 9? */ - m4 = (nmemb >> 2) * size; - m = med3(ptr + m4, ptr + 2 * m4, ptr + 3 * m4, cmp, opaque); - swap(ptr, m, size); /* move the pivot to the start or the array */ - i = lt = 1; - pi = plt = ptr + size; - gt = nmemb; - pj = pgt = top = ptr + nmemb * size; - for (;;) { - while (pi < pj && (c = cmp(ptr, pi, opaque)) >= 0) { - if (c == 0) { - swap(plt, pi, size); - lt++; - plt += size; - } - i++; - pi += size; - } - while (pi < (pj -= size) && (c = cmp(ptr, pj, opaque)) <= 0) { - if (c == 0) { - gt--; - pgt -= size; - swap(pgt, pj, size); - } - } - if (pi >= pj) - break; - swap(pi, pj, size); - i++; - pi += size; - } - /* array has 4 parts: - * from 0 to lt excluded: elements identical to pivot - * from lt to pi excluded: elements smaller than pivot - * from pi to gt excluded: elements greater than pivot - * from gt to n excluded: elements identical to pivot - */ - /* move elements identical to pivot in the middle of the array: */ - /* swap values in ranges [0..lt[ and [i-lt..i[ - swapping the smallest span between lt and i-lt is sufficient - */ - span = plt - ptr; - span2 = pi - plt; - lt = i - lt; - if (span > span2) - span = span2; - swap_block(ptr, pi - span, span); - /* swap values in ranges [gt..top[ and [i..top-(top-gt)[ - swapping the smallest span between top-gt and gt-i is sufficient - */ - span = top - pgt; - span2 = pgt - pi; - pgt = top - span2; - gt = nmemb - (gt - i); - if (span > span2) - span = span2; - swap_block(pi, top - span, span); - - /* now array has 3 parts: - * from 0 to lt excluded: elements smaller than pivot - * from lt to gt excluded: elements identical to pivot - * from gt to n excluded: elements greater than pivot - */ - /* stack the larger segment and keep processing the smaller one - to minimize stack use for pathological distributions */ - if (lt > nmemb - gt) { - sp->base = ptr; - sp->count = lt; - sp->depth = depth; - sp++; - ptr = pgt; - nmemb -= gt; - } else { - sp->base = pgt; - sp->count = nmemb - gt; - sp->depth = depth; - sp++; - nmemb = lt; - } - } - /* Use insertion sort for small fragments */ - for (pi = ptr + size, top = ptr + nmemb * size; pi < top; pi += size) { - for (pj = pi; pj > ptr && cmp(pj - size, pj, opaque) > 0; pj -= size) - swap(pj, pj - size, size); - } - } -} - -#endif diff --git a/third_party/quickjs/cutils.h b/third_party/quickjs/cutils.h deleted file mode 100644 index f53941960..000000000 --- a/third_party/quickjs/cutils.h +++ /dev/null @@ -1,259 +0,0 @@ -#ifndef COSMOPOLITAN_THIRD_PARTY_QUICKJS_CUTILS_H_ -#define COSMOPOLITAN_THIRD_PARTY_QUICKJS_CUTILS_H_ -#include "libc/intrin/bswap.h" -COSMOPOLITAN_C_START_ - -/* set if CPU is big endian */ -#undef WORDS_BIGENDIAN - -#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 countof -#define countof(x) (sizeof(x) / sizeof((x)[0])) -#endif - -typedef int BOOL; - -#ifndef FALSE -enum { - FALSE = 0, - TRUE = 1, -}; -#endif - -void pstrcpy(char *, int, const char *); -char *pstrcat(char *, int, const char *); -int strstart(const char *, const char *, const char **); -int has_suffix(const char *, const char *); - -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 */ -forceinline int clz32(unsigned int a) -{ - return __builtin_clz(a); -} - -/* WARNING: undefined if a = 0 */ -forceinline int clz64(uint64_t a) -{ - return __builtin_clzll(a); -} - -/* WARNING: undefined if a = 0 */ -forceinline int ctz32(unsigned int a) -{ - return __builtin_ctz(a); -} - -/* WARNING: undefined if a = 0 */ -forceinline int ctz64(uint64_t a) -{ - return __builtin_ctzll(a); -} - -struct thatispacked packed_u64 { - uint64_t v; -}; - -struct thatispacked packed_u32 { - uint32_t v; -}; - -struct thatispacked 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; -} - -forceinline uint16_t bswap16(uint16_t x) -{ - return bswap_16(x); -} - -forceinline uint32_t bswap32(uint32_t v) -{ - return bswap_32(v); -} - -forceinline uint64_t bswap64(uint64_t v) -{ - return bswap_64(v); -} - -/* 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 *); -void dbuf_init2(DynBuf *, void *, DynBufReallocFunc *); -int dbuf_realloc(DynBuf *, size_t); -int dbuf_write(DynBuf *, size_t, const uint8_t *, size_t); -int dbuf_put(DynBuf *, const uint8_t *, size_t); -int dbuf_put_self(DynBuf *, size_t, size_t); -int dbuf_putc(DynBuf *, uint8_t); -int dbuf_putstr(DynBuf *, const char *); -int dbuf_printf(DynBuf *, const char *, ...) printfesque(2); -void dbuf_free(DynBuf *); - -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 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); -} - -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 - -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); - -/* clang-format on */ -COSMOPOLITAN_C_END_ -#endif /* COSMOPOLITAN_THIRD_PARTY_QUICKJS_CUTILS_H_ */ diff --git a/third_party/quickjs/date.c b/third_party/quickjs/date.c deleted file mode 100644 index 7b6cb8402..000000000 --- a/third_party/quickjs/date.c +++ /dev/null @@ -1,1032 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/calls/struct/timeval.h" -#include "libc/calls/weirdtypes.h" -#include "libc/time/struct/tm.h" -#include "libc/time/time.h" -#include "third_party/quickjs/internal.h" -#include "third_party/quickjs/libregexp.h" -#include "third_party/quickjs/quickjs.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -#if 0 -/* OS dependent: return the UTC time in ms since 1970. */ -static JSValue js___date_now(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int64_t d; - struct timeval tv; - gettimeofday(&tv, NULL); - d = (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000); - return JS_NewInt64(ctx, d); -} -#endif - -/* OS dependent: return the UTC time in microseconds since 1970. */ -JSValue js___date_clock(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - int64_t d; - struct timeval tv; - gettimeofday(&tv, NULL); - d = (int64_t)tv.tv_sec * 1000000 + tv.tv_usec; - return JS_NewInt64(ctx, d); -} - -/* OS dependent. d = argv[0] is in ms from 1970. Return the difference - between UTC time and local time 'd' in minutes */ -static int getTimezoneOffset(int64_t time) { -#if defined(_WIN32) - /* XXX: TODO */ - return 0; -#else - time_t ti; - struct tm tm; - time /= 1000; /* convert to seconds */ - if (sizeof(time_t) == 4) { - /* on 32-bit systems, we need to clamp the time value to the - range of `time_t`. This is better than truncating values to - 32 bits and hopefully provides the same result as 64-bit - implementation of localtime_r. - */ - if ((time_t)-1 < 0) { - if (time < INT32_MIN) { - time = INT32_MIN; - } else if (time > INT32_MAX) { - time = INT32_MAX; - } - } else { - if (time < 0) { - time = 0; - } else if (time > UINT32_MAX) { - time = UINT32_MAX; - } - } - } - ti = time; - localtime_r(&ti, &tm); - return -tm.tm_gmtoff / 60; -#endif -} - -#if 0 -static JSValue js___date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - double dd; - - if (JS_ToFloat64(ctx, &dd, argv[0])) - return JS_EXCEPTION; - if (isnan(dd)) - return __JS_NewFloat64(ctx, dd); - else - return JS_NewInt32(ctx, getTimezoneOffset((int64_t)dd)); -} - -static JSValue js_get_prototype_from_ctor(JSContext *ctx, JSValueConst ctor, - JSValueConst def_proto) -{ - JSValue proto; - proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype); - if (JS_IsException(proto)) - return proto; - if (!JS_IsObject(proto)) { - JS_FreeValue(ctx, proto); - proto = JS_DupValue(ctx, def_proto); - } - return proto; -} - -/* create a new date object */ -static JSValue js___date_create(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj, proto; - proto = js_get_prototype_from_ctor(ctx, argv[0], argv[1]); - if (JS_IsException(proto)) - return proto; - obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_DATE); - JS_FreeValue(ctx, proto); - if (!JS_IsException(obj)) - JS_SetObjectData(ctx, obj, JS_DupValue(ctx, argv[2])); - return obj; -} -#endif - -static int64_t math_mod(int64_t a, int64_t b) { - /* return positive modulo */ - int64_t m = a % b; - return m + (m < 0) * b; -} - -static int64_t floor_div(int64_t a, int64_t b) { - /* integer division rounding toward -Infinity */ - int64_t m = a % b; - return (a - (m + (m < 0) * b)) / b; -} - -static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv); - -static __exception int JS_ThisTimeValue(JSContext *ctx, double *valp, JSValueConst this_val) -{ - if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(this_val); - if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data)) - return JS_ToFloat64(ctx, valp, p->u.object_data); - } - JS_ThrowTypeError(ctx, "not a Date object"); - return -1; -} - -static JSValue JS_SetThisTimeValue(JSContext *ctx, JSValueConst this_val, double v) -{ - if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(this_val); - if (p->class_id == JS_CLASS_DATE) { - JS_FreeValue(ctx, p->u.object_data); - p->u.object_data = JS_NewFloat64(ctx, v); - return JS_DupValue(ctx, p->u.object_data); - } - } - return JS_ThrowTypeError(ctx, "not a Date object"); -} - -static int64_t days_from_year(int64_t y) { - return 365 * (y - 1970) + floor_div(y - 1969, 4) - - floor_div(y - 1901, 100) + floor_div(y - 1601, 400); -} - -static int64_t days_in_year(int64_t y) { - return 365 + !(y % 4) - !(y % 100) + !(y % 400); -} - -/* return the year, update days */ -static int64_t year_from_days(int64_t *days) { - int64_t y, d1, nd, d = *days; - y = floor_div(d * 10000, 3652425) + 1970; - /* the initial approximation is very good, so only a few - iterations are necessary */ - for(;;) { - d1 = d - days_from_year(y); - if (d1 < 0) { - y--; - d1 += days_in_year(y); - } else { - nd = days_in_year(y); - if (d1 < nd) - break; - d1 -= nd; - y++; - } - } - *days = d1; - return y; -} - -static int const month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; -static char const month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; -static char const day_names[] = "SunMonTueWedThuFriSat"; - -static __exception int get_date_fields(JSContext *ctx, JSValueConst obj, - double fields[9], int is_local, int force) -{ - double dval; - int64_t d, days, wd, y, i, md, h, m, s, ms, tz = 0; - if (JS_ThisTimeValue(ctx, &dval, obj)) - return -1; - if (isnan(dval)) { - if (!force) - return FALSE; /* NaN */ - d = 0; /* initialize all fields to 0 */ - } else { - d = dval; - if (is_local) { - tz = -getTimezoneOffset(d); - d += tz * 60000; - } - } - /* result is >= 0, we can use % */ - h = math_mod(d, 86400000); - days = (d - h) / 86400000; - ms = h % 1000; - h = (h - ms) / 1000; - s = h % 60; - h = (h - s) / 60; - m = h % 60; - h = (h - m) / 60; - wd = math_mod(days + 4, 7); /* week day */ - y = year_from_days(&days); - for(i = 0; i < 11; i++) { - md = month_days[i]; - if (i == 1) - md += days_in_year(y) - 365; - if (days < md) - break; - days -= md; - } - fields[0] = y; - fields[1] = i; - fields[2] = days + 1; - fields[3] = h; - fields[4] = m; - fields[5] = s; - fields[6] = ms; - fields[7] = wd; - fields[8] = tz; - return TRUE; -} - -static double time_clip(double t) { - if (t >= -8.64e15 && t <= 8.64e15) - return trunc(t) + 0.0; /* convert -0 to +0 */ - else - return NAN; -} - -/* The spec mandates the use of 'double' and it fixes the order - of the operations */ -static double set_date_fields(double fields[], int is_local) { - int64_t y; - double days, d, h, m1; - int i, m, md; - m1 = fields[1]; - m = fmod(m1, 12); - if (m < 0) - m += 12; - y = (int64_t)(fields[0] + floor(m1 / 12)); - days = days_from_year(y); - for(i = 0; i < m; i++) { - md = month_days[i]; - if (i == 1) - md += days_in_year(y) - 365; - days += md; - } - days += fields[2] - 1; - h = fields[3] * 3600000 + fields[4] * 60000 + - fields[5] * 1000 + fields[6]; - d = days * 86400000 + h; - if (is_local) - d += getTimezoneOffset(d) * 60000; - return time_clip(d); -} - -static JSValue get_date_field(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - // get_date_field(obj, n, is_local) - double fields[9]; - int res, n, is_local; - is_local = magic & 0x0F; - n = (magic >> 4) & 0x0F; - res = get_date_fields(ctx, this_val, fields, is_local, 0); - if (res < 0) - return JS_EXCEPTION; - if (!res) - return JS_NAN; - if (magic & 0x100) { // getYear - fields[0] -= 1900; - } - return JS_NewFloat64(ctx, fields[n]); -} - -static JSValue set_date_field(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - // _field(obj, first_field, end_field, args, is_local) - double fields[9]; - int res, first_field, end_field, is_local, i, n; - double d, a; - d = NAN; - first_field = (magic >> 8) & 0x0F; - end_field = (magic >> 4) & 0x0F; - is_local = magic & 0x0F; - res = get_date_fields(ctx, this_val, fields, is_local, first_field == 0); - if (res < 0) - return JS_EXCEPTION; - if (res && argc > 0) { - n = end_field - first_field; - if (argc < n) - n = argc; - for(i = 0; i < n; i++) { - if (JS_ToFloat64(ctx, &a, argv[i])) - return JS_EXCEPTION; - if (!isfinite(a)) - goto done; - fields[first_field + i] = trunc(a); - } - d = set_date_fields(fields, is_local); - } -done: - return JS_SetThisTimeValue(ctx, this_val, d); -} - -/* fmt: - 0: toUTCString: "Tue, 02 Jan 2018 23:04:46 GMT" - 1: toString: "Wed Jan 03 2018 00:05:22 GMT+0100 (CET)" - 2: toISOString: "2018-01-02T23:02:56.927Z" - 3: toLocaleString: "1/2/2018, 11:40:40 PM" - part: 1=date, 2=time 3=all - XXX: should use a variant of strftime(). - */ -static JSValue get_date_string(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - // _string(obj, fmt, part) - char buf[64]; - double fields[9]; - int res, fmt, part, pos; - int y, mon, d, h, m, s, ms, wd, tz; - fmt = (magic >> 4) & 0x0F; - part = magic & 0x0F; - res = get_date_fields(ctx, this_val, fields, fmt & 1, 0); - if (res < 0) - return JS_EXCEPTION; - if (!res) { - if (fmt == 2) - return JS_ThrowRangeError(ctx, "Date value is NaN"); - else - return JS_NewString(ctx, "Invalid Date"); - } - y = fields[0]; - mon = fields[1]; - d = fields[2]; - h = fields[3]; - m = fields[4]; - s = fields[5]; - ms = fields[6]; - wd = fields[7]; - tz = fields[8]; - pos = 0; - if (part & 1) { /* date part */ - switch(fmt) { - case 0: - pos += snprintf(buf + pos, sizeof(buf) - pos, - "%.3s, %02d %.3s %0*d ", - day_names + wd * 3, d, - month_names + mon * 3, 4 + (y < 0), y); - break; - case 1: - pos += snprintf(buf + pos, sizeof(buf) - pos, - "%.3s %.3s %02d %0*d", - day_names + wd * 3, - month_names + mon * 3, d, 4 + (y < 0), y); - if (part == 3) { - buf[pos++] = ' '; - } - break; - case 2: - if (y >= 0 && y <= 9999) { - pos += snprintf(buf + pos, sizeof(buf) - pos, - "%04d", y); - } else { - pos += snprintf(buf + pos, sizeof(buf) - pos, - "%+07d", y); - } - pos += snprintf(buf + pos, sizeof(buf) - pos, - "-%02d-%02dT", mon + 1, d); - break; - case 3: - pos += snprintf(buf + pos, sizeof(buf) - pos, - "%02d/%02d/%0*d", mon + 1, d, 4 + (y < 0), y); - if (part == 3) { - buf[pos++] = ','; - buf[pos++] = ' '; - } - break; - } - } - if (part & 2) { /* time part */ - switch(fmt) { - case 0: - pos += snprintf(buf + pos, sizeof(buf) - pos, - "%02d:%02d:%02d GMT", h, m, s); - break; - case 1: - pos += snprintf(buf + pos, sizeof(buf) - pos, - "%02d:%02d:%02d GMT", h, m, s); - if (tz < 0) { - buf[pos++] = '-'; - tz = -tz; - } else { - buf[pos++] = '+'; - } - /* tz is >= 0, can use % */ - pos += snprintf(buf + pos, sizeof(buf) - pos, - "%02d%02d", tz / 60, tz % 60); - /* XXX: tack the time zone code? */ - break; - case 2: - pos += snprintf(buf + pos, sizeof(buf) - pos, - "%02d:%02d:%02d.%03dZ", h, m, s, ms); - break; - case 3: - pos += snprintf(buf + pos, sizeof(buf) - pos, - "%02d:%02d:%02d %cM", (h + 11) % 12 + 1, m, s, - (h < 12) ? 'A' : 'P'); - break; - } - } - return JS_NewStringLen(ctx, buf, pos); -} - -/* OS dependent: return the UTC time in ms since 1970. */ -static int64_t date_now(void) { - struct timeval tv; - gettimeofday(&tv, NULL); - return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000); -} - -static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) -{ - // Date(y, mon, d, h, m, s, ms) - JSValue rv; - int i, n; - double a, val; - if (JS_IsUndefined(new_target)) { - /* invoked as function */ - argc = 0; - } - n = argc; - if (n == 0) { - val = date_now(); - } else if (n == 1) { - JSValue v, dv; - if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(argv[0]); - if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data)) { - if (JS_ToFloat64(ctx, &val, p->u.object_data)) - return JS_EXCEPTION; - val = time_clip(val); - goto has_val; - } - } - v = JS_ToPrimitive(ctx, argv[0], HINT_NONE); - if (JS_IsString(v)) { - dv = js_Date_parse(ctx, JS_UNDEFINED, 1, (JSValueConst *)&v); - JS_FreeValue(ctx, v); - if (JS_IsException(dv)) - return JS_EXCEPTION; - if (JS_ToFloat64Free(ctx, &val, dv)) - return JS_EXCEPTION; - } else { - if (JS_ToFloat64Free(ctx, &val, v)) - return JS_EXCEPTION; - } - val = time_clip(val); - } else { - double fields[] = { 0, 0, 1, 0, 0, 0, 0 }; - if (n > 7) - n = 7; - for(i = 0; i < n; i++) { - if (JS_ToFloat64(ctx, &a, argv[i])) - return JS_EXCEPTION; - if (!isfinite(a)) - break; - fields[i] = trunc(a); - if (i == 0 && fields[0] >= 0 && fields[0] < 100) - fields[0] += 1900; - } - val = (i == n) ? set_date_fields(fields, 1) : NAN; - } -has_val: -#if 0 - JSValueConst args[3]; - args[0] = new_target; - args[1] = ctx->class_proto[JS_CLASS_DATE]; - args[2] = JS_NewFloat64(ctx, val); - rv = js___date_create(ctx, JS_UNDEFINED, 3, args); -#else - rv = js_create_from_ctor(ctx, new_target, JS_CLASS_DATE); - if (!JS_IsException(rv)) - JS_SetObjectData(ctx, rv, JS_NewFloat64(ctx, val)); -#endif - if (!JS_IsException(rv) && JS_IsUndefined(new_target)) { - /* invoked as a function, return (new Date()).toString(); */ - JSValue s; - s = get_date_string(ctx, rv, 0, NULL, 0x13); - JS_FreeValue(ctx, rv); - rv = s; - } - return rv; -} - -static JSValue js_Date_UTC(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // UTC(y, mon, d, h, m, s, ms) - double fields[] = { 0, 0, 1, 0, 0, 0, 0 }; - int i, n; - double a; - n = argc; - if (n == 0) - return JS_NAN; - if (n > 7) - n = 7; - for(i = 0; i < n; i++) { - if (JS_ToFloat64(ctx, &a, argv[i])) - return JS_EXCEPTION; - if (!isfinite(a)) - return JS_NAN; - fields[i] = trunc(a); - if (i == 0 && fields[0] >= 0 && fields[0] < 100) - fields[0] += 1900; - } - return JS_NewFloat64(ctx, set_date_fields(fields, 0)); -} - -static void string_skip_spaces(JSString *sp, int *pp) { - while (*pp < sp->len && string_get(sp, *pp) == ' ') - *pp += 1; -} - -static void string_skip_non_spaces(JSString *sp, int *pp) { - while (*pp < sp->len && string_get(sp, *pp) != ' ') - *pp += 1; -} - -/* parse a numeric field with an optional sign if accept_sign is TRUE */ -static int string_get_digits(JSString *sp, int *pp, int64_t *pval) { - int64_t v = 0; - int c, p = *pp, p_start; - if (p >= sp->len) - return -1; - p_start = p; - while (p < sp->len) { - c = string_get(sp, p); - if (!(c >= '0' && c <= '9')) { - if (p == p_start) - return -1; - else - break; - } - v = v * 10 + c - '0'; - p++; - } - *pval = v; - *pp = p; - return 0; -} - -static int string_get_signed_digits(JSString *sp, int *pp, int64_t *pval) { - int res, sgn, p = *pp; - if (p >= sp->len) - return -1; - sgn = string_get(sp, p); - if (sgn == '-' || sgn == '+') - p++; - res = string_get_digits(sp, &p, pval); - if (res == 0 && sgn == '-') - *pval = -*pval; - *pp = p; - return res; -} - -/* parse a fixed width numeric field */ -static int string_get_fixed_width_digits(JSString *sp, int *pp, int n, int64_t *pval) { - int64_t v = 0; - int i, c, p = *pp; - for(i = 0; i < n; i++) { - if (p >= sp->len) - return -1; - c = string_get(sp, p); - if (!(c >= '0' && c <= '9')) - return -1; - v = v * 10 + c - '0'; - p++; - } - *pval = v; - *pp = p; - return 0; -} - -static int string_get_milliseconds(JSString *sp, int *pp, int64_t *pval) { - /* parse milliseconds as a fractional part, round to nearest */ - /* XXX: the spec does not indicate which rounding should be used */ - int mul = 1000, ms = 0, p = *pp, c, p_start; - if (p >= sp->len) - return -1; - p_start = p; - while (p < sp->len) { - c = string_get(sp, p); - if (!(c >= '0' && c <= '9')) { - if (p == p_start) - return -1; - else - break; - } - if (mul == 1 && c >= '5') - ms += 1; - ms += (c - '0') * (mul /= 10); - p++; - } - *pval = ms; - *pp = p; - return 0; -} - - -static int find_abbrev(JSString *sp, int p, const char *list, int count) { - int n, i; - if (p + 3 <= sp->len) { - for (n = 0; n < count; n++) { - for (i = 0; i < 3; i++) { - if (string_get(sp, p + i) != month_names[n * 3 + i]) - goto next; - } - return n; - next:; - } - } - return -1; -} - -static int string_get_month(JSString *sp, int *pp, int64_t *pval) { - int n; - string_skip_spaces(sp, pp); - n = find_abbrev(sp, *pp, month_names, 12); - if (n < 0) - return -1; - *pval = n; - *pp += 3; - return 0; -} - -static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // parse(s) - JSValue s, rv; - int64_t fields[] = { 0, 1, 1, 0, 0, 0, 0 }; - double fields1[7]; - int64_t tz, hh, mm; - double d; - int p, i, c, sgn, l; - JSString *sp; - BOOL is_local; - rv = JS_NAN; - s = JS_ToString(ctx, argv[0]); - if (JS_IsException(s)) - return JS_EXCEPTION; - sp = JS_VALUE_GET_STRING(s); - p = 0; - if (p < sp->len && (((c = string_get(sp, p)) >= '0' && c <= '9') || c == '+' || c == '-')) { - /* ISO format */ - /* year field can be negative */ - if (string_get_signed_digits(sp, &p, &fields[0])) - goto done; - for (i = 1; i < 7; i++) { - if (p >= sp->len) - break; - switch(i) { - case 1: - case 2: - c = '-'; - break; - case 3: - c = 'T'; - break; - case 4: - case 5: - c = ':'; - break; - case 6: - c = '.'; - break; - } - if (string_get(sp, p) != c) - break; - p++; - if (i == 6) { - if (string_get_milliseconds(sp, &p, &fields[i])) - goto done; - } else { - if (string_get_digits(sp, &p, &fields[i])) - goto done; - } - } - /* no time: UTC by default */ - is_local = (i > 3); - fields[1] -= 1; - /* parse the time zone offset if present: [+-]HH:mm or [+-]HHmm */ - tz = 0; - if (p < sp->len) { - sgn = string_get(sp, p); - if (sgn == '+' || sgn == '-') { - p++; - l = sp->len - p; - if (l != 4 && l != 5) - goto done; - if (string_get_fixed_width_digits(sp, &p, 2, &hh)) - goto done; - if (l == 5) { - if (string_get(sp, p) != ':') - goto done; - p++; - } - if (string_get_fixed_width_digits(sp, &p, 2, &mm)) - goto done; - tz = hh * 60 + mm; - if (sgn == '-') - tz = -tz; - is_local = FALSE; - } else if (sgn == 'Z') { - p++; - is_local = FALSE; - } else { - goto done; - } - /* error if extraneous characters */ - if (p != sp->len) - goto done; - } - } else { - /* toString or toUTCString format */ - /* skip the day of the week */ - string_skip_non_spaces(sp, &p); - string_skip_spaces(sp, &p); - if (p >= sp->len) - goto done; - c = string_get(sp, p); - if (c >= '0' && c <= '9') { - /* day of month first */ - if (string_get_digits(sp, &p, &fields[2])) - goto done; - if (string_get_month(sp, &p, &fields[1])) - goto done; - } else { - /* month first */ - if (string_get_month(sp, &p, &fields[1])) - goto done; - string_skip_spaces(sp, &p); - if (string_get_digits(sp, &p, &fields[2])) - goto done; - } - /* year */ - string_skip_spaces(sp, &p); - if (string_get_signed_digits(sp, &p, &fields[0])) - goto done; - /* hour, min, seconds */ - string_skip_spaces(sp, &p); - for(i = 0; i < 3; i++) { - if (i == 1 || i == 2) { - if (p >= sp->len) - goto done; - if (string_get(sp, p) != ':') - goto done; - p++; - } - if (string_get_digits(sp, &p, &fields[3 + i])) - goto done; - } - // XXX: parse optional milliseconds? - /* parse the time zone offset if present: [+-]HHmm */ - is_local = FALSE; - tz = 0; - for (tz = 0; p < sp->len; p++) { - sgn = string_get(sp, p); - if (sgn == '+' || sgn == '-') { - p++; - if (string_get_fixed_width_digits(sp, &p, 2, &hh)) - goto done; - if (string_get_fixed_width_digits(sp, &p, 2, &mm)) - goto done; - tz = hh * 60 + mm; - if (sgn == '-') - tz = -tz; - break; - } - } - } - for(i = 0; i < 7; i++) - fields1[i] = fields[i]; - d = set_date_fields(fields1, is_local) - tz * 60000; - rv = JS_NewFloat64(ctx, d); -done: - JS_FreeValue(ctx, s); - return rv; -} - -static JSValue js_Date_now(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // now() - return JS_NewInt64(ctx, date_now()); -} - -static JSValue js_date_Symbol_toPrimitive(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // Symbol_toPrimitive(hint) - JSValueConst obj = this_val; - JSAtom hint = JS_ATOM_NULL; - int hint_num; - if (!JS_IsObject(obj)) - return JS_ThrowTypeErrorNotAnObject(ctx); - if (JS_IsString(argv[0])) { - hint = JS_ValueToAtom(ctx, argv[0]); - if (hint == JS_ATOM_NULL) - return JS_EXCEPTION; - JS_FreeAtom(ctx, hint); - } - switch (hint) { - case JS_ATOM_number: -#ifdef CONFIG_BIGNUM - case JS_ATOM_integer: -#endif - hint_num = HINT_NUMBER; - break; - case JS_ATOM_string: - case JS_ATOM_default: - hint_num = HINT_STRING; - break; - default: - return JS_ThrowTypeError(ctx, "invalid hint"); - } - return JS_ToPrimitive(ctx, obj, hint_num | HINT_FORCE_ORDINARY); -} - -static JSValue js_date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // getTimezoneOffset() - double v; - if (JS_ThisTimeValue(ctx, &v, this_val)) - return JS_EXCEPTION; - if (isnan(v)) - return JS_NAN; - else - return JS_NewInt64(ctx, getTimezoneOffset((int64_t)trunc(v))); -} - -static JSValue js_date_getTime(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // getTime() - double v; - - if (JS_ThisTimeValue(ctx, &v, this_val)) - return JS_EXCEPTION; - return JS_NewFloat64(ctx, v); -} - -static JSValue js_date_setTime(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // setTime(v) - double v; - - if (JS_ThisTimeValue(ctx, &v, this_val) || JS_ToFloat64(ctx, &v, argv[0])) - return JS_EXCEPTION; - return JS_SetThisTimeValue(ctx, this_val, time_clip(v)); -} - -static JSValue js_date_setYear(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // setYear(y) - double y; - JSValueConst args[1]; - - if (JS_ThisTimeValue(ctx, &y, this_val) || JS_ToFloat64(ctx, &y, argv[0])) - return JS_EXCEPTION; - y = +y; - if (isfinite(y)) { - y = trunc(y); - if (y >= 0 && y < 100) - y += 1900; - } - args[0] = JS_NewFloat64(ctx, y); - return set_date_field(ctx, this_val, 1, args, 0x011); -} - -static JSValue js_date_toJSON(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // toJSON(key) - JSValue obj, tv, method, rv; - double d; - rv = JS_EXCEPTION; - tv = JS_UNDEFINED; - obj = JS_ToObject(ctx, this_val); - tv = JS_ToPrimitive(ctx, obj, HINT_NUMBER); - if (JS_IsException(tv)) - goto exception; - if (JS_IsNumber(tv)) { - if (JS_ToFloat64(ctx, &d, tv) < 0) - goto exception; - if (!isfinite(d)) { - rv = JS_NULL; - goto done; - } - } - method = JS_GetPropertyStr(ctx, obj, "toISOString"); - if (JS_IsException(method)) - goto exception; - if (!JS_IsFunction(ctx, method)) { - JS_ThrowTypeError(ctx, "object needs toISOString method"); - JS_FreeValue(ctx, method); - goto exception; - } - rv = JS_CallFree(ctx, method, obj, 0, NULL); -exception: -done: - JS_FreeValue(ctx, obj); - JS_FreeValue(ctx, tv); - return rv; -} - -static const JSCFunctionListEntry js_date_funcs[] = { - JS_CFUNC_DEF("now", 0, js_Date_now ), - JS_CFUNC_DEF("parse", 1, js_Date_parse ), - JS_CFUNC_DEF("UTC", 7, js_Date_UTC ), -}; - -static const JSCFunctionListEntry js_date_proto_funcs[] = { - JS_CFUNC_DEF("valueOf", 0, js_date_getTime ), - JS_CFUNC_MAGIC_DEF("toString", 0, get_date_string, 0x13 ), - JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_date_Symbol_toPrimitive ), - JS_CFUNC_MAGIC_DEF("toUTCString", 0, get_date_string, 0x03 ), - JS_ALIAS_DEF("toGMTString", "toUTCString" ), - JS_CFUNC_MAGIC_DEF("toISOString", 0, get_date_string, 0x23 ), - JS_CFUNC_MAGIC_DEF("toDateString", 0, get_date_string, 0x11 ), - JS_CFUNC_MAGIC_DEF("toTimeString", 0, get_date_string, 0x12 ), - JS_CFUNC_MAGIC_DEF("toLocaleString", 0, get_date_string, 0x33 ), - JS_CFUNC_MAGIC_DEF("toLocaleDateString", 0, get_date_string, 0x31 ), - JS_CFUNC_MAGIC_DEF("toLocaleTimeString", 0, get_date_string, 0x32 ), - JS_CFUNC_DEF("getTimezoneOffset", 0, js_date_getTimezoneOffset ), - JS_CFUNC_DEF("getTime", 0, js_date_getTime ), - JS_CFUNC_MAGIC_DEF("getYear", 0, get_date_field, 0x101 ), - JS_CFUNC_MAGIC_DEF("getFullYear", 0, get_date_field, 0x01 ), - JS_CFUNC_MAGIC_DEF("getUTCFullYear", 0, get_date_field, 0x00 ), - JS_CFUNC_MAGIC_DEF("getMonth", 0, get_date_field, 0x11 ), - JS_CFUNC_MAGIC_DEF("getUTCMonth", 0, get_date_field, 0x10 ), - JS_CFUNC_MAGIC_DEF("getDate", 0, get_date_field, 0x21 ), - JS_CFUNC_MAGIC_DEF("getUTCDate", 0, get_date_field, 0x20 ), - JS_CFUNC_MAGIC_DEF("getHours", 0, get_date_field, 0x31 ), - JS_CFUNC_MAGIC_DEF("getUTCHours", 0, get_date_field, 0x30 ), - JS_CFUNC_MAGIC_DEF("getMinutes", 0, get_date_field, 0x41 ), - JS_CFUNC_MAGIC_DEF("getUTCMinutes", 0, get_date_field, 0x40 ), - JS_CFUNC_MAGIC_DEF("getSeconds", 0, get_date_field, 0x51 ), - JS_CFUNC_MAGIC_DEF("getUTCSeconds", 0, get_date_field, 0x50 ), - JS_CFUNC_MAGIC_DEF("getMilliseconds", 0, get_date_field, 0x61 ), - JS_CFUNC_MAGIC_DEF("getUTCMilliseconds", 0, get_date_field, 0x60 ), - JS_CFUNC_MAGIC_DEF("getDay", 0, get_date_field, 0x71 ), - JS_CFUNC_MAGIC_DEF("getUTCDay", 0, get_date_field, 0x70 ), - JS_CFUNC_DEF("setTime", 1, js_date_setTime ), - JS_CFUNC_MAGIC_DEF("setMilliseconds", 1, set_date_field, 0x671 ), - JS_CFUNC_MAGIC_DEF("setUTCMilliseconds", 1, set_date_field, 0x670 ), - JS_CFUNC_MAGIC_DEF("setSeconds", 2, set_date_field, 0x571 ), - JS_CFUNC_MAGIC_DEF("setUTCSeconds", 2, set_date_field, 0x570 ), - JS_CFUNC_MAGIC_DEF("setMinutes", 3, set_date_field, 0x471 ), - JS_CFUNC_MAGIC_DEF("setUTCMinutes", 3, set_date_field, 0x470 ), - JS_CFUNC_MAGIC_DEF("setHours", 4, set_date_field, 0x371 ), - JS_CFUNC_MAGIC_DEF("setUTCHours", 4, set_date_field, 0x370 ), - JS_CFUNC_MAGIC_DEF("setDate", 1, set_date_field, 0x231 ), - JS_CFUNC_MAGIC_DEF("setUTCDate", 1, set_date_field, 0x230 ), - JS_CFUNC_MAGIC_DEF("setMonth", 2, set_date_field, 0x131 ), - JS_CFUNC_MAGIC_DEF("setUTCMonth", 2, set_date_field, 0x130 ), - JS_CFUNC_DEF("setYear", 1, js_date_setYear ), - JS_CFUNC_MAGIC_DEF("setFullYear", 3, set_date_field, 0x031 ), - JS_CFUNC_MAGIC_DEF("setUTCFullYear", 3, set_date_field, 0x030 ), - JS_CFUNC_DEF("toJSON", 1, js_date_toJSON ), -}; - -void JS_AddIntrinsicDate(JSContext *ctx) -{ - JSValueConst obj; - /* Date */ - ctx->class_proto[JS_CLASS_DATE] = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_DATE], js_date_proto_funcs, - countof(js_date_proto_funcs)); - obj = JS_NewGlobalCConstructor(ctx, "Date", js_date_constructor, 7, - ctx->class_proto[JS_CLASS_DATE]); - JS_SetPropertyFunctionList(ctx, obj, js_date_funcs, countof(js_date_funcs)); -} diff --git a/third_party/quickjs/dbuf.c b/third_party/quickjs/dbuf.c deleted file mode 100644 index fe2261e8c..000000000 --- a/third_party/quickjs/dbuf.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/mem/mem.h" -#include "libc/str/str.h" -#include "third_party/quickjs/internal.h" -#include "third_party/quickjs/libregexp.h" -#include "third_party/quickjs/quickjs.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -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) -{ - bzero(s, 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 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); - } - bzero(s, sizeof(*s)); -} - -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; - } - } -} - -void dbuf_put_sleb128(DynBuf *s, int32_t v1) -{ - uint32_t v = v1; - dbuf_put_leb128(s, (2 * v) ^ -(v >> 31)); -} diff --git a/third_party/quickjs/diglet.c b/third_party/quickjs/diglet.c deleted file mode 100644 index 62c4b1498..000000000 --- a/third_party/quickjs/diglet.c +++ /dev/null @@ -1,30 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2021 Justine Alexandra Roberts Tunney │ -│ │ -│ Permission to use, copy, modify, and/or distribute this software for │ -│ any purpose with or without fee is hereby granted, provided that the │ -│ above copyright notice and this permission notice appear in all copies. │ -│ │ -│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -│ PERFORMANCE OF THIS SOFTWARE. │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "third_party/quickjs/diglet.h" - -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; -} diff --git a/third_party/quickjs/diglet.h b/third_party/quickjs/diglet.h deleted file mode 100644 index ac7ec9c52..000000000 --- a/third_party/quickjs/diglet.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef COSMOPOLITAN_THIRD_PARTY_QUICKJS_DIGLET_H_ -#define COSMOPOLITAN_THIRD_PARTY_QUICKJS_DIGLET_H_ -COSMOPOLITAN_C_START_ - -int to_digit(int); - -COSMOPOLITAN_C_END_ -#endif /* COSMOPOLITAN_THIRD_PARTY_QUICKJS_DIGLET_H_ */ diff --git a/third_party/quickjs/doc/jsbignum.html b/third_party/quickjs/doc/jsbignum.html deleted file mode 100644 index ab31612bd..000000000 --- a/third_party/quickjs/doc/jsbignum.html +++ /dev/null @@ -1,734 +0,0 @@ - - - - -Javascript Bignum Extensions - - - - - - - - - - - - - - - -

Javascript Bignum Extensions

- - -

Table of Contents

- - - - - -

1 Introduction

- -

The Bignum extensions add the following features to the Javascript -language while being 100% backward compatible: -

- - -

The extensions are independent from each other except the math -mode which relies on BigFloat and operator overloading. -

- -

2 Operator overloading

- -

Operator overloading is inspired from the proposal available at -https://github.com/tc39/proposal-operator-overloading/. It -implements the same dispatch logic but finds the operator sets by -looking at the Symbol.operatorSet property in the objects. The -changes were done in order to simplify the implementation. -

-

More precisely, the following modifications were made: -

- - - -

3 BigInt extensions

- -

A few properties are added to the BigInt object: -

-
-
tdiv(a, b)
-

Return trunc(a/b). b = 0 raises a RangeError -exception. -

-
-
fdiv(a, b)
-

Return \lfloor a/b \rfloor. b = 0 raises a RangeError -exception. -

-
-
cdiv(a, b)
-

Return \lceil a/b \rceil. b = 0 raises a RangeError -exception. -

-
-
ediv(a, b)
-

Return sgn(b) \lfloor a/{|b|} \rfloor (Euclidian -division). b = 0 raises a RangeError exception. -

-
-
tdivrem(a, b)
-
fdivrem(a, b)
-
cdivrem(a, b)
-
edivrem(a, b)
-

Return an array of two elements. The first element is the quotient, -the second is the remainder. The same rounding is done as the -corresponding division operation. -

-
-
sqrt(a)
-

Return \lfloor \sqrt(a) \rfloor. A RangeError exception is -raised if a < 0. -

-
-
sqrtrem(a)
-

Return an array of two elements. The first element is \lfloor -\sqrt{a} \rfloor. The second element is a-\lfloor \sqrt{a} -\rfloor^2. A RangeError exception is raised if a < 0. -

-
-
floorLog2(a)
-

Return -1 if a \leq 0 otherwise return \lfloor \log2(a) \rfloor. -

-
-
ctz(a)
-

Return the number of trailing zeros in the two’s complement binary representation of a. Return -1 if a=0. -

-
-
- - -

4 BigFloat

- - -

4.1 Introduction

- -

This extension adds the BigFloat primitive type. The -BigFloat type represents floating point numbers in base 2 -with the IEEE 754 semantics. A floating -point number is represented as a sign, mantissa and exponent. The -special values NaN, +/-Infinity, +0 and -0 -are supported. The mantissa and exponent can have any bit length with -an implementation specific minimum and maximum. -

- -

4.2 Floating point rounding

- -

Each floating point operation operates with infinite precision and -then rounds the result according to the specified floating point -environment (BigFloatEnv object). The status flags of the -environment are also set according to the result of the operation. -

-

If no floating point environment is provided, the global floating -point environment is used. -

-

The rounding mode of the global floating point environment is always -RNDN (“round to nearest with ties to even”)1. The status flags of the global environment cannot be -read2. The precision of the global environment is -BigFloatEnv.prec. The number of exponent bits of the global -environment is BigFloatEnv.expBits. The global environment -subnormal flag is set to true. -

-

For example, prec = 53 and expBits = 11 exactly give -the same precision as the IEEE 754 64 bit floating point format. The -default precision is prec = 113 and expBits = 15 (IEEE -754 128 bit floating point format). -

-

The global floating point environment can only be modified temporarily -when calling a function (see BigFloatEnv.setPrec). Hence a -function can change the global floating point environment for its -callees but not for its caller. -

- -

4.3 Operators

- -

The builtin operators are extended so that a BigFloat is returned if -at least one operand is a BigFloat. The computations are always done -with infinite precision and rounded according to the global floating -point environment. -

-

typeof applied on a BigFloat returns bigfloat. -

-

BigFloat can be compared with all the other numeric types and the -result follows the expected mathematical relations. -

-

However, since BigFloat and Number are different types they are never -equal when using the strict comparison operators (e.g. 0.0 === -0.0l is false). -

- -

4.4 BigFloat literals

- -

BigFloat literals are floating point numbers with a trailing l -suffix. BigFloat literals have an infinite precision. They are rounded -according to the global floating point environment when they are -evaluated.3 -

- -

4.5 Builtin Object changes

- - -

4.5.1 BigFloat function

- -

The BigFloat function cannot be invoked as a constructor. When -invoked as a function: the parameter is converted to a primitive -type. If the result is a numeric type, it is converted to BigFloat -without rounding. If the result is a string, it is converted to -BigFloat using the precision of the global floating point environment. -

-

BigFloat properties: -

-
-
LN2
-
PI
-

Getter. Return the value of the corresponding mathematical constant -rounded to nearest, ties to even with the current global -precision. The constant values are cached for small precisions. -

-
-
MIN_VALUE
-
MAX_VALUE
-
EPSILON
-

Getter. Return the minimum, maximum and epsilon BigFloat values -(same definition as the corresponding Number constants). -

-
-
fpRound(a[, e])
-

Round the floating point number a according to the floating -point environment e or the global environment if e is -undefined. -

-
-
parseFloat(a[, radix[, e]])
-

Parse the string a as a floating point number in radix -radix. The radix is 0 (default) or from 2 to 36. The radix 0 -means radix 10 unless there is a hexadecimal or binary prefix. The -result is rounded according to the floating point environment e -or the global environment if e is undefined. -

-
-
isFinite(a)
-

Return true if a is a finite bigfloat. -

-
-
isNaN(a)
-

Return true if a is a NaN bigfloat. -

-
-
add(a, b[, e])
-
sub(a, b[, e])
-
mul(a, b[, e])
-
div(a, b[, e])
-

Perform the specified floating point operation and round the floating -point number a according to the floating point environment -e or the global environment if e is undefined. If -e is specified, the floating point status flags are updated. -

-
-
floor(x)
-
ceil(x)
-
round(x)
-
trunc(x)
-

Round to an integer. No additional rounding is performed. -

-
-
abs(x)
-

Return the absolute value of x. No additional rounding is performed. -

-
-
fmod(x, y[, e])
-
remainder(x, y[, e])
-

Floating point remainder. The quotient is truncated to zero (fmod) or -to the nearest integer with ties to even (remainder). e is an -optional floating point environment. -

-
-
sqrt(x[, e])
-

Square root. Return a rounded floating point number. e is an -optional floating point environment. -

-
-
sin(x[, e])
-
cos(x[, e])
-
tan(x[, e])
-
asin(x[, e])
-
acos(x[, e])
-
atan(x[, e])
-
atan2(x, y[, e])
-
exp(x[, e])
-
log(x[, e])
-
pow(x, y[, e])
-

Transcendental operations. Return a rounded floating point -number. e is an optional floating point environment. -

-
-
- - -

4.5.2 BigFloat.prototype

- -

The following properties are modified: -

-
-
valueOf()
-

Return the bigfloat primitive value corresponding to this. -

-
-
toString(radix)
-
-

For floating point numbers: -

-
    -
  • If the radix is a power of two, the conversion is done with infinite -precision. -
  • Otherwise, the number is rounded to nearest with ties to even using -the global precision. It is then converted to string using the minimum -number of digits so that its conversion back to a floating point using -the global precision and round to nearest gives the same number. - -
- -

The exponent letter is e for base 10, p for bases 2, 8, -16 with a binary exponent and @ for the other bases. -

-
-
toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
-
toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
-
toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
-

Same semantics as the corresponding Number functions with -BigFloats. There is no limit on the accepted precision p. The -rounding mode and radix can be optionally specified. The radix must be -between 2 and 36. -

-
-
- - -

4.5.3 BigFloatEnv constructor

- -

The BigFloatEnv([p, [,rndMode]] constructor cannot be invoked as a -function. The floating point environment contains: -

- - -

new BigFloatEnv([p, [,rndMode]] creates a new floating point -environment. The status flags are reset. If no parameter is given the -precision, exponent bits and subnormal flags are copied from the -global floating point environment. Otherwise, the precision is set to -p, the number of exponent bits is set to expBitsMax and the -subnormal flags is set to false. If rndMode is -undefined, the rounding mode is set to RNDN. -

-

BigFloatEnv properties: -

-
-
prec
-

Getter. Return the precision in bits of the global floating point -environment. The initial value is 113. -

-
-
expBits
-

Getter. Return the exponent size in bits of the global floating point -environment assuming an IEEE 754 representation. The initial value is -15. -

-
-
setPrec(f, p[, e])
-

Set the precision of the global floating point environment to p -and the exponent size to e then call the function -f. Then the Float precision and exponent size are reset to -their precious value and the return value of f is returned (or -an exception is raised if f raised an exception). If e -is undefined it is set to BigFloatEnv.expBitsMax. -

-
-
precMin
-

Read-only integer. Return the minimum allowed precision. Must be at least 2. -

-
-
precMax
-

Read-only integer. Return the maximum allowed precision. Must be at least 113. -

-
-
expBitsMin
-

Read-only integer. Return the minimum allowed exponent size in -bits. Must be at least 3. -

-
-
expBitsMax
-

Read-only integer. Return the maximum allowed exponent size in -bits. Must be at least 15. -

-
-
RNDN
-

Read-only integer. Round to nearest, with ties to even rounding mode. -

-
-
RNDZ
-

Read-only integer. Round to zero rounding mode. -

-
-
RNDD
-

Read-only integer. Round to -Infinity rounding mode. -

-
-
RNDU
-

Read-only integer. Round to +Infinity rounding mode. -

-
-
RNDNA
-

Read-only integer. Round to nearest, with ties away from zero rounding mode. -

-
-
RNDA
-

Read-only integer. Round away from zero rounding mode. -

-
-
RNDF4
-

Read-only integer. Faithful rounding mode. The result is -non-deterministically rounded to -Infinity or +Infinity. This rounding -mode usually gives a faster and deterministic running time for the -floating point operations. -

-
-
- -

BigFloatEnv.prototype properties: -

-
-
prec
-

Getter and setter (Integer). Return or set the precision in bits. -

-
-
expBits
-

Getter and setter (Integer). Return or set the exponent size in bits -assuming an IEEE 754 representation. -

-
-
rndMode
-

Getter and setter (Integer). Return or set the rounding mode. -

-
-
subnormal
-

Getter and setter (Boolean). subnormal flag. It is false when -expBits = expBitsMax. -

-
-
clearStatus()
-

Clear the status flags. -

-
-
invalidOperation
-
divideByZero
-
overflow
-
underflow
-
inexact
-

Getter and setter (Boolean). Status flags. -

-
-
- - -

5 BigDecimal

- -

This extension adds the BigDecimal primitive type. The -BigDecimal type represents floating point numbers in base -10. It is inspired from the proposal available at -https://github.com/littledan/proposal-bigdecimal. -

-

The BigDecimal floating point numbers are always normalized and -finite. There is no concept of -0, Infinity or -NaN. By default, all the computations are done with infinite -precision. -

- -

5.1 Operators

- -

The following builtin operators support BigDecimal: -

-
-
+
-
-
-
*
-

Both operands must be BigDecimal. The result is computed with infinite -precision. -

-
%
-

Both operands must be BigDecimal. The result is computed with infinite -precision. A range error is throws in case of division by zero. -

-
-
/
-

Both operands must be BigDecimal. A range error is throws in case of -division by zero or if the result cannot be represented with infinite -precision (use BigDecimal.div to specify the rounding). -

-
-
**
-

Both operands must be BigDecimal. The exponent must be a positive -integer. The result is computed with infinite precision. -

-
-
===
-

When one of the operand is a BigDecimal, return true if both operands -are a BigDecimal and if they are equal. -

-
-
==
-
!=
-
<=
-
>=
-
<
-
>
-
-

Numerical comparison. When one of the operand is not a BigDecimal, it is -converted to BigDecimal by using ToString(). Hence comparisons between -Number and BigDecimal do not use the exact mathematical value of the -Number value. -

-
-
- - -

5.2 BigDecimal literals

- -

BigDecimal literals are decimal floating point numbers with a trailing -m suffix. -

- -

5.3 Builtin Object changes

- - -

5.3.1 The BigDecimal function.

- -

It returns 0m if no parameter is provided. Otherwise the first -parameter is converted to a bigdecimal by using ToString(). Hence -Number values are not converted to their exact numerical value as -BigDecimal. -

- -

5.3.2 Properties of the BigDecimal object

- -
-
add(a, b[, e])
-
sub(a, b[, e])
-
mul(a, b[, e])
-
div(a, b[, e])
-
mod(a, b[, e])
-
sqrt(a, e)
-
round(a, e)
-

Perform the specified floating point operation and round the floating -point result according to the rounding object e. If the -rounding object is not present, the operation is executed with -infinite precision. -

-

For div, a RangeError exception is thrown in case of -division by zero or if the result cannot be represented with infinite -precision if no rounding object is present. -

-

For sqrt, a range error is thrown if a is less than -zero. -

-

The rounding object must contain the following properties: -roundingMode is a string specifying the rounding mode -("floor", "ceiling", "down", "up", -"half-even", "half-up"). Either -maximumSignificantDigits or maximumFractionDigits must -be present to specify respectively the number of significant digits -(must be >= 1) or the number of digits after the decimal point (must -be >= 0). -

-
-
- - -

5.3.3 Properties of the BigDecimal.prototype object

- -
-
valueOf()
-

Return the bigdecimal primitive value corresponding to this. -

-
-
toString()
-

Convert this to a string with infinite precision in base 10. -

-
-
toPrecision(p, rnd_mode = "half-up")
-
toFixed(p, rnd_mode = "half-up")
-
toExponential(p, rnd_mode = "half-up")
-

Convert the BigDecimal this to string with the specified -precision p. There is no limit on the accepted precision -p. The rounding mode can be optionally -specified. toPrecision outputs either in decimal fixed notation -or in decimal exponential notation with a p digits of -precision. toExponential outputs in decimal exponential -notation with p digits after the decimal point. toFixed -outputs in decimal notation with p digits after the decimal -point. -

-
-
- - -

6 Math mode

- -

A new math mode is enabled with the "use math" -directive. It propagates the same way as the strict mode. It is -designed so that arbitrarily large integers and floating point numbers -are available by default. In order to minimize the number of changes -in the Javascript semantics, integers are represented either as Number -or BigInt depending on their magnitude. Floating point numbers are -always represented as BigFloat. -

-

The following changes are made to the Javascript semantics: -

- - -
-
-

Footnotes

- -

(1)

-

The -rationale is that the rounding mode changes must always be -explicit.

-

(2)

-

The rationale is to avoid side effects for the built-in -operators.

-

(3)

-

Base 10 floating point literals cannot usually be -exactly represented as base 2 floating point number. In order to -ensure that the literal is represented accurately with the current -precision, it must be evaluated at runtime.

-

(4)

-

Could be removed in case a deterministic behavior for floating point operations is required.

-
-
- - - - - diff --git a/third_party/quickjs/doc/jsbignum.pdf b/third_party/quickjs/doc/jsbignum.pdf deleted file mode 100644 index 442a8c04d..000000000 Binary files a/third_party/quickjs/doc/jsbignum.pdf and /dev/null differ diff --git a/third_party/quickjs/doc/jsbignum.texi b/third_party/quickjs/doc/jsbignum.texi deleted file mode 100644 index 079d92017..000000000 --- a/third_party/quickjs/doc/jsbignum.texi +++ /dev/null @@ -1,589 +0,0 @@ -\input texinfo - -@iftex -@afourpaper -@headings double -@end iftex - -@titlepage -@afourpaper -@sp 7 -@center @titlefont{Javascript Bignum Extensions} -@sp 3 -@center Version 2020-01-11 -@sp 3 -@center Author: Fabrice Bellard -@end titlepage - -@setfilename jsbignum.info -@settitle Javascript Bignum Extensions - -@contents - -@chapter Introduction - -The Bignum extensions add the following features to the Javascript -language while being 100% backward compatible: - -@itemize - -@item Operator overloading with a dispatch logic inspired from the proposal available at @url{https://github.com/tc39/proposal-operator-overloading/}. - -@item Arbitrarily large floating point numbers (@code{BigFloat}) in base 2 using the IEEE 754 semantics. - -@item Arbitrarily large floating point numbers (@code{BigDecimal}) in base 10 based on the proposal available at -@url{https://github.com/littledan/proposal-bigdecimal}. - -@item @code{math} mode: arbitrarily large integers and floating point numbers are available by default. The integer division and power can be overloaded for example to return a fraction. The modulo operator (@code{%}) is defined as the Euclidian -remainder. @code{^} is an alias to the power operator -(@code{**}). @code{^^} is used as the exclusive or operator. - -@end itemize - -The extensions are independent from each other except the @code{math} -mode which relies on BigFloat and operator overloading. - -@chapter Operator overloading - -Operator overloading is inspired from the proposal available at -@url{https://github.com/tc39/proposal-operator-overloading/}. It -implements the same dispatch logic but finds the operator sets by -looking at the @code{Symbol.operatorSet} property in the objects. The -changes were done in order to simplify the implementation. - -More precisely, the following modifications were made: - -@itemize - -@item @code{with operators from} is not supported. Operator overloading is always enabled. - -@item The dispatch is not based on a static @code{[[OperatorSet]]} field in all instances. Instead, a dynamic lookup of the @code{Symbol.operatorSet} property is done. This property is typically added in the prototype of each object. - -@item @code{Operators.create(...dictionaries)} is used to create a new OperatorSet object. The @code{Operators} function is supported as an helper to be closer to the TC39 proposal. - -@item @code{[]} cannot be overloaded. - -@item In math mode, the BigInt division and power operators can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}. - -@end itemize - -@chapter BigInt extensions - -A few properties are added to the BigInt object: - -@table @code - -@item tdiv(a, b) -Return @math{trunc(a/b)}. @code{b = 0} raises a RangeError -exception. - -@item fdiv(a, b) -Return @math{\lfloor a/b \rfloor}. @code{b = 0} raises a RangeError -exception. - -@item cdiv(a, b) -Return @math{\lceil a/b \rceil}. @code{b = 0} raises a RangeError -exception. - -@item ediv(a, b) -Return @math{sgn(b) \lfloor a/{|b|} \rfloor} (Euclidian -division). @code{b = 0} raises a RangeError exception. - -@item tdivrem(a, b) -@item fdivrem(a, b) -@item cdivrem(a, b) -@item edivrem(a, b) -Return an array of two elements. The first element is the quotient, -the second is the remainder. The same rounding is done as the -corresponding division operation. - -@item sqrt(a) -Return @math{\lfloor \sqrt(a) \rfloor}. A RangeError exception is -raised if @math{a < 0}. - -@item sqrtrem(a) -Return an array of two elements. The first element is @math{\lfloor -\sqrt{a} \rfloor}. The second element is @math{a-\lfloor \sqrt{a} -\rfloor^2}. A RangeError exception is raised if @math{a < 0}. - -@item floorLog2(a) -Return -1 if @math{a \leq 0} otherwise return @math{\lfloor \log2(a) \rfloor}. - -@item ctz(a) -Return the number of trailing zeros in the two's complement binary representation of a. Return -1 if @math{a=0}. - -@end table - -@chapter BigFloat - -@section Introduction - -This extension adds the @code{BigFloat} primitive type. The -@code{BigFloat} type represents floating point numbers in base 2 -with the IEEE 754 semantics. A floating -point number is represented as a sign, mantissa and exponent. The -special values @code{NaN}, @code{+/-Infinity}, @code{+0} and @code{-0} -are supported. The mantissa and exponent can have any bit length with -an implementation specific minimum and maximum. - -@section Floating point rounding - -Each floating point operation operates with infinite precision and -then rounds the result according to the specified floating point -environment (@code{BigFloatEnv} object). The status flags of the -environment are also set according to the result of the operation. - -If no floating point environment is provided, the global floating -point environment is used. - -The rounding mode of the global floating point environment is always -@code{RNDN} (``round to nearest with ties to even'')@footnote{The -rationale is that the rounding mode changes must always be -explicit.}. The status flags of the global environment cannot be -read@footnote{The rationale is to avoid side effects for the built-in -operators.}. The precision of the global environment is -@code{BigFloatEnv.prec}. The number of exponent bits of the global -environment is @code{BigFloatEnv.expBits}. The global environment -subnormal flag is set to @code{true}. - -For example, @code{prec = 53} and @code{ expBits = 11} exactly give -the same precision as the IEEE 754 64 bit floating point format. The -default precision is @code{prec = 113} and @code{ expBits = 15} (IEEE -754 128 bit floating point format). - -The global floating point environment can only be modified temporarily -when calling a function (see @code{BigFloatEnv.setPrec}). Hence a -function can change the global floating point environment for its -callees but not for its caller. - -@section Operators - -The builtin operators are extended so that a BigFloat is returned if -at least one operand is a BigFloat. The computations are always done -with infinite precision and rounded according to the global floating -point environment. - -@code{typeof} applied on a @code{BigFloat} returns @code{bigfloat}. - -BigFloat can be compared with all the other numeric types and the -result follows the expected mathematical relations. - -However, since BigFloat and Number are different types they are never -equal when using the strict comparison operators (e.g. @code{0.0 === -0.0l} is false). - -@section BigFloat literals - -BigFloat literals are floating point numbers with a trailing @code{l} -suffix. BigFloat literals have an infinite precision. They are rounded -according to the global floating point environment when they are -evaluated.@footnote{Base 10 floating point literals cannot usually be -exactly represented as base 2 floating point number. In order to -ensure that the literal is represented accurately with the current -precision, it must be evaluated at runtime.} - -@section Builtin Object changes - -@subsection @code{BigFloat} function - -The @code{BigFloat} function cannot be invoked as a constructor. When -invoked as a function: the parameter is converted to a primitive -type. If the result is a numeric type, it is converted to BigFloat -without rounding. If the result is a string, it is converted to -BigFloat using the precision of the global floating point environment. - -@code{BigFloat} properties: - -@table @code - -@item LN2 -@item PI -Getter. Return the value of the corresponding mathematical constant -rounded to nearest, ties to even with the current global -precision. The constant values are cached for small precisions. - -@item MIN_VALUE -@item MAX_VALUE -@item EPSILON -Getter. Return the minimum, maximum and epsilon @code{BigFloat} values -(same definition as the corresponding @code{Number} constants). - -@item fpRound(a[, e]) -Round the floating point number @code{a} according to the floating -point environment @code{e} or the global environment if @code{e} is -undefined. - -@item parseFloat(a[, radix[, e]]) -Parse the string @code{a} as a floating point number in radix -@code{radix}. The radix is 0 (default) or from 2 to 36. The radix 0 -means radix 10 unless there is a hexadecimal or binary prefix. The -result is rounded according to the floating point environment @code{e} -or the global environment if @code{e} is undefined. - -@item isFinite(a) -Return true if @code{a} is a finite bigfloat. - -@item isNaN(a) -Return true if @code{a} is a NaN bigfloat. - -@item add(a, b[, e]) -@item sub(a, b[, e]) -@item mul(a, b[, e]) -@item div(a, b[, e]) -Perform the specified floating point operation and round the floating -point number @code{a} according to the floating point environment -@code{e} or the global environment if @code{e} is undefined. If -@code{e} is specified, the floating point status flags are updated. - -@item floor(x) -@item ceil(x) -@item round(x) -@item trunc(x) -Round to an integer. No additional rounding is performed. - -@item abs(x) -Return the absolute value of x. No additional rounding is performed. - -@item fmod(x, y[, e]) -@item remainder(x, y[, e]) -Floating point remainder. The quotient is truncated to zero (fmod) or -to the nearest integer with ties to even (remainder). @code{e} is an -optional floating point environment. - -@item sqrt(x[, e]) -Square root. Return a rounded floating point number. @code{e} is an -optional floating point environment. - -@item sin(x[, e]) -@item cos(x[, e]) -@item tan(x[, e]) -@item asin(x[, e]) -@item acos(x[, e]) -@item atan(x[, e]) -@item atan2(x, y[, e]) -@item exp(x[, e]) -@item log(x[, e]) -@item pow(x, y[, e]) -Transcendental operations. Return a rounded floating point -number. @code{e} is an optional floating point environment. - -@end table - -@subsection @code{BigFloat.prototype} - -The following properties are modified: - -@table @code -@item valueOf() -Return the bigfloat primitive value corresponding to @code{this}. - -@item toString(radix) - -For floating point numbers: - -@itemize -@item -If the radix is a power of two, the conversion is done with infinite -precision. -@item -Otherwise, the number is rounded to nearest with ties to even using -the global precision. It is then converted to string using the minimum -number of digits so that its conversion back to a floating point using -the global precision and round to nearest gives the same number. - -@end itemize - -The exponent letter is @code{e} for base 10, @code{p} for bases 2, 8, -16 with a binary exponent and @code{@@} for the other bases. - -@item toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10) -@item toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10) -@item toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10) -Same semantics as the corresponding @code{Number} functions with -BigFloats. There is no limit on the accepted precision @code{p}. The -rounding mode and radix can be optionally specified. The radix must be -between 2 and 36. - -@end table - -@subsection @code{BigFloatEnv} constructor - -The @code{BigFloatEnv([p, [,rndMode]]} constructor cannot be invoked as a -function. The floating point environment contains: - -@itemize -@item the mantissa precision in bits - -@item the exponent size in bits assuming an IEEE 754 representation; - -@item the subnormal flag (if true, subnormal floating point numbers can -be generated by the floating point operations). - -@item the rounding mode - -@item the floating point status. The status flags can only be set by the floating point operations. They can be reset with @code{BigFloatEnv.prototype.clearStatus()} or with the various status flag setters. - -@end itemize - -@code{new BigFloatEnv([p, [,rndMode]]} creates a new floating point -environment. The status flags are reset. If no parameter is given the -precision, exponent bits and subnormal flags are copied from the -global floating point environment. Otherwise, the precision is set to -@code{p}, the number of exponent bits is set to @code{expBitsMax} and the -subnormal flags is set to @code{false}. If @code{rndMode} is -@code{undefined}, the rounding mode is set to @code{RNDN}. - -@code{BigFloatEnv} properties: - -@table @code - -@item prec -Getter. Return the precision in bits of the global floating point -environment. The initial value is @code{113}. - -@item expBits -Getter. Return the exponent size in bits of the global floating point -environment assuming an IEEE 754 representation. The initial value is -@code{15}. - -@item setPrec(f, p[, e]) -Set the precision of the global floating point environment to @code{p} -and the exponent size to @code{e} then call the function -@code{f}. Then the Float precision and exponent size are reset to -their precious value and the return value of @code{f} is returned (or -an exception is raised if @code{f} raised an exception). If @code{e} -is @code{undefined} it is set to @code{BigFloatEnv.expBitsMax}. - -@item precMin -Read-only integer. Return the minimum allowed precision. Must be at least 2. - -@item precMax -Read-only integer. Return the maximum allowed precision. Must be at least 113. - -@item expBitsMin -Read-only integer. Return the minimum allowed exponent size in -bits. Must be at least 3. - -@item expBitsMax -Read-only integer. Return the maximum allowed exponent size in -bits. Must be at least 15. - -@item RNDN -Read-only integer. Round to nearest, with ties to even rounding mode. - -@item RNDZ -Read-only integer. Round to zero rounding mode. - -@item RNDD -Read-only integer. Round to -Infinity rounding mode. - -@item RNDU -Read-only integer. Round to +Infinity rounding mode. - -@item RNDNA -Read-only integer. Round to nearest, with ties away from zero rounding mode. - -@item RNDA -Read-only integer. Round away from zero rounding mode. - -@item RNDF@footnote{Could be removed in case a deterministic behavior for floating point operations is required.} -Read-only integer. Faithful rounding mode. The result is -non-deterministically rounded to -Infinity or +Infinity. This rounding -mode usually gives a faster and deterministic running time for the -floating point operations. - -@end table - -@code{BigFloatEnv.prototype} properties: - -@table @code - -@item prec -Getter and setter (Integer). Return or set the precision in bits. - -@item expBits -Getter and setter (Integer). Return or set the exponent size in bits -assuming an IEEE 754 representation. - -@item rndMode -Getter and setter (Integer). Return or set the rounding mode. - -@item subnormal -Getter and setter (Boolean). subnormal flag. It is false when -@code{expBits = expBitsMax}. - -@item clearStatus() -Clear the status flags. - -@item invalidOperation -@item divideByZero -@item overflow -@item underflow -@item inexact -Getter and setter (Boolean). Status flags. - -@end table - -@chapter BigDecimal - -This extension adds the @code{BigDecimal} primitive type. The -@code{BigDecimal} type represents floating point numbers in base -10. It is inspired from the proposal available at -@url{https://github.com/littledan/proposal-bigdecimal}. - -The @code{BigDecimal} floating point numbers are always normalized and -finite. There is no concept of @code{-0}, @code{Infinity} or -@code{NaN}. By default, all the computations are done with infinite -precision. - -@section Operators - -The following builtin operators support BigDecimal: - -@table @code - -@item + -@item - -@item * -Both operands must be BigDecimal. The result is computed with infinite -precision. -@item % -Both operands must be BigDecimal. The result is computed with infinite -precision. A range error is throws in case of division by zero. - -@item / -Both operands must be BigDecimal. A range error is throws in case of -division by zero or if the result cannot be represented with infinite -precision (use @code{BigDecimal.div} to specify the rounding). - -@item ** -Both operands must be BigDecimal. The exponent must be a positive -integer. The result is computed with infinite precision. - -@item === -When one of the operand is a BigDecimal, return true if both operands -are a BigDecimal and if they are equal. - -@item == -@item != -@item <= -@item >= -@item < -@item > - -Numerical comparison. When one of the operand is not a BigDecimal, it is -converted to BigDecimal by using ToString(). Hence comparisons between -Number and BigDecimal do not use the exact mathematical value of the -Number value. - -@end table - -@section BigDecimal literals - -BigDecimal literals are decimal floating point numbers with a trailing -@code{m} suffix. - -@section Builtin Object changes - -@subsection The @code{BigDecimal} function. - -It returns @code{0m} if no parameter is provided. Otherwise the first -parameter is converted to a bigdecimal by using ToString(). Hence -Number values are not converted to their exact numerical value as -BigDecimal. - -@subsection Properties of the @code{BigDecimal} object - -@table @code - -@item add(a, b[, e]) -@item sub(a, b[, e]) -@item mul(a, b[, e]) -@item div(a, b[, e]) -@item mod(a, b[, e]) -@item sqrt(a, e) -@item round(a, e) -Perform the specified floating point operation and round the floating -point result according to the rounding object @code{e}. If the -rounding object is not present, the operation is executed with -infinite precision. - -For @code{div}, a @code{RangeError} exception is thrown in case of -division by zero or if the result cannot be represented with infinite -precision if no rounding object is present. - -For @code{sqrt}, a range error is thrown if @code{a} is less than -zero. - -The rounding object must contain the following properties: -@code{roundingMode} is a string specifying the rounding mode -(@code{"floor"}, @code{"ceiling"}, @code{"down"}, @code{"up"}, -@code{"half-even"}, @code{"half-up"}). Either -@code{maximumSignificantDigits} or @code{maximumFractionDigits} must -be present to specify respectively the number of significant digits -(must be >= 1) or the number of digits after the decimal point (must -be >= 0). - -@end table - -@subsection Properties of the @code{BigDecimal.prototype} object - -@table @code -@item valueOf() -Return the bigdecimal primitive value corresponding to @code{this}. - -@item toString() -Convert @code{this} to a string with infinite precision in base 10. - -@item toPrecision(p, rnd_mode = "half-up") -@item toFixed(p, rnd_mode = "half-up") -@item toExponential(p, rnd_mode = "half-up") -Convert the BigDecimal @code{this} to string with the specified -precision @code{p}. There is no limit on the accepted precision -@code{p}. The rounding mode can be optionally -specified. @code{toPrecision} outputs either in decimal fixed notation -or in decimal exponential notation with a @code{p} digits of -precision. @code{toExponential} outputs in decimal exponential -notation with @code{p} digits after the decimal point. @code{toFixed} -outputs in decimal notation with @code{p} digits after the decimal -point. - -@end table - -@chapter Math mode - -A new @emph{math mode} is enabled with the @code{"use math"} -directive. It propagates the same way as the @emph{strict mode}. It is -designed so that arbitrarily large integers and floating point numbers -are available by default. In order to minimize the number of changes -in the Javascript semantics, integers are represented either as Number -or BigInt depending on their magnitude. Floating point numbers are -always represented as BigFloat. - -The following changes are made to the Javascript semantics: - -@itemize - -@item Floating point literals (i.e. number with a decimal point or an exponent) are @code{BigFloat} by default (i.e. a @code{l} suffix is implied). Hence @code{typeof 1.0 === "bigfloat"}. - -@item Integer literals (i.e. numbers without a decimal point or an exponent) with or without the @code{n} suffix are @code{BigInt} if their value cannot be represented as a safe integer. A safe integer is defined as a integer whose absolute value is smaller or equal to @code{2**53-1}. Hence @code{typeof 1 === "number "}, @code{typeof 1n === "number"} but @code{typeof 9007199254740992 === "bigint" }. - -@item All the bigint builtin operators and functions are modified so that their result is returned as a Number if it is a safe integer. Otherwise the result stays a BigInt. - -@item The builtin operators are modified so that they return an exact result (which can be a BigInt) if their operands are safe integers. Operands between Number and BigInt are accepted provided the Number operand is a safe integer. The integer power with a negative exponent returns a BigFloat as result. The integer division returns a BigFloat as result. - -@item The @code{^} operator is an alias to the power operator (@code{**}). - -@item The power operator (both @code{^} and @code{**}) grammar is modified so that @code{-2^2} is allowed and yields @code{-4}. - -@item The logical xor operator is still available with the @code{^^} operator. - -@item The modulo operator (@code{%}) returns the Euclidian remainder (always positive) instead of the truncated remainder. - -@item The integer division operator can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}. - -@item The integer power operator with a non zero negative exponent can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}. - -@end itemize - -@bye diff --git a/third_party/quickjs/doc/quickjs.html b/third_party/quickjs/doc/quickjs.html deleted file mode 100644 index cd07ed7ec..000000000 --- a/third_party/quickjs/doc/quickjs.html +++ /dev/null @@ -1,1383 +0,0 @@ - - - - -QuickJS Javascript Engine - - - - - - - - - - - - - - - -

QuickJS Javascript Engine

- - -

Table of Contents

- - - - - -

1 Introduction

- -

QuickJS is a small and embeddable Javascript engine. It supports the -ES2020 specification -1 -including modules, asynchronous generators, proxies and BigInt. -

-

It supports mathematical extensions such as big decimal float float -numbers (BigDecimal), big binary floating point numbers (BigFloat), -and operator overloading. -

- -

1.1 Main Features

- - - - -

2 Usage

- - -

2.1 Installation

- -

A Makefile is provided to compile the engine on Linux or MacOS/X. A -preliminary Windows support is available thru cross compilation on a -Linux host with the MingGW tools. -

-

Edit the top of the Makefile if you wish to select specific -options then run make. -

-

You can type make install as root if you wish to install the binaries and support files to -/usr/local (this is not necessary to use QuickJS). -

- -

2.2 Quick start

- -

qjs is the command line interpreter (Read-Eval-Print Loop). You can pass -Javascript files and/or expressions as arguments to execute them: -

-
-
./qjs examples/hello.js
-
- -

qjsc is the command line compiler: -

-
-
./qjsc -o hello examples/hello.js
-./hello
-
- -

generates a hello executable with no external dependency. -

- -

2.3 Command line options

- - -

2.3.1 qjs interpreter

- -
usage: qjs [options] [file [args]]
-
-

Options are: -

-
-h
-
--help
-

List options. -

-
-
-e EXPR
-
--eval EXPR
-

Evaluate EXPR. -

-
-
-i
-
--interactive
-

Go to interactive mode (it is not the default when files are provided on the command line). -

-
-
-m
-
--module
-

Load as ES6 module (default=autodetect). A module is autodetected if -the filename extension is .mjs or if the first keyword of the -source is import. -

-
-
--script
-

Load as ES6 script (default=autodetect). -

-
-
--bignum
-

Enable the bignum extensions: BigDecimal object, BigFloat object and -the "use math" directive. -

-
-
-I file
-
--include file
-

Include an additional file. -

-
-
- -

Advanced options are: -

-
-
--std
-

Make the std and os modules available to the loaded -script even if it is not a module. -

-
-
-d
-
--dump
-

Dump the memory usage stats. -

-
-
-q
-
--quit
-

just instantiate the interpreter and quit. -

-
-
- - -

2.3.2 qjsc compiler

- -
usage: qjsc [options] [files]
-
-

Options are: -

-
-c
-

Only output bytecode in a C file. The default is to output an executable file. -

-
-e
-

Output main() and bytecode in a C file. The default is to output an -executable file. -

-
-o output
-

Set the output filename (default = out.c or a.out). -

-
-
-N cname
-

Set the C name of the generated data. -

-
-
-m
-

Compile as Javascript module (default=autodetect). -

-
-
-D module_name
-

Compile a dynamically loaded module and its dependencies. This option -is needed when your code uses the import keyword or the -os.Worker constructor because the compiler cannot statically -find the name of the dynamically loaded modules. -

-
-
-M module_name[,cname]
-

Add initialization code for an external C module. See the -c_module example. -

-
-
-x
-

Byte swapped output (only used for cross compilation). -

-
-
-flto
-

Use link time optimization. The compilation is slower but the -executable is smaller and faster. This option is automatically set -when the -fno-x options are used. -

-
-
-fno-[eval|string-normalize|regexp|json|proxy|map|typedarray|promise|bigint]
-

Disable selected language features to produce a smaller executable file. -

-
-
-fbignum
-

Enable the bignum extensions: BigDecimal object, BigFloat object and -the "use math" directive. -

-
-
- - -

2.4 qjscalc application

- -

The qjscalc application is a superset of the qjs -command line interpreter implementing a Javascript calculator with -arbitrarily large integer and floating point numbers, fractions, -complex numbers, polynomials and matrices. The source code is in -qjscalc.js. More documentation and a web version are available at -http://numcalc.com. -

- -

2.5 Built-in tests

- -

Run make test to run the few built-in tests included in the -QuickJS archive. -

- -

2.6 Test262 (ECMAScript Test Suite)

- -

A test262 runner is included in the QuickJS archive. The test262 tests -can be installed in the QuickJS source directory with: -

-
-
git clone https://github.com/tc39/test262.git test262
-cd test262
-patch -p1 < ../tests/test262.patch
-cd ..
-
- -

The patch adds the implementation specific harness functions -and optimizes the inefficient RegExp character classes and Unicode -property escapes tests (the tests themselves are not modified, only a -slow string initialization function is optimized). -

-

The tests can be run with -

-
make test2
-
- -

The configuration files test262.conf -(resp. test262o.conf for the old ES5.1 tests4)) -contain the options to run the various tests. Tests can be excluded -based on features or filename. -

-

The file test262_errors.txt contains the current list of -errors. The runner displays a message when a new error appears or when -an existing error is corrected or modified. Use the -u option -to update the current list of errors (or make test2-update). -

-

The file test262_report.txt contains the logs of all the -tests. It is useful to have a clearer analysis of a particular -error. In case of crash, the last line corresponds to the failing -test. -

-

Use the syntax ./run-test262 -c test262.conf -f filename.js to -run a single test. Use the syntax ./run-test262 -c test262.conf -N to start testing at test number N. -

-

For more information, run ./run-test262 to see the command line -options of the test262 runner. -

-

run-test262 accepts the -N option to be invoked from -test262-harness5 -thru eshost. Unless you want to compare QuickJS with other -engines under the same conditions, we do not recommend to run the -tests this way as it is much slower (typically half an hour instead of -about 100 seconds). -

- -

3 Specifications

- - -

3.1 Language support

- - -

3.1.1 ES2020 support

- -

The ES2020 specification is almost fully supported including the Annex -B (legacy web compatibility) and the Unicode related features. -

-

The following features are not supported yet: -

- - - -

3.1.2 ECMA402

- -

ECMA402 (Internationalization API) is not supported. -

- -

3.1.3 Extensions

- - - - -

3.1.4 Mathematical extensions

- -

The mathematical extensions are fully backward compatible with -standard Javascript. See jsbignum.pdf for more information. -

- - - -

3.2 Modules

- -

ES6 modules are fully supported. The default name resolution is the -following: -

- - - -

3.3 Standard library

- -

The standard library is included by default in the command line -interpreter. It contains the two modules std and os and -a few global objects. -

- -

3.3.1 Global objects

- -
-
scriptArgs
-

Provides the command line arguments. The first argument is the script name. -

-
print(...args)
-

Print the arguments separated by spaces and a trailing newline. -

-
console.log(...args)
-

Same as print(). -

-
-
- - -

3.3.2 std module

- -

The std module provides wrappers to the libc stdlib.h -and stdio.h and a few other utilities. -

-

Available exports: -

-
-
exit(n)
-

Exit the process. -

-
-
evalScript(str, options = undefined)
-

Evaluate the string str as a script (global -eval). options is an optional object containing the following -optional properties: -

-
-
backtrace_barrier
-

Boolean (default = false). If true, error backtraces do not list the - stack frames below the evalScript. -

-
- -
-
loadScript(filename)
-

Evaluate the file filename as a script (global eval). -

-
-
loadFile(filename)
-

Load the file filename and return it as a string assuming UTF-8 -encoding. Return null in case of I/O error. -

-
-
open(filename, flags, errorObj = undefined)
-

Open a file (wrapper to the libc fopen()). Return the FILE -object or null in case of I/O error. If errorObj is not -undefined, set its errno property to the error code or to 0 if -no error occured. -

-
-
popen(command, flags, errorObj = undefined)
-

Open a process by creating a pipe (wrapper to the libc -popen()). Return the FILE -object or null in case of I/O error. If errorObj is not -undefined, set its errno property to the error code or to 0 if -no error occured. -

-
-
fdopen(fd, flags, errorObj = undefined)
-

Open a file from a file handle (wrapper to the libc -fdopen()). Return the FILE -object or null in case of I/O error. If errorObj is not -undefined, set its errno property to the error code or to 0 if -no error occured. -

-
-
tmpfile(errorObj = undefined)
-

Open a temporary file. Return the FILE -object or null in case of I/O error. If errorObj is not -undefined, set its errno property to the error code or to 0 if -no error occured. -

-
-
puts(str)
-

Equivalent to std.out.puts(str). -

-
-
printf(fmt, ...args)
-

Equivalent to std.out.printf(fmt, ...args). -

-
-
sprintf(fmt, ...args)
-

Equivalent to the libc sprintf(). -

-
-
in
-
out
-
err
-

Wrappers to the libc file stdin, stdout, stderr. -

-
-
SEEK_SET
-
SEEK_CUR
-
SEEK_END
-

Constants for seek(). -

-
-
Error
-
-

Enumeration object containing the integer value of common errors -(additional error codes may be defined): -

-
-
EINVAL
-
EIO
-
EACCES
-
EEXIST
-
ENOSPC
-
ENOSYS
-
EBUSY
-
ENOENT
-
EPERM
-
EPIPE
-
- -
-
strerror(errno)
-

Return a string that describes the error errno. -

-
-
gc()
-

Manually invoke the cycle removal algorithm. The cycle removal -algorithm is automatically started when needed, so this function is -useful in case of specific memory constraints or for testing. -

-
-
getenv(name)
-

Return the value of the environment variable name or -undefined if it is not defined. -

-
-
setenv(name, value)
-

Set the value of the environment variable name to the string -value. -

-
-
unsetenv(name)
-

Delete the environment variable name. -

-
-
getenviron()
-

Return an object containing the environment variables as key-value pairs. -

-
-
urlGet(url, options = undefined)
-
-

Download url using the curl command line -utility. options is an optional object containing the following -optional properties: -

-
-
binary
-

Boolean (default = false). If true, the response is an ArrayBuffer - instead of a string. When a string is returned, the data is assumed - to be UTF-8 encoded. -

-
-
full
-
-

Boolean (default = false). If true, return the an object contains - the properties response (response content), - responseHeaders (headers separated by CRLF), status - (status code). response is null is case of protocol or - network error. If full is false, only the response is - returned if the status is between 200 and 299. Otherwise null - is returned. -

-
-
- -
-
parseExtJSON(str)
-
-

Parse str using a superset of JSON.parse. The - following extensions are accepted: -

-
    -
  • Single line and multiline comments -
  • unquoted properties (ASCII-only Javascript identifiers) -
  • trailing comma in array and object definitions -
  • single quoted strings -
  • \f and \v are accepted as space characters -
  • leading plus in numbers -
  • octal (0o prefix) and hexadecimal (0x prefix) numbers -
-
-
- -

FILE prototype: -

-
-
close()
-

Close the file. Return 0 if OK or -errno in case of I/O error. -

-
puts(str)
-

Outputs the string with the UTF-8 encoding. -

-
printf(fmt, ...args)
-

Formatted printf. -

-

The same formats as the standard C library printf are -supported. Integer format types (e.g. %d) truncate the Numbers -or BigInts to 32 bits. Use the l modifier (e.g. %ld) to -truncate to 64 bits. -

-
-
flush()
-

Flush the buffered file. -

-
seek(offset, whence)
-

Seek to a give file position (whence is -std.SEEK_*). offset can be a number or a bigint. Return -0 if OK or -errno in case of I/O error. -

-
tell()
-

Return the current file position. -

-
tello()
-

Return the current file position as a bigint. -

-
eof()
-

Return true if end of file. -

-
fileno()
-

Return the associated OS handle. -

-
error()
-

Return true if there was an error. -

-
clearerr()
-

Clear the error indication. -

-
-
read(buffer, position, length)
-

Read length bytes from the file to the ArrayBuffer buffer at byte -position position (wrapper to the libc fread). -

-
-
write(buffer, position, length)
-

Write length bytes to the file from the ArrayBuffer buffer at byte -position position (wrapper to the libc fwrite). -

-
-
getline()
-

Return the next line from the file, assuming UTF-8 encoding, excluding -the trailing line feed. -

-
-
readAsString(max_size = undefined)
-

Read max_size bytes from the file and return them as a string -assuming UTF-8 encoding. If max_size is not present, the file -is read up its end. -

-
-
getByte()
-

Return the next byte from the file. Return -1 if the end of file is reached. -

-
-
putByte(c)
-

Write one byte to the file. -

-
- - -

3.3.3 os module

- -

The os module provides Operating System specific functions: -

- - -

The OS functions usually return 0 if OK or an OS specific negative -error code. -

-

Available exports: -

-
-
open(filename, flags, mode = 0o666)
-

Open a file. Return a handle or < 0 if error. -

-
-
O_RDONLY
-
O_WRONLY
-
O_RDWR
-
O_APPEND
-
O_CREAT
-
O_EXCL
-
O_TRUNC
-

POSIX open flags. -

-
-
O_TEXT
-

(Windows specific). Open the file in text mode. The default is binary mode. -

-
-
close(fd)
-

Close the file handle fd. -

-
-
seek(fd, offset, whence)
-

Seek in the file. Use std.SEEK_* for -whence. offset is either a number or a bigint. If -offset is a bigint, a bigint is returned too. -

-
-
read(fd, buffer, offset, length)
-

Read length bytes from the file handle fd to the -ArrayBuffer buffer at byte position offset. -Return the number of read bytes or < 0 if error. -

-
-
write(fd, buffer, offset, length)
-

Write length bytes to the file handle fd from the -ArrayBuffer buffer at byte position offset. -Return the number of written bytes or < 0 if error. -

-
-
isatty(fd)
-

Return true is fd is a TTY (terminal) handle. -

-
-
ttyGetWinSize(fd)
-

Return the TTY size as [width, height] or null if not available. -

-
-
ttySetRaw(fd)
-

Set the TTY in raw mode. -

-
-
remove(filename)
-

Remove a file. Return 0 if OK or -errno. -

-
-
rename(oldname, newname)
-

Rename a file. Return 0 if OK or -errno. -

-
-
realpath(path)
-

Return [str, err] where str is the canonicalized absolute -pathname of path and err the error code. -

-
-
getcwd()
-

Return [str, err] where str is the current working directory -and err the error code. -

-
-
chdir(path)
-

Change the current directory. Return 0 if OK or -errno. -

-
-
mkdir(path, mode = 0o777)
-

Create a directory at path. Return 0 if OK or -errno. -

-
-
stat(path)
-
lstat(path)
-
-

Return [obj, err] where obj is an object containing the -file status of path. err is the error code. The -following fields are defined in obj: dev, ino, mode, nlink, -uid, gid, rdev, size, blocks, atime, mtime, ctime. The times are -specified in milliseconds since 1970. lstat() is the same as -stat() excepts that it returns information about the link -itself. -

-
-
S_IFMT
-
S_IFIFO
-
S_IFCHR
-
S_IFDIR
-
S_IFBLK
-
S_IFREG
-
S_IFSOCK
-
S_IFLNK
-
S_ISGID
-
S_ISUID
-

Constants to interpret the mode property returned by -stat(). They have the same value as in the C system header -sys/stat.h. -

-
-
utimes(path, atime, mtime)
-

Change the access and modification times of the file path. The -times are specified in milliseconds since 1970. Return 0 if OK or -errno. -

-
-
symlink(target, linkpath)
-

Create a link at linkpath containing the string target. Return 0 if OK or -errno. -

-
-
readlink(path)
-

Return [str, err] where str is the link target and err -the error code. -

-
-
readdir(path)
-

Return [array, err] where array is an array of strings -containing the filenames of the directory path. err is -the error code. -

-
-
setReadHandler(fd, func)
-

Add a read handler to the file handle fd. func is called -each time there is data pending for fd. A single read handler -per file handle is supported. Use func = null to remove the -handler. -

-
-
setWriteHandler(fd, func)
-

Add a write handler to the file handle fd. func is -called each time data can be written to fd. A single write -handler per file handle is supported. Use func = null to remove -the handler. -

-
-
signal(signal, func)
-

Call the function func when the signal signal -happens. Only a single handler per signal number is supported. Use -null to set the default handler or undefined to ignore -the signal. Signal handlers can only be defined in the main thread. -

-
-
SIGINT
-
SIGABRT
-
SIGFPE
-
SIGILL
-
SIGSEGV
-
SIGTERM
-

POSIX signal numbers. -

-
-
kill(pid, sig)
-

Send the signal sig to the process pid. -

-
-
exec(args[, options])
-

Execute a process with the arguments args. options is an -object containing optional parameters: -

-
-
block
-

Boolean (default = true). If true, wait until the process is - terminated. In this case, exec return the exit code if positive - or the negated signal number if the process was interrupted by a - signal. If false, do not block and return the process id of the child. -

-
-
usePath
-

Boolean (default = true). If true, the file is searched in the - PATH environment variable. -

-
-
file
-

String (default = args[0]). Set the file to be executed. -

-
-
cwd
-

String. If present, set the working directory of the new process. -

-
-
stdin
-
stdout
-
stderr
-

If present, set the handle in the child for stdin, stdout or stderr. -

-
-
env
-

Object. If present, set the process environment from the object - key-value pairs. Otherwise use the same environment as the current - process. -

-
-
uid
-

Integer. If present, the process uid with setuid. -

-
-
gid
-

Integer. If present, the process gid with setgid. -

-
-
- -
-
waitpid(pid, options)
-

waitpid Unix system call. Return the array [ret, -status]. ret contains -errno in case of error. -

-
-
WNOHANG
-

Constant for the options argument of waitpid. -

-
-
dup(fd)
-

dup Unix system call. -

-
-
dup2(oldfd, newfd)
-

dup2 Unix system call. -

-
-
pipe()
-

pipe Unix system call. Return two handles as [read_fd, -write_fd] or null in case of error. -

-
-
sleep(delay_ms)
-

Sleep during delay_ms milliseconds. -

-
-
setTimeout(func, delay)
-

Call the function func after delay ms. Return a handle -to the timer. -

-
-
clearTimeout(handle)
-

Cancel a timer. -

-
-
platform
-

Return a string representing the platform: "linux", "darwin", -"win32" or "js". -

-
-
Worker(module_filename)
-

Constructor to create a new thread (worker) with an API close to the -WebWorkers. module_filename is a string specifying the -module filename which is executed in the newly created thread. As for -dynamically imported module, it is relative to the current script or -module path. Threads normally don’t share any data and communicate -between each other with messages. Nested workers are not supported. An -example is available in tests/test_worker.js. -

-

The worker class has the following static properties: -

-
-
parent
-

In the created worker, Worker.parent represents the parent - worker and is used to send or receive messages. -

-
- -

The worker instances have the following properties: -

-
-
postMessage(msg)
-
-

Send a message to the corresponding worker. msg is cloned in - the destination worker using an algorithm similar to the HTML - structured clone algorithm. SharedArrayBuffer are shared - between workers. -

-

Current limitations: Map and Set are not supported - yet. -

-
-
onmessage
-
-

Getter and setter. Set a function which is called each time a - message is received. The function is called with a single - argument. It is an object with a data property containing the - received message. The thread is not terminated if there is at least - one non null onmessage handler. -

-
-
- -
-
- - -

3.4 QuickJS C API

- -

The C API was designed to be simple and efficient. The C API is -defined in the header quickjs.h. -

- -

3.4.1 Runtime and contexts

- -

JSRuntime represents a Javascript runtime corresponding to an -object heap. Several runtimes can exist at the same time but they -cannot exchange objects. Inside a given runtime, no multi-threading is -supported. -

-

JSContext represents a Javascript context (or Realm). Each -JSContext has its own global objects and system objects. There can be -several JSContexts per JSRuntime and they can share objects, similar -to frames of the same origin sharing Javascript objects in a -web browser. -

- -

3.4.2 JSValue

- -

JSValue represents a Javascript value which can be a primitive -type or an object. Reference counting is used, so it is important to -explicitly duplicate (JS_DupValue(), increment the reference -count) or free (JS_FreeValue(), decrement the reference count) -JSValues. -

- -

3.4.3 C functions

- -

C functions can be created with -JS_NewCFunction(). JS_SetPropertyFunctionList() is a -shortcut to easily add functions, setters and getters properties to a -given object. -

-

Unlike other embedded Javascript engines, there is no implicit stack, -so C functions get their parameters as normal C parameters. As a -general rule, C functions take constant JSValues as parameters -(so they don’t need to free them) and return a newly allocated (=live) -JSValue. -

- -

3.4.4 Exceptions

- -

Exceptions: most C functions can return a Javascript exception. It -must be explicitly tested and handled by the C code. The specific -JSValue JS_EXCEPTION indicates that an exception -occurred. The actual exception object is stored in the -JSContext and can be retrieved with JS_GetException(). -

- -

3.4.5 Script evaluation

- -

Use JS_Eval() to evaluate a script or module source. -

-

If the script or module was compiled to bytecode with qjsc, it -can be evaluated by calling js_std_eval_binary(). The advantage -is that no compilation is needed so it is faster and smaller because -the compiler can be removed from the executable if no eval is -required. -

-

Note: the bytecode format is linked to a given QuickJS -version. Moreover, no security check is done before its -execution. Hence the bytecode should not be loaded from untrusted -sources. That’s why there is no option to output the bytecode to a -binary file in qjsc. -

- -

3.4.6 JS Classes

- -

C opaque data can be attached to a Javascript object. The type of the -C opaque data is determined with the class ID (JSClassID) of -the object. Hence the first step is to register a new class ID and JS -class (JS_NewClassID(), JS_NewClass()). Then you can -create objects of this class with JS_NewObjectClass() and get or -set the C opaque point with -JS_GetOpaque()/JS_SetOpaque(). -

-

When defining a new JS class, it is possible to declare a finalizer -which is called when the object is destroyed. The finalizer should be -used to release C resources. It is invalid to execute JS code from -it. A gc_mark method can be provided so that the cycle removal -algorithm can find the other objects referenced by this object. Other -methods are available to define exotic object behaviors. -

-

The Class ID are globally allocated (i.e. for all runtimes). The -JSClass are allocated per JSRuntime. JS_SetClassProto() -is used to define a prototype for a given class in a given -JSContext. JS_NewObjectClass() sets this prototype in the -created object. -

-

Examples are available in quickjs-libc.c. -

- -

3.4.7 C Modules

- -

Native ES6 modules are supported and can be dynamically or statically -linked. Look at the test_bjson and bjson.so -examples. The standard library quickjs-libc.c is also a good example -of a native module. -

- -

3.4.8 Memory handling

- -

Use JS_SetMemoryLimit() to set a global memory allocation limit -to a given JSRuntime. -

-

Custom memory allocation functions can be provided with -JS_NewRuntime2(). -

-

The maximum system stack size can be set with JS_SetMaxStackSize(). -

- -

3.4.9 Execution timeout and interrupts

- -

Use JS_SetInterruptHandler() to set a callback which is -regularly called by the engine when it is executing code. This -callback can be used to implement an execution timeout. -

-

It is used by the command line interpreter to implement a -Ctrl-C handler. -

- -

4 Internals

- - -

4.1 Bytecode

- -

The compiler generates bytecode directly with no intermediate -representation such as a parse tree, hence it is very fast. Several -optimizations passes are done over the generated bytecode. -

-

A stack-based bytecode was chosen because it is simple and generates -compact code. -

-

For each function, the maximum stack size is computed at compile time so that -no runtime stack overflow tests are needed. -

-

A separate compressed line number table is maintained for the debug -information. -

-

Access to closure variables is optimized and is almost as fast as local -variables. -

-

Direct eval in strict mode is optimized. -

- -

4.2 Executable generation

- - -

4.2.1 qjsc compiler

- -

The qjsc compiler generates C sources from Javascript files. By -default the C sources are compiled with the system compiler -(gcc or clang). -

-

The generated C source contains the bytecode of the compiled functions -or modules. If a full complete executable is needed, it also -contains a main() function with the necessary C code to initialize the -Javascript engine and to load and execute the compiled functions and -modules. -

-

Javascript code can be mixed with C modules. -

-

In order to have smaller executables, specific Javascript features can -be disabled, in particular eval or the regular expressions. The -code removal relies on the Link Time Optimization of the system -compiler. -

- -

4.2.2 Binary JSON

- -

qjsc works by compiling scripts or modules and then serializing -them to a binary format. A subset of this format (without functions or -modules) can be used as binary JSON. The example test_bjson.js -shows how to use it. -

-

Warning: the binary JSON format may change without notice, so it -should not be used to store persistent data. The test_bjson.js -example is only used to test the binary object format functions. -

- -

4.3 Runtime

- - -

4.3.1 Strings

- -

Strings are stored either as an 8 bit or a 16 bit array of -characters. Hence random access to characters is always fast. -

-

The C API provides functions to convert Javascript Strings to C UTF-8 encoded -strings. The most common case where the Javascript string contains -only ASCII characters involves no copying. -

- -

4.3.2 Objects

- -

The object shapes (object prototype, property names and flags) are shared -between objects to save memory. -

-

Arrays with no holes (except at the end of the array) are optimized. -

-

TypedArray accesses are optimized. -

- -

4.3.3 Atoms

- -

Object property names and some strings are stored as Atoms (unique -strings) to save memory and allow fast comparison. Atoms are -represented as a 32 bit integer. Half of the atom range is reserved for -immediate integer literals from 0 to 2^{31}-1. -

- -

4.3.4 Numbers

- -

Numbers are represented either as 32-bit signed integers or 64-bit IEEE-754 -floating point values. Most operations have fast paths for the 32-bit -integer case. -

- -

4.3.5 Garbage collection

- -

Reference counting is used to free objects automatically and -deterministically. A separate cycle removal pass is done when the allocated -memory becomes too large. The cycle removal algorithm only uses the -reference counts and the object content, so no explicit garbage -collection roots need to be manipulated in the C code. -

- -

4.3.6 JSValue

- -

It is a Javascript value which can be a primitive type (such as -Number, String, ...) or an Object. NaN boxing is used in the 32-bit version -to store 64-bit floating point numbers. The representation is -optimized so that 32-bit integers and reference counted values can be -efficiently tested. -

-

In 64-bit code, JSValue are 128-bit large and no NaN boxing is used. The -rationale is that in 64-bit code memory usage is less critical. -

-

In both cases (32 or 64 bits), JSValue exactly fits two CPU registers, -so it can be efficiently returned by C functions. -

- -

4.3.7 Function call

- -

The engine is optimized so that function calls are fast. The system -stack holds the Javascript parameters and local variables. -

- -

4.4 RegExp

- -

A specific regular expression engine was developed. It is both small -and efficient and supports all the ES2020 features including the -Unicode properties. As the Javascript compiler, it directly generates -bytecode without a parse tree. -

-

Backtracking with an explicit stack is used so that there is no -recursion on the system stack. Simple quantifiers are specifically -optimized to avoid recursions. -

-

Infinite recursions coming from quantifiers with empty terms are -avoided. -

-

The full regexp library weights about 15 KiB (x86 code), excluding the -Unicode library. -

- -

4.5 Unicode

- -

A specific Unicode library was developed so that there is no -dependency on an external large Unicode library such as ICU. All the -Unicode tables are compressed while keeping a reasonable access -speed. -

-

The library supports case conversion, Unicode normalization, Unicode -script queries, Unicode general category queries and all Unicode -binary properties. -

-

The full Unicode library weights about 45 KiB (x86 code). -

- -

4.6 BigInt, BigFloat, BigDecimal

- -

BigInt, BigFloat and BigDecimal are implemented with the libbf -library7. It weights about 90 -KiB (x86 code) and provides arbitrary precision IEEE 754 floating -point operations and transcendental functions with exact rounding. -

- -

5 License

- -

QuickJS is released under the MIT license. -

-

Unless otherwise specified, the QuickJS sources are copyright Fabrice -Bellard and Charlie Gordon. -

-
-
-

Footnotes

- -

(1)

-

https://tc39.es/ecma262/

-

(2)

-

https://github.com/tc39/test262

-

(3)

-

https://tc39.github.io/ecma262/

-

(4)

-

The old -ES5.1 tests can be extracted with git clone --single-branch ---branch es5-tests https://github.com/tc39/test262.git test262o

-

(5)

-

https://github.com/bterlson/test262-harness

-

(6)

-

We believe the current specification of tails calls is too complicated and presents limited practical interests.

-

(7)

-

https://bellard.org/libbf

-
-
- - - - - diff --git a/third_party/quickjs/doc/quickjs.pdf b/third_party/quickjs/doc/quickjs.pdf deleted file mode 100644 index 53c8e7345..000000000 Binary files a/third_party/quickjs/doc/quickjs.pdf and /dev/null differ diff --git a/third_party/quickjs/doc/quickjs.texi b/third_party/quickjs/doc/quickjs.texi deleted file mode 100644 index 9eb6354b3..000000000 --- a/third_party/quickjs/doc/quickjs.texi +++ /dev/null @@ -1,1097 +0,0 @@ -\input texinfo - -@iftex -@afourpaper -@headings double -@end iftex - -@titlepage -@afourpaper -@sp 7 -@center @titlefont{QuickJS Javascript Engine} -@sp 3 -@end titlepage - -@setfilename spec.info -@settitle QuickJS Javascript Engine - -@contents - -@chapter Introduction - -QuickJS is a small and embeddable Javascript engine. It supports the -ES2020 specification -@footnote{@url{https://tc39.es/ecma262/}} -including modules, asynchronous generators, proxies and BigInt. - -It supports mathematical extensions such as big decimal float float -numbers (BigDecimal), big binary floating point numbers (BigFloat), -and operator overloading. - -@section Main Features - -@itemize - -@item Small and easily embeddable: just a few C files, no external dependency, 210 KiB of x86 code for a simple ``hello world'' program. - -@item Fast interpreter with very low startup time: runs the 69000 tests of the ECMAScript Test Suite@footnote{@url{https://github.com/tc39/test262}} in about 95 seconds on a single core of a desktop PC. The complete life cycle of a runtime instance completes in less than 300 microseconds. - -@item Almost complete ES2020 support including modules, asynchronous -generators and full Annex B support (legacy web compatibility). Many -features from the upcoming ES2021 specification -@footnote{@url{https://tc39.github.io/ecma262/}} are also supported. - -@item Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2020 features. - -@item Compile Javascript sources to executables with no external dependency. - -@item Garbage collection using reference counting (to reduce memory usage and have deterministic behavior) with cycle removal. - -@item Mathematical extensions: BigDecimal, BigFloat, operator overloading, bigint mode, math mode. - -@item Command line interpreter with contextual colorization and completion implemented in Javascript. - -@item Small built-in standard library with C library wrappers. - -@end itemize - -@chapter Usage - -@section Installation - -A Makefile is provided to compile the engine on Linux or MacOS/X. A -preliminary Windows support is available thru cross compilation on a -Linux host with the MingGW tools. - -Edit the top of the @code{Makefile} if you wish to select specific -options then run @code{make}. - -You can type @code{make install} as root if you wish to install the binaries and support files to -@code{/usr/local} (this is not necessary to use QuickJS). - -@section Quick start - -@code{qjs} is the command line interpreter (Read-Eval-Print Loop). You can pass -Javascript files and/or expressions as arguments to execute them: - -@example -./qjs examples/hello.js -@end example - -@code{qjsc} is the command line compiler: - -@example -./qjsc -o hello examples/hello.js -./hello -@end example - -generates a @code{hello} executable with no external dependency. - -@section Command line options - -@subsection @code{qjs} interpreter - -@verbatim -usage: qjs [options] [file [args]] -@end verbatim - -Options are: -@table @code -@item -h -@item --help -List options. - -@item -e @code{EXPR} -@item --eval @code{EXPR} -Evaluate EXPR. - -@item -i -@item --interactive -Go to interactive mode (it is not the default when files are provided on the command line). - -@item -m -@item --module -Load as ES6 module (default=autodetect). A module is autodetected if -the filename extension is @code{.mjs} or if the first keyword of the -source is @code{import}. - -@item --script -Load as ES6 script (default=autodetect). - -@item --bignum -Enable the bignum extensions: BigDecimal object, BigFloat object and -the @code{"use math"} directive. - -@item -I file -@item --include file -Include an additional file. - -@end table - -Advanced options are: - -@table @code -@item --std -Make the @code{std} and @code{os} modules available to the loaded -script even if it is not a module. - -@item -d -@item --dump -Dump the memory usage stats. - -@item -q -@item --quit -just instantiate the interpreter and quit. - -@end table - -@subsection @code{qjsc} compiler - -@verbatim -usage: qjsc [options] [files] -@end verbatim - -Options are: -@table @code -@item -c -Only output bytecode in a C file. The default is to output an executable file. -@item -e -Output @code{main()} and bytecode in a C file. The default is to output an -executable file. -@item -o output -Set the output filename (default = @file{out.c} or @file{a.out}). - -@item -N cname -Set the C name of the generated data. - -@item -m -Compile as Javascript module (default=autodetect). - -@item -D module_name -Compile a dynamically loaded module and its dependencies. This option -is needed when your code uses the @code{import} keyword or the -@code{os.Worker} constructor because the compiler cannot statically -find the name of the dynamically loaded modules. - -@item -M module_name[,cname] -Add initialization code for an external C module. See the -@code{c_module} example. - -@item -x -Byte swapped output (only used for cross compilation). - -@item -flto -Use link time optimization. The compilation is slower but the -executable is smaller and faster. This option is automatically set -when the @code{-fno-x} options are used. - -@item -fno-[eval|string-normalize|regexp|json|proxy|map|typedarray|promise|bigint] -Disable selected language features to produce a smaller executable file. - -@item -fbignum -Enable the bignum extensions: BigDecimal object, BigFloat object and -the @code{"use math"} directive. - -@end table - -@section @code{qjscalc} application - -The @code{qjscalc} application is a superset of the @code{qjs} -command line interpreter implementing a Javascript calculator with -arbitrarily large integer and floating point numbers, fractions, -complex numbers, polynomials and matrices. The source code is in -@file{qjscalc.js}. More documentation and a web version are available at -@url{http://numcalc.com}. - -@section Built-in tests - -Run @code{make test} to run the few built-in tests included in the -QuickJS archive. - -@section Test262 (ECMAScript Test Suite) - -A test262 runner is included in the QuickJS archive. The test262 tests -can be installed in the QuickJS source directory with: - -@example -git clone https://github.com/tc39/test262.git test262 -cd test262 -patch -p1 < ../tests/test262.patch -cd .. -@end example - -The patch adds the implementation specific @code{harness} functions -and optimizes the inefficient RegExp character classes and Unicode -property escapes tests (the tests themselves are not modified, only a -slow string initialization function is optimized). - -The tests can be run with -@example -make test2 -@end example - -The configuration files @code{test262.conf} -(resp. @code{test262o.conf} for the old ES5.1 tests@footnote{The old -ES5.1 tests can be extracted with @code{git clone --single-branch ---branch es5-tests https://github.com/tc39/test262.git test262o}})) -contain the options to run the various tests. Tests can be excluded -based on features or filename. - -The file @code{test262_errors.txt} contains the current list of -errors. The runner displays a message when a new error appears or when -an existing error is corrected or modified. Use the @code{-u} option -to update the current list of errors (or @code{make test2-update}). - -The file @code{test262_report.txt} contains the logs of all the -tests. It is useful to have a clearer analysis of a particular -error. In case of crash, the last line corresponds to the failing -test. - -Use the syntax @code{./run-test262 -c test262.conf -f filename.js} to -run a single test. Use the syntax @code{./run-test262 -c test262.conf -N} to start testing at test number @code{N}. - -For more information, run @code{./run-test262} to see the command line -options of the test262 runner. - -@code{run-test262} accepts the @code{-N} option to be invoked from -@code{test262-harness}@footnote{@url{https://github.com/bterlson/test262-harness}} -thru @code{eshost}. Unless you want to compare QuickJS with other -engines under the same conditions, we do not recommend to run the -tests this way as it is much slower (typically half an hour instead of -about 100 seconds). - -@chapter Specifications - -@section Language support - -@subsection ES2020 support - -The ES2020 specification is almost fully supported including the Annex -B (legacy web compatibility) and the Unicode related features. - -The following features are not supported yet: - -@itemize - -@item Tail calls@footnote{We believe the current specification of tails calls is too complicated and presents limited practical interests.} - -@end itemize - -@subsection ECMA402 - -ECMA402 (Internationalization API) is not supported. - -@subsection Extensions - -@itemize - -@item The directive @code{"use strip"} indicates that the debug information (including the source code of the functions) should not be retained to save memory. As @code{"use strict"}, the directive can be global to a script or local to a function. - -@item The first line of a script beginning with @code{#!} is ignored. - -@end itemize - -@subsection Mathematical extensions - -The mathematical extensions are fully backward compatible with -standard Javascript. See @code{jsbignum.pdf} for more information. - -@itemize - -@item @code{BigDecimal} support: arbitrary large floating point numbers in base 10. - -@item @code{BigFloat} support: arbitrary large floating point numbers in base 2. - -@item Operator overloading. - -@item The directive @code{"use bigint"} enables the bigint mode where integers are @code{BigInt} by default. - -@item The directive @code{"use math"} enables the math mode where the division and power operators on integers produce fractions. Floating point literals are @code{BigFloat} by default and integers are @code{BigInt} by default. - -@end itemize - -@section Modules - -ES6 modules are fully supported. The default name resolution is the -following: - -@itemize - -@item Module names with a leading @code{.} or @code{..} are relative -to the current module path. - -@item Module names without a leading @code{.} or @code{..} are system -modules, such as @code{std} or @code{os}. - -@item Module names ending with @code{.so} are native modules using the -QuickJS C API. - -@end itemize - -@section Standard library - -The standard library is included by default in the command line -interpreter. It contains the two modules @code{std} and @code{os} and -a few global objects. - -@subsection Global objects - -@table @code -@item scriptArgs -Provides the command line arguments. The first argument is the script name. -@item print(...args) -Print the arguments separated by spaces and a trailing newline. -@item console.log(...args) -Same as print(). - -@end table - -@subsection @code{std} module - -The @code{std} module provides wrappers to the libc @file{stdlib.h} -and @file{stdio.h} and a few other utilities. - -Available exports: - -@table @code - -@item exit(n) -Exit the process. - -@item evalScript(str, options = undefined) -Evaluate the string @code{str} as a script (global -eval). @code{options} is an optional object containing the following -optional properties: - - @table @code - @item backtrace_barrier - Boolean (default = false). If true, error backtraces do not list the - stack frames below the evalScript. - @end table - -@item loadScript(filename) -Evaluate the file @code{filename} as a script (global eval). - -@item loadFile(filename) -Load the file @code{filename} and return it as a string assuming UTF-8 -encoding. Return @code{null} in case of I/O error. - -@item open(filename, flags, errorObj = undefined) -Open a file (wrapper to the libc @code{fopen()}). Return the FILE -object or @code{null} in case of I/O error. If @code{errorObj} is not -undefined, set its @code{errno} property to the error code or to 0 if -no error occured. - -@item popen(command, flags, errorObj = undefined) -Open a process by creating a pipe (wrapper to the libc -@code{popen()}). Return the FILE -object or @code{null} in case of I/O error. If @code{errorObj} is not -undefined, set its @code{errno} property to the error code or to 0 if -no error occured. - -@item fdopen(fd, flags, errorObj = undefined) -Open a file from a file handle (wrapper to the libc -@code{fdopen()}). Return the FILE -object or @code{null} in case of I/O error. If @code{errorObj} is not -undefined, set its @code{errno} property to the error code or to 0 if -no error occured. - -@item tmpfile(errorObj = undefined) -Open a temporary file. Return the FILE -object or @code{null} in case of I/O error. If @code{errorObj} is not -undefined, set its @code{errno} property to the error code or to 0 if -no error occured. - -@item puts(str) -Equivalent to @code{std.out.puts(str)}. - -@item printf(fmt, ...args) -Equivalent to @code{std.out.printf(fmt, ...args)}. - -@item sprintf(fmt, ...args) -Equivalent to the libc sprintf(). - -@item in -@item out -@item err -Wrappers to the libc file @code{stdin}, @code{stdout}, @code{stderr}. - -@item SEEK_SET -@item SEEK_CUR -@item SEEK_END -Constants for seek(). - -@item Error - -Enumeration object containing the integer value of common errors -(additional error codes may be defined): - - @table @code - @item EINVAL - @item EIO - @item EACCES - @item EEXIST - @item ENOSPC - @item ENOSYS - @item EBUSY - @item ENOENT - @item EPERM - @item EPIPE - @end table - -@item strerror(errno) -Return a string that describes the error @code{errno}. - -@item gc() -Manually invoke the cycle removal algorithm. The cycle removal -algorithm is automatically started when needed, so this function is -useful in case of specific memory constraints or for testing. - -@item getenv(name) -Return the value of the environment variable @code{name} or -@code{undefined} if it is not defined. - -@item setenv(name, value) -Set the value of the environment variable @code{name} to the string -@code{value}. - -@item unsetenv(name) -Delete the environment variable @code{name}. - -@item getenviron() -Return an object containing the environment variables as key-value pairs. - -@item urlGet(url, options = undefined) - -Download @code{url} using the @file{curl} command line -utility. @code{options} is an optional object containing the following -optional properties: - - @table @code - @item binary - Boolean (default = false). If true, the response is an ArrayBuffer - instead of a string. When a string is returned, the data is assumed - to be UTF-8 encoded. - - @item full - - Boolean (default = false). If true, return the an object contains - the properties @code{response} (response content), - @code{responseHeaders} (headers separated by CRLF), @code{status} - (status code). @code{response} is @code{null} is case of protocol or - network error. If @code{full} is false, only the response is - returned if the status is between 200 and 299. Otherwise @code{null} - is returned. - - @end table - -@item parseExtJSON(str) - - Parse @code{str} using a superset of @code{JSON.parse}. The - following extensions are accepted: - - @itemize - @item Single line and multiline comments - @item unquoted properties (ASCII-only Javascript identifiers) - @item trailing comma in array and object definitions - @item single quoted strings - @item @code{\f} and @code{\v} are accepted as space characters - @item leading plus in numbers - @item octal (@code{0o} prefix) and hexadecimal (@code{0x} prefix) numbers - @end itemize -@end table - -FILE prototype: - -@table @code -@item close() -Close the file. Return 0 if OK or @code{-errno} in case of I/O error. -@item puts(str) -Outputs the string with the UTF-8 encoding. -@item printf(fmt, ...args) -Formatted printf. - -The same formats as the standard C library @code{printf} are -supported. Integer format types (e.g. @code{%d}) truncate the Numbers -or BigInts to 32 bits. Use the @code{l} modifier (e.g. @code{%ld}) to -truncate to 64 bits. - -@item flush() -Flush the buffered file. -@item seek(offset, whence) -Seek to a give file position (whence is -@code{std.SEEK_*}). @code{offset} can be a number or a bigint. Return -0 if OK or @code{-errno} in case of I/O error. -@item tell() -Return the current file position. -@item tello() -Return the current file position as a bigint. -@item eof() -Return true if end of file. -@item fileno() -Return the associated OS handle. -@item error() -Return true if there was an error. -@item clearerr() -Clear the error indication. - -@item read(buffer, position, length) -Read @code{length} bytes from the file to the ArrayBuffer @code{buffer} at byte -position @code{position} (wrapper to the libc @code{fread}). - -@item write(buffer, position, length) -Write @code{length} bytes to the file from the ArrayBuffer @code{buffer} at byte -position @code{position} (wrapper to the libc @code{fwrite}). - -@item getline() -Return the next line from the file, assuming UTF-8 encoding, excluding -the trailing line feed. - -@item readAsString(max_size = undefined) -Read @code{max_size} bytes from the file and return them as a string -assuming UTF-8 encoding. If @code{max_size} is not present, the file -is read up its end. - -@item getByte() -Return the next byte from the file. Return -1 if the end of file is reached. - -@item putByte(c) -Write one byte to the file. -@end table - -@subsection @code{os} module - -The @code{os} module provides Operating System specific functions: - -@itemize -@item low level file access -@item signals -@item timers -@item asynchronous I/O -@item workers (threads) -@end itemize - -The OS functions usually return 0 if OK or an OS specific negative -error code. - -Available exports: - -@table @code -@item open(filename, flags, mode = 0o666) -Open a file. Return a handle or < 0 if error. - -@item O_RDONLY -@item O_WRONLY -@item O_RDWR -@item O_APPEND -@item O_CREAT -@item O_EXCL -@item O_TRUNC -POSIX open flags. - -@item O_TEXT -(Windows specific). Open the file in text mode. The default is binary mode. - -@item close(fd) -Close the file handle @code{fd}. - -@item seek(fd, offset, whence) -Seek in the file. Use @code{std.SEEK_*} for -@code{whence}. @code{offset} is either a number or a bigint. If -@code{offset} is a bigint, a bigint is returned too. - -@item read(fd, buffer, offset, length) -Read @code{length} bytes from the file handle @code{fd} to the -ArrayBuffer @code{buffer} at byte position @code{offset}. -Return the number of read bytes or < 0 if error. - -@item write(fd, buffer, offset, length) -Write @code{length} bytes to the file handle @code{fd} from the -ArrayBuffer @code{buffer} at byte position @code{offset}. -Return the number of written bytes or < 0 if error. - -@item isatty(fd) -Return @code{true} is @code{fd} is a TTY (terminal) handle. - -@item ttyGetWinSize(fd) -Return the TTY size as @code{[width, height]} or @code{null} if not available. - -@item ttySetRaw(fd) -Set the TTY in raw mode. - -@item remove(filename) -Remove a file. Return 0 if OK or @code{-errno}. - -@item rename(oldname, newname) -Rename a file. Return 0 if OK or @code{-errno}. - -@item realpath(path) -Return @code{[str, err]} where @code{str} is the canonicalized absolute -pathname of @code{path} and @code{err} the error code. - -@item getcwd() -Return @code{[str, err]} where @code{str} is the current working directory -and @code{err} the error code. - -@item chdir(path) -Change the current directory. Return 0 if OK or @code{-errno}. - -@item mkdir(path, mode = 0o777) -Create a directory at @code{path}. Return 0 if OK or @code{-errno}. - -@item stat(path) -@item lstat(path) - -Return @code{[obj, err]} where @code{obj} is an object containing the -file status of @code{path}. @code{err} is the error code. The -following fields are defined in @code{obj}: dev, ino, mode, nlink, -uid, gid, rdev, size, blocks, atime, mtime, ctime. The times are -specified in milliseconds since 1970. @code{lstat()} is the same as -@code{stat()} excepts that it returns information about the link -itself. - -@item S_IFMT -@item S_IFIFO -@item S_IFCHR -@item S_IFDIR -@item S_IFBLK -@item S_IFREG -@item S_IFSOCK -@item S_IFLNK -@item S_ISGID -@item S_ISUID -Constants to interpret the @code{mode} property returned by -@code{stat()}. They have the same value as in the C system header -@file{sys/stat.h}. - -@item utimes(path, atime, mtime) -Change the access and modification times of the file @code{path}. The -times are specified in milliseconds since 1970. Return 0 if OK or @code{-errno}. - -@item symlink(target, linkpath) -Create a link at @code{linkpath} containing the string @code{target}. Return 0 if OK or @code{-errno}. - -@item readlink(path) -Return @code{[str, err]} where @code{str} is the link target and @code{err} -the error code. - -@item readdir(path) -Return @code{[array, err]} where @code{array} is an array of strings -containing the filenames of the directory @code{path}. @code{err} is -the error code. - -@item setReadHandler(fd, func) -Add a read handler to the file handle @code{fd}. @code{func} is called -each time there is data pending for @code{fd}. A single read handler -per file handle is supported. Use @code{func = null} to remove the -handler. - -@item setWriteHandler(fd, func) -Add a write handler to the file handle @code{fd}. @code{func} is -called each time data can be written to @code{fd}. A single write -handler per file handle is supported. Use @code{func = null} to remove -the handler. - -@item signal(signal, func) -Call the function @code{func} when the signal @code{signal} -happens. Only a single handler per signal number is supported. Use -@code{null} to set the default handler or @code{undefined} to ignore -the signal. Signal handlers can only be defined in the main thread. - -@item SIGINT -@item SIGABRT -@item SIGFPE -@item SIGILL -@item SIGSEGV -@item SIGTERM -POSIX signal numbers. - -@item kill(pid, sig) -Send the signal @code{sig} to the process @code{pid}. - -@item exec(args[, options]) -Execute a process with the arguments @code{args}. @code{options} is an -object containing optional parameters: - - @table @code - @item block - Boolean (default = true). If true, wait until the process is - terminated. In this case, @code{exec} return the exit code if positive - or the negated signal number if the process was interrupted by a - signal. If false, do not block and return the process id of the child. - - @item usePath - Boolean (default = true). If true, the file is searched in the - @code{PATH} environment variable. - - @item file - String (default = @code{args[0]}). Set the file to be executed. - - @item cwd - String. If present, set the working directory of the new process. - - @item stdin - @item stdout - @item stderr - If present, set the handle in the child for stdin, stdout or stderr. - - @item env - Object. If present, set the process environment from the object - key-value pairs. Otherwise use the same environment as the current - process. - - @item uid - Integer. If present, the process uid with @code{setuid}. - - @item gid - Integer. If present, the process gid with @code{setgid}. - - @end table - -@item waitpid(pid, options) -@code{waitpid} Unix system call. Return the array @code{[ret, -status]}. @code{ret} contains @code{-errno} in case of error. - -@item WNOHANG -Constant for the @code{options} argument of @code{waitpid}. - -@item dup(fd) -@code{dup} Unix system call. - -@item dup2(oldfd, newfd) -@code{dup2} Unix system call. - -@item pipe() -@code{pipe} Unix system call. Return two handles as @code{[read_fd, -write_fd]} or null in case of error. - -@item sleep(delay_ms) -Sleep during @code{delay_ms} milliseconds. - -@item setTimeout(func, delay) -Call the function @code{func} after @code{delay} ms. Return a handle -to the timer. - -@item clearTimeout(handle) -Cancel a timer. - -@item platform -Return a string representing the platform: @code{"linux"}, @code{"darwin"}, -@code{"win32"} or @code{"js"}. - -@item Worker(module_filename) -Constructor to create a new thread (worker) with an API close to the -@code{WebWorkers}. @code{module_filename} is a string specifying the -module filename which is executed in the newly created thread. As for -dynamically imported module, it is relative to the current script or -module path. Threads normally don't share any data and communicate -between each other with messages. Nested workers are not supported. An -example is available in @file{tests/test_worker.js}. - -The worker class has the following static properties: - - @table @code - @item parent - In the created worker, @code{Worker.parent} represents the parent - worker and is used to send or receive messages. - @end table - -The worker instances have the following properties: - - @table @code - @item postMessage(msg) - - Send a message to the corresponding worker. @code{msg} is cloned in - the destination worker using an algorithm similar to the @code{HTML} - structured clone algorithm. @code{SharedArrayBuffer} are shared - between workers. - - Current limitations: @code{Map} and @code{Set} are not supported - yet. - - @item onmessage - - Getter and setter. Set a function which is called each time a - message is received. The function is called with a single - argument. It is an object with a @code{data} property containing the - received message. The thread is not terminated if there is at least - one non @code{null} @code{onmessage} handler. - - @end table - -@end table - -@section QuickJS C API - -The C API was designed to be simple and efficient. The C API is -defined in the header @code{quickjs.h}. - -@subsection Runtime and contexts - -@code{JSRuntime} represents a Javascript runtime corresponding to an -object heap. Several runtimes can exist at the same time but they -cannot exchange objects. Inside a given runtime, no multi-threading is -supported. - -@code{JSContext} represents a Javascript context (or Realm). Each -JSContext has its own global objects and system objects. There can be -several JSContexts per JSRuntime and they can share objects, similar -to frames of the same origin sharing Javascript objects in a -web browser. - -@subsection JSValue - -@code{JSValue} represents a Javascript value which can be a primitive -type or an object. Reference counting is used, so it is important to -explicitly duplicate (@code{JS_DupValue()}, increment the reference -count) or free (@code{JS_FreeValue()}, decrement the reference count) -JSValues. - -@subsection C functions - -C functions can be created with -@code{JS_NewCFunction()}. @code{JS_SetPropertyFunctionList()} is a -shortcut to easily add functions, setters and getters properties to a -given object. - -Unlike other embedded Javascript engines, there is no implicit stack, -so C functions get their parameters as normal C parameters. As a -general rule, C functions take constant @code{JSValue}s as parameters -(so they don't need to free them) and return a newly allocated (=live) -@code{JSValue}. - -@subsection Exceptions - -Exceptions: most C functions can return a Javascript exception. It -must be explicitly tested and handled by the C code. The specific -@code{JSValue} @code{JS_EXCEPTION} indicates that an exception -occurred. The actual exception object is stored in the -@code{JSContext} and can be retrieved with @code{JS_GetException()}. - -@subsection Script evaluation - -Use @code{JS_Eval()} to evaluate a script or module source. - -If the script or module was compiled to bytecode with @code{qjsc}, it -can be evaluated by calling @code{js_std_eval_binary()}. The advantage -is that no compilation is needed so it is faster and smaller because -the compiler can be removed from the executable if no @code{eval} is -required. - -Note: the bytecode format is linked to a given QuickJS -version. Moreover, no security check is done before its -execution. Hence the bytecode should not be loaded from untrusted -sources. That's why there is no option to output the bytecode to a -binary file in @code{qjsc}. - -@subsection JS Classes - -C opaque data can be attached to a Javascript object. The type of the -C opaque data is determined with the class ID (@code{JSClassID}) of -the object. Hence the first step is to register a new class ID and JS -class (@code{JS_NewClassID()}, @code{JS_NewClass()}). Then you can -create objects of this class with @code{JS_NewObjectClass()} and get or -set the C opaque point with -@code{JS_GetOpaque()}/@code{JS_SetOpaque()}. - -When defining a new JS class, it is possible to declare a finalizer -which is called when the object is destroyed. The finalizer should be -used to release C resources. It is invalid to execute JS code from -it. A @code{gc_mark} method can be provided so that the cycle removal -algorithm can find the other objects referenced by this object. Other -methods are available to define exotic object behaviors. - -The Class ID are globally allocated (i.e. for all runtimes). The -JSClass are allocated per @code{JSRuntime}. @code{JS_SetClassProto()} -is used to define a prototype for a given class in a given -JSContext. @code{JS_NewObjectClass()} sets this prototype in the -created object. - -Examples are available in @file{quickjs-libc.c}. - -@subsection C Modules - -Native ES6 modules are supported and can be dynamically or statically -linked. Look at the @file{test_bjson} and @file{bjson.so} -examples. The standard library @file{quickjs-libc.c} is also a good example -of a native module. - -@subsection Memory handling - -Use @code{JS_SetMemoryLimit()} to set a global memory allocation limit -to a given JSRuntime. - -Custom memory allocation functions can be provided with -@code{JS_NewRuntime2()}. - -The maximum system stack size can be set with @code{JS_SetMaxStackSize()}. - -@subsection Execution timeout and interrupts - -Use @code{JS_SetInterruptHandler()} to set a callback which is -regularly called by the engine when it is executing code. This -callback can be used to implement an execution timeout. - -It is used by the command line interpreter to implement a -@code{Ctrl-C} handler. - -@chapter Internals - -@section Bytecode - -The compiler generates bytecode directly with no intermediate -representation such as a parse tree, hence it is very fast. Several -optimizations passes are done over the generated bytecode. - -A stack-based bytecode was chosen because it is simple and generates -compact code. - -For each function, the maximum stack size is computed at compile time so that -no runtime stack overflow tests are needed. - -A separate compressed line number table is maintained for the debug -information. - -Access to closure variables is optimized and is almost as fast as local -variables. - -Direct @code{eval} in strict mode is optimized. - -@section Executable generation - -@subsection @code{qjsc} compiler - -The @code{qjsc} compiler generates C sources from Javascript files. By -default the C sources are compiled with the system compiler -(@code{gcc} or @code{clang}). - -The generated C source contains the bytecode of the compiled functions -or modules. If a full complete executable is needed, it also -contains a @code{main()} function with the necessary C code to initialize the -Javascript engine and to load and execute the compiled functions and -modules. - -Javascript code can be mixed with C modules. - -In order to have smaller executables, specific Javascript features can -be disabled, in particular @code{eval} or the regular expressions. The -code removal relies on the Link Time Optimization of the system -compiler. - -@subsection Binary JSON - -@code{qjsc} works by compiling scripts or modules and then serializing -them to a binary format. A subset of this format (without functions or -modules) can be used as binary JSON. The example @file{test_bjson.js} -shows how to use it. - -Warning: the binary JSON format may change without notice, so it -should not be used to store persistent data. The @file{test_bjson.js} -example is only used to test the binary object format functions. - -@section Runtime - -@subsection Strings - -Strings are stored either as an 8 bit or a 16 bit array of -characters. Hence random access to characters is always fast. - -The C API provides functions to convert Javascript Strings to C UTF-8 encoded -strings. The most common case where the Javascript string contains -only ASCII characters involves no copying. - -@subsection Objects - -The object shapes (object prototype, property names and flags) are shared -between objects to save memory. - -Arrays with no holes (except at the end of the array) are optimized. - -TypedArray accesses are optimized. - -@subsection Atoms - -Object property names and some strings are stored as Atoms (unique -strings) to save memory and allow fast comparison. Atoms are -represented as a 32 bit integer. Half of the atom range is reserved for -immediate integer literals from @math{0} to @math{2^{31}-1}. - -@subsection Numbers - -Numbers are represented either as 32-bit signed integers or 64-bit IEEE-754 -floating point values. Most operations have fast paths for the 32-bit -integer case. - -@subsection Garbage collection - -Reference counting is used to free objects automatically and -deterministically. A separate cycle removal pass is done when the allocated -memory becomes too large. The cycle removal algorithm only uses the -reference counts and the object content, so no explicit garbage -collection roots need to be manipulated in the C code. - -@subsection JSValue - -It is a Javascript value which can be a primitive type (such as -Number, String, ...) or an Object. NaN boxing is used in the 32-bit version -to store 64-bit floating point numbers. The representation is -optimized so that 32-bit integers and reference counted values can be -efficiently tested. - -In 64-bit code, JSValue are 128-bit large and no NaN boxing is used. The -rationale is that in 64-bit code memory usage is less critical. - -In both cases (32 or 64 bits), JSValue exactly fits two CPU registers, -so it can be efficiently returned by C functions. - -@subsection Function call - -The engine is optimized so that function calls are fast. The system -stack holds the Javascript parameters and local variables. - -@section RegExp - -A specific regular expression engine was developed. It is both small -and efficient and supports all the ES2020 features including the -Unicode properties. As the Javascript compiler, it directly generates -bytecode without a parse tree. - -Backtracking with an explicit stack is used so that there is no -recursion on the system stack. Simple quantifiers are specifically -optimized to avoid recursions. - -Infinite recursions coming from quantifiers with empty terms are -avoided. - -The full regexp library weights about 15 KiB (x86 code), excluding the -Unicode library. - -@section Unicode - -A specific Unicode library was developed so that there is no -dependency on an external large Unicode library such as ICU. All the -Unicode tables are compressed while keeping a reasonable access -speed. - -The library supports case conversion, Unicode normalization, Unicode -script queries, Unicode general category queries and all Unicode -binary properties. - -The full Unicode library weights about 45 KiB (x86 code). - -@section BigInt, BigFloat, BigDecimal - -BigInt, BigFloat and BigDecimal are implemented with the @code{libbf} -library@footnote{@url{https://bellard.org/libbf}}. It weights about 90 -KiB (x86 code) and provides arbitrary precision IEEE 754 floating -point operations and transcendental functions with exact rounding. - -@chapter License - -QuickJS is released under the MIT license. - -Unless otherwise specified, the QuickJS sources are copyright Fabrice -Bellard and Charlie Gordon. - -@bye diff --git a/third_party/quickjs/eq.c b/third_party/quickjs/eq.c deleted file mode 100644 index 4a01cba32..000000000 --- a/third_party/quickjs/eq.c +++ /dev/null @@ -1,458 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "third_party/quickjs/internal.h" -#include "third_party/quickjs/libregexp.h" -#include "third_party/quickjs/quickjs.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -/* XXX: Should take JSValueConst arguments */ -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; -} - -BOOL js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2) -{ - return js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT); -} - -BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2) -{ - return js_strict_eq2(ctx, - JS_DupValue(ctx, op1), JS_DupValue(ctx, op2), - JS_EQ_SAME_VALUE); -} - -BOOL js_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); -} - -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 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 inline BOOL JS_IsHTMLDDA(JSContext *ctx, JSValueConst obj) -{ - JSObject *p; - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - return FALSE; - p = JS_VALUE_GET_OBJ(obj); - return p->is_HTMLDDA; -} - -int js_eq_slow(JSContext *ctx, JSValue *sp, BOOL is_neq) -{ -#ifdef CONFIG_BIGNUM - 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 { - /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */ - if ((JS_IsHTMLDDA(ctx, op1) && - (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) || - (JS_IsHTMLDDA(ctx, op2) && - (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) { - res = TRUE; - } else { - res = FALSE; - } - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - } - done: - sp[-2] = JS_NewBool(ctx, res ^ is_neq); - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -#else /* CONFIG_BIGNUM */ - 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 { - /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */ - if ((JS_IsHTMLDDA(ctx, op1) && - (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) || - (JS_IsHTMLDDA(ctx, op2) && - (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) { - res = TRUE; - } else { - res = FALSE; - } - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - } - sp[-2] = JS_NewBool(ctx, res ^ is_neq); - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -#endif /* CONFIG_BIGNUM */ -} diff --git a/third_party/quickjs/err.c b/third_party/quickjs/err.c deleted file mode 100644 index c2e2b776f..000000000 --- a/third_party/quickjs/err.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "third_party/quickjs/internal.h" -#include "third_party/quickjs/leb128.h" -#include "third_party/quickjs/libregexp.h" -#include "third_party/quickjs/quickjs.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -int 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; -} - -JSValue JS_NewError(JSContext *ctx) -{ - return JS_NewObjectClass(ctx, JS_CLASS_ERROR); -} - -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; -} - -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 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 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; -} - -int 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 */ -JSValue __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 */ -JSValue __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)); -} - -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 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 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 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; -} - -JSValue JS_ThrowStackOverflow(JSContext *ctx) -{ - return JS_ThrowInternalError(ctx, "stack overflow"); -} - -JSValue JS_ThrowTypeErrorNotAnObject(JSContext *ctx) -{ - return JS_ThrowTypeError(ctx, "not an object"); -} - -JSValue JS_ThrowTypeErrorNotASymbol(JSContext *ctx) -{ - return JS_ThrowTypeError(ctx, "not a symbol"); -} - -int js_throw_URIError(JSContext *ctx, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - JS_ThrowError(ctx, JS_URI_ERROR, fmt, ap); - va_end(ap); - return -1; -} - -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)); -} - -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)); -} - -JSValue JS_ThrowReferenceErrorUninitialized2(JSContext *ctx, - JSFunctionBytecode *b, - int idx, BOOL is_ref) -{ - JSAtom atom = JS_ATOM_NULL; - if (is_ref) { - atom = b->closure_var[idx].var_name; - } else { - /* not present if the function is stripped and contains no eval() */ - if (b->vardefs) - atom = b->vardefs[b->arg_count + idx].var_name; - } - return JS_ThrowReferenceErrorUninitialized(ctx, atom); -} - -JSValue JS_ThrowSyntaxErrorVarRedeclaration(JSContext *ctx, JSAtom prop) -{ - return JS_ThrowSyntaxErrorAtom(ctx, "redeclaration of '%s'", prop); -} - -JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom) -{ - return JS_ThrowTypeErrorAtom(ctx, "private class field '%s' does not exist", - atom); -} - -JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx) -{ - return JS_ThrowTypeError(ctx, "ArrayBuffer is detached"); -} - -/* 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); -} - -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; -} - -/* if filename != NULL, an additional level is added with the filename - and line number information (used for parse error). */ -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); -} - -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); -} diff --git a/third_party/quickjs/examples/fib.c b/third_party/quickjs/examples/fib.c deleted file mode 100644 index c77b70562..000000000 --- a/third_party/quickjs/examples/fib.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * QuickJS: Example of C module - * - * Copyright (c) 2017-2018 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "../quickjs.h" - -#define countof(x) (sizeof(x) / sizeof((x)[0])) - -static int fib(int n) -{ - if (n <= 0) - return 0; - else if (n == 1) - return 1; - else - return fib(n - 1) + fib(n - 2); -} - -static JSValue js_fib(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int n, res; - if (JS_ToInt32(ctx, &n, argv[0])) - return JS_EXCEPTION; - res = fib(n); - return JS_NewInt32(ctx, res); -} - -static const JSCFunctionListEntry js_fib_funcs[] = { - JS_CFUNC_DEF("fib", 1, js_fib ), -}; - -static int js_fib_init(JSContext *ctx, JSModuleDef *m) -{ - return JS_SetModuleExportList(ctx, m, js_fib_funcs, - countof(js_fib_funcs)); -} - -#ifdef JS_SHARED_LIBRARY -#define JS_INIT_MODULE js_init_module -#else -#define JS_INIT_MODULE js_init_module_fib -#endif - -JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name) -{ - JSModuleDef *m; - m = JS_NewCModule(ctx, module_name, js_fib_init); - if (!m) - return NULL; - JS_AddModuleExportList(ctx, m, js_fib_funcs, countof(js_fib_funcs)); - return m; -} diff --git a/third_party/quickjs/examples/fib_module.js b/third_party/quickjs/examples/fib_module.js deleted file mode 100644 index 6a8107163..000000000 --- a/third_party/quickjs/examples/fib_module.js +++ /dev/null @@ -1,10 +0,0 @@ -/* fib module */ -export function fib(n) -{ - if (n <= 0) - return 0; - else if (n == 1) - return 1; - else - return fib(n - 1) + fib(n - 2); -} diff --git a/third_party/quickjs/examples/hello.js b/third_party/quickjs/examples/hello.js deleted file mode 100644 index accefceba..000000000 --- a/third_party/quickjs/examples/hello.js +++ /dev/null @@ -1 +0,0 @@ -console.log("Hello World"); diff --git a/third_party/quickjs/examples/hello_module.js b/third_party/quickjs/examples/hello_module.js deleted file mode 100644 index 463660f6a..000000000 --- a/third_party/quickjs/examples/hello_module.js +++ /dev/null @@ -1,6 +0,0 @@ -/* example of JS module */ - -import { fib } from "./fib_module.js"; - -console.log("Hello World"); -console.log("fib(10)=", fib(10)); diff --git a/third_party/quickjs/examples/pi_bigdecimal.js b/third_party/quickjs/examples/pi_bigdecimal.js deleted file mode 100644 index 6a416b793..000000000 --- a/third_party/quickjs/examples/pi_bigdecimal.js +++ /dev/null @@ -1,68 +0,0 @@ -/* - * PI computation in Javascript using the QuickJS bigdecimal type - * (decimal floating point) - */ -"use strict"; - -/* compute PI with a precision of 'prec' digits */ -function calc_pi(prec) { - const CHUD_A = 13591409m; - const CHUD_B = 545140134m; - const CHUD_C = 640320m; - const CHUD_C3 = 10939058860032000m; /* C^3/24 */ - const CHUD_DIGITS_PER_TERM = 14.18164746272548; /* log10(C/12)*3 */ - - /* return [P, Q, G] */ - function chud_bs(a, b, need_G) { - var c, P, Q, G, P1, Q1, G1, P2, Q2, G2, b1; - if (a == (b - 1n)) { - b1 = BigDecimal(b); - G = (2m * b1 - 1m) * (6m * b1 - 1m) * (6m * b1 - 5m); - P = G * (CHUD_B * b1 + CHUD_A); - if (b & 1n) - P = -P; - G = G; - Q = b1 * b1 * b1 * CHUD_C3; - } else { - c = (a + b) >> 1n; - [P1, Q1, G1] = chud_bs(a, c, true); - [P2, Q2, G2] = chud_bs(c, b, need_G); - P = P1 * Q2 + P2 * G1; - Q = Q1 * Q2; - if (need_G) - G = G1 * G2; - else - G = 0m; - } - return [P, Q, G]; - } - - var n, P, Q, G; - /* number of serie terms */ - n = BigInt(Math.ceil(prec / CHUD_DIGITS_PER_TERM)) + 10n; - [P, Q, G] = chud_bs(0n, n, false); - Q = BigDecimal.div(Q, (P + Q * CHUD_A), - { roundingMode: "half-even", - maximumSignificantDigits: prec }); - G = (CHUD_C / 12m) * BigDecimal.sqrt(CHUD_C, - { roundingMode: "half-even", - maximumSignificantDigits: prec }); - return Q * G; -} - -(function() { - var r, n_digits, n_bits; - if (typeof scriptArgs != "undefined") { - if (scriptArgs.length < 2) { - print("usage: pi n_digits"); - return; - } - n_digits = scriptArgs[1] | 0; - } else { - n_digits = 1000; - } - /* we add more digits to reduce the probability of bad rounding for - the last digits */ - r = calc_pi(n_digits + 20); - print(r.toFixed(n_digits, "down")); -})(); diff --git a/third_party/quickjs/examples/pi_bigfloat.js b/third_party/quickjs/examples/pi_bigfloat.js deleted file mode 100644 index 2bcda22fd..000000000 --- a/third_party/quickjs/examples/pi_bigfloat.js +++ /dev/null @@ -1,66 +0,0 @@ -/* - * PI computation in Javascript using the QuickJS bigfloat type - * (binary floating point) - */ -"use strict"; - -/* compute PI with a precision of 'prec' bits */ -function calc_pi() { - const CHUD_A = 13591409n; - const CHUD_B = 545140134n; - const CHUD_C = 640320n; - const CHUD_C3 = 10939058860032000n; /* C^3/24 */ - const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */ - - /* return [P, Q, G] */ - function chud_bs(a, b, need_G) { - var c, P, Q, G, P1, Q1, G1, P2, Q2, G2; - if (a == (b - 1n)) { - G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n); - P = BigFloat(G * (CHUD_B * b + CHUD_A)); - if (b & 1n) - P = -P; - G = BigFloat(G); - Q = BigFloat(b * b * b * CHUD_C3); - } else { - c = (a + b) >> 1n; - [P1, Q1, G1] = chud_bs(a, c, true); - [P2, Q2, G2] = chud_bs(c, b, need_G); - P = P1 * Q2 + P2 * G1; - Q = Q1 * Q2; - if (need_G) - G = G1 * G2; - else - G = 0l; - } - return [P, Q, G]; - } - - var n, P, Q, G; - /* number of serie terms */ - n = BigInt(Math.ceil(BigFloatEnv.prec / CHUD_BITS_PER_TERM)) + 10n; - [P, Q, G] = chud_bs(0n, n, false); - Q = Q / (P + Q * BigFloat(CHUD_A)); - G = BigFloat((CHUD_C / 12n)) * BigFloat.sqrt(BigFloat(CHUD_C)); - return Q * G; -} - -(function() { - var r, n_digits, n_bits; - if (typeof scriptArgs != "undefined") { - if (scriptArgs.length < 2) { - print("usage: pi n_digits"); - return; - } - n_digits = scriptArgs[1]; - } else { - n_digits = 1000; - } - n_bits = Math.ceil(n_digits * Math.log2(10)); - /* we add more bits to reduce the probability of bad rounding for - the last digits */ - BigFloatEnv.setPrec( () => { - r = calc_pi(); - print(r.toFixed(n_digits, BigFloatEnv.RNDZ)); - }, n_bits + 32); -})(); diff --git a/third_party/quickjs/examples/pi_bigint.js b/third_party/quickjs/examples/pi_bigint.js deleted file mode 100644 index cbbb2c409..000000000 --- a/third_party/quickjs/examples/pi_bigint.js +++ /dev/null @@ -1,118 +0,0 @@ -/* - * PI computation in Javascript using the BigInt type - */ -"use strict"; - -/* return floor(log2(a)) for a > 0 and 0 for a = 0 */ -function floor_log2(a) -{ - var k_max, a1, k, i; - k_max = 0n; - while ((a >> (2n ** k_max)) != 0n) { - k_max++; - } - k = 0n; - a1 = a; - for(i = k_max - 1n; i >= 0n; i--) { - a1 = a >> (2n ** i); - if (a1 != 0n) { - a = a1; - k |= (1n << i); - } - } - return k; -} - -/* return ceil(log2(a)) for a > 0 */ -function ceil_log2(a) -{ - return floor_log2(a - 1n) + 1n; -} - -/* return floor(sqrt(a)) (not efficient but simple) */ -function int_sqrt(a) -{ - var l, u, s; - if (a == 0n) - return a; - l = ceil_log2(a); - u = 1n << ((l + 1n) / 2n); - /* u >= floor(sqrt(a)) */ - for(;;) { - s = u; - u = ((a / s) + s) / 2n; - if (u >= s) - break; - } - return s; -} - -/* return pi * 2**prec */ -function calc_pi(prec) { - const CHUD_A = 13591409n; - const CHUD_B = 545140134n; - const CHUD_C = 640320n; - const CHUD_C3 = 10939058860032000n; /* C^3/24 */ - const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */ - - /* return [P, Q, G] */ - function chud_bs(a, b, need_G) { - var c, P, Q, G, P1, Q1, G1, P2, Q2, G2; - if (a == (b - 1n)) { - G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n); - P = G * (CHUD_B * b + CHUD_A); - if (b & 1n) - P = -P; - Q = b * b * b * CHUD_C3; - } else { - c = (a + b) >> 1n; - [P1, Q1, G1] = chud_bs(a, c, true); - [P2, Q2, G2] = chud_bs(c, b, need_G); - P = P1 * Q2 + P2 * G1; - Q = Q1 * Q2; - if (need_G) - G = G1 * G2; - else - G = 0n; - } - return [P, Q, G]; - } - - var n, P, Q, G; - /* number of serie terms */ - n = BigInt(Math.ceil(Number(prec) / CHUD_BITS_PER_TERM)) + 10n; - [P, Q, G] = chud_bs(0n, n, false); - Q = (CHUD_C / 12n) * (Q << prec) / (P + Q * CHUD_A); - G = int_sqrt(CHUD_C << (2n * prec)); - return (Q * G) >> prec; -} - -function main(args) { - var r, n_digits, n_bits, out; - if (args.length < 1) { - print("usage: pi n_digits"); - return; - } - n_digits = args[0] | 0; - - /* we add more bits to reduce the probability of bad rounding for - the last digits */ - n_bits = BigInt(Math.ceil(n_digits * Math.log2(10))) + 32n; - r = calc_pi(n_bits); - r = ((10n ** BigInt(n_digits)) * r) >> n_bits; - out = r.toString(); - print(out[0] + "." + out.slice(1)); -} - -var args; -if (typeof scriptArgs != "undefined") { - args = scriptArgs; - args.shift(); -} else if (typeof arguments != "undefined") { - args = arguments; -} else { - /* default: 1000 digits */ - args=[1000]; -} - -main(args); diff --git a/third_party/quickjs/examples/point.c b/third_party/quickjs/examples/point.c deleted file mode 100644 index fbe2ce100..000000000 --- a/third_party/quickjs/examples/point.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * QuickJS: Example of C module with a class - * - * Copyright (c) 2019 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "../quickjs.h" -#include - -#define countof(x) (sizeof(x) / sizeof((x)[0])) - -/* Point Class */ - -typedef struct { - int x; - int y; -} JSPointData; - -static JSClassID js_point_class_id; - -static void js_point_finalizer(JSRuntime *rt, JSValue val) -{ - JSPointData *s = JS_GetOpaque(val, js_point_class_id); - /* Note: 's' can be NULL in case JS_SetOpaque() was not called */ - js_free_rt(rt, s); -} - -static JSValue js_point_ctor(JSContext *ctx, - JSValueConst new_target, - int argc, JSValueConst *argv) -{ - JSPointData *s; - JSValue obj = JS_UNDEFINED; - JSValue proto; - - s = js_mallocz(ctx, sizeof(*s)); - if (!s) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &s->x, argv[0])) - goto fail; - if (JS_ToInt32(ctx, &s->y, argv[1])) - goto fail; - /* using new_target to get the prototype is necessary when the - class is extended. */ - proto = JS_GetPropertyStr(ctx, new_target, "prototype"); - if (JS_IsException(proto)) - goto fail; - obj = JS_NewObjectProtoClass(ctx, proto, js_point_class_id); - JS_FreeValue(ctx, proto); - if (JS_IsException(obj)) - goto fail; - JS_SetOpaque(obj, s); - return obj; - fail: - js_free(ctx, s); - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue js_point_get_xy(JSContext *ctx, JSValueConst this_val, int magic) -{ - JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); - if (!s) - return JS_EXCEPTION; - if (magic == 0) - return JS_NewInt32(ctx, s->x); - else - return JS_NewInt32(ctx, s->y); -} - -static JSValue js_point_set_xy(JSContext *ctx, JSValueConst this_val, JSValue val, int magic) -{ - JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); - int v; - if (!s) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &v, val)) - return JS_EXCEPTION; - if (magic == 0) - s->x = v; - else - s->y = v; - return JS_UNDEFINED; -} - -static JSValue js_point_norm(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); - if (!s) - return JS_EXCEPTION; - return JS_NewFloat64(ctx, sqrt((double)s->x * s->x + (double)s->y * s->y)); -} - -static JSClassDef js_point_class = { - "Point", - .finalizer = js_point_finalizer, -}; - -static const JSCFunctionListEntry js_point_proto_funcs[] = { - JS_CGETSET_MAGIC_DEF("x", js_point_get_xy, js_point_set_xy, 0), - JS_CGETSET_MAGIC_DEF("y", js_point_get_xy, js_point_set_xy, 1), - JS_CFUNC_DEF("norm", 0, js_point_norm), -}; - -static int js_point_init(JSContext *ctx, JSModuleDef *m) -{ - JSValue point_proto, point_class; - - /* create the Point class */ - JS_NewClassID(&js_point_class_id); - JS_NewClass(JS_GetRuntime(ctx), js_point_class_id, &js_point_class); - - point_proto = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, point_proto, js_point_proto_funcs, countof(js_point_proto_funcs)); - - point_class = JS_NewCFunction2(ctx, js_point_ctor, "Point", 2, JS_CFUNC_constructor, 0); - /* set proto.constructor and ctor.prototype */ - JS_SetConstructor(ctx, point_class, point_proto); - JS_SetClassProto(ctx, js_point_class_id, point_proto); - - JS_SetModuleExport(ctx, m, "Point", point_class); - return 0; -} - -JSModuleDef *js_init_module(JSContext *ctx, const char *module_name) -{ - JSModuleDef *m; - m = JS_NewCModule(ctx, module_name, js_point_init); - if (!m) - return NULL; - JS_AddModuleExport(ctx, m, "Point"); - return m; -} diff --git a/third_party/quickjs/examples/test_fib.js b/third_party/quickjs/examples/test_fib.js deleted file mode 100644 index 70d26bd8c..000000000 --- a/third_party/quickjs/examples/test_fib.js +++ /dev/null @@ -1,6 +0,0 @@ -/* example of JS module importing a C module */ - -import { fib } from "./fib.so"; - -console.log("Hello World"); -console.log("fib(10)=", fib(10)); diff --git a/third_party/quickjs/examples/test_point.js b/third_party/quickjs/examples/test_point.js deleted file mode 100644 index 0659bc350..000000000 --- a/third_party/quickjs/examples/test_point.js +++ /dev/null @@ -1,40 +0,0 @@ -/* example of JS module importing a C module */ -import { Point } from "./point.so"; - -function assert(b, str) -{ - if (b) { - return; - } else { - throw Error("assertion failed: " + str); - } -} - -class ColorPoint extends Point { - constructor(x, y, color) { - super(x, y); - this.color = color; - } - get_color() { - return this.color; - } -}; - -function main() -{ - var pt, pt2; - - pt = new Point(2, 3); - assert(pt.x === 2); - assert(pt.y === 3); - pt.x = 4; - assert(pt.x === 4); - assert(pt.norm() == 5); - - pt2 = new ColorPoint(2, 3, 0xffffff); - assert(pt2.x === 2); - assert(pt2.color === 0xffffff); - assert(pt2.get_color() === 0xffffff); -} - -main(); diff --git a/third_party/quickjs/float.c b/third_party/quickjs/float.c deleted file mode 100644 index 62818ec4e..000000000 --- a/third_party/quickjs/float.c +++ /dev/null @@ -1,1160 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/runtime/runtime.h" -#include "third_party/quickjs/internal.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -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_float_env_constructor(JSContext *ctx, - JSValueConst new_target, - int argc, JSValueConst *argv) -{ - JSValue obj; - JSFloatEnv *fe; - int64_t prec; - int flags, rndmode; - prec = ctx->fp_env.prec; - flags = ctx->fp_env.flags; - if (!JS_IsUndefined(argv[0])) { - if (JS_ToInt64Sat(ctx, &prec, argv[0])) - return JS_EXCEPTION; - if (prec < BF_PREC_MIN || prec > BF_PREC_MAX) - return JS_ThrowRangeError(ctx, "invalid precision"); - flags = BF_RNDN; /* RNDN, max exponent size, no subnormal */ - if (argc > 1 && !JS_IsUndefined(argv[1])) { - if (JS_ToInt32Sat(ctx, &rndmode, argv[1])) - return JS_EXCEPTION; - if (rndmode < BF_RNDN || rndmode > BF_RNDF) - return JS_ThrowRangeError(ctx, "invalid rounding mode"); - flags = rndmode; - } - } - obj = JS_NewObjectClass(ctx, JS_CLASS_FLOAT_ENV); - if (JS_IsException(obj)) - return JS_EXCEPTION; - fe = js_malloc(ctx, sizeof(*fe)); - if (!fe) - return JS_EXCEPTION; - fe->prec = prec; - fe->flags = flags; - fe->status = 0; - JS_SetOpaque(obj, fe); - return obj; -} - -/* 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. */ -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; -} - -static JSValue js_float_env_get_prec(JSContext *ctx, JSValueConst this_val) -{ - return JS_NewInt64(ctx, ctx->fp_env.prec); -} - -static JSValue js_float_env_get_expBits(JSContext *ctx, JSValueConst this_val) -{ - return JS_NewInt32(ctx, bf_get_exp_bits(ctx->fp_env.flags)); -} - -static JSValue js_float_env_setPrec(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst func; - int exp_bits, flags, saved_flags; - JSValue ret; - limb_t saved_prec; - int64_t prec; - func = argv[0]; - if (JS_ToInt64Sat(ctx, &prec, argv[1])) - return JS_EXCEPTION; - if (prec < BF_PREC_MIN || prec > BF_PREC_MAX) - return JS_ThrowRangeError(ctx, "invalid precision"); - exp_bits = BF_EXP_BITS_MAX; - if (argc > 2 && !JS_IsUndefined(argv[2])) { - if (JS_ToInt32Sat(ctx, &exp_bits, argv[2])) - return JS_EXCEPTION; - if (exp_bits < BF_EXP_BITS_MIN || exp_bits > BF_EXP_BITS_MAX) - return JS_ThrowRangeError(ctx, "invalid number of exponent bits"); - } - flags = BF_RNDN | BF_FLAG_SUBNORMAL | bf_set_exp_bits(exp_bits); - saved_prec = ctx->fp_env.prec; - saved_flags = ctx->fp_env.flags; - ctx->fp_env.prec = prec; - ctx->fp_env.flags = flags; - ret = JS_Call(ctx, func, JS_UNDEFINED, 0, NULL); - /* always restore the floating point precision */ - ctx->fp_env.prec = saved_prec; - ctx->fp_env.flags = saved_flags; - return ret; -} - -static JSValue js_float_env_proto_get_status(JSContext *ctx, JSValueConst this_val, int magic) -{ - JSFloatEnv *fe; - fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV); - if (!fe) - return JS_EXCEPTION; - switch(magic) { - case FE_PREC: - return JS_NewInt64(ctx, fe->prec); - case FE_EXP: - return JS_NewInt32(ctx, bf_get_exp_bits(fe->flags)); - case FE_RNDMODE: - return JS_NewInt32(ctx, fe->flags & BF_RND_MASK); - case FE_SUBNORMAL: - return JS_NewBool(ctx, (fe->flags & BF_FLAG_SUBNORMAL) != 0); - default: - return JS_NewBool(ctx, (fe->status & magic) != 0); - } -} - -static int bigfloat_get_rnd_mode(JSContext *ctx, JSValueConst val) -{ - int rnd_mode; - if (JS_ToInt32Sat(ctx, &rnd_mode, val)) - return -1; - if (rnd_mode < BF_RNDN || rnd_mode > BF_RNDF) { - JS_ThrowRangeError(ctx, "invalid rounding mode"); - return -1; - } - return rnd_mode; -} - -static JSValue js_float_env_proto_set_status(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic) -{ - JSFloatEnv *fe; - int b; - int64_t prec; - fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV); - if (!fe) - return JS_EXCEPTION; - switch(magic) { - case FE_PREC: - if (JS_ToInt64Sat(ctx, &prec, val)) - return JS_EXCEPTION; - if (prec < BF_PREC_MIN || prec > BF_PREC_MAX) - return JS_ThrowRangeError(ctx, "invalid precision"); - fe->prec = prec; - break; - case FE_EXP: - if (JS_ToInt32Sat(ctx, &b, val)) - return JS_EXCEPTION; - if (b < BF_EXP_BITS_MIN || b > BF_EXP_BITS_MAX) - return JS_ThrowRangeError(ctx, "invalid number of exponent bits"); - fe->flags = (fe->flags & ~(BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)) | - bf_set_exp_bits(b); - break; - case FE_RNDMODE: - b = bigfloat_get_rnd_mode(ctx, val); - if (b < 0) - return JS_EXCEPTION; - fe->flags = (fe->flags & ~BF_RND_MASK) | b; - break; - case FE_SUBNORMAL: - b = JS_ToBool(ctx, val); - fe->flags = (fe->flags & ~BF_FLAG_SUBNORMAL) | (b ? BF_FLAG_SUBNORMAL: 0); - break; - default: - b = JS_ToBool(ctx, val); - fe->status = (fe->status & ~magic) & ((-b) & magic); - break; - } - return JS_UNDEFINED; -} - -static JSValue js_float_env_clearStatus(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSFloatEnv *fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV); - if (!fe) - return JS_EXCEPTION; - fe->status = 0; - return JS_UNDEFINED; -} - -static const JSCFunctionListEntry js_float_env_funcs[] = { - JS_CGETSET_DEF("prec", js_float_env_get_prec, NULL ), - JS_CGETSET_DEF("expBits", js_float_env_get_expBits, NULL ), - JS_CFUNC_DEF("setPrec", 2, js_float_env_setPrec ), - JS_PROP_INT32_DEF("RNDN", BF_RNDN, 0 ), - JS_PROP_INT32_DEF("RNDZ", BF_RNDZ, 0 ), - JS_PROP_INT32_DEF("RNDU", BF_RNDU, 0 ), - JS_PROP_INT32_DEF("RNDD", BF_RNDD, 0 ), - JS_PROP_INT32_DEF("RNDNA", BF_RNDNA, 0 ), - JS_PROP_INT32_DEF("RNDA", BF_RNDA, 0 ), - JS_PROP_INT32_DEF("RNDF", BF_RNDF, 0 ), - JS_PROP_INT32_DEF("precMin", BF_PREC_MIN, 0 ), - JS_PROP_INT64_DEF("precMax", BF_PREC_MAX, 0 ), - JS_PROP_INT32_DEF("expBitsMin", BF_EXP_BITS_MIN, 0 ), - JS_PROP_INT32_DEF("expBitsMax", BF_EXP_BITS_MAX, 0 ), -}; - -static const JSCFunctionListEntry js_float_env_proto_funcs[] = { - JS_CGETSET_MAGIC_DEF("prec", js_float_env_proto_get_status, - js_float_env_proto_set_status, FE_PREC ), - JS_CGETSET_MAGIC_DEF("expBits", js_float_env_proto_get_status, - js_float_env_proto_set_status, FE_EXP ), - JS_CGETSET_MAGIC_DEF("rndMode", js_float_env_proto_get_status, - js_float_env_proto_set_status, FE_RNDMODE ), - JS_CGETSET_MAGIC_DEF("subnormal", js_float_env_proto_get_status, - js_float_env_proto_set_status, FE_SUBNORMAL ), - JS_CGETSET_MAGIC_DEF("invalidOperation", js_float_env_proto_get_status, - js_float_env_proto_set_status, BF_ST_INVALID_OP ), - JS_CGETSET_MAGIC_DEF("divideByZero", js_float_env_proto_get_status, - js_float_env_proto_set_status, BF_ST_DIVIDE_ZERO ), - JS_CGETSET_MAGIC_DEF("overflow", js_float_env_proto_get_status, - js_float_env_proto_set_status, BF_ST_OVERFLOW ), - JS_CGETSET_MAGIC_DEF("underflow", js_float_env_proto_get_status, - js_float_env_proto_set_status, BF_ST_UNDERFLOW ), - JS_CGETSET_MAGIC_DEF("inexact", js_float_env_proto_get_status, - js_float_env_proto_set_status, BF_ST_INEXACT ), - JS_CFUNC_DEF("clearStatus", 0, js_float_env_clearStatus ), -}; - -static JSValue js_thisBigFloatValue(JSContext *ctx, JSValueConst this_val) -{ - if (JS_IsBigFloat(this_val)) - return JS_DupValue(ctx, this_val); - if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(this_val); - if (p->class_id == JS_CLASS_BIG_FLOAT) { - if (JS_IsBigFloat(p->u.object_data)) - return JS_DupValue(ctx, p->u.object_data); - } - } - return JS_ThrowTypeError(ctx, "not a bigfloat"); -} - -static JSValue js_bigfloat_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val; - int base; - JSValue ret; - val = js_thisBigFloatValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (argc == 0 || JS_IsUndefined(argv[0])) { - base = 10; - } else { - base = js_get_radix(ctx, argv[0]); - if (base < 0) - goto fail; - } - ret = js_ftoa(ctx, val, base, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN); - JS_FreeValue(ctx, val); - return ret; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static JSValue js_bigfloat_valueOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return js_thisBigFloatValue(ctx, this_val); -} - -static JSValue js_bigfloat_toFixed(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val, ret; - int64_t f; - int rnd_mode, radix; - val = js_thisBigFloatValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (JS_ToInt64Sat(ctx, &f, argv[0])) - goto fail; - if (f < 0 || f > BF_PREC_MAX) { - JS_ThrowRangeError(ctx, "invalid number of digits"); - goto fail; - } - rnd_mode = BF_RNDNA; - radix = 10; - /* XXX: swap parameter order for rounding mode and radix */ - if (argc > 1) { - rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]); - if (rnd_mode < 0) - goto fail; - } - if (argc > 2) { - radix = js_get_radix(ctx, argv[2]); - if (radix < 0) - goto fail; - } - ret = js_ftoa(ctx, val, radix, f, rnd_mode | BF_FTOA_FORMAT_FRAC); - JS_FreeValue(ctx, val); - return ret; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static BOOL js_bigfloat_is_finite(JSContext *ctx, JSValueConst val) -{ - BOOL res; - uint32_t tag; - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_BIG_FLOAT: - { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - res = bf_is_finite(&p->num); - } - break; - default: - res = FALSE; - break; - } - return res; -} - -static JSValue js_bigfloat_toExponential(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val, ret; - int64_t f; - int rnd_mode, radix; - val = js_thisBigFloatValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (JS_ToInt64Sat(ctx, &f, argv[0])) - goto fail; - if (!js_bigfloat_is_finite(ctx, val)) { - ret = JS_ToString(ctx, val); - } else if (JS_IsUndefined(argv[0])) { - ret = js_ftoa(ctx, val, 10, 0, - BF_RNDN | BF_FTOA_FORMAT_FREE_MIN | BF_FTOA_FORCE_EXP); - } else { - if (f < 0 || f > BF_PREC_MAX) { - JS_ThrowRangeError(ctx, "invalid number of digits"); - goto fail; - } - rnd_mode = BF_RNDNA; - radix = 10; - if (argc > 1) { - rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]); - if (rnd_mode < 0) - goto fail; - } - if (argc > 2) { - radix = js_get_radix(ctx, argv[2]); - if (radix < 0) - goto fail; - } - ret = js_ftoa(ctx, val, radix, f + 1, - rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP); - } - JS_FreeValue(ctx, val); - return ret; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static JSValue js_bigfloat_toPrecision(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val, ret; - int64_t p; - int rnd_mode, radix; - - val = js_thisBigFloatValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (JS_IsUndefined(argv[0])) - goto to_string; - if (JS_ToInt64Sat(ctx, &p, argv[0])) - goto fail; - if (!js_bigfloat_is_finite(ctx, val)) { - to_string: - ret = JS_ToString(ctx, this_val); - } else { - if (p < 1 || p > BF_PREC_MAX) { - JS_ThrowRangeError(ctx, "invalid number of digits"); - goto fail; - } - rnd_mode = BF_RNDNA; - radix = 10; - if (argc > 1) { - rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]); - if (rnd_mode < 0) - goto fail; - } - if (argc > 2) { - radix = js_get_radix(ctx, argv[2]); - if (radix < 0) - goto fail; - } - ret = js_ftoa(ctx, val, radix, p, rnd_mode | BF_FTOA_FORMAT_FIXED); - } - JS_FreeValue(ctx, val); - return ret; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static const JSCFunctionListEntry js_bigfloat_proto_funcs[] = { - JS_CFUNC_DEF("toString", 0, js_bigfloat_toString ), - JS_CFUNC_DEF("valueOf", 0, js_bigfloat_valueOf ), - JS_CFUNC_DEF("toPrecision", 1, js_bigfloat_toPrecision ), - JS_CFUNC_DEF("toFixed", 1, js_bigfloat_toFixed ), - JS_CFUNC_DEF("toExponential", 1, js_bigfloat_toExponential ), -}; - -static JSValue js_bigfloat_constructor(JSContext *ctx, - JSValueConst new_target, - int argc, JSValueConst *argv) -{ - JSValue val; - if (!JS_IsUndefined(new_target)) - return JS_ThrowTypeError(ctx, "not a constructor"); - if (argc == 0) { - bf_t *r; - val = JS_NewBigFloat(ctx); - if (JS_IsException(val)) - return val; - r = JS_GetBigFloat(val); - bf_set_zero(r, 0); - } else { - val = JS_DupValue(ctx, argv[0]); - redo: - switch(JS_VALUE_GET_NORM_TAG(val)) { - case JS_TAG_BIG_FLOAT: - break; - case JS_TAG_FLOAT64: - { - bf_t *r; - double d = JS_VALUE_GET_FLOAT64(val); - val = JS_NewBigFloat(ctx); - if (JS_IsException(val)) - break; - r = JS_GetBigFloat(val); - if (bf_set_float64(r, d)) - goto fail; - } - break; - case JS_TAG_INT: - { - bf_t *r; - int32_t v = JS_VALUE_GET_INT(val); - val = JS_NewBigFloat(ctx); - if (JS_IsException(val)) - break; - r = JS_GetBigFloat(val); - if (bf_set_si(r, v)) - goto fail; - } - break; - case JS_TAG_BIG_INT: - /* We keep the full precision of the integer */ - { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - val = JS_MKPTR(JS_TAG_BIG_FLOAT, p); - } - break; - case JS_TAG_BIG_DECIMAL: - val = JS_ToStringFree(ctx, val); - if (JS_IsException(val)) - break; - goto redo; - case JS_TAG_STRING: - { - const char *str, *p; - size_t len; - int err; - 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) { - bf_t *r; - val = JS_NewBigFloat(ctx); - if (JS_IsException(val)) - break; - r = JS_GetBigFloat(val); - bf_set_zero(r, 0); - err = 0; - } else { - val = js_atof(ctx, p, &p, 0, ATOD_ACCEPT_BIN_OCT | - ATOD_TYPE_BIG_FLOAT | - ATOD_ACCEPT_PREFIX_AFTER_SIGN); - if (JS_IsException(val)) { - JS_FreeCString(ctx, str); - return JS_EXCEPTION; - } - p += skip_spaces(p); - err = ((p - str) != len); - } - JS_FreeCString(ctx, str); - if (err) { - JS_FreeValue(ctx, val); - return JS_ThrowSyntaxError(ctx, "invalid bigfloat literal"); - } - } - break; - case JS_TAG_OBJECT: - val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER); - if (JS_IsException(val)) - break; - goto redo; - case JS_TAG_NULL: - case JS_TAG_UNDEFINED: - default: - JS_FreeValue(ctx, val); - return JS_ThrowTypeError(ctx, "cannot convert to bigfloat"); - } - } - return val; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static JSValue js_bigfloat_get_const(JSContext *ctx, - JSValueConst this_val, int magic) -{ - bf_t *r; - JSValue val; - val = JS_NewBigFloat(ctx); - if (JS_IsException(val)) - return val; - r = JS_GetBigFloat(val); - switch(magic) { - case 0: /* PI */ - bf_const_pi(r, ctx->fp_env.prec, ctx->fp_env.flags); - break; - case 1: /* LN2 */ - bf_const_log2(r, ctx->fp_env.prec, ctx->fp_env.flags); - break; - case 2: /* MIN_VALUE */ - case 3: /* MAX_VALUE */ - { - slimb_t e_range, e; - e_range = (limb_t)1 << (bf_get_exp_bits(ctx->fp_env.flags) - 1); - bf_set_ui(r, 1); - if (magic == 2) { - e = -e_range + 2; - if (ctx->fp_env.flags & BF_FLAG_SUBNORMAL) - e -= ctx->fp_env.prec - 1; - bf_mul_2exp(r, e, ctx->fp_env.prec, ctx->fp_env.flags); - } else { - bf_mul_2exp(r, ctx->fp_env.prec, ctx->fp_env.prec, - ctx->fp_env.flags); - bf_add_si(r, r, -1, ctx->fp_env.prec, ctx->fp_env.flags); - bf_mul_2exp(r, e_range - ctx->fp_env.prec, ctx->fp_env.prec, - ctx->fp_env.flags); - } - } - break; - case 4: /* EPSILON */ - bf_set_ui(r, 1); - bf_mul_2exp(r, 1 - ctx->fp_env.prec, - ctx->fp_env.prec, ctx->fp_env.flags); - break; - default: - abort(); - } - return val; -} - -static JSValue js_bigfloat_parseFloat(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - bf_t *a; - const char *str; - JSValue ret; - int radix; - JSFloatEnv *fe; - str = JS_ToCString(ctx, argv[0]); - if (!str) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &radix, argv[1])) { - fail: - JS_FreeCString(ctx, str); - return JS_EXCEPTION; - } - if (radix != 0 && (radix < 2 || radix > 36)) { - JS_ThrowRangeError(ctx, "radix must be between 2 and 36"); - goto fail; - } - fe = &ctx->fp_env; - if (argc > 2) { - fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV); - if (!fe) - goto fail; - } - ret = JS_NewBigFloat(ctx); - if (JS_IsException(ret)) - goto done; - a = JS_GetBigFloat(ret); - /* XXX: use js_atof() */ - bf_atof(a, str, NULL, radix, fe->prec, fe->flags); - done: - JS_FreeCString(ctx, str); - return ret; -} - -static JSValue js_bigfloat_isFinite(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst val = argv[0]; - JSBigFloat *p; - if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT) - return JS_FALSE; - p = JS_VALUE_GET_PTR(val); - return JS_NewBool(ctx, bf_is_finite(&p->num)); -} - -static JSValue js_bigfloat_isNaN(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst val = argv[0]; - JSBigFloat *p; - if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT) - return JS_FALSE; - p = JS_VALUE_GET_PTR(val); - return JS_NewBool(ctx, bf_is_nan(&p->num)); -} - -static JSValue js_bigfloat_fop(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - bf_t a_s, *a, *r; - JSFloatEnv *fe; - int rnd_mode; - JSValue op1, res; - op1 = JS_ToNumeric(ctx, argv[0]); - if (JS_IsException(op1)) - return op1; - a = JS_ToBigFloat(ctx, &a_s, op1); - fe = &ctx->fp_env; - if (argc > 1) { - fe = JS_GetOpaque2(ctx, argv[1], JS_CLASS_FLOAT_ENV); - if (!fe) - goto fail; - } - res = JS_NewBigFloat(ctx); - if (JS_IsException(res)) { - fail: - if (a == &a_s) - bf_delete(a); - JS_FreeValue(ctx, op1); - return JS_EXCEPTION; - } - r = JS_GetBigFloat(res); - switch (magic) { - case MATH_OP_ABS: - bf_set(r, a); - r->sign = 0; - break; - case MATH_OP_FLOOR: - rnd_mode = BF_RNDD; - goto rint; - case MATH_OP_CEIL: - rnd_mode = BF_RNDU; - goto rint; - case MATH_OP_ROUND: - rnd_mode = BF_RNDNA; - goto rint; - case MATH_OP_TRUNC: - rnd_mode = BF_RNDZ; - rint: - bf_set(r, a); - fe->status |= bf_rint(r, rnd_mode); - break; - case MATH_OP_SQRT: - fe->status |= bf_sqrt(r, a, fe->prec, fe->flags); - break; - case MATH_OP_FPROUND: - bf_set(r, a); - fe->status |= bf_round(r, fe->prec, fe->flags); - break; - case MATH_OP_ACOS: - fe->status |= bf_acos(r, a, fe->prec, fe->flags); - break; - case MATH_OP_ASIN: - fe->status |= bf_asin(r, a, fe->prec, fe->flags); - break; - case MATH_OP_ATAN: - fe->status |= bf_atan(r, a, fe->prec, fe->flags); - break; - case MATH_OP_COS: - fe->status |= bf_cos(r, a, fe->prec, fe->flags); - break; - case MATH_OP_EXP: - fe->status |= bf_exp(r, a, fe->prec, fe->flags); - break; - case MATH_OP_LOG: - fe->status |= bf_log(r, a, fe->prec, fe->flags); - break; - case MATH_OP_SIN: - fe->status |= bf_sin(r, a, fe->prec, fe->flags); - break; - case MATH_OP_TAN: - fe->status |= bf_tan(r, a, fe->prec, fe->flags); - break; - case MATH_OP_SIGN: - if (bf_is_nan(a) || bf_is_zero(a)) { - bf_set(r, a); - } else { - bf_set_si(r, 1 - 2 * a->sign); - } - break; - default: - abort(); - } - if (a == &a_s) - bf_delete(a); - JS_FreeValue(ctx, op1); - return res; -} - -static JSValue js_bigfloat_fop2(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - bf_t a_s, *a, b_s, *b, r_s, *r = &r_s; - JSFloatEnv *fe; - JSValue op1, op2, res; - - op1 = JS_ToNumeric(ctx, argv[0]); - if (JS_IsException(op1)) - return op1; - op2 = JS_ToNumeric(ctx, argv[1]); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - return op2; - } - a = JS_ToBigFloat(ctx, &a_s, op1); - b = JS_ToBigFloat(ctx, &b_s, op2); - fe = &ctx->fp_env; - if (argc > 2) { - fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV); - if (!fe) - goto fail; - } - res = JS_NewBigFloat(ctx); - if (JS_IsException(res)) { - fail: - if (a == &a_s) - bf_delete(a); - if (b == &b_s) - bf_delete(b); - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - return JS_EXCEPTION; - } - r = JS_GetBigFloat(res); - switch (magic) { - case MATH_OP_ATAN2: - fe->status |= bf_atan2(r, a, b, fe->prec, fe->flags); - break; - case MATH_OP_POW: - fe->status |= bf_pow(r, a, b, fe->prec, fe->flags | BF_POW_JS_QUIRKS); - break; - case MATH_OP_FMOD: - fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ); - break; - case MATH_OP_REM: - fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDN); - break; - case MATH_OP_ADD: - fe->status |= bf_add(r, a, b, fe->prec, fe->flags); - break; - case MATH_OP_SUB: - fe->status |= bf_sub(r, a, b, fe->prec, fe->flags); - break; - case MATH_OP_MUL: - fe->status |= bf_mul(r, a, b, fe->prec, fe->flags); - break; - case MATH_OP_DIV: - fe->status |= bf_div(r, a, b, fe->prec, fe->flags); - 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 const JSCFunctionListEntry js_bigfloat_funcs[] = { - JS_CGETSET_MAGIC_DEF("PI", js_bigfloat_get_const, NULL, 0 ), - JS_CGETSET_MAGIC_DEF("LN2", js_bigfloat_get_const, NULL, 1 ), - JS_CGETSET_MAGIC_DEF("MIN_VALUE", js_bigfloat_get_const, NULL, 2 ), - JS_CGETSET_MAGIC_DEF("MAX_VALUE", js_bigfloat_get_const, NULL, 3 ), - JS_CGETSET_MAGIC_DEF("EPSILON", js_bigfloat_get_const, NULL, 4 ), - JS_CFUNC_DEF("parseFloat", 1, js_bigfloat_parseFloat ), - JS_CFUNC_DEF("isFinite", 1, js_bigfloat_isFinite ), - JS_CFUNC_DEF("isNaN", 1, js_bigfloat_isNaN ), - JS_CFUNC_MAGIC_DEF("abs", 1, js_bigfloat_fop, MATH_OP_ABS ), - JS_CFUNC_MAGIC_DEF("fpRound", 1, js_bigfloat_fop, MATH_OP_FPROUND ), - JS_CFUNC_MAGIC_DEF("floor", 1, js_bigfloat_fop, MATH_OP_FLOOR ), - JS_CFUNC_MAGIC_DEF("ceil", 1, js_bigfloat_fop, MATH_OP_CEIL ), - JS_CFUNC_MAGIC_DEF("round", 1, js_bigfloat_fop, MATH_OP_ROUND ), - JS_CFUNC_MAGIC_DEF("trunc", 1, js_bigfloat_fop, MATH_OP_TRUNC ), - JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigfloat_fop, MATH_OP_SQRT ), - JS_CFUNC_MAGIC_DEF("acos", 1, js_bigfloat_fop, MATH_OP_ACOS ), - JS_CFUNC_MAGIC_DEF("asin", 1, js_bigfloat_fop, MATH_OP_ASIN ), - JS_CFUNC_MAGIC_DEF("atan", 1, js_bigfloat_fop, MATH_OP_ATAN ), - JS_CFUNC_MAGIC_DEF("atan2", 2, js_bigfloat_fop2, MATH_OP_ATAN2 ), - JS_CFUNC_MAGIC_DEF("cos", 1, js_bigfloat_fop, MATH_OP_COS ), - JS_CFUNC_MAGIC_DEF("exp", 1, js_bigfloat_fop, MATH_OP_EXP ), - JS_CFUNC_MAGIC_DEF("log", 1, js_bigfloat_fop, MATH_OP_LOG ), - JS_CFUNC_MAGIC_DEF("pow", 2, js_bigfloat_fop2, MATH_OP_POW ), - JS_CFUNC_MAGIC_DEF("sin", 1, js_bigfloat_fop, MATH_OP_SIN ), - JS_CFUNC_MAGIC_DEF("tan", 1, js_bigfloat_fop, MATH_OP_TAN ), - JS_CFUNC_MAGIC_DEF("sign", 1, js_bigfloat_fop, MATH_OP_SIGN ), - JS_CFUNC_MAGIC_DEF("add", 2, js_bigfloat_fop2, MATH_OP_ADD ), - JS_CFUNC_MAGIC_DEF("sub", 2, js_bigfloat_fop2, MATH_OP_SUB ), - JS_CFUNC_MAGIC_DEF("mul", 2, js_bigfloat_fop2, MATH_OP_MUL ), - JS_CFUNC_MAGIC_DEF("div", 2, js_bigfloat_fop2, MATH_OP_DIV ), - JS_CFUNC_MAGIC_DEF("fmod", 2, js_bigfloat_fop2, MATH_OP_FMOD ), - JS_CFUNC_MAGIC_DEF("remainder", 2, js_bigfloat_fop2, MATH_OP_REM ), -}; - -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 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_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; -} - -/* Note: also used for bigint */ -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 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 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; -} - -void JS_AddIntrinsicBigFloat(JSContext *ctx) -{ - JSRuntime *rt = ctx->rt; - JSValueConst obj1; - rt->bigfloat_ops.to_string = js_bigfloat_to_string; - rt->bigfloat_ops.from_string = js_string_to_bigfloat; - rt->bigfloat_ops.unary_arith = js_unary_arith_bigfloat; - rt->bigfloat_ops.binary_arith = js_binary_arith_bigfloat; - rt->bigfloat_ops.compare = js_compare_bigfloat; - rt->bigfloat_ops.mul_pow10_to_float64 = js_mul_pow10_to_float64; - rt->bigfloat_ops.mul_pow10 = js_mul_pow10; - ctx->class_proto[JS_CLASS_BIG_FLOAT] = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT], - js_bigfloat_proto_funcs, - countof(js_bigfloat_proto_funcs)); - obj1 = JS_NewGlobalCConstructor(ctx, "BigFloat", js_bigfloat_constructor, 1, - ctx->class_proto[JS_CLASS_BIG_FLOAT]); - JS_SetPropertyFunctionList(ctx, obj1, js_bigfloat_funcs, - countof(js_bigfloat_funcs)); - ctx->class_proto[JS_CLASS_FLOAT_ENV] = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_FLOAT_ENV], - js_float_env_proto_funcs, - countof(js_float_env_proto_funcs)); - obj1 = JS_NewGlobalCConstructorOnly(ctx, "BigFloatEnv", - js_float_env_constructor, 1, - ctx->class_proto[JS_CLASS_FLOAT_ENV]); - JS_SetPropertyFunctionList(ctx, obj1, js_float_env_funcs, - countof(js_float_env_funcs)); -} diff --git a/third_party/quickjs/gc.c b/third_party/quickjs/gc.c deleted file mode 100644 index 94e59d22d..000000000 --- a/third_party/quickjs/gc.c +++ /dev/null @@ -1,495 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/assert.h" -#include "libc/runtime/runtime.h" -#include "third_party/quickjs/internal.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -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); - } -} - -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 js_mark_module_def(JSRuntime *rt, JSModuleDef *m, - JS_MarkFunc *mark_func) -{ - int i; - 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) { - mark_func(rt, &me->u.local.var_ref->header); - } - } - JS_MarkValue(rt, m->module_ns, mark_func); - JS_MarkValue(rt, m->func_obj, mark_func); - JS_MarkValue(rt, m->eval_exception, mark_func); - JS_MarkValue(rt, m->meta_obj, mark_func); -} - -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); -} - -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 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(); - } -} - -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; -} - -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; -} - -/* 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); -} diff --git a/third_party/quickjs/gen.c b/third_party/quickjs/gen.c deleted file mode 100644 index 623e20955..000000000 --- a/third_party/quickjs/gen.c +++ /dev/null @@ -1,509 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/assert.h" -#include "libc/runtime/runtime.h" -#include "third_party/quickjs/internal.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -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; -} - -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); -} - -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); -} - -static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - BOOL *pdone, int magic) -{ - JSGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_GENERATOR); - JSStackFrame *sf; - JSValue ret, func_ret; - *pdone = TRUE; - if (!s) - return JS_ThrowTypeError(ctx, "not a generator"); - sf = &s->func_state.frame; - 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: - 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 && - s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) { - JS_Throw(ctx, ret); - s->func_state.throw_flag = TRUE; - } else { - sf->cur_sp[-1] = ret; - sf->cur_sp[0] = JS_NewInt32(ctx, magic); - sf->cur_sp++; - exec_no_arg: - s->func_state.throw_flag = FALSE; - } - s->state = JS_GENERATOR_STATE_EXECUTING; - func_ret = async_func_resume(ctx, &s->func_state); - s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD; - if (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) { - /* get the returned yield value at the top of the stack */ - ret = sf->cur_sp[-1]; - sf->cur_sp[-1] = JS_UNDEFINED; - if (JS_VALUE_GET_INT(func_ret) == FUNC_RET_YIELD_STAR) { - s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR; - /* return (value, done) object */ - *pdone = 2; - } else { - *pdone = FALSE; - } - } 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; -} - -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; -} - -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; -} - -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; -} - -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 const JSCFunctionListEntry js_generator_function_proto_funcs[] = { - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "GeneratorFunction", JS_PROP_CONFIGURABLE), -}; - -static const JSCFunctionListEntry js_generator_proto_funcs[] = { - JS_ITERATOR_NEXT_DEF("next", 1, js_generator_next, GEN_MAGIC_NEXT ), - JS_ITERATOR_NEXT_DEF("return", 1, js_generator_next, GEN_MAGIC_RETURN ), - JS_ITERATOR_NEXT_DEF("throw", 1, js_generator_next, GEN_MAGIC_THROW ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Generator", JS_PROP_CONFIGURABLE), -}; - -void JS_AddIntrinsicGenerator(JSContext *ctx) -{ - JSValue obj1; - ctx->class_proto[JS_CLASS_GENERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_GENERATOR], - js_generator_proto_funcs, - countof(js_generator_proto_funcs)); - ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION] = JS_NewObjectProto(ctx, ctx->function_proto); - obj1 = JS_NewCFunctionMagic(ctx, js_function_constructor, - "GeneratorFunction", 1, - JS_CFUNC_constructor_or_func_magic, JS_FUNC_GENERATOR); - JS_SetPropertyFunctionList(ctx, - ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION], - js_generator_function_proto_funcs, - countof(js_generator_function_proto_funcs)); - JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION], - ctx->class_proto[JS_CLASS_GENERATOR], - JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE); - JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION], - 0, JS_PROP_CONFIGURABLE); - JS_FreeValue(ctx, obj1); -} diff --git a/third_party/quickjs/internal.h b/third_party/quickjs/internal.h deleted file mode 100644 index c3a4d9eea..000000000 --- a/third_party/quickjs/internal.h +++ /dev/null @@ -1,2211 +0,0 @@ -#ifndef COSMOPOLITAN_THIRD_PARTY_QUICKJS_INTERNAL_H_ -#define COSMOPOLITAN_THIRD_PARTY_QUICKJS_INTERNAL_H_ -#include "third_party/quickjs/cutils.h" -#include "third_party/quickjs/libbf.h" -#include "third_party/quickjs/list.h" -#include "third_party/quickjs/quickjs.h" -COSMOPOLITAN_C_START_ - -#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) && defined(USE_WORKER) -#define CONFIG_ATOMICS -#endif - -#if !defined(EMSCRIPTEN) -/* enable stack limitation */ -#define CONFIG_STACK_CHECK -#endif - -#define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1) - -#define HINT_STRING 0 -#define HINT_NUMBER 1 -#define HINT_NONE 2 -#define HINT_FORCE_ORDINARY (1 << 4) /* don't try Symbol.toPrimitive */ - -/* 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) - -#define ATOM_GET_STR_BUF_SIZE 64 - -#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) - -#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 - -typedef enum { - PUT_LVALUE_NOKEEP, /* [depth] v -> */ - PUT_LVALUE_NOKEEP_DEPTH, /* [depth] v -> , keep depth (currently - just disable optimizations) */ - PUT_LVALUE_KEEP_TOP, /* [depth] v -> v */ - PUT_LVALUE_KEEP_SECOND, /* [depth] v0 v -> v0 */ - PUT_LVALUE_NOKEEP_BOTTOM, /* v [depth] -> */ -} PutLValueEnum; - -/* 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; - -typedef enum FuncCallType { - FUNC_CALL_NORMAL, - FUNC_CALL_NEW, - FUNC_CALL_SUPER_CTOR, - FUNC_CALL_TEMPLATE, -} FuncCallType; - -typedef enum { - JS_VAR_DEF_WITH, - JS_VAR_DEF_LET, - JS_VAR_DEF_CONST, - JS_VAR_DEF_FUNCTION_DECL, /* function declaration */ - JS_VAR_DEF_NEW_FUNCTION_DECL, /* async/generator function declaration */ - JS_VAR_DEF_CATCH, - JS_VAR_DEF_VAR, -} JSVarDefEnum; - -#define FUNC_RET_AWAIT 0 -#define FUNC_RET_YIELD 1 -#define FUNC_RET_YIELD_STAR 2 - -#define FE_PREC (-1) -#define FE_EXP (-2) -#define FE_RNDMODE (-3) -#define FE_SUBNORMAL (-4) - -#define JS_CALL_FLAG_COPY_ARGV (1 << 1) -#define JS_CALL_FLAG_GENERATOR (1 << 2) - -#define TOK_FIRST_KEYWORD TOK_NULL -#define TOK_LAST_KEYWORD TOK_AWAIT - -#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) - -/* unicode code points */ -#define CP_NBSP 0x00a0 -#define CP_BOM 0xfeff - -#define CP_LS 0x2028 -#define CP_PS 0x2029 - -#define MAGIC_SET (1 << 0) -#define MAGIC_WEAK (1 << 1) - -/* XXX: use enum */ -#define GEN_MAGIC_NEXT 0 -#define GEN_MAGIC_RETURN 1 -#define GEN_MAGIC_THROW 2 - -#define OP_DEFINE_METHOD_METHOD 0 -#define OP_DEFINE_METHOD_GETTER 1 -#define OP_DEFINE_METHOD_SETTER 2 -#define OP_DEFINE_METHOD_ENUMERABLE 4 - -#define JS_THROW_VAR_RO 0 -#define JS_THROW_VAR_REDECL 1 -#define JS_THROW_VAR_UNINITIALIZED 2 -#define JS_THROW_ERROR_DELETE_SUPER 3 -#define JS_THROW_ERROR_ITERATOR_THROW 4 - -#define GLOBAL_VAR_OFFSET 0x40000000 -#define ARGUMENT_VAR_OFFSET 0x20000000 - -#define DEFINE_GLOBAL_LEX_VAR (1 << 7) -#define DEFINE_GLOBAL_FUNC_VAR (1 << 6) - -#define JS_DEFINE_CLASS_HAS_HERITAGE (1 << 0) - -#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) - -#define special_reduce 0 -#define special_reduceRight 1 - -#define special_every 0 -#define special_some 1 -#define special_forEach 2 -#define special_map 3 -#define special_filter 4 -#define special_TA 8 - -#define PF_IN_ACCEPTED (1 << 0) /* allow the 'in' binary operator */ -#define PF_POSTFIX_CALL (1 << 1) /* allow function calls parsing in js_parse_postfix_expr() */ -#define PF_ARROW_FUNC (1 << 2) /* allow arrow functions parsing in js_parse_postfix_expr() */ -#define PF_POW_ALLOWED (1 << 3) /* allow the exponentiation operator in js_parse_unary() */ -#define PF_POW_FORBIDDEN (1 << 4) /* forbid the exponentiation operator in js_parse_unary() */ - -#define PROP_TYPE_IDENT 0 -#define PROP_TYPE_VAR 1 -#define PROP_TYPE_GET 2 -#define PROP_TYPE_SET 3 -#define PROP_TYPE_STAR 4 -#define PROP_TYPE_ASYNC 5 -#define PROP_TYPE_ASYNC_STAR 6 - -#define PROP_TYPE_PRIVATE (1 << 4) - -#define SKIP_HAS_SEMI (1 << 0) -#define SKIP_HAS_ELLIPSIS (1 << 1) -#define SKIP_HAS_ASSIGNMENT (1 << 2) - -#define DECL_MASK_FUNC (1 << 0) /* allow normal function declaration */ -/* ored with DECL_MASK_FUNC if function declarations are allowed with a label */ -#define DECL_MASK_FUNC_WITH_LABEL (1 << 1) -#define DECL_MASK_OTHER (1 << 2) /* all other declarations */ -#define DECL_MASK_ALL (DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL | DECL_MASK_OTHER) - -/* 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 - -enum { - MATH_OP_ABS, - MATH_OP_FLOOR, - MATH_OP_CEIL, - MATH_OP_ROUND, - MATH_OP_TRUNC, - MATH_OP_SQRT, - MATH_OP_FPROUND, - MATH_OP_ACOS, - MATH_OP_ASIN, - MATH_OP_ATAN, - MATH_OP_ATAN2, - MATH_OP_COS, - MATH_OP_EXP, - MATH_OP_LOG, - MATH_OP_POW, - MATH_OP_SIN, - MATH_OP_TAN, - MATH_OP_FMOD, - MATH_OP_REM, - MATH_OP_SIGN, - MATH_OP_ADD, - MATH_OP_SUB, - MATH_OP_MUL, - MATH_OP_DIV, -}; - -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 */ -}; - -typedef enum OPCodeFormat { -#define FMT(f) OP_FMT_ ## f, -#define DEF(id, size, n_pop, n_push, f) -#include "third_party/quickjs/quickjs-opcode.inc" -#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 "third_party/quickjs/quickjs-opcode.inc" -#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 "third_party/quickjs/quickjs-opcode.inc" -#undef def -#undef DEF -#undef FMT - OP_TEMP_END, -}; - -enum { - __JS_ATOM_NULL = JS_ATOM_NULL, -#define DEF(name, str) JS_ATOM_ ## name, -#include "third_party/quickjs/quickjs-atom.inc" -#undef DEF - JS_ATOM_END, -}; -#define JS_ATOM_LAST_KEYWORD JS_ATOM_super -#define JS_ATOM_LAST_STRICT_KEYWORD JS_ATOM_yield - -typedef enum JSStrictEqModeEnum { - JS_EQ_STRICT, - JS_EQ_SAME_VALUE, - JS_EQ_SAME_VALUE_ZERO, -} JSStrictEqModeEnum; - -/* 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 65534 -#define JS_STRING_LEN_MAX ((1 << 30) - 1) - -#define __exception __wur - -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 - -typedef enum JSIteratorKindEnum { - JS_ITERATOR_KIND_KEY, - JS_ITERATOR_KIND_VALUE, - JS_ITERATOR_KIND_KEY_AND_VALUE, -} JSIteratorKindEnum; - -typedef struct JSMapRecord { - int ref_count; /* used during enumeration to avoid freeing the record */ - BOOL empty; /* TRUE if the record is deleted */ - struct JSMapState *map; - struct JSMapRecord *next_weak_ref; - struct list_head link; - struct list_head hash_link; - JSValue key; - JSValue value; -} JSMapRecord; - -typedef struct JSMapIteratorData { - JSValue obj; - JSIteratorKindEnum kind; - JSMapRecord *cur_record; -} JSMapIteratorData; - -typedef struct JSMapState { - BOOL is_weak; /* TRUE if WeakSet/WeakMap */ - struct list_head records; /* list of JSMapRecord.link */ - uint32_t record_count; - struct list_head *hash_table; - uint32_t hash_size; /* must be a power of two */ - uint32_t record_count_threshold; /* count at which a hash table - resize is needed */ -} JSMapState; - -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 */ - uintptr_t stack_size; /* in bytes, 0 if no limit */ - uintptr_t stack_top; - uintptr_t stack_limit; /* lower stack limit */ - JSValue current_exception; - /* true if 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; - -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; - -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 : 4; /* see JSVarKindEnum */ - /* 8 bits available */ - uint16_t var_idx; /* is_local = TRUE: index to a normal variable of the - parent function. otherwise: index to a closure - variable of the parent function */ - JSAtom var_name; -} JSClosureVar; - -#define ARG_SCOPE_INDEX 1 -#define ARG_SCOPE_END (-2) - -typedef struct JSVarScope { - int parent; /* index into fd->scopes of the enclosing scope */ - int first; /* index into fd->vars of the last variable in this scope */ -} JSVarScope; - -typedef enum { - /* XXX: add more variable kinds here instead of using bit fields */ - JS_VAR_NORMAL, - JS_VAR_FUNCTION_DECL, /* lexical var with function declaration */ - JS_VAR_NEW_FUNCTION_DECL, /* lexical var with async/generator - function declaration */ - JS_VAR_CATCH, - JS_VAR_FUNCTION_NAME, /* function expression name */ - JS_VAR_PRIVATE_FIELD, - JS_VAR_PRIVATE_METHOD, - JS_VAR_PRIVATE_GETTER, - JS_VAR_PRIVATE_SETTER, /* must come after JS_VAR_PRIVATE_GETTER */ - JS_VAR_PRIVATE_GETTER_SETTER, /* must come after JS_VAR_PRIVATE_SETTER */ -} JSVarKindEnum; - -/* XXX: could use a different structure in bytecode functions to save - memory */ -typedef struct JSVarDef { - JSAtom var_name; - /* index into fd->scopes of this variable lexical scope */ - int scope_level; - /* during compilation: - - if scope_level = 0: scope in which the variable is defined - - if scope_level != 0: index into fd->vars of the next - variable in the same or enclosing lexical scope - in a bytecode function: - index into fd->vars of the next - variable in the same or enclosing lexical scope - */ - int scope_next; - uint8_t is_const : 1; - uint8_t is_lexical : 1; - uint8_t is_captured : 1; - uint8_t var_kind : 4; /* see JSVarKindEnum */ - /* only used during compilation: function pool index for lexical - variables with var_kind = - JS_VAR_FUNCTION_DECL/JS_VAR_NEW_FUNCTION_DECL or scope level of - the definition of the 'var' variables (they have scope_level = - 0) */ - int func_pool_idx : 24; /* only used during compilation : index in - the constant pool for hoisted function - definition */ -} JSVarDef; - -/* for the encoding of the pc2line table */ -#define PC2LINE_BASE (-1) -#define PC2LINE_RANGE 5 -#define PC2LINE_OP_FIRST 1 -#define PC2LINE_DIFF_PC_MAX ((255 - PC2LINE_OP_FIRST) / PC2LINE_RANGE) - -typedef enum JSFunctionKindEnum { - JS_FUNC_NORMAL = 0, - JS_FUNC_GENERATOR = (1 << 0), - JS_FUNC_ASYNC = (1 << 1), - JS_FUNC_ASYNC_GENERATOR = (JS_FUNC_GENERATOR | JS_FUNC_ASYNC), -} JSFunctionKindEnum; - -typedef struct JSRegExpStringIteratorData { - JSValue iterating_regexp; - JSValue iterated_string; - BOOL global; - BOOL unicode; - BOOL done; -} JSRegExpStringIteratorData; - -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 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 StringBuffer { - JSContext *ctx; - JSString *str; - int len; - int size; - int is_wide_char; - int error_status; -} StringBuffer; - -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 { - /* hash table of size hash_mask + 1 before the start of the - structure (see prop_hash_end()). */ - JSGCObjectHeader header; - /* true if the shape is inserted in the shape hash table. If not, - JSShape.hash is not valid */ - uint8_t is_hashed; - /* If true, the shape may have small array index properties 'n' with 0 - <= n <= 2^31-1. If false, the shape is guaranteed not to have - small array index properties */ - uint8_t has_small_array_index; - uint32_t hash; /* current hash value */ - uint32_t prop_hash_mask; - int prop_size; /* allocated properties */ - int prop_count; /* include deleted properties */ - int deleted_prop_count; - JSShape *shape_hash_next; /* in JSRuntime.shape_hash[h] list */ - JSObject *proto; - JSShapeProperty prop[0]; /* prop_size elements */ -}; - -struct JSObject { - union { - JSGCObjectHeader header; - struct { - int __gc_ref_count; /* corresponds to header.ref_count */ - uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */ - - uint8_t extensible : 1; - uint8_t free_mark : 1; /* only used when freeing objects with cycles */ - uint8_t is_exotic : 1; /* TRUE if object has exotic property handlers */ - uint8_t fast_array : 1; /* TRUE if u.array is used for get/put (for JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS and typed arrays) */ - uint8_t is_constructor : 1; /* TRUE if object is a constructor function */ - uint8_t is_uncatchable_error : 1; /* if TRUE, error is not catchable */ - uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */ - uint8_t is_HTMLDDA : 1; /* specific annex B IsHtmlDDA behavior */ - uint16_t class_id; /* see JS_CLASS_x */ - }; - }; - /* 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 { - 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_LAND_ASSIGN, - TOK_LOR_ASSIGN, - TOK_DOUBLE_QUESTION_MARK_ASSIGN, - TOK_DEC, - TOK_INC, - TOK_SHL, - TOK_SAR, - TOK_SHR, - TOK_LT, - TOK_LTE, - TOK_GT, - TOK_GTE, - TOK_EQ, - TOK_STRICT_EQ, - TOK_NEQ, - TOK_STRICT_NEQ, - TOK_LAND, - TOK_LOR, -#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() */ -}; - -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 JSGlobalVar { - int cpool_idx; /* if >= 0, index in the constant pool for hoisted - function defintion*/ - uint8_t force_init : 1; /* force initialization to undefined */ - uint8_t is_lexical : 1; /* global let/const definition */ - uint8_t is_const : 1; /* const definition */ - int scope_level; /* scope of definition */ - JSAtom var_name; /* variable name */ -} JSGlobalVar; - -typedef struct RelocEntry { - struct RelocEntry *next; - uint32_t addr; /* address to patch */ - int size; /* address size: 1, 2 or 4 bytes */ -} RelocEntry; - -typedef struct JumpSlot { - int op; - int size; - int pos; - int label; -} JumpSlot; - -typedef struct LabelSlot { - int ref_count; - int pos; /* phase 1 address, -1 means not resolved yet */ - int pos2; /* phase 2 address, -1 means not resolved yet */ - int addr; /* phase 3 address, -1 means not resolved yet */ - RelocEntry *first_reloc; -} LabelSlot; - -typedef struct LineNumberSlot { - uint32_t pc; - 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_parameter_expressions; /* if true, an argument scope is created */ - BOOL has_use_strict; /* to reject directive in special cases */ - BOOL has_eval_call; /* true if the function contains a call to eval() */ - BOOL has_arguments_binding; /* true if the 'arguments' binding is - available in the function */ - BOOL has_this_binding; /* true if the 'this' and new.target binding are - available in the function */ - BOOL new_target_allowed; /* true if the 'new.target' does not - throw a syntax error */ - BOOL super_call_allowed; /* true if super() is allowed */ - BOOL super_allowed; /* true if super. or super[] is allowed */ - BOOL arguments_allowed; /* true if the 'arguments' identifier is allowed */ - BOOL is_derived_class_constructor; - BOOL in_function_body; - 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 arg_var_object_idx; /* -1 if none (var object for the argument scope) */ - int arguments_var_idx; /* -1 if none */ - int arguments_arg_idx; /* argument variable definition in argument scope, - -1 if none */ - int func_var_idx; /* variable containing the current function (-1 - if none, only used if is_func_expr is true) */ - int eval_ret_idx; /* variable containing the return value of the eval, -1 if none */ - int this_var_idx; /* variable containg the 'this' value, -1 if none */ - int new_target_var_idx; /* variable containg the 'new.target' value, -1 if none */ - int this_active_func_var_idx; /* variable containg the 'this.active_func' value, -1 if none */ - int home_object_var_idx; - BOOL need_home_object; - int scope_level; /* index into fd->scopes if the current lexical scope */ - int scope_first; /* index into vd->vars of first lexically scoped variable */ - int scope_size; /* allocated size of fd->scopes array */ - int scope_count; /* number of entries used in the fd->scopes array */ - JSVarScope *scopes; - JSVarScope def_scope_array[4]; - int body_scope; /* scope of the body of the function or eval */ - int global_var_count; - int global_var_size; - JSGlobalVar *global_vars; - DynBuf byte_code; - int last_opcode_pos; /* -1 if no last opcode */ - 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 JSCFunctionDataRecord { - JSCFunctionData *func; - uint8_t length; - uint8_t data_len; - uint16_t magic; - JSValue data[0]; -} JSCFunctionDataRecord; - -typedef struct { - JSFunctionDef *fields_init_fd; - int computed_fields_count; - BOOL has_brand; - int brand_push_pos; -} ClassFieldsDef; - -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; - -typedef struct JSArrayIteratorData { - JSValue obj; - JSIteratorKindEnum kind; - uint32_t idx; -} JSArrayIteratorData; - -typedef struct JSParsePos { - int last_line_num; - int line_num; - BOOL got_lf; - const uint8_t *ptr; -} JSParsePos; - -typedef struct JSClassShortDef { - JSAtom class_name; - JSClassFinalizer *finalizer; - JSClassGCMark *gc_mark; -} JSClassShortDef; - -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; - -typedef struct JSAsyncFromSyncIteratorData { - JSValue sync_iter; - JSValue next_method; -} JSAsyncFromSyncIteratorData; - -typedef struct JSONStringifyContext { - JSValueConst replacer_func; - JSValue stack; - JSValue property_list; - JSValue gap; - JSValue empty; - StringBuffer *b; -} JSONStringifyContext; - -typedef struct BCReaderState { - JSContext *ctx; - const uint8_t *buf_start, *ptr, *buf_end; - uint32_t first_atom; - uint32_t idx_to_atom_count; - JSAtom *idx_to_atom; - int error_state; - BOOL allow_sab : 8; - BOOL allow_bytecode : 8; - BOOL is_rom_data : 8; - BOOL allow_reference : 8; - /* object references */ - JSObject **objects; - int objects_count; - int objects_size; -#ifdef DUMP_READ_OBJECT - const uint8_t *ptr_last; - int level; -#endif -} BCReaderState; - -extern const JSClassShortDef js_std_class_def[]; -extern const JSOpCode opcode_info[]; - -void JS_FreeAtomStruct(JSRuntime *, JSAtomStruct *); - -JSString *js_alloc_string(JSContext *, int, int); -JSString *js_alloc_string_rt(JSRuntime *, int, int); -JSValue js_new_string16(JSContext *, const uint16_t *, int); -JSValue js_new_string8(JSContext *, const uint8_t *, int); -JSValue js_new_string_char(JSContext *, uint16_t); -int js_string_compare(JSContext *, const JSString *, const JSString *); -int js_string_memcmp(const JSString *, const JSString *, int); -void js_free_string(JSRuntime *, JSString *); - -JSValue string_buffer_end(StringBuffer *); -int string_buffer_concat(StringBuffer *, const JSString *, uint32_t, uint32_t); -int string_buffer_concat_value(StringBuffer *, JSValueConst); -int string_buffer_concat_value_free(StringBuffer *, JSValue); -int string_buffer_fill(StringBuffer *, int, int); -int string_buffer_init(JSContext *, StringBuffer *, int); -int string_buffer_init2(JSContext *, StringBuffer *, int, int); -int string_buffer_putc(StringBuffer *, uint32_t); -int string_buffer_putc16(StringBuffer *, uint32_t); -int string_buffer_putc8(StringBuffer *, uint32_t); -int string_buffer_putc_slow(StringBuffer *, uint32_t); -int string_buffer_puts8(StringBuffer *, const char *); -int string_buffer_realloc(StringBuffer *, int, int); -int string_buffer_set_error(StringBuffer *); -int string_buffer_widen(StringBuffer *, int); -int string_buffer_write16(StringBuffer *, const uint16_t *, int); -int string_buffer_write8(StringBuffer *, const uint8_t *, int); -void string_buffer_free(StringBuffer *); - -JSContext *JS_GetFunctionRealm(JSContext *, JSValueConst); -JSValue JS_ThrowTypeErrorInvalidClass(JSContext *, int); -JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *); -JSValue js_create_from_ctor(JSContext *, JSValueConst, int); -int JS_ToBoolFree(JSContext *, JSValue); - -BOOL js_same_value(JSContext *, JSValueConst, JSValueConst); -BOOL js_same_value_zero(JSContext *, JSValueConst, JSValueConst); -BOOL js_strict_eq(JSContext *, JSValue, JSValue); -BOOL js_strict_eq2(JSContext *, JSValue, JSValue, JSStrictEqModeEnum); -int js_strict_eq_slow(JSContext *, JSValue *, BOOL); - -JSRegExp *js_get_regexp(JSContext *, JSValueConst, BOOL); -JSValue JS_RegExpExec(JSContext *, JSValueConst, JSValueConst); -JSValue js_compile_regexp(JSContext *, JSValueConst, JSValueConst); -JSValue js_regexp_Symbol_matchAll(JSContext *, JSValueConst, int, JSValueConst *); -JSValue js_regexp_compile(JSContext *, JSValueConst, int, JSValueConst *); -JSValue js_regexp_constructor(JSContext *, JSValueConst, int, JSValueConst *); -JSValue js_regexp_constructor_internal(JSContext *, JSValueConst, JSValue, JSValue); -JSValue js_regexp_exec(JSContext *, JSValueConst, int, JSValueConst *); -JSValue js_regexp_get_flag(JSContext *, JSValueConst, int); -JSValue js_regexp_get_flags(JSContext *, JSValueConst); -JSValue js_regexp_get_source(JSContext *, JSValueConst); -JSValue js_regexp_string_iterator_next(JSContext *, JSValueConst, int, JSValueConst *, BOOL *, int); -JSValue js_regexp_toString(JSContext *, JSValueConst, int, JSValueConst *); -int js_is_regexp(JSContext *, JSValueConst); -void js_regexp_finalizer(JSRuntime *, JSValue); -void js_regexp_string_iterator_finalizer(JSRuntime *, JSValue); -void js_regexp_string_iterator_mark(JSRuntime *, JSValueConst, JS_MarkFunc *); - -JSValue JS_GetPropertyInt64(JSContext *, JSValueConst, int64_t); -JSValue JS_ThrowError(JSContext *, JSErrorEnum, const char *, va_list); -JSValue JS_ThrowError2(JSContext *, JSErrorEnum, const char *, va_list, BOOL); -JSValue JS_ThrowReferenceErrorNotDefined(JSContext *, JSAtom); -JSValue JS_ThrowReferenceErrorUninitialized(JSContext *, JSAtom); -JSValue JS_ThrowReferenceErrorUninitialized2(JSContext *, JSFunctionBytecode *, int, BOOL); -JSValue JS_ThrowStackOverflow(JSContext *); -JSValue JS_ThrowSyntaxErrorVarRedeclaration(JSContext *, JSAtom); -JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *); -JSValue JS_ThrowTypeErrorNotASymbol(JSContext *); -JSValue JS_ThrowTypeErrorNotAnObject(JSContext *); -JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *, JSAtom); -JSValue __JS_ThrowSyntaxErrorAtom(JSContext *, JSAtom, const char *, ...) printfesque(3); -JSValue __JS_ThrowTypeErrorAtom(JSContext *, JSAtom, const char *, ...) printfesque(3); -JSValue throw_bf_exception(JSContext *, int); -int JS_ThrowTypeErrorOrFalse(JSContext *, int, const char *, ...) printfesque(3); -int JS_ThrowTypeErrorReadOnly(JSContext *, int, JSAtom); -int js_parse_error(JSParseState *, const char *, ...) printfesque(2); -int js_throw_URIError(JSContext *, const char *, ...) printfesque(2); -void build_backtrace(JSContext *, JSValueConst, const char *, int, int); -int js_compare_bigfloat(JSContext *, OPCodeEnum, JSValue, JSValue); - -/* %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, "") - -JSValue JS_ToLocaleStringFree(JSContext *, JSValue); -JSValue JS_ToStringFree(JSContext *, JSValue); -JSValue JS_ToStringInternal(JSContext *, JSValueConst, BOOL); -JSValue js_atof(JSContext *, const char *, const char **, int, int); -JSValue js_atof2(JSContext *, const char *, const char **, int, int, slimb_t *); -JSValue js_bigdecimal_to_string(JSContext *, JSValueConst); -JSValue js_bigdecimal_to_string1(JSContext *, JSValueConst, limb_t, int); -JSValue js_bigfloat_to_string(JSContext *, JSValueConst); -JSValue js_bigint_to_string(JSContext *, JSValueConst); -JSValue js_bigint_to_string1(JSContext *, JSValueConst, int); -JSValue js_dtoa(JSContext *, double, int, int, int); -JSValue js_ftoa(JSContext *, JSValueConst, int, limb_t, bf_flags_t); -bfdec_t *JS_ToBigDecimal(JSContext *, JSValueConst); - -bf_t *JS_ToBigInt(JSContext *, bf_t *, JSValueConst); -void JS_FreeBigInt(JSContext *, bf_t *, bf_t *); -JSValue JS_ToNumeric(JSContext *, JSValueConst); -bf_t *JS_ToBigFloat(JSContext *, bf_t *, JSValueConst); -JSValue JS_NewBigInt64_1(JSContext *, int64_t); - -JSValue js_sub_string(JSContext *, JSString *, int, int); -int string_cmp(JSString *, JSString *, int, int, int); -int string_getc(const JSString *, int *); -int string_indexof(JSString *, JSString *, int); -int string_indexof_char(JSString *, int, int); -int64_t string_advance_index(JSString *, int64_t, BOOL); - -BOOL js_class_has_bytecode(JSClassID); -JSFunctionBytecode *JS_GetFunctionBytecode(JSValueConst); -int check_function(JSContext *, JSValueConst); -int find_line_num(JSContext *, JSFunctionBytecode *, uint32_t); -void js_bytecode_function_mark(JSRuntime *, JSValueConst, JS_MarkFunc *); - -JSAtom js_get_atom_index(JSRuntime *, JSAtomStruct *); -const char *JS_AtomGetStrRT(JSRuntime *, char *, int, JSAtom); -const char *JS_AtomGetStr(JSContext *, char *, int, JSAtom); -BOOL JS_AtomIsArrayIndex(JSContext *, uint32_t *, JSAtom); -BOOL is_num_string(uint32_t *, const JSString *); -JSAtom js_symbol_to_atom(JSContext *, JSValue); -JSValue JS_NewSymbol(JSContext *, JSString *, int); -int JS_DefineObjectNameComputed(JSContext *, JSValueConst, JSValueConst, int); -int JS_SetPrototypeInternal(JSContext *, JSValueConst, JSValueConst, BOOL); -void js_method_set_home_object(JSContext *, JSValueConst, JSValueConst); -JSValue js_get_function_name(JSContext *, JSAtom); -JSValue JS_ConcatString3(JSContext *, const char *, JSValue, const char *); - -BOOL JS_IsCFunction(JSContext *, JSValueConst, JSCFunction *, int); -JSAtom JS_NewAtomInt64(JSContext *, int64_t); -JSAtom JS_NewAtomStr(JSContext *, JSString *); -JSAtomKindEnum JS_AtomGetKind(JSContext *, JSAtom); -JSValue JS_CallFree(JSContext *, JSValue, JSValueConst, int, JSValueConst *); -JSValue JS_ConcatString(JSContext *, JSValue, JSValue); -JSValue JS_EvalObject(JSContext *, JSValueConst, JSValueConst, int, int); -JSValue JS_GetIterator(JSContext *, JSValueConst, BOOL); -JSValue JS_GetPropertyValue(JSContext *, JSValueConst, JSValue); -JSValue JS_GetPrototypeFree(JSContext *, JSValue); -JSValue JS_InvokeFree(JSContext *, JSValue, JSAtom, int, JSValueConst *); -JSValue JS_IteratorNext(JSContext *, JSValueConst, JSValueConst, int, JSValueConst *, BOOL *); -JSValue JS_IteratorNext2(JSContext *, JSValueConst, JSValueConst, int, JSValueConst *, int *); -JSValue JS_NewBigFloat(JSContext *); -JSValue JS_SpeciesConstructor(JSContext *, JSValueConst, JSValueConst); -JSValue JS_ToNumberFree(JSContext *, JSValue); -JSValue JS_ToNumericFree(JSContext *, JSValue); -JSValue JS_ToObjectFree(JSContext *, JSValue); -JSValue JS_ToPrimitive(JSContext *, JSValueConst, int); -JSValue JS_ToPrimitiveFree(JSContext *, JSValue, int); -JSValue JS_ToQuotedString(JSContext *, JSValueConst); -JSValue JS_ToStringCheckObject(JSContext *, JSValueConst); -int JS_CreateDataPropertyUint32(JSContext *, JSValueConst, int64_t, JSValue, int); -int JS_DefinePropertyValueInt64(JSContext *, JSValueConst, int64_t, JSValue, int); -int JS_DefinePropertyValueValue(JSContext *, JSValueConst, JSValue, JSValue, int); -int JS_ReadFunctionBytecode(BCReaderState *, JSFunctionBytecode *, int, uint32_t); -int JS_SetPropertyGeneric(JSContext *, JSValueConst, JSAtom, JSValue, JSValueConst, int); -int JS_SetPropertyValue(JSContext *, JSValueConst, JSValue, JSValue, int); -int JS_ToInt32Free(JSContext *, int32_t *, JSValue); -int JS_ToInt32Sat(JSContext *, int *, JSValueConst); -int JS_ToInt64Clamp(JSContext *, int64_t *, JSValueConst, int64_t, int64_t, int64_t); -int JS_ToInt64SatFree(JSContext *, int64_t *, JSValue); -void JS_SetConstructor2(JSContext *, JSValueConst, JSValueConst, int, int); - -JSValue JS_NewBigInt(JSContext *); -JSValue JS_CompactBigInt(JSContext *, JSValue); -JSValue JS_StringToBigInt(JSContext *, JSValue); -int JS_ToBigInt64Free(JSContext *, int64_t *, JSValue); - -BOOL check_define_prop_flags(int, int); -JSAtom get_private_setter_name(JSContext *, JSAtom); -JSAtom js_atom_concat_str(JSContext *, JSAtom, const char *); -JSExportEntry *add_export_entry(JSParseState *, JSModuleDef *, JSAtom, JSAtom, JSExportTypeEnum); -JSFunctionDef *js_new_function_def(JSContext *, JSFunctionDef *, BOOL, BOOL, const char *, int); -JSGlobalVar *add_global_var(JSContext *, JSFunctionDef *, JSAtom); -JSGlobalVar *find_global_var(JSFunctionDef *, JSAtom); -JSModuleDef *js_new_module_def(JSContext *, JSAtom); -JSValue JS_GetIterator2(JSContext *, JSValueConst, JSValueConst); -JSValue JS_GetOwnPropertyNames2(JSContext *, JSValueConst, int, int); -JSValue JS_NewBigDecimal(JSContext *); -JSValue JS_ToObject(JSContext *, JSValueConst); -JSValue js___date_clock(JSContext *, JSValueConst, int, JSValueConst *); -JSValue js_generator_function_call(JSContext *, JSValueConst, JSValueConst, int, JSValueConst *, int); -JSValue js_global_decodeURI(JSContext *, JSValueConst, int, JSValueConst *, int); -JSValue js_global_encodeURI(JSContext *, JSValueConst, int, JSValueConst *, int); -JSValue js_global_escape(JSContext *, JSValueConst, int, JSValueConst *); -JSValue js_global_unescape(JSContext *, JSValueConst, int, JSValueConst *); -JSValue js_object_defineProperty(JSContext *, JSValueConst, int, JSValueConst *, int); -JSValue js_object_getOwnPropertyDescriptor(JSContext *, JSValueConst, int, JSValueConst *, int); -JSValue js_object_getPrototypeOf(JSContext *, JSValueConst, int, JSValueConst *, int); -JSValue js_object_isExtensible(JSContext *, JSValueConst, int, JSValueConst *, int); -JSValue js_object_keys(JSContext *, JSValueConst, int, JSValueConst *, int); -JSValue js_object_preventExtensions(JSContext *, JSValueConst, int, JSValueConst *, int); -JSValue js_object_toString(JSContext *, JSValueConst, int, JSValueConst *); -JSValue js_promise_resolve(JSContext *, JSValueConst, int, JSValueConst *, int); -JSValue js_string___GetSubstitution(JSContext *, JSValueConst, int, JSValueConst *); -JSValue js_string_constructor(JSContext *, JSValueConst, int, JSValueConst *); -JSValueConst JS_NewGlobalCConstructor(JSContext *, const char *, JSCFunction *, int, JSValueConst); -int JS_CopyDataProperties(JSContext *, JSValueConst, JSValueConst, JSValueConst, BOOL) __wur; -int JS_GetOwnPropertyInternal(JSContext *, JSPropertyDescriptor *, JSObject *, JSAtom); -int JS_GetOwnPropertyNamesInternal(JSContext *, JSPropertyEnum **, uint32_t *, JSObject *, int) __wur; -int JS_SetObjectData(JSContext *, JSValueConst, JSValue); -int JS_ToArrayLengthFree(JSContext *, uint32_t *, JSValue, BOOL) __wur; -int JS_ToInt32Clamp(JSContext *, int *, JSValueConst, int, int, int); -int JS_ToInt64Sat(JSContext *, int64_t *, JSValueConst); -int JS_ToLengthFree(JSContext *, int64_t *, JSValue) __wur; -int JS_ToUint8ClampFree(JSContext *, int32_t *, JSValue); -int __JS_ToFloat64Free(JSContext *, double *, JSValue) __wur; -int __js_poll_interrupts(JSContext *) __wur; -int add_closure_var(JSContext *, JSFunctionDef *, BOOL, BOOL, int, JSAtom, BOOL, BOOL, JSVarKindEnum); -int add_scope_var(JSContext *, JSFunctionDef *, JSAtom, JSVarKindEnum); -int add_var(JSContext *, JSFunctionDef *, JSAtom); -int bc_get_buf(BCReaderState *, uint8_t *, uint32_t); -int bc_idx_to_atom(BCReaderState *, JSAtom *, uint32_t); -int bc_read_error_end(BCReaderState *); -int check_exception_free(JSContext *, JSValue); -int cpool_add(JSParseState *, JSValue); -int define_var(JSParseState *, JSFunctionDef *, JSAtom, JSVarDefEnum); -int delete_property(JSContext *, JSObject *, JSAtom); -int emit_label(JSParseState *, int); -int find_lexical_decl(JSContext *, JSFunctionDef *, JSAtom, int, BOOL); -int find_private_class_field(JSContext *, JSFunctionDef *, JSAtom, int); -int find_var(JSContext *, JSFunctionDef *, JSAtom); -int get_ovop_from_opcode(OPCodeEnum); -int ident_realloc(JSContext *, char **, size_t *, char *) __wur; -int init_class_range(JSRuntime *, JSClassShortDef const *, int, int); -int js_add_slow(JSContext *, JSValue *) __wur; -int js_binary_arith_slow(JSContext *, JSValue *, OPCodeEnum) __wur; -int js_binary_logic_slow(JSContext *, JSValue *, OPCodeEnum); -int js_call_binary_op_fallback(JSContext *, JSValue *, JSValueConst, JSValueConst, OPCodeEnum, BOOL, int); -int js_eq_slow(JSContext *, JSValue *, BOOL) __wur; -int js_for_of_start(JSContext *, JSValue *, BOOL) __wur; -int js_get_length32(JSContext *, uint32_t *, JSValueConst) __wur; -int js_get_length64(JSContext *, int64_t *, JSValueConst) __wur; -int js_get_radix(JSContext *, JSValueConst); -int js_not_slow(JSContext *, JSValue *); -int js_obj_to_desc(JSContext *, JSPropertyDescriptor *, JSValueConst); -int js_operator_in(JSContext *, JSValue *) __wur; -int js_parse_export(JSParseState *) __wur; -int js_parse_string(JSParseState *, int, BOOL, const uint8_t *, JSToken *, const uint8_t **); -int js_parse_template_part(JSParseState *, const uint8_t *) __wur; -int js_post_inc_slow(JSContext *, JSValue *, OPCodeEnum) __wur; -int js_relational_slow(JSContext *, JSValue *, OPCodeEnum); -int js_shr_slow(JSContext *, JSValue *); -int js_unary_arith_slow(JSContext *, JSValue *, OPCodeEnum) __wur; -int js_update_property_flags(JSContext *, JSObject *, JSShapeProperty **, int); -int new_label(JSParseState *); -int perform_promise_then(JSContext *, JSValueConst, JSValueConst *, JSValueConst *); -int push_scope(JSParseState *); -int resize_properties(JSContext *, JSShape **, JSObject *, uint32_t); -int skip_spaces(const char *); -int to_digit(int); -int update_label(JSFunctionDef *, int, int); -uint32_t hash_string(const JSString *, uint32_t); -uint32_t js_string_obj_get_length(JSContext *, JSValueConst); -void close_scopes(JSParseState *, int, int); -void emit_atom(JSParseState *, JSAtom); -void emit_op(JSParseState *, uint8_t); -void js_async_generator_resume_next(JSContext *, JSAsyncGeneratorData *); -void js_bytecode_function_finalizer(JSRuntime *, JSValue); -void js_free_desc(JSContext *, JSPropertyDescriptor *); -void js_free_function_def(JSContext *, JSFunctionDef *); -void js_free_module_def(JSContext *, JSModuleDef *); -void js_free_prop_enum(JSContext *, JSPropertyEnum *, uint32_t); -void js_generator_finalizer(JSRuntime *, JSValue); -void js_generator_mark(JSRuntime *, JSValueConst, JS_MarkFunc *); -void js_parse_init(JSContext *, JSParseState *, const char *, size_t, const char *); - -int js_proxy_setPrototypeOf(JSContext *, JSValueConst, JSValueConst, BOOL); -JSValue js_proxy_getPrototypeOf(JSContext *, JSValueConst); -int js_proxy_isExtensible(JSContext *, JSValueConst); -int js_proxy_isArray(JSContext *, JSValueConst); -int js_proxy_preventExtensions(JSContext *, JSValueConst); - -void js_map_iterator_finalizer(JSRuntime *, JSValue); -void js_map_finalizer(JSRuntime *, JSValue); -void js_map_mark(JSRuntime *, JSValueConst, JS_MarkFunc *); -void js_map_iterator_mark(JSRuntime *, JSValueConst, JS_MarkFunc *); -void reset_weak_ref(JSRuntime *, JSObject *); - -void free_property(JSRuntime *, JSProperty *, int); -void js_autoinit_mark(JSRuntime *, JSProperty *, JS_MarkFunc *); -void free_zero_refcount(JSRuntime *); - -void free_token(JSParseState *, JSToken *); -int next_token(JSParseState *) __wur; -int simple_next_token(const uint8_t **, BOOL); -int js_parse_program(JSParseState *) __wur; - -JSValue JS_IteratorGetCompleteValue(JSContext *, JSValueConst, BOOL *); -JSValue js_create_iterator_result(JSContext *, JSValue, BOOL); -JSValue js_iterator_proto_iterator(JSContext *, JSValueConst, int, JSValueConst *); -int JS_IteratorClose(JSContext *, JSValueConst, BOOL); -void JS_AddIteratorProto(JSContext *); - -JSValue *build_arg_list(JSContext *, uint32_t *, JSValueConst); -void free_arg_list(JSContext *, JSValue *, uint32_t); - -JSValue js_get_module_ns(JSContext *, JSModuleDef *); - -static inline BOOL JS_IsEmptyString(JSValueConst v) { return JS_VALUE_GET_TAG(v) == JS_TAG_STRING && JS_VALUE_GET_STRING(v)->len == 0; } -static inline BOOL __JS_AtomIsTaggedInt(JSAtom v) { return (v & JS_ATOM_TAG_INT) != 0; } -static inline BOOL atom_is_free(const JSAtomStruct *p) { return (uintptr_t)p & 1; } -static inline JSAtom __JS_AtomFromUInt32(uint32_t v) { return v | JS_ATOM_TAG_INT; } -static inline JSAtomStruct *atom_set_free(uint32_t v) { return (JSAtomStruct *)(((uintptr_t)v << 1) | 1); } -static inline JSValueConst JS_GetActiveFunction(JSContext *ctx) { return ctx->rt->current_stack_frame->cur_func; } /* only valid inside C functions */ -static inline int string_get(const JSString *p, int idx) { return p->is_wide_char ? p->u.str16[idx] : p->u.str8[idx]; } -static inline uint32_t __JS_AtomToUInt32(JSAtom atom) { return atom & ~JS_ATOM_TAG_INT; } -static inline uint32_t atom_get_free(const JSAtomStruct *p) { return (uintptr_t)p >> 1; } - -JSValue async_func_resume(JSContext *, JSAsyncFunctionState *); -JSValue js_call_bound_function(JSContext *, JSValueConst, JSValueConst, int, JSValueConst *, int); -JSValue js_call_c_function(JSContext *, JSValueConst, JSValueConst, int, JSValueConst *, int); -JSValue js_closure(JSContext *, JSValue, JSVarRef **, JSStackFrame *); -JSValue js_closure2(JSContext *, JSValue, JSFunctionBytecode *, JSVarRef **, JSStackFrame *); -JSValue js_function_apply(JSContext *, JSValueConst, int, JSValueConst *, int); -JSValue js_function_constructor(JSContext *, JSValueConst, int, JSValueConst *, int); -JSVarRef *get_var_ref(JSContext *, JSStackFrame *, int, BOOL); -int async_func_init(JSContext *, JSAsyncFunctionState *, JSValueConst, JSValueConst, int, JSValueConst *) __wur; -void async_func_free(JSRuntime *, JSAsyncFunctionState *); -void async_func_mark(JSRuntime *, JSAsyncFunctionState *, JS_MarkFunc *); -void js_async_generator_free(JSRuntime *, JSAsyncGeneratorData *); - -JSProperty *add_property(JSContext *, JSObject *, JSAtom, int); -int JS_DefineAutoInitProperty(JSContext *, JSValueConst, JSAtom, JSAutoInitIDEnum, void *, int); -void free_var_ref(JSRuntime *, JSVarRef *); -void js_function_set_properties(JSContext *, JSValueConst, JSAtom, int); -int JS_DefineObjectName(JSContext *, JSValueConst, JSAtom, int); -JSValue js_get_this(JSContext *, JSValueConst); - -BOOL js_get_fast_array(JSContext *, JSValueConst, JSValue **, uint32_t *); -JSValue js_array_constructor(JSContext *, JSValueConst, int, JSValueConst *); -JSValue js_array_every(JSContext *, JSValueConst, int, JSValueConst *, int); -JSValue js_array_from(JSContext *, JSValueConst, int, JSValueConst *); -JSValue js_array_includes(JSContext *, JSValueConst, int, JSValueConst *); -JSValue js_array_iterator_next(JSContext *, JSValueConst, int, JSValueConst *, BOOL *, int); -JSValue js_array_pop(JSContext *, JSValueConst, int, JSValueConst *, int); -JSValue js_array_push(JSContext *, JSValueConst, int, JSValueConst *, int); -JSValue js_array_reduce(JSContext *, JSValueConst, int, JSValueConst *, int); -JSValue js_create_array(JSContext *, int, JSValueConst *); -JSValue js_create_array_iterator(JSContext *, JSValueConst, int, JSValueConst *, int); -int add_fast_array_element(JSContext *, JSObject *, JSValue, int); -int js_realloc_array(JSContext *, void **, int, int *, int); -int set_array_length(JSContext *, JSObject *, JSValue, int); -void JS_AddArrayIteratorProto(JSContext *); -void JS_AddIntrinsicArray(JSContext *); -void JS_AddIntrinsicGenerator(JSContext *); -void JS_AddIntrinsicMath(JSContext *); -void JS_AddIntrinsicObject(JSContext *); -void JS_AddIntrinsicReflect(JSContext *); -void JS_AddIntrinsicString(JSContext *); -void js_array_finalizer(JSRuntime *, JSValue); -void js_array_iterator_finalizer(JSRuntime *, JSValue); -void js_array_iterator_mark(JSRuntime *, JSValueConst, JS_MarkFunc *); -void js_array_mark(JSRuntime *, JSValueConst, JS_MarkFunc *); - -void js_object_data_finalizer(JSRuntime *, JSValue); -void js_object_data_mark(JSRuntime *, JSValueConst, JS_MarkFunc *); -JSValue js_object_seal(JSContext *, JSValueConst, int, JSValueConst *, int); - -void free_function_bytecode(JSRuntime *, JSFunctionBytecode *); -void free_bytecode_atoms(JSRuntime *, const uint8_t *, int, BOOL); - -JSShape *find_hashed_shape_proto(JSRuntime *, JSObject *); -JSShape *js_dup_shape(JSShape *); -JSShape *js_new_shape(JSContext *, JSObject *); -JSValue JS_NewObjectFromShape(JSContext *, JSShape *, JSClassID); -int add_shape_property(JSContext *, JSShape **, JSObject *, JSAtom, int); -void js_shape_hash_unlink(JSRuntime *, JSShape *); -void js_shape_hash_link(JSRuntime *, JSShape *); -JSShape *find_hashed_shape_prop(JSRuntime *, JSShape *, JSAtom, int); -JSShape *js_clone_shape(JSContext *, JSShape *); -JSShape *js_new_shape2(JSContext *, JSObject *, int, int); -int init_shape_hash(JSRuntime *); -void js_free_shape(JSRuntime *, JSShape *); -double js_pow(double, double); - -void js_trigger_gc(JSRuntime *, size_t); -void js_async_function_free0(JSRuntime *, JSAsyncFunctionData *); - -BOOL typed_array_is_detached(JSContext *, JSObject *); -JSValue js_typed_array___speciesCreate(JSContext *, JSValueConst, int, JSValueConst *); -JSValue js_typed_array_constructor(JSContext *, JSValueConst, int, JSValueConst *, int); -JSValue js_typed_array_get_buffer(JSContext *, JSValueConst, int); -JSValue js_typed_array_get_byteLength(JSContext *, JSValueConst, int); -JSValue js_typed_array_get_byteOffset(JSContext *, JSValueConst, int); -int js_typed_array_get_length_internal(JSContext *, JSValueConst); -uint32_t typed_array_get_length(JSContext *, JSObject *); -void js_typed_array_finalizer(JSRuntime *, JSValue); -void js_typed_array_mark(JSRuntime *, JSValueConst, JS_MarkFunc *); - -JSArrayBuffer *js_get_array_buffer(JSContext *, JSValueConst); -JSValue js_array_buffer_constructor(JSContext *, JSValueConst, int, JSValueConst *); -JSValue js_array_buffer_constructor1(JSContext *, JSValueConst, uint64_t); -JSValue js_array_buffer_constructor2(JSContext *, JSValueConst, uint64_t, JSClassID); -JSValue js_array_buffer_constructor3(JSContext *, JSValueConst, uint64_t, JSClassID, uint8_t *, JSFreeArrayBufferDataFunc *, void *, BOOL); -void js_array_buffer_finalizer(JSRuntime *, JSValue); - -JSValue JS_NewCFunction3(JSContext *, JSCFunction *, const char *, int, JSCFunctionEnum, int, JSValueConst); -JSValueConst JS_NewGlobalCConstructorOnly(JSContext *, const char *, JSCFunction *, int, JSValueConst); -void JS_NewGlobalCConstructor2(JSContext *, JSValue, const char *, JSValueConst); - -JSModuleDef *js_find_loaded_module(JSContext *, JSAtom); - -void dbuf_put_leb128(DynBuf *, uint32_t); -void dbuf_put_sleb128(DynBuf *, int32_t); - -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 - -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 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); - } -} - -#if !defined(CONFIG_STACK_CHECK) -static inline uintptr_t js_get_stack_pointer(void) { return 0; } -static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size) { return FALSE; } -#else -static inline uintptr_t js_get_stack_pointer(void) { return (uintptr_t)__builtin_frame_address(0); } -static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size) { - uintptr_t sp; - sp = js_get_stack_pointer() - alloca_size; - return UNLIKELY(sp < rt->stack_limit); -} -#endif - -static inline __exception int js_poll_interrupts(JSContext *ctx) { - if (UNLIKELY(--ctx->interrupt_counter <= 0)) { - return __js_poll_interrupts(ctx); - } else { - return 0; - } -} - -static inline uint32_t *prop_hash_end(JSShape *sh) { - return (uint32_t *)sh; -} - -static inline JSShapeProperty *get_shape_prop(JSShape *sh) { - return sh->prop; -} - -forceinline JSShapeProperty *find_own_property1(JSObject *p, JSAtom atom) { - JSShape *sh; - JSShapeProperty *pr, *prop; - intptr_t h; - sh = p->shape; - h = (uintptr_t)atom & sh->prop_hash_mask; - h = prop_hash_end(sh)[-h - 1]; - prop = get_shape_prop(sh); - while (h) { - pr = &prop[h - 1]; - if (LIKELY(pr->atom == atom)) { - return pr; - } - h = pr->hash_next; - } - return NULL; -} - -forceinline JSShapeProperty *find_own_property(JSProperty **ppr, - JSObject *p, - JSAtom atom) { - JSShape *sh; - JSShapeProperty *pr, *prop; - intptr_t h; - sh = p->shape; - h = (uintptr_t)atom & sh->prop_hash_mask; - h = prop_hash_end(sh)[-h - 1]; - prop = get_shape_prop(sh); - while (h) { - pr = &prop[h - 1]; - if (LIKELY(pr->atom == atom)) { - *ppr = &p->prop[h - 1]; - /* the compiler should be able to assume that pr != NULL here */ - return pr; - } - h = pr->hash_next; - } - *ppr = NULL; - return NULL; -} - -/* 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); -} - -/* indicate that the object may be part of a function prototype cycle */ -static inline void set_cycle_flag(JSContext *ctx, JSValueConst obj) {} - -static inline void js_dbuf_init(JSContext *ctx, DynBuf *s) { - dbuf_init2(s, ctx->rt, (DynBufReallocFunc *)js_realloc_rt); -} - -static inline void emit_u8(JSParseState *s, uint8_t val) { - dbuf_putc(&s->cur_func->byte_code, val); -} - -static inline void emit_u16(JSParseState *s, uint16_t val) { - dbuf_put_u16(&s->cur_func->byte_code, val); -} - -static inline void emit_u32(JSParseState *s, uint32_t val) { - dbuf_put_u32(&s->cur_func->byte_code, val); -} - -static inline int get_prev_opcode(JSFunctionDef *fd) { - if (fd->last_opcode_pos < 0) - return OP_invalid; - else - return fd->byte_code.buf[fd->last_opcode_pos]; -} - -/* 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 bf_t *JS_GetBigFloat(JSValueConst val) { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - return &p->num; -} - -static inline bfdec_t *JS_GetBigDecimal(JSValueConst val) { - JSBigDecimal *p = JS_VALUE_GET_PTR(val); - return &p->num; -} - -static inline 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 inline void remove_gc_object(JSGCObjectHeader *h) { - list_del(&h->link); -} - -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 prop_hash_end(sh) - ((intptr_t)sh->prop_hash_mask + 1); -} - -static inline 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); -} - -static inline void js_free_shape_null(JSRuntime *rt, JSShape *sh) { - if (sh) js_free_shape(rt, sh); -} - -static inline bf_t *JS_GetBigInt(JSValueConst val) { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - return &p->num; -} - -static inline void js_async_function_free(JSRuntime *rt, JSAsyncFunctionData *s) { - if (--s->header.ref_count == 0) { - js_async_function_free0(rt, s); - } -} - -COSMOPOLITAN_C_END_ -#endif /* COSMOPOLITAN_THIRD_PARTY_QUICKJS_INTERNAL_H_ */ diff --git a/third_party/quickjs/iter.c b/third_party/quickjs/iter.c deleted file mode 100644 index ffaadfe1e..000000000 --- a/third_party/quickjs/iter.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "third_party/quickjs/internal.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -JSValue js_iterator_proto_iterator(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) { - return JS_DupValue(ctx, this_val); -} - -static const JSCFunctionListEntry js_iterator_proto_funcs[] = { - JS_CFUNC_DEF("[Symbol.iterator]", 0, js_iterator_proto_iterator), -}; - -void JS_AddIteratorProto(JSContext *ctx) { - ctx->iterator_proto = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->iterator_proto, - js_iterator_proto_funcs, - countof(js_iterator_proto_funcs)); -} diff --git a/third_party/quickjs/json.c b/third_party/quickjs/json.c deleted file mode 100644 index b08d65e28..000000000 --- a/third_party/quickjs/json.c +++ /dev/null @@ -1,991 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/assert.h" -#include "libc/str/str.h" -#include "third_party/quickjs/internal.h" -#include "third_party/quickjs/libregexp.h" -#include "third_party/quickjs/quickjs.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -/* 'c' is the first character. Return JS_ATOM_NULL in case of error */ -static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c) -{ - const uint8_t *p; - 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; - for(;;) { - buf[ident_pos++] = c; - c = *p; - if (c >= 128 || - !((lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1)) - break; - p++; - 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 json_next_token(JSParseState *s) -{ - const uint8_t *p; - int c; - 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->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 (!s->ext_json) { - /* JSON does not accept single quoted strings */ - goto def_token; - } - /* fall through */ - 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++; - s->line_num++; - goto redo; - case '\f': - case '\v': - if (!s->ext_json) { - /* JSONWhitespace does not match , nor */ - goto def_token; - } - /* fall through */ - case ' ': - case '\t': - p++; - goto redo; - case '/': - if (!s->ext_json) { - /* JSON does not accept comments */ - goto def_token; - } - 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++; - p++; - } else if (*p == '\r') { - p++; - } else if (*p >= 0x80) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); - if (c == -1) { - p++; /* skip invalid UTF-8 */ - } - } else { - p++; - } - } - goto redo; - } else if (p[1] == '/') { - /* line comment */ - p += 2; - 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 { - goto def_token; - } - break; - case 'a': case 'b': case 'c': case 'd': - case 'e': case 'f': case 'g': case 'h': - case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': - case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - case 'A': case 'B': case 'C': case 'D': - case 'E': case 'F': case 'G': case 'H': - case 'I': case 'J': case 'K': case 'L': - case 'M': case 'N': case 'O': case 'P': - case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - case '_': - case '$': - /* identifier : only pure ascii characters are accepted */ - p++; - atom = json_parse_ident(s, &p, c); - if (atom == JS_ATOM_NULL) - goto fail; - s->token.u.ident.atom = atom; - s->token.u.ident.has_escape = FALSE; - s->token.u.ident.is_reserved = FALSE; - s->token.val = TOK_IDENT; - break; - case '+': - if (!s->ext_json || !isdigit(p[1])) - goto def_token; - goto parse_number; - case '0': - if (isdigit(p[1])) - goto def_token; - goto parse_number; - case '-': - if (!isdigit(p[1])) - goto def_token; - goto parse_number; - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': - case '9': - /* number */ - parse_number: - { - JSValue ret; - int flags, radix; - if (!s->ext_json) { - flags = 0; - radix = 10; - } else { - flags = ATOD_ACCEPT_BIN_OCT; - radix = 0; - } - ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix, - flags); - if (JS_IsException(ret)) - goto fail; - s->token.val = TOK_NUMBER; - s->token.u.num.val = ret; - } - break; - default: - if (c >= 128) { - js_parse_error(s, "unexpected character"); - goto fail; - } - def_token: - s->token.val = c; - p++; - break; - } - s->buf_ptr = p; - // dump_token(s, &s->token); - return 0; - fail: - s->token.val = TOK_ERROR; - return -1; -} - -static int json_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 json_next_token(s); -} - -static JSValue json_parse_value(JSParseState *s) -{ - JSContext *ctx = s->ctx; - JSValue val = JS_NULL; - int ret; - switch(s->token.val) { - case '{': - { - JSValue prop_val; - JSAtom prop_name; - if (json_next_token(s)) - goto fail; - val = JS_NewObject(ctx); - if (JS_IsException(val)) - goto fail; - if (s->token.val != '}') { - for(;;) { - if (s->token.val == TOK_STRING) { - prop_name = JS_ValueToAtom(ctx, s->token.u.str.str); - if (prop_name == JS_ATOM_NULL) - goto fail; - } else if (s->ext_json && s->token.val == TOK_IDENT) { - prop_name = JS_DupAtom(ctx, s->token.u.ident.atom); - } else { - js_parse_error(s, "expecting property name"); - goto fail; - } - if (json_next_token(s)) - goto fail1; - if (json_parse_expect(s, ':')) - goto fail1; - prop_val = json_parse_value(s); - if (JS_IsException(prop_val)) { - fail1: - JS_FreeAtom(ctx, prop_name); - goto fail; - } - ret = JS_DefinePropertyValue(ctx, val, prop_name, - prop_val, JS_PROP_C_W_E); - JS_FreeAtom(ctx, prop_name); - if (ret < 0) - goto fail; - if (s->token.val != ',') - break; - if (json_next_token(s)) - goto fail; - if (s->ext_json && s->token.val == '}') - break; - } - } - if (json_parse_expect(s, '}')) - goto fail; - } - break; - case '[': - { - JSValue el; - uint32_t idx; - if (json_next_token(s)) - goto fail; - val = JS_NewArray(ctx); - if (JS_IsException(val)) - goto fail; - if (s->token.val != ']') { - idx = 0; - for(;;) { - el = json_parse_value(s); - if (JS_IsException(el)) - goto fail; - ret = JS_DefinePropertyValueUint32(ctx, val, idx, el, JS_PROP_C_W_E); - if (ret < 0) - goto fail; - if (s->token.val != ',') - break; - if (json_next_token(s)) - goto fail; - idx++; - if (s->ext_json && s->token.val == ']') - break; - } - } - if (json_parse_expect(s, ']')) - goto fail; - } - break; - case TOK_STRING: - val = JS_DupValue(ctx, s->token.u.str.str); - if (json_next_token(s)) - goto fail; - break; - case TOK_NUMBER: - val = s->token.u.num.val; - if (json_next_token(s)) - goto fail; - break; - case TOK_IDENT: - if (s->token.u.ident.atom == JS_ATOM_false || - s->token.u.ident.atom == JS_ATOM_true) { - val = JS_NewBool(ctx, (s->token.u.ident.atom == JS_ATOM_true)); - } else if (s->token.u.ident.atom == JS_ATOM_null) { - val = JS_NULL; - } else { - goto def_token; - } - if (json_next_token(s)) - goto fail; - break; - default: - def_token: - if (s->token.val == TOK_EOF) { - js_parse_error(s, "unexpected end of input"); - } else { - js_parse_error(s, "unexpected token: '%.*s'", - (int)(s->buf_ptr - s->token.ptr), s->token.ptr); - } - goto fail; - } - return val; - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len, - const char *filename, int flags) -{ - JSParseState s1, *s = &s1; - JSValue val = JS_UNDEFINED; - js_parse_init(ctx, s, buf, buf_len, filename); - s->ext_json = ((flags & JS_PARSE_JSON_EXT) != 0); - if (json_next_token(s)) - goto fail; - val = json_parse_value(s); - if (JS_IsException(val)) - goto fail; - if (s->token.val != TOK_EOF) { - if (js_parse_error(s, "unexpected data at the end")) - goto fail; - } - return val; - fail: - JS_FreeValue(ctx, val); - free_token(s, &s->token); - return JS_EXCEPTION; -} - -JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, - const char *filename) -{ - return JS_ParseJSON2(ctx, buf, buf_len, filename, 0); -} - -static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder, - JSAtom name, JSValueConst reviver) -{ - JSValue val, new_el, name_val, res; - JSValueConst args[2]; - int ret, is_array; - uint32_t i, len = 0; - JSAtom prop; - JSPropertyEnum *atoms = NULL; - if (js_check_stack_overflow(ctx->rt, 0)) { - return JS_ThrowStackOverflow(ctx); - } - val = JS_GetProperty(ctx, holder, name); - if (JS_IsException(val)) - return val; - if (JS_IsObject(val)) { - is_array = JS_IsArray(ctx, val); - if (is_array < 0) - goto fail; - if (is_array) { - if (js_get_length32(ctx, &len, val)) - goto fail; - } else { - ret = JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, JS_VALUE_GET_OBJ(val), JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK); - if (ret < 0) - goto fail; - } - for(i = 0; i < len; i++) { - if (is_array) { - prop = JS_NewAtomUInt32(ctx, i); - if (prop == JS_ATOM_NULL) - goto fail; - } else { - prop = JS_DupAtom(ctx, atoms[i].atom); - } - new_el = internalize_json_property(ctx, val, prop, reviver); - if (JS_IsException(new_el)) { - JS_FreeAtom(ctx, prop); - goto fail; - } - if (JS_IsUndefined(new_el)) { - ret = JS_DeleteProperty(ctx, val, prop, 0); - } else { - ret = JS_DefinePropertyValue(ctx, val, prop, new_el, JS_PROP_C_W_E); - } - JS_FreeAtom(ctx, prop); - if (ret < 0) - goto fail; - } - } - js_free_prop_enum(ctx, atoms, len); - atoms = NULL; - name_val = JS_AtomToValue(ctx, name); - if (JS_IsException(name_val)) - goto fail; - args[0] = name_val; - args[1] = val; - res = JS_Call(ctx, reviver, holder, 2, args); - JS_FreeValue(ctx, name_val); - JS_FreeValue(ctx, val); - return res; - fail: - js_free_prop_enum(ctx, atoms, len); - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static JSValue js_json_parse(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj, root; - JSValueConst reviver; - const char *str; - size_t len; - str = JS_ToCStringLen(ctx, &len, argv[0]); - if (!str) - return JS_EXCEPTION; - obj = JS_ParseJSON(ctx, str, len, ""); - JS_FreeCString(ctx, str); - if (JS_IsException(obj)) - return obj; - if (argc > 1 && JS_IsFunction(ctx, argv[1])) { - reviver = argv[1]; - root = JS_NewObject(ctx); - if (JS_IsException(root)) { - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - if (JS_DefinePropertyValue(ctx, root, JS_ATOM_empty_string, obj, - JS_PROP_C_W_E) < 0) { - JS_FreeValue(ctx, root); - return JS_EXCEPTION; - } - obj = internalize_json_property(ctx, root, JS_ATOM_empty_string, - reviver); - JS_FreeValue(ctx, root); - } - return obj; -} - -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 JSValue JS_ToQuotedStringFree(JSContext *ctx, JSValue val) { - JSValue r = JS_ToQuotedString(ctx, val); - JS_FreeValue(ctx, val); - return r; -} - -static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc, - JSValueConst holder, JSValue val, JSValueConst key) -{ - JSValue v; - JSValueConst args[2]; - if (JS_IsObject(val) -#ifdef CONFIG_BIGNUM - || JS_IsBigInt(ctx, val) /* XXX: probably useless */ -#endif - ) { - JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON); - if (JS_IsException(f)) - goto exception; - if (JS_IsFunction(ctx, f)) { - v = JS_CallFree(ctx, f, val, 1, &key); - JS_FreeValue(ctx, val); - val = v; - if (JS_IsException(val)) - goto exception; - } else { - JS_FreeValue(ctx, f); - } - } - if (!JS_IsUndefined(jsc->replacer_func)) { - args[0] = key; - args[1] = val; - v = JS_Call(ctx, jsc->replacer_func, holder, 2, args); - JS_FreeValue(ctx, val); - val = v; - if (JS_IsException(val)) - goto exception; - } - switch (JS_VALUE_GET_NORM_TAG(val)) { - case JS_TAG_OBJECT: - if (JS_IsFunction(ctx, val)) - break; - case JS_TAG_STRING: - case JS_TAG_INT: - case JS_TAG_FLOAT64: -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: -#endif - case JS_TAG_BOOL: - case JS_TAG_NULL: -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_INT: -#endif - case JS_TAG_EXCEPTION: - return val; - default: - break; - } - JS_FreeValue(ctx, val); - return JS_UNDEFINED; -exception: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, - JSValueConst holder, JSValue val, - JSValueConst indent) -{ - JSValue indent1, sep, sep1, tab, v, prop; - JSObject *p; - int64_t i, len; - int cl, ret; - BOOL has_content; - indent1 = JS_UNDEFINED; - sep = JS_UNDEFINED; - sep1 = JS_UNDEFINED; - tab = JS_UNDEFINED; - prop = JS_UNDEFINED; - switch (JS_VALUE_GET_NORM_TAG(val)) { - case JS_TAG_OBJECT: - p = JS_VALUE_GET_OBJ(val); - cl = p->class_id; - if (cl == JS_CLASS_STRING) { - val = JS_ToStringFree(ctx, val); - if (JS_IsException(val)) - goto exception; - val = JS_ToQuotedStringFree(ctx, val); - if (JS_IsException(val)) - goto exception; - return string_buffer_concat_value_free(jsc->b, val); - } else if (cl == JS_CLASS_NUMBER) { - val = JS_ToNumberFree(ctx, val); - if (JS_IsException(val)) - goto exception; - return string_buffer_concat_value_free(jsc->b, val); - } else if (cl == JS_CLASS_BOOLEAN) { - ret = string_buffer_concat_value(jsc->b, p->u.object_data); - JS_FreeValue(ctx, val); - return ret; - } -#ifdef CONFIG_BIGNUM - else if (cl == JS_CLASS_BIG_FLOAT) { - return string_buffer_concat_value_free(jsc->b, val); - } else if (cl == JS_CLASS_BIG_INT) { - JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify"); - goto exception; - } -#endif - v = js_array_includes(ctx, jsc->stack, 1, (JSValueConst *)&val); - if (JS_IsException(v)) - goto exception; - if (JS_ToBoolFree(ctx, v)) { - JS_ThrowTypeError(ctx, "circular reference"); - goto exception; - } - indent1 = JS_ConcatString(ctx, JS_DupValue(ctx, indent), JS_DupValue(ctx, jsc->gap)); - if (JS_IsException(indent1)) - goto exception; - if (!JS_IsEmptyString(jsc->gap)) { - sep = JS_ConcatString3(ctx, "\n", JS_DupValue(ctx, indent1), ""); - if (JS_IsException(sep)) - goto exception; - sep1 = JS_NewString(ctx, " "); - if (JS_IsException(sep1)) - goto exception; - } else { - sep = JS_DupValue(ctx, jsc->empty); - sep1 = JS_DupValue(ctx, jsc->empty); - } - v = js_array_push(ctx, jsc->stack, 1, (JSValueConst *)&val, 0); - if (check_exception_free(ctx, v)) - goto exception; - ret = JS_IsArray(ctx, val); - if (ret < 0) - goto exception; - if (ret) { - if (js_get_length64(ctx, &len, val)) - goto exception; - string_buffer_putc8(jsc->b, '['); - for(i = 0; i < len; i++) { - if (i > 0) - string_buffer_putc8(jsc->b, ','); - string_buffer_concat_value(jsc->b, sep); - v = JS_GetPropertyInt64(ctx, val, i); - if (JS_IsException(v)) - goto exception; - /* XXX: could do this string conversion only when needed */ - prop = JS_ToStringFree(ctx, JS_NewInt64(ctx, i)); - if (JS_IsException(prop)) - goto exception; - v = js_json_check(ctx, jsc, val, v, prop); - JS_FreeValue(ctx, prop); - prop = JS_UNDEFINED; - if (JS_IsException(v)) - goto exception; - if (JS_IsUndefined(v)) - v = JS_NULL; - if (js_json_to_str(ctx, jsc, val, v, indent1)) - goto exception; - } - if (len > 0 && !JS_IsEmptyString(jsc->gap)) { - string_buffer_putc8(jsc->b, '\n'); - string_buffer_concat_value(jsc->b, indent); - } - string_buffer_putc8(jsc->b, ']'); - } else { - if (!JS_IsUndefined(jsc->property_list)) - tab = JS_DupValue(ctx, jsc->property_list); - else - tab = js_object_keys(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val, JS_ITERATOR_KIND_KEY); - if (JS_IsException(tab)) - goto exception; - if (js_get_length64(ctx, &len, tab)) - goto exception; - string_buffer_putc8(jsc->b, '{'); - has_content = FALSE; - for(i = 0; i < len; i++) { - JS_FreeValue(ctx, prop); - prop = JS_GetPropertyInt64(ctx, tab, i); - if (JS_IsException(prop)) - goto exception; - v = JS_GetPropertyValue(ctx, val, JS_DupValue(ctx, prop)); - if (JS_IsException(v)) - goto exception; - v = js_json_check(ctx, jsc, val, v, prop); - if (JS_IsException(v)) - goto exception; - if (!JS_IsUndefined(v)) { - if (has_content) - string_buffer_putc8(jsc->b, ','); - prop = JS_ToQuotedStringFree(ctx, prop); - if (JS_IsException(prop)) { - JS_FreeValue(ctx, v); - goto exception; - } - string_buffer_concat_value(jsc->b, sep); - string_buffer_concat_value(jsc->b, prop); - string_buffer_putc8(jsc->b, ':'); - string_buffer_concat_value(jsc->b, sep1); - if (js_json_to_str(ctx, jsc, val, v, indent1)) - goto exception; - has_content = TRUE; - } - } - if (has_content && JS_VALUE_GET_STRING(jsc->gap)->len != 0) { - string_buffer_putc8(jsc->b, '\n'); - string_buffer_concat_value(jsc->b, indent); - } - string_buffer_putc8(jsc->b, '}'); - } - if (check_exception_free(ctx, js_array_pop(ctx, jsc->stack, 0, NULL, 0))) - goto exception; - JS_FreeValue(ctx, val); - JS_FreeValue(ctx, tab); - JS_FreeValue(ctx, sep); - JS_FreeValue(ctx, sep1); - JS_FreeValue(ctx, indent1); - JS_FreeValue(ctx, prop); - return 0; - case JS_TAG_STRING: - val = JS_ToQuotedStringFree(ctx, val); - if (JS_IsException(val)) - goto exception; - goto concat_value; - case JS_TAG_FLOAT64: - if (!isfinite(JS_VALUE_GET_FLOAT64(val))) { - val = JS_NULL; - } - goto concat_value; - case JS_TAG_INT: -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_FLOAT: -#endif - case JS_TAG_BOOL: - case JS_TAG_NULL: - concat_value: - return string_buffer_concat_value_free(jsc->b, val); -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_INT: - JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify"); - goto exception; -#endif - default: - JS_FreeValue(ctx, val); - return 0; - } -exception: - JS_FreeValue(ctx, val); - JS_FreeValue(ctx, tab); - JS_FreeValue(ctx, sep); - JS_FreeValue(ctx, sep1); - JS_FreeValue(ctx, indent1); - JS_FreeValue(ctx, prop); - return -1; -} - -JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj, - JSValueConst replacer, JSValueConst space0) -{ - StringBuffer b_s; - JSONStringifyContext jsc_s, *jsc = &jsc_s; - JSValue val, v, space, ret, wrapper; - int res; - int64_t i, j, n; - jsc->replacer_func = JS_UNDEFINED; - jsc->stack = JS_UNDEFINED; - jsc->property_list = JS_UNDEFINED; - jsc->gap = JS_UNDEFINED; - jsc->b = &b_s; - jsc->empty = JS_AtomToString(ctx, JS_ATOM_empty_string); - ret = JS_UNDEFINED; - wrapper = JS_UNDEFINED; - string_buffer_init(ctx, jsc->b, 0); - jsc->stack = JS_NewArray(ctx); - if (JS_IsException(jsc->stack)) - goto exception; - if (JS_IsFunction(ctx, replacer)) { - jsc->replacer_func = replacer; - } else { - res = JS_IsArray(ctx, replacer); - if (res < 0) - goto exception; - if (res) { - /* XXX: enumeration is not fully correct */ - jsc->property_list = JS_NewArray(ctx); - if (JS_IsException(jsc->property_list)) - goto exception; - if (js_get_length64(ctx, &n, replacer)) - goto exception; - for (i = j = 0; i < n; i++) { - JSValue present; - v = JS_GetPropertyInt64(ctx, replacer, i); - if (JS_IsException(v)) - goto exception; - if (JS_IsObject(v)) { - JSObject *p = JS_VALUE_GET_OBJ(v); - if (p->class_id == JS_CLASS_STRING || - p->class_id == JS_CLASS_NUMBER) { - v = JS_ToStringFree(ctx, v); - if (JS_IsException(v)) - goto exception; - } else { - JS_FreeValue(ctx, v); - continue; - } - } else if (JS_IsNumber(v)) { - v = JS_ToStringFree(ctx, v); - if (JS_IsException(v)) - goto exception; - } else if (!JS_IsString(v)) { - JS_FreeValue(ctx, v); - continue; - } - present = js_array_includes(ctx, jsc->property_list, - 1, (JSValueConst *)&v); - if (JS_IsException(present)) { - JS_FreeValue(ctx, v); - goto exception; - } - if (!JS_ToBoolFree(ctx, present)) { - JS_SetPropertyInt64(ctx, jsc->property_list, j++, v); - } else { - JS_FreeValue(ctx, v); - } - } - } - } - space = JS_DupValue(ctx, space0); - if (JS_IsObject(space)) { - JSObject *p = JS_VALUE_GET_OBJ(space); - if (p->class_id == JS_CLASS_NUMBER) { - space = JS_ToNumberFree(ctx, space); - } else if (p->class_id == JS_CLASS_STRING) { - space = JS_ToStringFree(ctx, space); - } - if (JS_IsException(space)) { - JS_FreeValue(ctx, space); - goto exception; - } - } - if (JS_IsNumber(space)) { - int n; - if (JS_ToInt32Clamp(ctx, &n, space, 0, 10, 0)) - goto exception; - jsc->gap = JS_NewStringLen(ctx, " ", n); - } else if (JS_IsString(space)) { - JSString *p = JS_VALUE_GET_STRING(space); - jsc->gap = js_sub_string(ctx, p, 0, min_int(p->len, 10)); - } else { - jsc->gap = JS_DupValue(ctx, jsc->empty); - } - JS_FreeValue(ctx, space); - if (JS_IsException(jsc->gap)) - goto exception; - wrapper = JS_NewObject(ctx); - if (JS_IsException(wrapper)) - goto exception; - if (JS_DefinePropertyValue(ctx, wrapper, JS_ATOM_empty_string, - JS_DupValue(ctx, obj), JS_PROP_C_W_E) < 0) - goto exception; - val = JS_DupValue(ctx, obj); - val = js_json_check(ctx, jsc, wrapper, val, jsc->empty); - if (JS_IsException(val)) - goto exception; - if (JS_IsUndefined(val)) { - ret = JS_UNDEFINED; - goto done1; - } - if (js_json_to_str(ctx, jsc, wrapper, val, jsc->empty)) - goto exception; - ret = string_buffer_end(jsc->b); - goto done; -exception: - ret = JS_EXCEPTION; -done1: - string_buffer_free(jsc->b); -done: - JS_FreeValue(ctx, wrapper); - JS_FreeValue(ctx, jsc->empty); - JS_FreeValue(ctx, jsc->gap); - JS_FreeValue(ctx, jsc->property_list); - JS_FreeValue(ctx, jsc->stack); - return ret; -} - -static JSValue js_json_stringify(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // stringify(val, replacer, space) - return JS_JSONStringify(ctx, argv[0], argv[1], argv[2]); -} - -static const JSCFunctionListEntry js_json_funcs[] = { - JS_CFUNC_DEF("parse", 2, js_json_parse ), - JS_CFUNC_DEF("stringify", 3, js_json_stringify ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "JSON", JS_PROP_CONFIGURABLE ), -}; - -static const JSCFunctionListEntry js_json_obj[] = { - JS_OBJECT_DEF("JSON", js_json_funcs, countof(js_json_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ), -}; - -void JS_AddIntrinsicJSON(JSContext *ctx) -{ - /* add JSON as autoinit object */ - JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_json_obj, countof(js_json_obj)); -} diff --git a/third_party/quickjs/leb128.c b/third_party/quickjs/leb128.c deleted file mode 100644 index 25d0e0f2a..000000000 --- a/third_party/quickjs/leb128.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/intrin/likely.h" -#include "third_party/quickjs/leb128.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -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; -} - -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; -} diff --git a/third_party/quickjs/leb128.h b/third_party/quickjs/leb128.h deleted file mode 100644 index e6eb7c19d..000000000 --- a/third_party/quickjs/leb128.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef COSMOPOLITAN_THIRD_PARTY_QUICKJS_LEB128_H_ -#define COSMOPOLITAN_THIRD_PARTY_QUICKJS_LEB128_H_ -COSMOPOLITAN_C_START_ - -int get_leb128(uint32_t *, const uint8_t *, const uint8_t *); -int get_sleb128(int32_t *, const uint8_t *, const uint8_t *); - -COSMOPOLITAN_C_END_ -#endif /* COSMOPOLITAN_THIRD_PARTY_QUICKJS_LEB128_H_ */ diff --git a/third_party/quickjs/libbf.c b/third_party/quickjs/libbf.c deleted file mode 100644 index 36f8625be..000000000 --- a/third_party/quickjs/libbf.c +++ /dev/null @@ -1,8504 +0,0 @@ -/* - * Tiny arbitrary precision floating point library - * - * Copyright (c) 2017-2021 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "third_party/quickjs/libbf.h" -#include "libc/assert.h" -#include "libc/intrin/likely.h" -#include "libc/inttypes.h" -#include "libc/runtime/runtime.h" -#include "libc/stdio/stdio.h" -#include "libc/str/str.h" -#include "third_party/intel/immintrin.internal.h" -#include "third_party/quickjs/cutils.h" -#include "third_party/quickjs/diglet.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -/* TODO(jart): let's use asm() instead of intel's strange and unusual veneer */ -/* #ifdef __AVX2__ */ -/* #undef __AVX2__ */ -/* #endif */ - - -/* enable it to check the multiplication result */ -//#define USE_MUL_CHECK -/* enable it to use FFT/NTT multiplication */ -#define USE_FFT_MUL -/* enable decimal floating point support */ -#define USE_BF_DEC - -//#define inline __attribute__((always_inline)) - -#define FFT_MUL_THRESHOLD 100 /* in limbs of the smallest factor */ - -/* XXX: adjust */ -#define DIVNORM_LARGE_THRESHOLD 50 -#define UDIV1NORM_THRESHOLD 3 - -#if LIMB_BITS == 64 -#define FMT_LIMB1 "%" PRIx64 -#define FMT_LIMB "%016" PRIx64 -#define PRId_LIMB PRId64 -#define PRIu_LIMB PRIu64 - -#else - -#define FMT_LIMB1 "%x" -#define FMT_LIMB "%08x" -#define PRId_LIMB "d" -#define PRIu_LIMB "u" - -#endif - -typedef intptr_t mp_size_t; - -typedef int bf_op2_func_t(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, - bf_flags_t flags); - -#ifdef USE_FFT_MUL - -#define FFT_MUL_R_OVERLAP_A (1 << 0) -#define FFT_MUL_R_OVERLAP_B (1 << 1) -#define FFT_MUL_R_NORESIZE (1 << 2) - -static dontinline int fft_mul(bf_context_t *s, - bf_t *res, limb_t *a_tab, limb_t a_len, - limb_t *b_tab, limb_t b_len, int mul_flags); -static void fft_clear_cache(bf_context_t *s); -#endif -#ifdef USE_BF_DEC -static limb_t get_digit(const limb_t *tab, limb_t len, slimb_t pos); -#endif - - -/* could leading zeros */ -static inline int clz(limb_t a) -{ - if (a == 0) { - return LIMB_BITS; - } else { -#if LIMB_BITS == 64 - return clz64(a); -#else - return clz32(a); -#endif - } -} - -static inline int ctz(limb_t a) -{ - if (a == 0) { - return LIMB_BITS; - } else { -#if LIMB_BITS == 64 - return ctz64(a); -#else - return ctz32(a); -#endif - } -} - -static inline int ceil_log2(limb_t a) -{ - if (a <= 1) - return 0; - else - return LIMB_BITS - clz(a - 1); -} - -/* b must be >= 1 */ -static inline slimb_t ceil_div(slimb_t a, slimb_t b) -{ - if (a >= 0) - return (a + b - 1) / b; - else - return a / b; -} - -/* b must be >= 1 */ -static inline slimb_t floor_div(slimb_t a, slimb_t b) -{ - if (a >= 0) { - return a / b; - } else { - return (a - b + 1) / b; - } -} - -/* return r = a modulo b (0 <= r <= b - 1. b must be >= 1 */ -static inline limb_t smod(slimb_t a, slimb_t b) -{ - a = a % (slimb_t)b; - if (a < 0) - a += b; - return a; -} - -/* signed addition with saturation */ -static inline slimb_t sat_add(slimb_t a, slimb_t b) -{ - slimb_t r; - r = a + b; - /* overflow ? */ - if (((a ^ r) & (b ^ r)) < 0) - r = (a >> (LIMB_BITS - 1)) ^ (((limb_t)1 << (LIMB_BITS - 1)) - 1); - return r; -} - -#define malloc(s) malloc_is_forbidden(s) -#define free(p) free_is_forbidden(p) -#define realloc(p, s) realloc_is_forbidden(p, s) - -void bf_context_init(bf_context_t *s, bf_realloc_func_t *realloc_func, - void *realloc_opaque) -{ - bzero(s, sizeof(*s)); - s->realloc_func = realloc_func; - s->realloc_opaque = realloc_opaque; -} - -void bf_context_end(bf_context_t *s) -{ - bf_clear_cache(s); -} - -void bf_init(bf_context_t *s, bf_t *r) -{ - r->ctx = s; - r->sign = 0; - r->expn = BF_EXP_ZERO; - r->len = 0; - r->tab = NULL; -} - -/* return 0 if OK, -1 if alloc error */ -int bf_resize(bf_t *r, limb_t len) -{ - limb_t *tab; - - if (len != r->len) { - tab = bf_realloc(r->ctx, r->tab, len * sizeof(limb_t)); - if (!tab && len != 0) - return -1; - r->tab = tab; - r->len = len; - } - return 0; -} - -/* return 0 or BF_ST_MEM_ERROR */ -int bf_set_ui(bf_t *r, uint64_t a) -{ - r->sign = 0; - if (a == 0) { - r->expn = BF_EXP_ZERO; - bf_resize(r, 0); /* cannot fail */ - } -#if LIMB_BITS == 32 - else if (a <= 0xffffffff) -#else - else -#endif - { - int shift; - if (bf_resize(r, 1)) - goto fail; - shift = clz(a); - r->tab[0] = a << shift; - r->expn = LIMB_BITS - shift; - } -#if LIMB_BITS == 32 - else { - uint32_t a1, a0; - int shift; - if (bf_resize(r, 2)) - goto fail; - a0 = a; - a1 = a >> 32; - shift = clz(a1); - /* shift < 32 because a > 0xffffffff */ - r->tab[0] = a0 << shift; - if (shift == 0) - r->tab[1] = a1; - else - r->tab[1] = (a1 << shift) | (a0 >> (LIMB_BITS - shift)); - r->expn = 2 * LIMB_BITS - shift; - } -#endif - return 0; - fail: - bf_set_nan(r); - return BF_ST_MEM_ERROR; -} - -/* return 0 or BF_ST_MEM_ERROR */ -int bf_set_si(bf_t *r, int64_t a) -{ - int ret; - - if (a < 0) { - ret = bf_set_ui(r, -a); - r->sign = 1; - } else { - ret = bf_set_ui(r, a); - } - return ret; -} - -void bf_set_nan(bf_t *r) -{ - bf_resize(r, 0); /* cannot fail */ - r->expn = BF_EXP_NAN; - r->sign = 0; -} - -void bf_set_zero(bf_t *r, int is_neg) -{ - bf_resize(r, 0); /* cannot fail */ - r->expn = BF_EXP_ZERO; - r->sign = is_neg; -} - -void bf_set_inf(bf_t *r, int is_neg) -{ - bf_resize(r, 0); /* cannot fail */ - r->expn = BF_EXP_INF; - r->sign = is_neg; -} - -/* return 0 or BF_ST_MEM_ERROR */ -int bf_set(bf_t *r, const bf_t *a) -{ - if (r == a) - return 0; - if (bf_resize(r, a->len)) { - bf_set_nan(r); - return BF_ST_MEM_ERROR; - } - r->sign = a->sign; - r->expn = a->expn; - if (a->len) memcpy(r->tab, a->tab, a->len * sizeof(limb_t)); - return 0; -} - -/* equivalent to bf_set(r, a); bf_delete(a) */ -void bf_move(bf_t *r, bf_t *a) -{ - bf_context_t *s = r->ctx; - if (r == a) - return; - bf_free(s, r->tab); - *r = *a; -} - -static limb_t get_limbz(const bf_t *a, limb_t idx) -{ - if (idx >= a->len) - return 0; - else - return a->tab[idx]; -} - -/* get LIMB_BITS at bit position 'pos' in tab */ -static inline limb_t get_bits(const limb_t *tab, limb_t len, slimb_t pos) -{ - limb_t i, a0, a1; - int p; - - i = pos >> LIMB_LOG2_BITS; - p = pos & (LIMB_BITS - 1); - if (i < len) - a0 = tab[i]; - else - a0 = 0; - if (p == 0) { - return a0; - } else { - i++; - if (i < len) - a1 = tab[i]; - else - a1 = 0; - return (a0 >> p) | (a1 << (LIMB_BITS - p)); - } -} - -static inline limb_t get_bit(const limb_t *tab, limb_t len, slimb_t pos) -{ - slimb_t i; - i = pos >> LIMB_LOG2_BITS; - if (i < 0 || i >= len) - return 0; - return (tab[i] >> (pos & (LIMB_BITS - 1))) & 1; -} - -static inline limb_t limb_mask(int start, int last) -{ - limb_t v; - int n; - n = last - start + 1; - if (n == LIMB_BITS) - v = -1; - else - v = (((limb_t)1 << n) - 1) << start; - return v; -} - -static limb_t mp_scan_nz(const limb_t *tab, mp_size_t n) -{ - mp_size_t i; - for(i = 0; i < n; i++) { - if (tab[i] != 0) - return 1; - } - return 0; -} - -/* return != 0 if one bit between 0 and bit_pos inclusive is not zero. */ -static inline limb_t scan_bit_nz(const bf_t *r, slimb_t bit_pos) -{ - slimb_t pos; - limb_t v; - - pos = bit_pos >> LIMB_LOG2_BITS; - if (pos < 0) - return 0; - v = r->tab[pos] & limb_mask(0, bit_pos & (LIMB_BITS - 1)); - if (v != 0) - return 1; - pos--; - while (pos >= 0) { - if (r->tab[pos] != 0) - return 1; - pos--; - } - return 0; -} - -/* return the addend for rounding. Note that prec can be <= 0 (for - BF_FLAG_RADPNT_PREC) */ -static int bf_get_rnd_add(int *pret, const bf_t *r, limb_t l, - slimb_t prec, int rnd_mode) -{ - int add_one, inexact; - limb_t bit1, bit0; - - if (rnd_mode == BF_RNDF) { - bit0 = 1; /* faithful rounding does not honor the INEXACT flag */ - } else { - /* starting limb for bit 'prec + 1' */ - bit0 = scan_bit_nz(r, l * LIMB_BITS - 1 - bf_max(0, prec + 1)); - } - - /* get the bit at 'prec' */ - bit1 = get_bit(r->tab, l, l * LIMB_BITS - 1 - prec); - inexact = (bit1 | bit0) != 0; - - add_one = 0; - switch(rnd_mode) { - case BF_RNDZ: - break; - case BF_RNDN: - if (bit1) { - if (bit0) { - add_one = 1; - } else { - /* round to even */ - add_one = - get_bit(r->tab, l, l * LIMB_BITS - 1 - (prec - 1)); - } - } - break; - case BF_RNDD: - case BF_RNDU: - if (r->sign == (rnd_mode == BF_RNDD)) - add_one = inexact; - break; - case BF_RNDA: - add_one = inexact; - break; - case BF_RNDNA: - case BF_RNDF: - add_one = bit1; - break; - default: - abort(); - } - - if (inexact) - *pret |= BF_ST_INEXACT; - return add_one; -} - -static int bf_set_overflow(bf_t *r, int sign, limb_t prec, bf_flags_t flags) -{ - slimb_t i, l, e_max; - int rnd_mode; - - rnd_mode = flags & BF_RND_MASK; - if (prec == BF_PREC_INF || - rnd_mode == BF_RNDN || - rnd_mode == BF_RNDNA || - rnd_mode == BF_RNDA || - (rnd_mode == BF_RNDD && sign == 1) || - (rnd_mode == BF_RNDU && sign == 0)) { - bf_set_inf(r, sign); - } else { - /* set to maximum finite number */ - l = (prec + LIMB_BITS - 1) / LIMB_BITS; - if (bf_resize(r, l)) { - bf_set_nan(r); - return BF_ST_MEM_ERROR; - } - r->tab[0] = limb_mask((-prec) & (LIMB_BITS - 1), - LIMB_BITS - 1); - for(i = 1; i < l; i++) - r->tab[i] = (limb_t)-1; - e_max = (limb_t)1 << (bf_get_exp_bits(flags) - 1); - r->expn = e_max; - r->sign = sign; - } - return BF_ST_OVERFLOW | BF_ST_INEXACT; -} - -/* round to prec1 bits assuming 'r' is non zero and finite. 'r' is - assumed to have length 'l' (1 <= l <= r->len). Note: 'prec1' can be - infinite (BF_PREC_INF). 'ret' is 0 or BF_ST_INEXACT if the result - is known to be inexact. Can fail with BF_ST_MEM_ERROR in case of - overflow not returning infinity. */ -static int __bf_round(bf_t *r, limb_t prec1, bf_flags_t flags, limb_t l, - int ret) -{ - limb_t v, a; - int shift, add_one, rnd_mode; - slimb_t i, bit_pos, pos, e_min, e_max, e_range, prec; - - /* e_min and e_max are computed to match the IEEE 754 conventions */ - e_range = (limb_t)1 << (bf_get_exp_bits(flags) - 1); - e_min = -e_range + 3; - e_max = e_range; - - if (flags & BF_FLAG_RADPNT_PREC) { - /* 'prec' is the precision after the radix point */ - if (prec1 != BF_PREC_INF) - prec = r->expn + prec1; - else - prec = prec1; - } else if (UNLIKELY(r->expn < e_min) && (flags & BF_FLAG_SUBNORMAL)) { - /* restrict the precision in case of potentially subnormal - result */ - assert(prec1 != BF_PREC_INF); - prec = prec1 - (e_min - r->expn); - } else { - prec = prec1; - } - - /* round to prec bits */ - rnd_mode = flags & BF_RND_MASK; - add_one = bf_get_rnd_add(&ret, r, l, prec, rnd_mode); - - if (prec <= 0) { - if (add_one) { - bf_resize(r, 1); /* cannot fail */ - r->tab[0] = (limb_t)1 << (LIMB_BITS - 1); - r->expn += 1 - prec; - ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT; - return ret; - } else { - goto underflow; - } - } else if (add_one) { - limb_t carry; - - /* add one starting at digit 'prec - 1' */ - bit_pos = l * LIMB_BITS - 1 - (prec - 1); - pos = bit_pos >> LIMB_LOG2_BITS; - carry = (limb_t)1 << (bit_pos & (LIMB_BITS - 1)); - - for(i = pos; i < l; i++) { - v = r->tab[i] + carry; - carry = (v < carry); - r->tab[i] = v; - if (carry == 0) - break; - } - if (carry) { - /* shift right by one digit */ - v = 1; - for(i = l - 1; i >= pos; i--) { - a = r->tab[i]; - r->tab[i] = (a >> 1) | (v << (LIMB_BITS - 1)); - v = a; - } - r->expn++; - } - } - - /* check underflow */ - if (UNLIKELY(r->expn < e_min)) { - if (flags & BF_FLAG_SUBNORMAL) { - /* if inexact, also set the underflow flag */ - if (ret & BF_ST_INEXACT) - ret |= BF_ST_UNDERFLOW; - } else { - underflow: - ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT; - bf_set_zero(r, r->sign); - return ret; - } - } - - /* check overflow */ - if (UNLIKELY(r->expn > e_max)) - return bf_set_overflow(r, r->sign, prec1, flags); - - /* keep the bits starting at 'prec - 1' */ - bit_pos = l * LIMB_BITS - 1 - (prec - 1); - i = bit_pos >> LIMB_LOG2_BITS; - if (i >= 0) { - shift = bit_pos & (LIMB_BITS - 1); - if (shift != 0) - r->tab[i] &= limb_mask(shift, LIMB_BITS - 1); - } else { - i = 0; - } - /* remove trailing zeros */ - while (r->tab[i] == 0) - i++; - if (i > 0) { - l -= i; - memmove(r->tab, r->tab + i, l * sizeof(limb_t)); - } - bf_resize(r, l); /* cannot fail */ - return ret; -} - -/* 'r' must be a finite number. */ -int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags) -{ - limb_t l, v, a; - int shift, ret; - slimb_t i; - - // bf_print_str("bf_renorm", r); - l = r->len; - while (l > 0 && r->tab[l - 1] == 0) - l--; - if (l == 0) { - /* zero */ - r->expn = BF_EXP_ZERO; - bf_resize(r, 0); /* cannot fail */ - ret = 0; - } else { - r->expn -= (r->len - l) * LIMB_BITS; - /* shift to have the MSB set to '1' */ - v = r->tab[l - 1]; - shift = clz(v); - if (shift != 0) { - v = 0; - for(i = 0; i < l; i++) { - a = r->tab[i]; - r->tab[i] = (a << shift) | (v >> (LIMB_BITS - shift)); - v = a; - } - r->expn -= shift; - } - ret = __bf_round(r, prec1, flags, l, 0); - } - // bf_print_str("r_final", r); - return ret; -} - -/* return true if rounding can be done at precision 'prec' assuming - the exact result r is such that |r-a| <= 2^(EXP(a)-k). */ -/* XXX: check the case where the exponent would be incremented by the - rounding */ -int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k) -{ - BOOL is_rndn; - slimb_t bit_pos, n; - limb_t bit; - - if (a->expn == BF_EXP_INF || a->expn == BF_EXP_NAN) - return FALSE; - if (rnd_mode == BF_RNDF) { - return (k >= (prec + 1)); - } - if (a->expn == BF_EXP_ZERO) - return FALSE; - is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA); - if (k < (prec + 2)) - return FALSE; - bit_pos = a->len * LIMB_BITS - 1 - prec; - n = k - prec; - /* bit pattern for RNDN or RNDNA: 0111.. or 1000... - for other rounding modes: 000... or 111... - */ - bit = get_bit(a->tab, a->len, bit_pos); - bit_pos--; - n--; - bit ^= is_rndn; - /* XXX: slow, but a few iterations on average */ - while (n != 0) { - if (get_bit(a->tab, a->len, bit_pos) != bit) - return TRUE; - bit_pos--; - n--; - } - return FALSE; -} - -/* Cannot fail with BF_ST_MEM_ERROR. */ -int bf_round(bf_t *r, limb_t prec, bf_flags_t flags) -{ - if (r->len == 0) - return 0; - return __bf_round(r, prec, flags, r->len, 0); -} - -/* for debugging */ -static __maybe_unused void dump_limbs(const char *str, const limb_t *tab, limb_t n) -{ - limb_t i; - printf("%s: len=%" PRId_LIMB "\n", str, n); - for(i = 0; i < n; i++) { - printf("%" PRId_LIMB ": " FMT_LIMB "\n", - i, tab[i]); - } -} - -void mp_print_str(const char *str, const limb_t *tab, limb_t n) -{ - slimb_t i; - printf("%s= 0x", str); - for(i = n - 1; i >= 0; i--) { - if (i != (n - 1)) - printf("_"); - printf(FMT_LIMB, tab[i]); - } - printf("\n"); -} - -static __maybe_unused void mp_print_str_h(const char *str, - const limb_t *tab, limb_t n, - limb_t high) -{ - slimb_t i; - printf("%s= 0x", str); - printf(FMT_LIMB, high); - for(i = n - 1; i >= 0; i--) { - printf("_"); - printf(FMT_LIMB, tab[i]); - } - printf("\n"); -} - -/* for debugging */ -void bf_print_str(const char *str, const bf_t *a) -{ - slimb_t i; - printf("%s=", str); - - if (a->expn == BF_EXP_NAN) { - printf("NaN"); - } else { - if (a->sign) - putchar('-'); - if (a->expn == BF_EXP_ZERO) { - putchar('0'); - } else if (a->expn == BF_EXP_INF) { - printf("Inf"); - } else { - printf("0x0."); - for(i = a->len - 1; i >= 0; i--) - printf(FMT_LIMB, a->tab[i]); - printf("p%" PRId_LIMB, a->expn); - } - } - printf("\n"); -} - -/* compare the absolute value of 'a' and 'b'. Return < 0 if a < b, 0 - if a = b and > 0 otherwise. */ -int bf_cmpu(const bf_t *a, const bf_t *b) -{ - slimb_t i; - limb_t len, v1, v2; - - if (a->expn != b->expn) { - if (a->expn < b->expn) - return -1; - else - return 1; - } - len = bf_max(a->len, b->len); - for(i = len - 1; i >= 0; i--) { - v1 = get_limbz(a, a->len - len + i); - v2 = get_limbz(b, b->len - len + i); - if (v1 != v2) { - if (v1 < v2) - return -1; - else - return 1; - } - } - return 0; -} - -/* Full order: -0 < 0, NaN == NaN and NaN is larger than all other numbers */ -int bf_cmp_full(const bf_t *a, const bf_t *b) -{ - int res; - - if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) { - if (a->expn == b->expn) - res = 0; - else if (a->expn == BF_EXP_NAN) - res = 1; - else - res = -1; - } else if (a->sign != b->sign) { - res = 1 - 2 * a->sign; - } else { - res = bf_cmpu(a, b); - if (a->sign) - res = -res; - } - return res; -} - -/* Standard floating point comparison: return 2 if one of the operands - is NaN (unordered) or -1, 0, 1 depending on the ordering assuming - -0 == +0 */ -int bf_cmp(const bf_t *a, const bf_t *b) -{ - int res; - - if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) { - res = 2; - } else if (a->sign != b->sign) { - if (a->expn == BF_EXP_ZERO && b->expn == BF_EXP_ZERO) - res = 0; - else - res = 1 - 2 * a->sign; - } else { - res = bf_cmpu(a, b); - if (a->sign) - res = -res; - } - return res; -} - -/* Compute the number of bits 'n' matching the pattern: - a= X1000..0 - b= X0111..1 - - When computing a-b, the result will have at least n leading zero - bits. - - Precondition: a > b and a.expn - b.expn = 0 or 1 -*/ -static limb_t count_cancelled_bits(const bf_t *a, const bf_t *b) -{ - slimb_t bit_offset, b_offset, n; - int p, p1; - limb_t v1, v2, mask; - - bit_offset = a->len * LIMB_BITS - 1; - b_offset = (b->len - a->len) * LIMB_BITS - (LIMB_BITS - 1) + - a->expn - b->expn; - n = 0; - - /* first search the equals bits */ - for(;;) { - v1 = get_limbz(a, bit_offset >> LIMB_LOG2_BITS); - v2 = get_bits(b->tab, b->len, bit_offset + b_offset); - // printf("v1=" FMT_LIMB " v2=" FMT_LIMB "\n", v1, v2); - if (v1 != v2) - break; - n += LIMB_BITS; - bit_offset -= LIMB_BITS; - } - /* find the position of the first different bit */ - p = clz(v1 ^ v2) + 1; - n += p; - /* then search for '0' in a and '1' in b */ - p = LIMB_BITS - p; - if (p > 0) { - /* search in the trailing p bits of v1 and v2 */ - mask = limb_mask(0, p - 1); - p1 = bf_min(clz(v1 & mask), clz((~v2) & mask)) - (LIMB_BITS - p); - n += p1; - if (p1 != p) - goto done; - } - bit_offset -= LIMB_BITS; - for(;;) { - v1 = get_limbz(a, bit_offset >> LIMB_LOG2_BITS); - v2 = get_bits(b->tab, b->len, bit_offset + b_offset); - // printf("v1=" FMT_LIMB " v2=" FMT_LIMB "\n", v1, v2); - if (v1 != 0 || v2 != -1) { - /* different: count the matching bits */ - p1 = bf_min(clz(v1), clz(~v2)); - n += p1; - break; - } - n += LIMB_BITS; - bit_offset -= LIMB_BITS; - } - done: - return n; -} - -static int bf_add_internal(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, - bf_flags_t flags, int b_neg) -{ - const bf_t *tmp; - int is_sub, ret, cmp_res, a_sign, b_sign; - - a_sign = a->sign; - b_sign = b->sign ^ b_neg; - is_sub = a_sign ^ b_sign; - cmp_res = bf_cmpu(a, b); - if (cmp_res < 0) { - tmp = a; - a = b; - b = tmp; - a_sign = b_sign; /* b_sign is never used later */ - } - /* abs(a) >= abs(b) */ - if (cmp_res == 0 && is_sub && a->expn < BF_EXP_INF) { - /* zero result */ - bf_set_zero(r, (flags & BF_RND_MASK) == BF_RNDD); - ret = 0; - } else if (a->len == 0 || b->len == 0) { - ret = 0; - if (a->expn >= BF_EXP_INF) { - if (a->expn == BF_EXP_NAN) { - /* at least one operand is NaN */ - bf_set_nan(r); - } else if (b->expn == BF_EXP_INF && is_sub) { - /* infinities with different signs */ - bf_set_nan(r); - ret = BF_ST_INVALID_OP; - } else { - bf_set_inf(r, a_sign); - } - } else { - /* at least one zero and not subtract */ - bf_set(r, a); - r->sign = a_sign; - goto renorm; - } - } else { - slimb_t d, a_offset, b_bit_offset, i, cancelled_bits; - limb_t carry, v1, v2, u, r_len, carry1, precl, tot_len, z, sub_mask; - - r->sign = a_sign; - r->expn = a->expn; - d = a->expn - b->expn; - /* must add more precision for the leading cancelled bits in - subtraction */ - if (is_sub) { - if (d <= 1) - cancelled_bits = count_cancelled_bits(a, b); - else - cancelled_bits = 1; - } else { - cancelled_bits = 0; - } - - /* add two extra bits for rounding */ - precl = (cancelled_bits + prec + 2 + LIMB_BITS - 1) / LIMB_BITS; - tot_len = bf_max(a->len, b->len + (d + LIMB_BITS - 1) / LIMB_BITS); - r_len = bf_min(precl, tot_len); - if (bf_resize(r, r_len)) - goto fail; - a_offset = a->len - r_len; - b_bit_offset = (b->len - r_len) * LIMB_BITS + d; - - /* compute the bits before for the rounding */ - carry = is_sub; - z = 0; - sub_mask = -is_sub; - i = r_len - tot_len; - while (i < 0) { - slimb_t ap, bp; - BOOL inflag; - - ap = a_offset + i; - bp = b_bit_offset + i * LIMB_BITS; - inflag = FALSE; - if (ap >= 0 && ap < a->len) { - v1 = a->tab[ap]; - inflag = TRUE; - } else { - v1 = 0; - } - if (bp + LIMB_BITS > 0 && bp < (slimb_t)(b->len * LIMB_BITS)) { - v2 = get_bits(b->tab, b->len, bp); - inflag = TRUE; - } else { - v2 = 0; - } - if (!inflag) { - /* outside 'a' and 'b': go directly to the next value - inside a or b so that the running time does not - depend on the exponent difference */ - i = 0; - if (ap < 0) - i = bf_min(i, -a_offset); - /* b_bit_offset + i * LIMB_BITS + LIMB_BITS >= 1 - equivalent to - i >= ceil(-b_bit_offset + 1 - LIMB_BITS) / LIMB_BITS) - */ - if (bp + LIMB_BITS <= 0) - i = bf_min(i, (-b_bit_offset) >> LIMB_LOG2_BITS); - } else { - i++; - } - v2 ^= sub_mask; - u = v1 + v2; - carry1 = u < v1; - u += carry; - carry = (u < carry) | carry1; - z |= u; - } - /* and the result */ - for(i = 0; i < r_len; i++) { - v1 = get_limbz(a, a_offset + i); - v2 = get_bits(b->tab, b->len, b_bit_offset + i * LIMB_BITS); - v2 ^= sub_mask; - u = v1 + v2; - carry1 = u < v1; - u += carry; - carry = (u < carry) | carry1; - r->tab[i] = u; - } - /* set the extra bits for the rounding */ - r->tab[0] |= (z != 0); - - /* carry is only possible in add case */ - if (!is_sub && carry) { - if (bf_resize(r, r_len + 1)) - goto fail; - r->tab[r_len] = 1; - r->expn += LIMB_BITS; - } - renorm: - ret = bf_normalize_and_round(r, prec, flags); - } - return ret; - fail: - bf_set_nan(r); - return BF_ST_MEM_ERROR; -} - -static int __bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, - bf_flags_t flags) -{ - return bf_add_internal(r, a, b, prec, flags, 0); -} - -static int __bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, - bf_flags_t flags) -{ - return bf_add_internal(r, a, b, prec, flags, 1); -} - -limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2, - limb_t n, limb_t carry) -{ - slimb_t i; - limb_t k, a, v, k1; - - k = carry; - for(i=0;i v; - v = a - k; - k = (v > a) | k1; - res[i] = v; - } - return k; -} - -/* compute 0 - op2 */ -static limb_t mp_neg(limb_t *res, const limb_t *op2, mp_size_t n, limb_t carry) -{ - int i; - limb_t k, a, v, k1; - - k = carry; - for(i=0;i v; - v = a - k; - k = (v > a) | k1; - res[i] = v; - } - return k; -} - -limb_t mp_sub_ui(limb_t *tab, limb_t b, mp_size_t n) -{ - mp_size_t i; - limb_t k, a, v; - - k=b; - for(i=0;i v; - tab[i] = a; - if (k == 0) - break; - } - return k; -} - -/* r = (a + high*B^n) >> shift. Return the remainder r (0 <= r < 2^shift). - 1 <= shift <= LIMB_BITS - 1 */ -static limb_t mp_shr(limb_t *tab_r, const limb_t *tab, mp_size_t n, - int shift, limb_t high) -{ - mp_size_t i; - limb_t l, a; - - assert(shift >= 1 && shift < LIMB_BITS); - l = high; - for(i = n - 1; i >= 0; i--) { - a = tab[i]; - tab_r[i] = (a >> shift) | (l << (LIMB_BITS - shift)); - l = a; - } - return l & (((limb_t)1 << shift) - 1); -} - -/* tabr[] = taba[] * b + l. Return the high carry */ -static limb_t mp_mul1(limb_t *tabr, const limb_t *taba, limb_t n, - limb_t b, limb_t l) -{ - limb_t i; - dlimb_t t; - - for(i = 0; i < n; i++) { - t = (dlimb_t)taba[i] * (dlimb_t)b + l; - tabr[i] = t; - l = t >> LIMB_BITS; - } - return l; -} - -/* tabr[] += taba[] * b, return the high word. */ -static limb_t mp_add_mul1(limb_t *tabr, const limb_t *taba, limb_t n, - limb_t b) -{ - limb_t i, l; - dlimb_t t; - - l = 0; - for(i = 0; i < n; i++) { - t = (dlimb_t)taba[i] * (dlimb_t)b + l + tabr[i]; - tabr[i] = t; - l = t >> LIMB_BITS; - } - return l; -} - -/* size of the result : op1_size + op2_size. */ -static void mp_mul_basecase(limb_t *result, - const limb_t *op1, limb_t op1_size, - const limb_t *op2, limb_t op2_size) -{ - limb_t i, r; - - result[op1_size] = mp_mul1(result, op1, op1_size, op2[0], 0); - for(i=1;i= FFT_MUL_THRESHOLD)) { - bf_t r_s, *r = &r_s; - r->tab = result; - /* XXX: optimize memory usage in API */ - if (fft_mul(s, r, (limb_t *)op1, op1_size, - (limb_t *)op2, op2_size, FFT_MUL_R_NORESIZE)) - return -1; - } else -#endif - { - mp_mul_basecase(result, op1, op1_size, op2, op2_size); - } - return 0; -} - -/* tabr[] -= taba[] * b. Return the value to substract to the high - word. */ -static limb_t mp_sub_mul1(limb_t *tabr, const limb_t *taba, limb_t n, - limb_t b) -{ - limb_t i, l; - dlimb_t t; - - l = 0; - for(i = 0; i < n; i++) { - t = tabr[i] - (dlimb_t)taba[i] * (dlimb_t)b - l; - tabr[i] = t; - l = -(t >> LIMB_BITS); - } - return l; -} - -/* WARNING: d must be >= 2^(LIMB_BITS-1) */ -static inline limb_t udiv1norm_init(limb_t d) -{ - limb_t a0, a1; - a1 = -d - 1; - a0 = -1; - return (((dlimb_t)a1 << LIMB_BITS) | a0) / d; -} - -/* return the quotient and the remainder in '*pr'of 'a1*2^LIMB_BITS+a0 - / d' with 0 <= a1 < d. */ -static inline limb_t udiv1norm(limb_t *pr, limb_t a1, limb_t a0, - limb_t d, limb_t d_inv) -{ - limb_t n1m, n_adj, q, r, ah; - dlimb_t a; - n1m = ((slimb_t)a0 >> (LIMB_BITS - 1)); - n_adj = a0 + (n1m & d); - a = (dlimb_t)d_inv * (a1 - n1m) + n_adj; - q = (a >> LIMB_BITS) + a1; - /* compute a - q * r and update q so that the remainder is\ - between 0 and d - 1 */ - a = ((dlimb_t)a1 << LIMB_BITS) | a0; - a = a - (dlimb_t)q * d - d; - ah = a >> LIMB_BITS; - q += 1 + ah; - r = (limb_t)a + (ah & d); - *pr = r; - return q; -} - -/* b must be >= 1 << (LIMB_BITS - 1) */ -static limb_t mp_div1norm(limb_t *tabr, const limb_t *taba, limb_t n, - limb_t b, limb_t r) -{ - slimb_t i; - - if (n >= UDIV1NORM_THRESHOLD) { - limb_t b_inv; - b_inv = udiv1norm_init(b); - for(i = n - 1; i >= 0; i--) { - tabr[i] = udiv1norm(&r, r, taba[i], b, b_inv); - } - } else { - dlimb_t a1; - for(i = n - 1; i >= 0; i--) { - a1 = ((dlimb_t)r << LIMB_BITS) | taba[i]; - tabr[i] = a1 / b; - r = a1 % b; - } - } - return r; -} - -static int mp_divnorm_large(bf_context_t *s, - limb_t *tabq, limb_t *taba, limb_t na, - const limb_t *tabb, limb_t nb); - -/* base case division: divides taba[0..na-1] by tabb[0..nb-1]. tabb[nb - - 1] must be >= 1 << (LIMB_BITS - 1). na - nb must be >= 0. 'taba' - is modified and contains the remainder (nb limbs). tabq[0..na-nb] - contains the quotient with tabq[na - nb] <= 1. */ -static int mp_divnorm(bf_context_t *s, limb_t *tabq, limb_t *taba, limb_t na, - const limb_t *tabb, limb_t nb) -{ - limb_t r, a, c, q, v, b1, b1_inv, n, dummy_r; - slimb_t i, j; - - b1 = tabb[nb - 1]; - if (nb == 1) { - taba[0] = mp_div1norm(tabq, taba, na, b1, 0); - return 0; - } - n = na - nb; - if (bf_min(n, nb) >= DIVNORM_LARGE_THRESHOLD) { - return mp_divnorm_large(s, tabq, taba, na, tabb, nb); - } - - if (n >= UDIV1NORM_THRESHOLD) - b1_inv = udiv1norm_init(b1); - else - b1_inv = 0; - - /* first iteration: the quotient is only 0 or 1 */ - q = 1; - for(j = nb - 1; j >= 0; j--) { - if (taba[n + j] != tabb[j]) { - if (taba[n + j] < tabb[j]) - q = 0; - break; - } - } - tabq[n] = q; - if (q) { - mp_sub(taba + n, taba + n, tabb, nb, 0); - } - - for(i = n - 1; i >= 0; i--) { - if (UNLIKELY(taba[i + nb] >= b1)) { - q = -1; - } else if (b1_inv) { - q = udiv1norm(&dummy_r, taba[i + nb], taba[i + nb - 1], b1, b1_inv); - } else { - dlimb_t al; - al = ((dlimb_t)taba[i + nb] << LIMB_BITS) | taba[i + nb - 1]; - q = al / b1; - r = al % b1; - } - r = mp_sub_mul1(taba + i, tabb, nb, q); - - v = taba[i + nb]; - a = v - r; - c = (a > v); - taba[i + nb] = a; - - if (c != 0) { - /* negative result */ - for(;;) { - q--; - c = mp_add(taba + i, taba + i, tabb, nb, 0); - /* propagate carry and test if positive result */ - if (c != 0) { - if (++taba[i + nb] == 0) { - break; - } - } - } - } - tabq[i] = q; - } - return 0; -} - -/* compute r=B^(2*n)/a such as a*r < B^(2*n) < a*r + 2 with n >= 1. 'a' - has n limbs with a[n-1] >= B/2 and 'r' has n+1 limbs with r[n] = 1. - - See Modern Computer Arithmetic by Richard P. Brent and Paul - Zimmermann, algorithm 3.5 */ -int mp_recip(bf_context_t *s, limb_t *tabr, const limb_t *taba, limb_t n) -{ - mp_size_t l, h, k, i; - limb_t *tabxh, *tabt, c, *tabu; - - if (n <= 2) { - /* return ceil(B^(2*n)/a) - 1 */ - /* XXX: could avoid allocation */ - tabu = bf_malloc(s, sizeof(limb_t) * (2 * n + 1)); - tabt = bf_malloc(s, sizeof(limb_t) * (n + 2)); - if (!tabt || !tabu) - goto fail; - for(i = 0; i < 2 * n; i++) - tabu[i] = 0; - tabu[2 * n] = 1; - if (mp_divnorm(s, tabt, tabu, 2 * n + 1, taba, n)) - goto fail; - for(i = 0; i < n + 1; i++) - tabr[i] = tabt[i]; - if (mp_scan_nz(tabu, n) == 0) { - /* only happens for a=B^n/2 */ - mp_sub_ui(tabr, 1, n + 1); - } - } else { - l = (n - 1) / 2; - h = n - l; - /* n=2p -> l=p-1, h = p + 1, k = p + 3 - n=2p+1-> l=p, h = p + 1; k = p + 2 - */ - tabt = bf_malloc(s, sizeof(limb_t) * (n + h + 1)); - tabu = bf_malloc(s, sizeof(limb_t) * (n + 2 * h - l + 2)); - if (!tabt || !tabu) - goto fail; - tabxh = tabr + l; - if (mp_recip(s, tabxh, taba + l, h)) - goto fail; - if (mp_mul(s, tabt, taba, n, tabxh, h + 1)) /* n + h + 1 limbs */ - goto fail; - while (tabt[n + h] != 0) { - mp_sub_ui(tabxh, 1, h + 1); - c = mp_sub(tabt, tabt, taba, n, 0); - mp_sub_ui(tabt + n, c, h + 1); - } - /* T = B^(n+h) - T */ - mp_neg(tabt, tabt, n + h + 1, 0); - tabt[n + h]++; - if (mp_mul(s, tabu, tabt + l, n + h + 1 - l, tabxh, h + 1)) - goto fail; - /* n + 2*h - l + 2 limbs */ - k = 2 * h - l; - for(i = 0; i < l; i++) - tabr[i] = tabu[i + k]; - mp_add(tabr + l, tabr + l, tabu + 2 * h, h, 0); - } - bf_free(s, tabt); - bf_free(s, tabu); - return 0; - fail: - bf_free(s, tabt); - bf_free(s, tabu); - return -1; -} - -/* return -1, 0 or 1 */ -static int mp_cmp(const limb_t *taba, const limb_t *tabb, mp_size_t n) -{ - mp_size_t i; - for(i = n - 1; i >= 0; i--) { - if (taba[i] != tabb[i]) { - if (taba[i] < tabb[i]) - return -1; - else - return 1; - } - } - return 0; -} - -//#define DEBUG_DIVNORM_LARGE -//#define DEBUG_DIVNORM_LARGE2 - -/* subquadratic divnorm */ -static int mp_divnorm_large(bf_context_t *s, - limb_t *tabq, limb_t *taba, limb_t na, - const limb_t *tabb, limb_t nb) -{ - limb_t *tabb_inv, nq, *tabt, i, n; - nq = na - nb; -#ifdef DEBUG_DIVNORM_LARGE - printf("na=%d nb=%d nq=%d\n", (int)na, (int)nb, (int)nq); - mp_print_str("a", taba, na); - mp_print_str("b", tabb, nb); -#endif - assert(nq >= 1); - n = nq; - if (nq < nb) - n++; - tabb_inv = bf_malloc(s, sizeof(limb_t) * (n + 1)); - tabt = bf_malloc(s, sizeof(limb_t) * 2 * (n + 1)); - if (!tabb_inv || !tabt) - goto fail; - - if (n >= nb) { - for(i = 0; i < n - nb; i++) - tabt[i] = 0; - for(i = 0; i < nb; i++) - tabt[i + n - nb] = tabb[i]; - } else { - /* truncate B: need to increment it so that the approximate - inverse is smaller that the exact inverse */ - for(i = 0; i < n; i++) - tabt[i] = tabb[i + nb - n]; - if (mp_add_ui(tabt, 1, n)) { - /* tabt = B^n : tabb_inv = B^n */ - bzero(tabb_inv, n * sizeof(limb_t)); - tabb_inv[n] = 1; - goto recip_done; - } - } - if (mp_recip(s, tabb_inv, tabt, n)) - goto fail; - recip_done: - /* Q=A*B^-1 */ - if (mp_mul(s, tabt, tabb_inv, n + 1, taba + na - (n + 1), n + 1)) - goto fail; - - for(i = 0; i < nq + 1; i++) - tabq[i] = tabt[i + 2 * (n + 1) - (nq + 1)]; -#ifdef DEBUG_DIVNORM_LARGE - mp_print_str("q", tabq, nq + 1); -#endif - - bf_free(s, tabt); - bf_free(s, tabb_inv); - tabb_inv = NULL; - - /* R=A-B*Q */ - tabt = bf_malloc(s, sizeof(limb_t) * (na + 1)); - if (!tabt) - goto fail; - if (mp_mul(s, tabt, tabq, nq + 1, tabb, nb)) - goto fail; - /* we add one more limb for the result */ - mp_sub(taba, taba, tabt, nb + 1, 0); - bf_free(s, tabt); - /* the approximated quotient is smaller than than the exact one, - hence we may have to increment it */ -#ifdef DEBUG_DIVNORM_LARGE2 - int cnt = 0; - static int cnt_max; -#endif - for(;;) { - if (taba[nb] == 0 && mp_cmp(taba, tabb, nb) < 0) - break; - taba[nb] -= mp_sub(taba, taba, tabb, nb, 0); - mp_add_ui(tabq, 1, nq + 1); -#ifdef DEBUG_DIVNORM_LARGE2 - cnt++; -#endif - } -#ifdef DEBUG_DIVNORM_LARGE2 - if (cnt > cnt_max) { - cnt_max = cnt; - printf("\ncnt=%d nq=%d nb=%d\n", cnt_max, (int)nq, (int)nb); - } -#endif - return 0; - fail: - bf_free(s, tabb_inv); - bf_free(s, tabt); - return -1; -} - -int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, - bf_flags_t flags) -{ - int ret, r_sign; - - if (a->len < b->len) { - const bf_t *tmp = a; - a = b; - b = tmp; - } - r_sign = a->sign ^ b->sign; - /* here b->len <= a->len */ - if (b->len == 0) { - if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) { - bf_set_nan(r); - ret = 0; - } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_INF) { - if ((a->expn == BF_EXP_INF && b->expn == BF_EXP_ZERO) || - (a->expn == BF_EXP_ZERO && b->expn == BF_EXP_INF)) { - bf_set_nan(r); - ret = BF_ST_INVALID_OP; - } else { - bf_set_inf(r, r_sign); - ret = 0; - } - } else { - bf_set_zero(r, r_sign); - ret = 0; - } - } else { - bf_t tmp, *r1 = NULL; - limb_t a_len, b_len, precl; - limb_t *a_tab, *b_tab; - - a_len = a->len; - b_len = b->len; - - if ((flags & BF_RND_MASK) == BF_RNDF) { - /* faithful rounding does not require using the full inputs */ - precl = (prec + 2 + LIMB_BITS - 1) / LIMB_BITS; - a_len = bf_min(a_len, precl); - b_len = bf_min(b_len, precl); - } - a_tab = a->tab + a->len - a_len; - b_tab = b->tab + b->len - b_len; - -#ifdef USE_FFT_MUL - if (b_len >= FFT_MUL_THRESHOLD) { - int mul_flags = 0; - if (r == a) - mul_flags |= FFT_MUL_R_OVERLAP_A; - if (r == b) - mul_flags |= FFT_MUL_R_OVERLAP_B; - if (fft_mul(r->ctx, r, a_tab, a_len, b_tab, b_len, mul_flags)) - goto fail; - } else -#endif - { - if (r == a || r == b) { - bf_init(r->ctx, &tmp); - r1 = r; - r = &tmp; - } - if (bf_resize(r, a_len + b_len)) { - fail: - bf_set_nan(r); - ret = BF_ST_MEM_ERROR; - goto done; - } - mp_mul_basecase(r->tab, a_tab, a_len, b_tab, b_len); - } - r->sign = r_sign; - r->expn = a->expn + b->expn; - ret = bf_normalize_and_round(r, prec, flags); - done: - if (r == &tmp) - bf_move(r1, &tmp); - } - return ret; -} - -/* multiply 'r' by 2^e */ -int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags) -{ - slimb_t e_max; - if (r->len == 0) - return 0; - e_max = ((limb_t)1 << BF_EXT_EXP_BITS_MAX) - 1; - e = bf_max(e, -e_max); - e = bf_min(e, e_max); - r->expn += e; - return __bf_round(r, prec, flags, r->len, 0); -} - -/* Return e such as a=m*2^e with m odd integer. return 0 if a is zero, - Infinite or Nan. */ -slimb_t bf_get_exp_min(const bf_t *a) -{ - slimb_t i; - limb_t v; - int k; - - for(i = 0; i < a->len; i++) { - v = a->tab[i]; - if (v != 0) { - k = ctz(v); - return a->expn - (a->len - i) * LIMB_BITS + k; - } - } - return 0; -} - -/* a and b must be finite numbers with a >= 0 and b > 0. 'q' is the - integer defined as floor(a/b) and r = a - q * b. */ -static void bf_tdivremu(bf_t *q, bf_t *r, - const bf_t *a, const bf_t *b) -{ - if (bf_cmpu(a, b) < 0) { - bf_set_ui(q, 0); - bf_set(r, a); - } else { - bf_div(q, a, b, bf_max(a->expn - b->expn + 1, 2), BF_RNDZ); - bf_rint(q, BF_RNDZ); - bf_mul(r, q, b, BF_PREC_INF, BF_RNDZ); - bf_sub(r, a, r, BF_PREC_INF, BF_RNDZ); - } -} - -static int __bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, - bf_flags_t flags) -{ - bf_context_t *s = r->ctx; - int ret, r_sign; - limb_t n, nb, precl; - - r_sign = a->sign ^ b->sign; - if (a->expn >= BF_EXP_INF || b->expn >= BF_EXP_INF) { - if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) { - bf_set_nan(r); - return 0; - } else if (a->expn == BF_EXP_INF && b->expn == BF_EXP_INF) { - bf_set_nan(r); - return BF_ST_INVALID_OP; - } else if (a->expn == BF_EXP_INF) { - bf_set_inf(r, r_sign); - return 0; - } else { - bf_set_zero(r, r_sign); - return 0; - } - } else if (a->expn == BF_EXP_ZERO) { - if (b->expn == BF_EXP_ZERO) { - bf_set_nan(r); - return BF_ST_INVALID_OP; - } else { - bf_set_zero(r, r_sign); - return 0; - } - } else if (b->expn == BF_EXP_ZERO) { - bf_set_inf(r, r_sign); - return BF_ST_DIVIDE_ZERO; - } - - /* number of limbs of the quotient (2 extra bits for rounding) */ - precl = (prec + 2 + LIMB_BITS - 1) / LIMB_BITS; - nb = b->len; - n = bf_max(a->len, precl); - - { - limb_t *taba, na; - slimb_t d; - - na = n + nb; - taba = bf_malloc(s, (na + 1) * sizeof(limb_t)); - if (!taba) - goto fail; - d = na - a->len; - bzero(taba, d * sizeof(limb_t)); - memcpy(taba + d, a->tab, a->len * sizeof(limb_t)); - if (bf_resize(r, n + 1)) - goto fail1; - if (mp_divnorm(s, r->tab, taba, na, b->tab, nb)) { - fail1: - bf_free(s, taba); - goto fail; - } - /* see if non zero remainder */ - if (mp_scan_nz(taba, nb)) - r->tab[0] |= 1; - bf_free(r->ctx, taba); - r->expn = a->expn - b->expn + LIMB_BITS; - r->sign = r_sign; - ret = bf_normalize_and_round(r, prec, flags); - } - return ret; - fail: - bf_set_nan(r); - return BF_ST_MEM_ERROR; -} - -/* division and remainder. - - rnd_mode is the rounding mode for the quotient. The additional - rounding mode BF_RND_EUCLIDIAN is supported. - - 'q' is an integer. 'r' is rounded with prec and flags (prec can be - BF_PREC_INF). -*/ -int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b, - limb_t prec, bf_flags_t flags, int rnd_mode) -{ - bf_t a1_s, *a1 = &a1_s; - bf_t b1_s, *b1 = &b1_s; - int q_sign, ret; - BOOL is_ceil, is_rndn; - - assert(q != a && q != b); - assert(r != a && r != b); - assert(q != r); - - if (a->len == 0 || b->len == 0) { - bf_set_zero(q, 0); - if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) { - bf_set_nan(r); - return 0; - } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_ZERO) { - bf_set_nan(r); - return BF_ST_INVALID_OP; - } else { - bf_set(r, a); - return bf_round(r, prec, flags); - } - } - - q_sign = a->sign ^ b->sign; - is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA); - switch(rnd_mode) { - default: - case BF_RNDZ: - case BF_RNDN: - case BF_RNDNA: - is_ceil = FALSE; - break; - case BF_RNDD: - is_ceil = q_sign; - break; - case BF_RNDU: - is_ceil = q_sign ^ 1; - break; - case BF_RNDA: - is_ceil = TRUE; - break; - case BF_DIVREM_EUCLIDIAN: - is_ceil = a->sign; - break; - } - - a1->expn = a->expn; - a1->tab = a->tab; - a1->len = a->len; - a1->sign = 0; - - b1->expn = b->expn; - b1->tab = b->tab; - b1->len = b->len; - b1->sign = 0; - - /* XXX: could improve to avoid having a large 'q' */ - bf_tdivremu(q, r, a1, b1); - if (bf_is_nan(q) || bf_is_nan(r)) - goto fail; - - if (r->len != 0) { - if (is_rndn) { - int res; - b1->expn--; - res = bf_cmpu(r, b1); - b1->expn++; - if (res > 0 || - (res == 0 && - (rnd_mode == BF_RNDNA || - get_bit(q->tab, q->len, q->len * LIMB_BITS - q->expn)))) { - goto do_sub_r; - } - } else if (is_ceil) { - do_sub_r: - ret = bf_add_si(q, q, 1, BF_PREC_INF, BF_RNDZ); - ret |= bf_sub(r, r, b1, BF_PREC_INF, BF_RNDZ); - if (ret & BF_ST_MEM_ERROR) - goto fail; - } - } - - r->sign ^= a->sign; - q->sign = q_sign; - return bf_round(r, prec, flags); - fail: - bf_set_nan(q); - bf_set_nan(r); - return BF_ST_MEM_ERROR; -} - -int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, - bf_flags_t flags, int rnd_mode) -{ - bf_t q_s, *q = &q_s; - int ret; - - bf_init(r->ctx, q); - ret = bf_divrem(q, r, a, b, prec, flags, rnd_mode); - bf_delete(q); - return ret; -} - -static inline int bf_get_limb(slimb_t *pres, const bf_t *a, int flags) -{ -#if LIMB_BITS == 32 - return bf_get_int32(pres, a, flags); -#else - return bf_get_int64(pres, a, flags); -#endif -} - -int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, - bf_flags_t flags, int rnd_mode) -{ - bf_t q_s, *q = &q_s; - int ret; - - bf_init(r->ctx, q); - ret = bf_divrem(q, r, a, b, prec, flags, rnd_mode); - bf_get_limb(pq, q, BF_GET_INT_MOD); - bf_delete(q); - return ret; -} - -static __maybe_unused inline limb_t mul_mod(limb_t a, limb_t b, limb_t m) -{ - dlimb_t t; - t = (dlimb_t)a * (dlimb_t)b; - return t % m; -} - -#if defined(USE_MUL_CHECK) -static limb_t mp_mod1(const limb_t *tab, limb_t n, limb_t m, limb_t r) -{ - slimb_t i; - dlimb_t t; - - for(i = n - 1; i >= 0; i--) { - t = ((dlimb_t)r << LIMB_BITS) | tab[i]; - r = t % m; - } - return r; -} -#endif - -static const uint16_t sqrt_table[192] = { -128,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,144,145,146,147,148,149,150,150,151,152,153,154,155,155,156,157,158,159,160,160,161,162,163,163,164,165,166,167,167,168,169,170,170,171,172,173,173,174,175,176,176,177,178,178,179,180,181,181,182,183,183,184,185,185,186,187,187,188,189,189,190,191,192,192,193,193,194,195,195,196,197,197,198,199,199,200,201,201,202,203,203,204,204,205,206,206,207,208,208,209,209,210,211,211,212,212,213,214,214,215,215,216,217,217,218,218,219,219,220,221,221,222,222,223,224,224,225,225,226,226,227,227,228,229,229,230,230,231,231,232,232,233,234,234,235,235,236,236,237,237,238,238,239,240,240,241,241,242,242,243,243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,251,252,252,253,253,254,254,255, -}; - -/* a >= 2^(LIMB_BITS - 2). Return (s, r) with s=floor(sqrt(a)) and - r=a-s^2. 0 <= r <= 2 * s */ -static limb_t mp_sqrtrem1(limb_t *pr, limb_t a) -{ - limb_t s1, r1, s, r, q, u, num; - - /* use a table for the 16 -> 8 bit sqrt */ - s1 = sqrt_table[(a >> (LIMB_BITS - 8)) - 64]; - r1 = (a >> (LIMB_BITS - 16)) - s1 * s1; - if (r1 > 2 * s1) { - r1 -= 2 * s1 + 1; - s1++; - } - - /* one iteration to get a 32 -> 16 bit sqrt */ - num = (r1 << 8) | ((a >> (LIMB_BITS - 32 + 8)) & 0xff); - q = num / (2 * s1); /* q <= 2^8 */ - u = num % (2 * s1); - s = (s1 << 8) + q; - r = (u << 8) | ((a >> (LIMB_BITS - 32)) & 0xff); - r -= q * q; - if ((slimb_t)r < 0) { - s--; - r += 2 * s + 1; - } - -#if LIMB_BITS == 64 - s1 = s; - r1 = r; - /* one more iteration for 64 -> 32 bit sqrt */ - num = (r1 << 16) | ((a >> (LIMB_BITS - 64 + 16)) & 0xffff); - q = num / (2 * s1); /* q <= 2^16 */ - u = num % (2 * s1); - s = (s1 << 16) + q; - r = (u << 16) | ((a >> (LIMB_BITS - 64)) & 0xffff); - r -= q * q; - if ((slimb_t)r < 0) { - s--; - r += 2 * s + 1; - } -#endif - *pr = r; - return s; -} - -/* return floor(sqrt(a)) */ -limb_t bf_isqrt(limb_t a) -{ - limb_t s, r; - int k; - - if (a == 0) - return 0; - k = clz(a) & ~1; - s = mp_sqrtrem1(&r, a << k); - s >>= (k >> 1); - return s; -} - -static limb_t mp_sqrtrem2(limb_t *tabs, limb_t *taba) -{ - limb_t s1, r1, s, q, u, a0, a1; - dlimb_t r, num; - int l; - - a0 = taba[0]; - a1 = taba[1]; - s1 = mp_sqrtrem1(&r1, a1); - l = LIMB_BITS / 2; - num = ((dlimb_t)r1 << l) | (a0 >> l); - q = num / (2 * s1); - u = num % (2 * s1); - s = (s1 << l) + q; - r = ((dlimb_t)u << l) | (a0 & (((limb_t)1 << l) - 1)); - if (UNLIKELY((q >> l) != 0)) - r -= (dlimb_t)1 << LIMB_BITS; /* special case when q=2^l */ - else - r -= q * q; - if ((slimb_t)(r >> LIMB_BITS) < 0) { - s--; - r += 2 * (dlimb_t)s + 1; - } - tabs[0] = s; - taba[0] = r; - return r >> LIMB_BITS; -} - -//#define DEBUG_SQRTREM - -/* tmp_buf must contain (n / 2 + 1 limbs). *prh contains the highest - limb of the remainder. */ -static int mp_sqrtrem_rec(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n, - limb_t *tmp_buf, limb_t *prh) -{ - limb_t l, h, rh, ql, qh, c, i; - - if (n == 1) { - *prh = mp_sqrtrem2(tabs, taba); - return 0; - } -#ifdef DEBUG_SQRTREM - mp_print_str("a", taba, 2 * n); -#endif - l = n / 2; - h = n - l; - if (mp_sqrtrem_rec(s, tabs + l, taba + 2 * l, h, tmp_buf, &qh)) - return -1; -#ifdef DEBUG_SQRTREM - mp_print_str("s1", tabs + l, h); - mp_print_str_h("r1", taba + 2 * l, h, qh); - mp_print_str_h("r2", taba + l, n, qh); -#endif - - /* the remainder is in taba + 2 * l. Its high bit is in qh */ - if (qh) { - mp_sub(taba + 2 * l, taba + 2 * l, tabs + l, h, 0); - } - /* instead of dividing by 2*s, divide by s (which is normalized) - and update q and r */ - if (mp_divnorm(s, tmp_buf, taba + l, n, tabs + l, h)) - return -1; - qh += tmp_buf[l]; - for(i = 0; i < l; i++) - tabs[i] = tmp_buf[i]; - ql = mp_shr(tabs, tabs, l, 1, qh & 1); - qh = qh >> 1; /* 0 or 1 */ - if (ql) - rh = mp_add(taba + l, taba + l, tabs + l, h, 0); - else - rh = 0; -#ifdef DEBUG_SQRTREM - mp_print_str_h("q", tabs, l, qh); - mp_print_str_h("u", taba + l, h, rh); -#endif - - mp_add_ui(tabs + l, qh, h); -#ifdef DEBUG_SQRTREM - mp_print_str_h("s2", tabs, n, sh); -#endif - - /* q = qh, tabs[l - 1 ... 0], r = taba[n - 1 ... l] */ - /* subtract q^2. if qh = 1 then q = B^l, so we can take shortcuts */ - if (qh) { - c = qh; - } else { - if (mp_mul(s, taba + n, tabs, l, tabs, l)) - return -1; - c = mp_sub(taba, taba, taba + n, 2 * l, 0); - } - rh -= mp_sub_ui(taba + 2 * l, c, n - 2 * l); - if ((slimb_t)rh < 0) { - mp_sub_ui(tabs, 1, n); - rh += mp_add_mul1(taba, tabs, n, 2); - rh += mp_add_ui(taba, 1, n); - } - *prh = rh; - return 0; -} - -/* 'taba' has 2*n limbs with n >= 1 and taba[2*n-1] >= 2 ^ (LIMB_BITS - - 2). Return (s, r) with s=floor(sqrt(a)) and r=a-s^2. 0 <= r <= 2 - * s. tabs has n limbs. r is returned in the lower n limbs of - taba. Its r[n] is the returned value of the function. */ -/* Algorithm from the article "Karatsuba Square Root" by Paul Zimmermann and - inspirated from its GMP implementation */ -int mp_sqrtrem(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n) -{ - limb_t tmp_buf1[8]; - limb_t *tmp_buf; - mp_size_t n2; - int ret; - n2 = n / 2 + 1; - if (n2 <= countof(tmp_buf1)) { - tmp_buf = tmp_buf1; - } else { - tmp_buf = bf_malloc(s, sizeof(limb_t) * n2); - if (!tmp_buf) - return -1; - } - ret = mp_sqrtrem_rec(s, tabs, taba, n, tmp_buf, taba + n); - if (tmp_buf != tmp_buf1) - bf_free(s, tmp_buf); - return ret; -} - -/* Integer square root with remainder. 'a' must be an integer. r = - floor(sqrt(a)) and rem = a - r^2. BF_ST_INEXACT is set if the result - is inexact. 'rem' can be NULL if the remainder is not needed. */ -int bf_sqrtrem(bf_t *r, bf_t *rem1, const bf_t *a) -{ - int ret; - - if (a->len == 0) { - if (a->expn == BF_EXP_NAN) { - bf_set_nan(r); - } else if (a->expn == BF_EXP_INF && a->sign) { - goto invalid_op; - } else { - bf_set(r, a); - } - if (rem1) - bf_set_ui(rem1, 0); - ret = 0; - } else if (a->sign) { - invalid_op: - bf_set_nan(r); - if (rem1) - bf_set_ui(rem1, 0); - ret = BF_ST_INVALID_OP; - } else { - bf_t rem_s, *rem; - - bf_sqrt(r, a, (a->expn + 1) / 2, BF_RNDZ); - bf_rint(r, BF_RNDZ); - /* see if the result is exact by computing the remainder */ - if (rem1) { - rem = rem1; - } else { - rem = &rem_s; - bf_init(r->ctx, rem); - } - /* XXX: could avoid recomputing the remainder */ - bf_mul(rem, r, r, BF_PREC_INF, BF_RNDZ); - bf_neg(rem); - bf_add(rem, rem, a, BF_PREC_INF, BF_RNDZ); - if (bf_is_nan(rem)) { - ret = BF_ST_MEM_ERROR; - goto done; - } - if (rem->len != 0) { - ret = BF_ST_INEXACT; - } else { - ret = 0; - } - done: - if (!rem1) - bf_delete(rem); - } - return ret; -} - -int bf_sqrt(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) -{ - bf_context_t *s = a->ctx; - int ret; - - assert(r != a); - - if (a->len == 0) { - if (a->expn == BF_EXP_NAN) { - bf_set_nan(r); - } else if (a->expn == BF_EXP_INF && a->sign) { - goto invalid_op; - } else { - bf_set(r, a); - } - ret = 0; - } else if (a->sign) { - invalid_op: - bf_set_nan(r); - ret = BF_ST_INVALID_OP; - } else { - limb_t *a1; - slimb_t n, n1; - limb_t res; - - /* convert the mantissa to an integer with at least 2 * - prec + 4 bits */ - n = (2 * (prec + 2) + 2 * LIMB_BITS - 1) / (2 * LIMB_BITS); - if (bf_resize(r, n)) - goto fail; - a1 = bf_malloc(s, sizeof(limb_t) * 2 * n); - if (!a1) - goto fail; - n1 = bf_min(2 * n, a->len); - bzero(a1, (2 * n - n1) * sizeof(limb_t)); - memcpy(a1 + 2 * n - n1, a->tab + a->len - n1, n1 * sizeof(limb_t)); - if (a->expn & 1) { - res = mp_shr(a1, a1, 2 * n, 1, 0); - } else { - res = 0; - } - if (mp_sqrtrem(s, r->tab, a1, n)) { - bf_free(s, a1); - goto fail; - } - if (!res) { - res = mp_scan_nz(a1, n + 1); - } - bf_free(s, a1); - if (!res) { - res = mp_scan_nz(a->tab, a->len - n1); - } - if (res != 0) - r->tab[0] |= 1; - r->sign = 0; - r->expn = (a->expn + 1) >> 1; - ret = bf_round(r, prec, flags); - } - return ret; - fail: - bf_set_nan(r); - return BF_ST_MEM_ERROR; -} - -static dontinline int bf_op2(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, - bf_flags_t flags, bf_op2_func_t *func) -{ - bf_t tmp; - int ret; - - if (r == a || r == b) { - bf_init(r->ctx, &tmp); - ret = func(&tmp, a, b, prec, flags); - bf_move(r, &tmp); - } else { - ret = func(r, a, b, prec, flags); - } - return ret; -} - -int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, - bf_flags_t flags) -{ - return bf_op2(r, a, b, prec, flags, __bf_add); -} - -int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, - bf_flags_t flags) -{ - return bf_op2(r, a, b, prec, flags, __bf_sub); -} - -int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, - bf_flags_t flags) -{ - return bf_op2(r, a, b, prec, flags, __bf_div); -} - -int bf_mul_ui(bf_t *r, const bf_t *a, uint64_t b1, limb_t prec, - bf_flags_t flags) -{ - bf_t b; - int ret; - bf_init(r->ctx, &b); - ret = bf_set_ui(&b, b1); - ret |= bf_mul(r, a, &b, prec, flags); - bf_delete(&b); - return ret; -} - -int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, - bf_flags_t flags) -{ - bf_t b; - int ret; - bf_init(r->ctx, &b); - ret = bf_set_si(&b, b1); - ret |= bf_mul(r, a, &b, prec, flags); - bf_delete(&b); - return ret; -} - -int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, - bf_flags_t flags) -{ - bf_t b; - int ret; - - bf_init(r->ctx, &b); - ret = bf_set_si(&b, b1); - ret |= bf_add(r, a, &b, prec, flags); - bf_delete(&b); - return ret; -} - -static int bf_pow_ui(bf_t *r, const bf_t *a, limb_t b, limb_t prec, - bf_flags_t flags) -{ - int ret, n_bits, i; - - assert(r != a); - if (b == 0) - return bf_set_ui(r, 1); - ret = bf_set(r, a); - n_bits = LIMB_BITS - clz(b); - for(i = n_bits - 2; i >= 0; i--) { - ret |= bf_mul(r, r, r, prec, flags); - if ((b >> i) & 1) - ret |= bf_mul(r, r, a, prec, flags); - } - return ret; -} - -static int bf_pow_ui_ui(bf_t *r, limb_t a1, limb_t b, - limb_t prec, bf_flags_t flags) -{ - bf_t a; - int ret; - - if (a1 == 10 && b <= LIMB_DIGITS) { - /* use precomputed powers. We do not round at this point - because we expect the caller to do it */ - ret = bf_set_ui(r, mp_pow_dec[b]); - } else { - bf_init(r->ctx, &a); - ret = bf_set_ui(&a, a1); - ret |= bf_pow_ui(r, &a, b, prec, flags); - bf_delete(&a); - } - return ret; -} - -/* convert to integer (infinite precision) */ -int bf_rint(bf_t *r, int rnd_mode) -{ - return bf_round(r, 0, rnd_mode | BF_FLAG_RADPNT_PREC); -} - -/* logical operations */ -#define BF_LOGIC_OR 0 -#define BF_LOGIC_XOR 1 -#define BF_LOGIC_AND 2 - -static inline limb_t bf_logic_op1(limb_t a, limb_t b, int op) -{ - switch(op) { - case BF_LOGIC_OR: - return a | b; - case BF_LOGIC_XOR: - return a ^ b; - default: - case BF_LOGIC_AND: - return a & b; - } -} - -static int bf_logic_op(bf_t *r, const bf_t *a1, const bf_t *b1, int op) -{ - bf_t b1_s, a1_s, *a, *b; - limb_t a_sign, b_sign, r_sign; - slimb_t l, i, a_bit_offset, b_bit_offset; - limb_t v1, v2, v1_mask, v2_mask, r_mask; - int ret; - - assert(r != a1 && r != b1); - - if (a1->expn <= 0) - a_sign = 0; /* minus zero is considered as positive */ - else - a_sign = a1->sign; - - if (b1->expn <= 0) - b_sign = 0; /* minus zero is considered as positive */ - else - b_sign = b1->sign; - - if (a_sign) { - a = &a1_s; - bf_init(r->ctx, a); - if (bf_add_si(a, a1, 1, BF_PREC_INF, BF_RNDZ)) { - b = NULL; - goto fail; - } - } else { - a = (bf_t *)a1; - } - - if (b_sign) { - b = &b1_s; - bf_init(r->ctx, b); - if (bf_add_si(b, b1, 1, BF_PREC_INF, BF_RNDZ)) - goto fail; - } else { - b = (bf_t *)b1; - } - - r_sign = bf_logic_op1(a_sign, b_sign, op); - if (op == BF_LOGIC_AND && r_sign == 0) { - /* no need to compute extra zeros for and */ - if (a_sign == 0 && b_sign == 0) - l = bf_min(a->expn, b->expn); - else if (a_sign == 0) - l = a->expn; - else - l = b->expn; - } else { - l = bf_max(a->expn, b->expn); - } - /* Note: a or b can be zero */ - l = (bf_max(l, 1) + LIMB_BITS - 1) / LIMB_BITS; - if (bf_resize(r, l)) - goto fail; - a_bit_offset = a->len * LIMB_BITS - a->expn; - b_bit_offset = b->len * LIMB_BITS - b->expn; - v1_mask = -a_sign; - v2_mask = -b_sign; - r_mask = -r_sign; - for(i = 0; i < l; i++) { - v1 = get_bits(a->tab, a->len, a_bit_offset + i * LIMB_BITS) ^ v1_mask; - v2 = get_bits(b->tab, b->len, b_bit_offset + i * LIMB_BITS) ^ v2_mask; - r->tab[i] = bf_logic_op1(v1, v2, op) ^ r_mask; - } - r->expn = l * LIMB_BITS; - r->sign = r_sign; - bf_normalize_and_round(r, BF_PREC_INF, BF_RNDZ); /* cannot fail */ - if (r_sign) { - if (bf_add_si(r, r, -1, BF_PREC_INF, BF_RNDZ)) - goto fail; - } - ret = 0; - done: - if (a == &a1_s) - bf_delete(a); - if (b == &b1_s) - bf_delete(b); - return ret; - fail: - bf_set_nan(r); - ret = BF_ST_MEM_ERROR; - goto done; -} - -/* 'a' and 'b' must be integers. Return 0 or BF_ST_MEM_ERROR. */ -int bf_logic_or(bf_t *r, const bf_t *a, const bf_t *b) -{ - return bf_logic_op(r, a, b, BF_LOGIC_OR); -} - -/* 'a' and 'b' must be integers. Return 0 or BF_ST_MEM_ERROR. */ -int bf_logic_xor(bf_t *r, const bf_t *a, const bf_t *b) -{ - return bf_logic_op(r, a, b, BF_LOGIC_XOR); -} - -/* 'a' and 'b' must be integers. Return 0 or BF_ST_MEM_ERROR. */ -int bf_logic_and(bf_t *r, const bf_t *a, const bf_t *b) -{ - return bf_logic_op(r, a, b, BF_LOGIC_AND); -} - -/* conversion between fixed size types */ - -typedef union { - double d; - uint64_t u; -} Float64Union; - -int bf_get_float64(const bf_t *a, double *pres, bf_rnd_t rnd_mode) -{ - Float64Union u; - int e, ret; - uint64_t m; - - ret = 0; - if (a->expn == BF_EXP_NAN) { - u.u = 0x7ff8000000000000; /* quiet nan */ - } else { - bf_t b_s, *b = &b_s; - - bf_init(a->ctx, b); - bf_set(b, a); - if (bf_is_finite(b)) { - ret = bf_round(b, 53, rnd_mode | BF_FLAG_SUBNORMAL | bf_set_exp_bits(11)); - } - if (b->expn == BF_EXP_INF) { - e = (1 << 11) - 1; - m = 0; - } else if (b->expn == BF_EXP_ZERO) { - e = 0; - m = 0; - } else { - e = b->expn + 1023 - 1; -#if LIMB_BITS == 32 - if (b->len == 2) { - m = ((uint64_t)b->tab[1] << 32) | b->tab[0]; - } else { - m = ((uint64_t)b->tab[0] << 32); - } -#else - m = b->tab[0]; -#endif - if (e <= 0) { - /* subnormal */ - m = m >> (12 - e); - e = 0; - } else { - m = (m << 1) >> 12; - } - } - u.u = m | ((uint64_t)e << 52) | ((uint64_t)b->sign << 63); - bf_delete(b); - } - *pres = u.d; - return ret; -} - -int bf_set_float64(bf_t *a, double d) -{ - Float64Union u; - uint64_t m; - int shift, e, sgn; - - u.d = d; - sgn = u.u >> 63; - e = (u.u >> 52) & ((1 << 11) - 1); - m = u.u & (((uint64_t)1 << 52) - 1); - if (e == ((1 << 11) - 1)) { - if (m != 0) { - bf_set_nan(a); - } else { - bf_set_inf(a, sgn); - } - } else if (e == 0) { - if (m == 0) { - bf_set_zero(a, sgn); - } else { - /* subnormal number */ - m <<= 12; - shift = clz64(m); - m <<= shift; - e = -shift; - goto norm; - } - } else { - m = (m << 11) | ((uint64_t)1 << 63); - norm: - a->expn = e - 1023 + 1; -#if LIMB_BITS == 32 - if (bf_resize(a, 2)) - goto fail; - a->tab[0] = m; - a->tab[1] = m >> 32; -#else - if (bf_resize(a, 1)) - goto fail; - a->tab[0] = m; -#endif - a->sign = sgn; - } - return 0; -fail: - bf_set_nan(a); - return BF_ST_MEM_ERROR; -} - -/* The rounding mode is always BF_RNDZ. Return BF_ST_INVALID_OP if there - is an overflow and 0 otherwise. */ -int bf_get_int32(int *pres, const bf_t *a, int flags) -{ - uint32_t v; - int ret; - if (a->expn >= BF_EXP_INF) { - ret = BF_ST_INVALID_OP; - if (flags & BF_GET_INT_MOD) { - v = 0; - } else if (a->expn == BF_EXP_INF) { - v = (uint32_t)INT32_MAX + a->sign; - } else { - v = INT32_MAX; - } - } else if (a->expn <= 0) { - v = 0; - ret = 0; - } else if (a->expn <= 31) { - v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn); - if (a->sign) - v = -v; - ret = 0; - } else if (!(flags & BF_GET_INT_MOD)) { - ret = BF_ST_INVALID_OP; - if (a->sign) { - v = (uint32_t)INT32_MAX + 1; - if (a->expn == 32 && - (a->tab[a->len - 1] >> (LIMB_BITS - 32)) == v) { - ret = 0; - } - } else { - v = INT32_MAX; - } - } else { - v = get_bits(a->tab, a->len, a->len * LIMB_BITS - a->expn); - if (a->sign) - v = -v; - ret = 0; - } - *pres = v; - return ret; -} - -/* The rounding mode is always BF_RNDZ. Return BF_ST_INVALID_OP if there - is an overflow and 0 otherwise. */ -int bf_get_int64(int64_t *pres, const bf_t *a, int flags) -{ - uint64_t v; - int ret; - if (a->expn >= BF_EXP_INF) { - ret = BF_ST_INVALID_OP; - if (flags & BF_GET_INT_MOD) { - v = 0; - } else if (a->expn == BF_EXP_INF) { - v = (uint64_t)INT64_MAX + a->sign; - } else { - v = INT64_MAX; - } - } else if (a->expn <= 0) { - v = 0; - ret = 0; - } else if (a->expn <= 63) { -#if LIMB_BITS == 32 - if (a->expn <= 32) - v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn); - else - v = (((uint64_t)a->tab[a->len - 1] << 32) | - get_limbz(a, a->len - 2)) >> (64 - a->expn); -#else - v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn); -#endif - if (a->sign) - v = -v; - ret = 0; - } else if (!(flags & BF_GET_INT_MOD)) { - ret = BF_ST_INVALID_OP; - if (a->sign) { - uint64_t v1; - v = (uint64_t)INT64_MAX + 1; - if (a->expn == 64) { - v1 = a->tab[a->len - 1]; -#if LIMB_BITS == 32 - v1 = (v1 << 32) | get_limbz(a, a->len - 2); -#endif - if (v1 == v) - ret = 0; - } - } else { - v = INT64_MAX; - } - } else { - slimb_t bit_pos = a->len * LIMB_BITS - a->expn; - v = get_bits(a->tab, a->len, bit_pos); -#if LIMB_BITS == 32 - v |= (uint64_t)get_bits(a->tab, a->len, bit_pos + 32) << 32; -#endif - if (a->sign) - v = -v; - ret = 0; - } - *pres = v; - return ret; -} - -/* The rounding mode is always BF_RNDZ. Return BF_ST_INVALID_OP if there - is an overflow and 0 otherwise. */ -int bf_get_uint64(uint64_t *pres, const bf_t *a) -{ - uint64_t v; - int ret; - if (a->expn == BF_EXP_NAN) { - goto overflow; - } else if (a->expn <= 0) { - v = 0; - ret = 0; - } else if (a->sign) { - v = 0; - ret = BF_ST_INVALID_OP; - } else if (a->expn <= 64) { -#if LIMB_BITS == 32 - if (a->expn <= 32) - v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn); - else - v = (((uint64_t)a->tab[a->len - 1] << 32) | - get_limbz(a, a->len - 2)) >> (64 - a->expn); -#else - v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn); -#endif - ret = 0; - } else { - overflow: - v = UINT64_MAX; - ret = BF_ST_INVALID_OP; - } - *pres = v; - return ret; -} - -/* base conversion from radix */ - -static const uint8_t digits_per_limb_table[BF_RADIX_MAX - 1] = { -#if LIMB_BITS == 32 -32,20,16,13,12,11,10,10, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -#else -64,40,32,27,24,22,21,20,19,18,17,17,16,16,16,15,15,15,14,14,14,14,13,13,13,13,13,13,13,12,12,12,12,12,12, -#endif -}; - -static limb_t get_limb_radix(int radix) -{ - int i, k; - limb_t radixl; - - k = digits_per_limb_table[radix - 2]; - radixl = radix; - for(i = 1; i < k; i++) - radixl *= radix; - return radixl; -} - -/* return != 0 if error */ -static int bf_integer_from_radix_rec(bf_t *r, const limb_t *tab, - limb_t n, int level, limb_t n0, - limb_t radix, bf_t *pow_tab) -{ - int ret; - if (n == 1) { - ret = bf_set_ui(r, tab[0]); - } else { - bf_t T_s, *T = &T_s, *B; - limb_t n1, n2; - - n2 = (((n0 * 2) >> (level + 1)) + 1) / 2; - n1 = n - n2; - // printf("level=%d n0=%ld n1=%ld n2=%ld\n", level, n0, n1, n2); - B = &pow_tab[level]; - if (B->len == 0) { - ret = bf_pow_ui_ui(B, radix, n2, BF_PREC_INF, BF_RNDZ); - if (ret) - return ret; - } - ret = bf_integer_from_radix_rec(r, tab + n2, n1, level + 1, n0, - radix, pow_tab); - if (ret) - return ret; - ret = bf_mul(r, r, B, BF_PREC_INF, BF_RNDZ); - if (ret) - return ret; - bf_init(r->ctx, T); - ret = bf_integer_from_radix_rec(T, tab, n2, level + 1, n0, - radix, pow_tab); - if (!ret) - ret = bf_add(r, r, T, BF_PREC_INF, BF_RNDZ); - bf_delete(T); - } - return ret; - // bf_print_str(" r=", r); -} - -/* return 0 if OK != 0 if memory error */ -static int bf_integer_from_radix(bf_t *r, const limb_t *tab, - limb_t n, limb_t radix) -{ - bf_context_t *s = r->ctx; - int pow_tab_len, i, ret; - limb_t radixl; - bf_t *pow_tab; - - radixl = get_limb_radix(radix); - pow_tab_len = ceil_log2(n) + 2; /* XXX: check */ - pow_tab = bf_malloc(s, sizeof(pow_tab[0]) * pow_tab_len); - if (!pow_tab) - return -1; - for(i = 0; i < pow_tab_len; i++) - bf_init(r->ctx, &pow_tab[i]); - ret = bf_integer_from_radix_rec(r, tab, n, 0, n, radixl, pow_tab); - for(i = 0; i < pow_tab_len; i++) { - bf_delete(&pow_tab[i]); - } - bf_free(s, pow_tab); - return ret; -} - -/* compute and round T * radix^expn. */ -int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix, - slimb_t expn, limb_t prec, bf_flags_t flags) -{ - int ret, expn_sign, overflow; - slimb_t e, extra_bits, prec1, ziv_extra_bits; - bf_t B_s, *B = &B_s; - - if (T->len == 0) { - return bf_set(r, T); - } else if (expn == 0) { - ret = bf_set(r, T); - ret |= bf_round(r, prec, flags); - return ret; - } - - e = expn; - expn_sign = 0; - if (e < 0) { - e = -e; - expn_sign = 1; - } - bf_init(r->ctx, B); - if (prec == BF_PREC_INF) { - /* infinite precision: only used if the result is known to be exact */ - ret = bf_pow_ui_ui(B, radix, e, BF_PREC_INF, BF_RNDN); - if (expn_sign) { - ret |= bf_div(r, T, B, T->len * LIMB_BITS, BF_RNDN); - } else { - ret |= bf_mul(r, T, B, BF_PREC_INF, BF_RNDN); - } - } else { - ziv_extra_bits = 16; - for(;;) { - prec1 = prec + ziv_extra_bits; - /* XXX: correct overflow/underflow handling */ - /* XXX: rigorous error analysis needed */ - extra_bits = ceil_log2(e) * 2 + 1; - ret = bf_pow_ui_ui(B, radix, e, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP); - overflow = !bf_is_finite(B); - /* XXX: if bf_pow_ui_ui returns an exact result, can stop - after the next operation */ - if (expn_sign) - ret |= bf_div(r, T, B, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP); - else - ret |= bf_mul(r, T, B, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP); - if (ret & BF_ST_MEM_ERROR) - break; - if ((ret & BF_ST_INEXACT) && - !bf_can_round(r, prec, flags & BF_RND_MASK, prec1) && - !overflow) { - /* and more precision and retry */ - ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2); - } else { - /* XXX: need to use __bf_round() to pass the inexact - flag for the subnormal case */ - ret = bf_round(r, prec, flags) | (ret & BF_ST_INEXACT); - break; - } - } - } - bf_delete(B); - return ret; -} - -/* add a limb at 'pos' and decrement pos. new space is created if - needed. Return 0 if OK, -1 if memory error */ -static int bf_add_limb(bf_t *a, slimb_t *ppos, limb_t v) -{ - slimb_t pos; - pos = *ppos; - if (UNLIKELY(pos < 0)) { - limb_t new_size, d, *new_tab; - new_size = bf_max(a->len + 1, a->len * 3 / 2); - new_tab = bf_realloc(a->ctx, a->tab, sizeof(limb_t) * new_size); - if (!new_tab) - return -1; - a->tab = new_tab; - d = new_size - a->len; - memmove(a->tab + d, a->tab, a->len * sizeof(limb_t)); - a->len = new_size; - pos += d; - } - a->tab[pos--] = v; - *ppos = pos; - return 0; -} - -static int bf_tolower(int c) -{ - if (c >= 'A' && c <= 'Z') - c = c - 'A' + 'a'; - return c; -} - -static int strcasestart(const char *str, const char *val, const char **ptr) -{ - const char *p, *q; - p = str; - q = val; - while (*q != '\0') { - if (bf_tolower(*p) != *q) - return 0; - p++; - q++; - } - if (ptr) - *ptr = p; - return 1; -} - -static int bf_atof_internal(bf_t *r, slimb_t *pexponent, - const char *str, const char **pnext, int radix, - limb_t prec, bf_flags_t flags, BOOL is_dec) -{ - const char *p, *p_start; - int is_neg, radix_bits, exp_is_neg, ret, digits_per_limb, shift; - limb_t cur_limb; - slimb_t pos, expn, int_len, digit_count; - BOOL has_decpt, is_bin_exp; - bf_t a_s, *a; - - *pexponent = 0; - p = str; - if (!(flags & BF_ATOF_NO_NAN_INF) && radix <= 16 && - strcasestart(p, "nan", &p)) { - bf_set_nan(r); - ret = 0; - goto done; - } - is_neg = 0; - - if (p[0] == '+') { - p++; - p_start = p; - } else if (p[0] == '-') { - is_neg = 1; - p++; - p_start = p; - } else { - p_start = p; - } - if (p[0] == '0') { - if ((p[1] == 'x' || p[1] == 'X') && - (radix == 0 || radix == 16) && - !(flags & BF_ATOF_NO_HEX)) { - radix = 16; - p += 2; - } else if ((p[1] == 'o' || p[1] == 'O') && - radix == 0 && (flags & BF_ATOF_BIN_OCT)) { - p += 2; - radix = 8; - } else if ((p[1] == 'b' || p[1] == 'B') && - radix == 0 && (flags & BF_ATOF_BIN_OCT)) { - p += 2; - radix = 2; - } else { - goto no_prefix; - } - /* there must be a digit after the prefix */ - if (to_digit((uint8_t)*p) >= radix) { - bf_set_nan(r); - ret = 0; - goto done; - } - no_prefix: ; - } else { - if (!(flags & BF_ATOF_NO_NAN_INF) && radix <= 16 && - strcasestart(p, "inf", &p)) { - bf_set_inf(r, is_neg); - ret = 0; - goto done; - } - } - - if (radix == 0) - radix = 10; - if (is_dec) { - assert(radix == 10); - radix_bits = 0; - a = r; - } else if ((radix & (radix - 1)) != 0) { - radix_bits = 0; /* base is not a power of two */ - a = &a_s; - bf_init(r->ctx, a); - } else { - radix_bits = ceil_log2(radix); - a = r; - } - - /* skip leading zeros */ - /* XXX: could also skip zeros after the decimal point */ - while (*p == '0') - p++; - - if (radix_bits) { - shift = digits_per_limb = LIMB_BITS; - } else { - radix_bits = 0; - shift = digits_per_limb = digits_per_limb_table[radix - 2]; - } - cur_limb = 0; - bf_resize(a, 1); - pos = 0; - has_decpt = FALSE; - int_len = digit_count = 0; - for(;;) { - limb_t c; - if (*p == '.' && (p > p_start || to_digit(p[1]) < radix)) { - if (has_decpt) - break; - has_decpt = TRUE; - int_len = digit_count; - p++; - } - c = to_digit(*p); - if (c >= radix) - break; - digit_count++; - p++; - if (radix_bits) { - shift -= radix_bits; - if (shift <= 0) { - cur_limb |= c >> (-shift); - if (bf_add_limb(a, &pos, cur_limb)) - goto mem_error; - if (shift < 0) - cur_limb = c << (LIMB_BITS + shift); - else - cur_limb = 0; - shift += LIMB_BITS; - } else { - cur_limb |= c << shift; - } - } else { - cur_limb = cur_limb * radix + c; - shift--; - if (shift == 0) { - if (bf_add_limb(a, &pos, cur_limb)) - goto mem_error; - shift = digits_per_limb; - cur_limb = 0; - } - } - } - if (!has_decpt) - int_len = digit_count; - - /* add the last limb and pad with zeros */ - if (shift != digits_per_limb) { - if (radix_bits == 0) { - while (shift != 0) { - cur_limb *= radix; - shift--; - } - } - if (bf_add_limb(a, &pos, cur_limb)) { - mem_error: - ret = BF_ST_MEM_ERROR; - if (!radix_bits) - bf_delete(a); - bf_set_nan(r); - goto done; - } - } - - /* reset the next limbs to zero (we prefer to reallocate in the - renormalization) */ - bzero(a->tab, (pos + 1) * sizeof(limb_t)); - - if (p == p_start) { - ret = 0; - if (!radix_bits) - bf_delete(a); - bf_set_nan(r); - goto done; - } - - /* parse the exponent, if any */ - expn = 0; - is_bin_exp = FALSE; - if (((radix == 10 && (*p == 'e' || *p == 'E')) || - (radix != 10 && (*p == '@' || - (radix_bits && (*p == 'p' || *p == 'P'))))) && - p > p_start) { - is_bin_exp = (*p == 'p' || *p == 'P'); - p++; - exp_is_neg = 0; - if (*p == '+') { - p++; - } else if (*p == '-') { - exp_is_neg = 1; - p++; - } - for(;;) { - int c; - c = to_digit(*p); - if (c >= 10) - break; - if (UNLIKELY(expn > ((BF_RAW_EXP_MAX - 2 - 9) / 10))) { - /* exponent overflow */ - if (exp_is_neg) { - bf_set_zero(r, is_neg); - ret = BF_ST_UNDERFLOW | BF_ST_INEXACT; - } else { - bf_set_inf(r, is_neg); - ret = BF_ST_OVERFLOW | BF_ST_INEXACT; - } - goto done; - } - p++; - expn = expn * 10 + c; - } - if (exp_is_neg) - expn = -expn; - } - if (is_dec) { - a->expn = expn + int_len; - a->sign = is_neg; - ret = bfdec_normalize_and_round((bfdec_t *)a, prec, flags); - } else if (radix_bits) { - /* XXX: may overflow */ - if (!is_bin_exp) - expn *= radix_bits; - a->expn = expn + (int_len * radix_bits); - a->sign = is_neg; - ret = bf_normalize_and_round(a, prec, flags); - } else { - limb_t l; - pos++; - l = a->len - pos; /* number of limbs */ - if (l == 0) { - bf_set_zero(r, is_neg); - ret = 0; - } else { - bf_t T_s, *T = &T_s; - - expn -= l * digits_per_limb - int_len; - bf_init(r->ctx, T); - if (bf_integer_from_radix(T, a->tab + pos, l, radix)) { - bf_set_nan(r); - ret = BF_ST_MEM_ERROR; - } else { - T->sign = is_neg; - if (flags & BF_ATOF_EXPONENT) { - /* return the exponent */ - *pexponent = expn; - ret = bf_set(r, T); - } else { - ret = bf_mul_pow_radix(r, T, radix, expn, prec, flags); - } - } - bf_delete(T); - } - bf_delete(a); - } - done: - if (pnext) - *pnext = p; - return ret; -} - -/* - Return (status, n, exp). 'status' is the floating point status. 'n' - is the parsed number. - - If (flags & BF_ATOF_EXPONENT) and if the radix is not a power of - two, the parsed number is equal to r * - (*pexponent)^radix. Otherwise *pexponent = 0. -*/ -int bf_atof2(bf_t *r, slimb_t *pexponent, - const char *str, const char **pnext, int radix, - limb_t prec, bf_flags_t flags) -{ - return bf_atof_internal(r, pexponent, str, pnext, radix, prec, flags, - FALSE); -} - -int bf_atof(bf_t *r, const char *str, const char **pnext, int radix, - limb_t prec, bf_flags_t flags) -{ - slimb_t dummy_exp; - return bf_atof_internal(r, &dummy_exp, str, pnext, radix, prec, flags, FALSE); -} - -/* base conversion to radix */ - -#if LIMB_BITS == 64 -#define RADIXL_10 UINT64_C(10000000000000000000) -#else -#define RADIXL_10 UINT64_C(1000000000) -#endif - -static const uint32_t inv_log2_radix[BF_RADIX_MAX - 1][LIMB_BITS / 32 + 1] = { -#if LIMB_BITS == 32 -{ 0x80000000, 0x00000000,}, -{ 0x50c24e60, 0xd4d4f4a7,}, -{ 0x40000000, 0x00000000,}, -{ 0x372068d2, 0x0a1ee5ca,}, -{ 0x3184648d, 0xb8153e7a,}, -{ 0x2d983275, 0x9d5369c4,}, -{ 0x2aaaaaaa, 0xaaaaaaab,}, -{ 0x28612730, 0x6a6a7a54,}, -{ 0x268826a1, 0x3ef3fde6,}, -{ 0x25001383, 0xbac8a744,}, -{ 0x23b46706, 0x82c0c709,}, -{ 0x229729f1, 0xb2c83ded,}, -{ 0x219e7ffd, 0xa5ad572b,}, -{ 0x20c33b88, 0xda7c29ab,}, -{ 0x20000000, 0x00000000,}, -{ 0x1f50b57e, 0xac5884b3,}, -{ 0x1eb22cc6, 0x8aa6e26f,}, -{ 0x1e21e118, 0x0c5daab2,}, -{ 0x1d9dcd21, 0x439834e4,}, -{ 0x1d244c78, 0x367a0d65,}, -{ 0x1cb40589, 0xac173e0c,}, -{ 0x1c4bd95b, 0xa8d72b0d,}, -{ 0x1bead768, 0x98f8ce4c,}, -{ 0x1b903469, 0x050f72e5,}, -{ 0x1b3b433f, 0x2eb06f15,}, -{ 0x1aeb6f75, 0x9c46fc38,}, -{ 0x1aa038eb, 0x0e3bfd17,}, -{ 0x1a593062, 0xb38d8c56,}, -{ 0x1a15f4c3, 0x2b95a2e6,}, -{ 0x19d630dc, 0xcc7ddef9,}, -{ 0x19999999, 0x9999999a,}, -{ 0x195fec80, 0x8a609431,}, -{ 0x1928ee7b, 0x0b4f22f9,}, -{ 0x18f46acf, 0x8c06e318,}, -{ 0x18c23246, 0xdc0a9f3d,}, -#else -{ 0x80000000, 0x00000000, 0x00000000,}, -{ 0x50c24e60, 0xd4d4f4a7, 0x021f57bc,}, -{ 0x40000000, 0x00000000, 0x00000000,}, -{ 0x372068d2, 0x0a1ee5ca, 0x19ea911b,}, -{ 0x3184648d, 0xb8153e7a, 0x7fc2d2e1,}, -{ 0x2d983275, 0x9d5369c4, 0x4dec1661,}, -{ 0x2aaaaaaa, 0xaaaaaaaa, 0xaaaaaaab,}, -{ 0x28612730, 0x6a6a7a53, 0x810fabde,}, -{ 0x268826a1, 0x3ef3fde6, 0x23e2566b,}, -{ 0x25001383, 0xbac8a744, 0x385a3349,}, -{ 0x23b46706, 0x82c0c709, 0x3f891718,}, -{ 0x229729f1, 0xb2c83ded, 0x15fba800,}, -{ 0x219e7ffd, 0xa5ad572a, 0xe169744b,}, -{ 0x20c33b88, 0xda7c29aa, 0x9bddee52,}, -{ 0x20000000, 0x00000000, 0x00000000,}, -{ 0x1f50b57e, 0xac5884b3, 0x70e28eee,}, -{ 0x1eb22cc6, 0x8aa6e26f, 0x06d1a2a2,}, -{ 0x1e21e118, 0x0c5daab1, 0x81b4f4bf,}, -{ 0x1d9dcd21, 0x439834e3, 0x81667575,}, -{ 0x1d244c78, 0x367a0d64, 0xc8204d6d,}, -{ 0x1cb40589, 0xac173e0c, 0x3b7b16ba,}, -{ 0x1c4bd95b, 0xa8d72b0d, 0x5879f25a,}, -{ 0x1bead768, 0x98f8ce4c, 0x66cc2858,}, -{ 0x1b903469, 0x050f72e5, 0x0cf5488e,}, -{ 0x1b3b433f, 0x2eb06f14, 0x8c89719c,}, -{ 0x1aeb6f75, 0x9c46fc37, 0xab5fc7e9,}, -{ 0x1aa038eb, 0x0e3bfd17, 0x1bd62080,}, -{ 0x1a593062, 0xb38d8c56, 0x7998ab45,}, -{ 0x1a15f4c3, 0x2b95a2e6, 0x46aed6a0,}, -{ 0x19d630dc, 0xcc7ddef9, 0x5aadd61b,}, -{ 0x19999999, 0x99999999, 0x9999999a,}, -{ 0x195fec80, 0x8a609430, 0xe1106014,}, -{ 0x1928ee7b, 0x0b4f22f9, 0x5f69791d,}, -{ 0x18f46acf, 0x8c06e318, 0x4d2aeb2c,}, -{ 0x18c23246, 0xdc0a9f3d, 0x3fe16970,}, -#endif -}; - -static const limb_t log2_radix[BF_RADIX_MAX - 1] = { -#if LIMB_BITS == 32 -0x20000000, -0x32b80347, -0x40000000, -0x4a4d3c26, -0x52b80347, -0x59d5d9fd, -0x60000000, -0x6570068e, -0x6a4d3c26, -0x6eb3a9f0, -0x72b80347, -0x766a008e, -0x79d5d9fd, -0x7d053f6d, -0x80000000, -0x82cc7edf, -0x8570068e, -0x87ef05ae, -0x8a4d3c26, -0x8c8ddd45, -0x8eb3a9f0, -0x90c10501, -0x92b80347, -0x949a784c, -0x966a008e, -0x982809d6, -0x99d5d9fd, -0x9b74948f, -0x9d053f6d, -0x9e88c6b3, -0xa0000000, -0xa16bad37, -0xa2cc7edf, -0xa4231623, -0xa570068e, -#else -0x2000000000000000, -0x32b803473f7ad0f4, -0x4000000000000000, -0x4a4d3c25e68dc57f, -0x52b803473f7ad0f4, -0x59d5d9fd5010b366, -0x6000000000000000, -0x6570068e7ef5a1e8, -0x6a4d3c25e68dc57f, -0x6eb3a9f01975077f, -0x72b803473f7ad0f4, -0x766a008e4788cbcd, -0x79d5d9fd5010b366, -0x7d053f6d26089673, -0x8000000000000000, -0x82cc7edf592262d0, -0x8570068e7ef5a1e8, -0x87ef05ae409a0289, -0x8a4d3c25e68dc57f, -0x8c8ddd448f8b845a, -0x8eb3a9f01975077f, -0x90c10500d63aa659, -0x92b803473f7ad0f4, -0x949a784bcd1b8afe, -0x966a008e4788cbcd, -0x982809d5be7072dc, -0x99d5d9fd5010b366, -0x9b74948f5532da4b, -0x9d053f6d26089673, -0x9e88c6b3626a72aa, -0xa000000000000000, -0xa16bad3758efd873, -0xa2cc7edf592262d0, -0xa4231623369e78e6, -0xa570068e7ef5a1e8, -#endif -}; - -/* compute floor(a*b) or ceil(a*b) with b = log2(radix) or - b=1/log2(radix). For is_inv = 0, strict accuracy is not guaranteed - when radix is not a power of two. */ -slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv, - int is_ceil1) -{ - int is_neg; - limb_t a; - BOOL is_ceil; - - is_ceil = is_ceil1; - a = a1; - if (a1 < 0) { - a = -a; - is_neg = 1; - } else { - is_neg = 0; - } - is_ceil ^= is_neg; - if ((radix & (radix - 1)) == 0) { - int radix_bits; - /* radix is a power of two */ - radix_bits = ceil_log2(radix); - if (is_inv) { - if (is_ceil) - a += radix_bits - 1; - a = a / radix_bits; - } else { - a = a * radix_bits; - } - } else { - const uint32_t *tab; - limb_t b0, b1; - dlimb_t t; - - if (is_inv) { - tab = inv_log2_radix[radix - 2]; -#if LIMB_BITS == 32 - b1 = tab[0]; - b0 = tab[1]; -#else - b1 = ((limb_t)tab[0] << 32) | tab[1]; - b0 = (limb_t)tab[2] << 32; -#endif - t = (dlimb_t)b0 * (dlimb_t)a; - t = (dlimb_t)b1 * (dlimb_t)a + (t >> LIMB_BITS); - a = t >> (LIMB_BITS - 1); - } else { - b0 = log2_radix[radix - 2]; - t = (dlimb_t)b0 * (dlimb_t)a; - a = t >> (LIMB_BITS - 3); - } - /* a = floor(result) and 'result' cannot be an integer */ - a += is_ceil; - } - if (is_neg) - a = -a; - return a; -} - -/* 'n' is the number of output limbs */ -static int bf_integer_to_radix_rec(bf_t *pow_tab, - limb_t *out, const bf_t *a, limb_t n, - int level, limb_t n0, limb_t radixl, - unsigned int radixl_bits) -{ - limb_t n1, n2, q_prec; - int ret; - - assert(n >= 1); - if (n == 1) { - out[0] = get_bits(a->tab, a->len, a->len * LIMB_BITS - a->expn); - } else if (n == 2) { - dlimb_t t; - slimb_t pos; - pos = a->len * LIMB_BITS - a->expn; - t = ((dlimb_t)get_bits(a->tab, a->len, pos + LIMB_BITS) << LIMB_BITS) | - get_bits(a->tab, a->len, pos); - if (LIKELY(radixl == RADIXL_10)) { - /* use division by a constant when possible */ - out[0] = t % RADIXL_10; - out[1] = t / RADIXL_10; - } else { - out[0] = t % radixl; - out[1] = t / radixl; - } - } else { - bf_t Q, R, *B, *B_inv; - int q_add; - bf_init(a->ctx, &Q); - bf_init(a->ctx, &R); - n2 = (((n0 * 2) >> (level + 1)) + 1) / 2; - n1 = n - n2; - B = &pow_tab[2 * level]; - B_inv = &pow_tab[2 * level + 1]; - ret = 0; - if (B->len == 0) { - /* compute BASE^n2 */ - ret |= bf_pow_ui_ui(B, radixl, n2, BF_PREC_INF, BF_RNDZ); - /* we use enough bits for the maximum possible 'n1' value, - i.e. n2 + 1 */ - ret |= bf_set_ui(&R, 1); - ret |= bf_div(B_inv, &R, B, (n2 + 1) * radixl_bits + 2, BF_RNDN); - } - // printf("%d: n1=% " PRId64 " n2=%" PRId64 "\n", level, n1, n2); - q_prec = n1 * radixl_bits; - ret |= bf_mul(&Q, a, B_inv, q_prec, BF_RNDN); - ret |= bf_rint(&Q, BF_RNDZ); - - ret |= bf_mul(&R, &Q, B, BF_PREC_INF, BF_RNDZ); - ret |= bf_sub(&R, a, &R, BF_PREC_INF, BF_RNDZ); - - if (ret & BF_ST_MEM_ERROR) - goto fail; - /* adjust if necessary */ - q_add = 0; - while (R.sign && R.len != 0) { - if (bf_add(&R, &R, B, BF_PREC_INF, BF_RNDZ)) - goto fail; - q_add--; - } - while (bf_cmpu(&R, B) >= 0) { - if (bf_sub(&R, &R, B, BF_PREC_INF, BF_RNDZ)) - goto fail; - q_add++; - } - if (q_add != 0) { - if (bf_add_si(&Q, &Q, q_add, BF_PREC_INF, BF_RNDZ)) - goto fail; - } - if (bf_integer_to_radix_rec(pow_tab, out + n2, &Q, n1, level + 1, n0, - radixl, radixl_bits)) - goto fail; - if (bf_integer_to_radix_rec(pow_tab, out, &R, n2, level + 1, n0, - radixl, radixl_bits)) { - fail: - bf_delete(&Q); - bf_delete(&R); - return -1; - } - bf_delete(&Q); - bf_delete(&R); - } - return 0; -} - -/* return 0 if OK != 0 if memory error */ -static int bf_integer_to_radix(bf_t *r, const bf_t *a, limb_t radixl) -{ - bf_context_t *s = r->ctx; - limb_t r_len; - bf_t *pow_tab; - int i, pow_tab_len, ret; - - r_len = r->len; - pow_tab_len = (ceil_log2(r_len) + 2) * 2; /* XXX: check */ - pow_tab = bf_malloc(s, sizeof(pow_tab[0]) * pow_tab_len); - if (!pow_tab) - return -1; - for(i = 0; i < pow_tab_len; i++) - bf_init(r->ctx, &pow_tab[i]); - - ret = bf_integer_to_radix_rec(pow_tab, r->tab, a, r_len, 0, r_len, radixl, - ceil_log2(radixl)); - - for(i = 0; i < pow_tab_len; i++) { - bf_delete(&pow_tab[i]); - } - bf_free(s, pow_tab); - return ret; -} - -/* a must be >= 0. 'P' is the wanted number of digits in radix - 'radix'. 'r' is the mantissa represented as an integer. *pE - contains the exponent. Return != 0 if memory error. */ -static int bf_convert_to_radix(bf_t *r, slimb_t *pE, - const bf_t *a, int radix, - limb_t P, bf_rnd_t rnd_mode, - BOOL is_fixed_exponent) -{ - slimb_t E, e, prec, extra_bits, ziv_extra_bits, prec0; - bf_t B_s, *B = &B_s; - int e_sign, ret, res; - - if (a->len == 0) { - /* zero case */ - *pE = 0; - return bf_set(r, a); - } - - if (is_fixed_exponent) { - E = *pE; - } else { - /* compute the new exponent */ - E = 1 + bf_mul_log2_radix(a->expn - 1, radix, TRUE, FALSE); - } - // bf_print_str("a", a); - // printf("E=%ld P=%ld radix=%d\n", E, P, radix); - - for(;;) { - e = P - E; - e_sign = 0; - if (e < 0) { - e = -e; - e_sign = 1; - } - /* Note: precision for log2(radix) is not critical here */ - prec0 = bf_mul_log2_radix(P, radix, FALSE, TRUE); - ziv_extra_bits = 16; - for(;;) { - prec = prec0 + ziv_extra_bits; - /* XXX: rigorous error analysis needed */ - extra_bits = ceil_log2(e) * 2 + 1; - ret = bf_pow_ui_ui(r, radix, e, prec + extra_bits, - BF_RNDN | BF_FLAG_EXT_EXP); - if (!e_sign) - ret |= bf_mul(r, r, a, prec + extra_bits, - BF_RNDN | BF_FLAG_EXT_EXP); - else - ret |= bf_div(r, a, r, prec + extra_bits, - BF_RNDN | BF_FLAG_EXT_EXP); - if (ret & BF_ST_MEM_ERROR) - return BF_ST_MEM_ERROR; - /* if the result is not exact, check that it can be safely - rounded to an integer */ - if ((ret & BF_ST_INEXACT) && - !bf_can_round(r, r->expn, rnd_mode, prec)) { - /* and more precision and retry */ - ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2); - continue; - } else { - ret = bf_rint(r, rnd_mode); - if (ret & BF_ST_MEM_ERROR) - return BF_ST_MEM_ERROR; - break; - } - } - if (is_fixed_exponent) - break; - /* check that the result is < B^P */ - /* XXX: do a fast approximate test first ? */ - bf_init(r->ctx, B); - ret = bf_pow_ui_ui(B, radix, P, BF_PREC_INF, BF_RNDZ); - if (ret) { - bf_delete(B); - return ret; - } - res = bf_cmpu(r, B); - bf_delete(B); - if (res < 0) - break; - /* try a larger exponent */ - E++; - } - *pE = E; - return 0; -} - -static void limb_to_a(char *buf, limb_t n, unsigned int radix, int len) -{ - int digit, i; - - if (radix == 10) { - /* specific case with constant divisor */ - for(i = len - 1; i >= 0; i--) { - digit = (limb_t)n % 10; - n = (limb_t)n / 10; - buf[i] = digit + '0'; - } - } else { - for(i = len - 1; i >= 0; i--) { - digit = (limb_t)n % radix; - n = (limb_t)n / radix; - if (digit < 10) - digit += '0'; - else - digit += 'a' - 10; - buf[i] = digit; - } - } -} - -/* for power of 2 radixes */ -static void limb_to_a2(char *buf, limb_t n, unsigned int radix_bits, int len) -{ - int digit, i; - unsigned int mask; - - mask = (1 << radix_bits) - 1; - for(i = len - 1; i >= 0; i--) { - digit = n & mask; - n >>= radix_bits; - if (digit < 10) - digit += '0'; - else - digit += 'a' - 10; - buf[i] = digit; - } -} - -/* 'a' must be an integer if the is_dec = FALSE or if the radix is not - a power of two. A dot is added before the 'dot_pos' digit. dot_pos - = n_digits does not display the dot. 0 <= dot_pos <= - n_digits. n_digits >= 1. */ -static void output_digits(DynBuf *s, const bf_t *a1, int radix, limb_t n_digits, - limb_t dot_pos, BOOL is_dec) -{ - limb_t i, v, l; - slimb_t pos, pos_incr; - int digits_per_limb, buf_pos, radix_bits, first_buf_pos; - char buf[65]; - bf_t a_s, *a; - - if (is_dec) { - digits_per_limb = LIMB_DIGITS; - a = (bf_t *)a1; - radix_bits = 0; - pos = a->len; - pos_incr = 1; - first_buf_pos = 0; - } else if ((radix & (radix - 1)) == 0) { - a = (bf_t *)a1; - radix_bits = ceil_log2(radix); - digits_per_limb = LIMB_BITS / radix_bits; - pos_incr = digits_per_limb * radix_bits; - /* digits are aligned relative to the radix point */ - pos = a->len * LIMB_BITS + smod(-a->expn, radix_bits); - first_buf_pos = 0; - } else { - limb_t n, radixl; - - digits_per_limb = digits_per_limb_table[radix - 2]; - radixl = get_limb_radix(radix); - a = &a_s; - bf_init(a1->ctx, a); - n = (n_digits + digits_per_limb - 1) / digits_per_limb; - if (bf_resize(a, n)) { - dbuf_set_error(s); - goto done; - } - if (bf_integer_to_radix(a, a1, radixl)) { - dbuf_set_error(s); - goto done; - } - radix_bits = 0; - pos = n; - pos_incr = 1; - first_buf_pos = pos * digits_per_limb - n_digits; - } - buf_pos = digits_per_limb; - i = 0; - while (i < n_digits) { - if (buf_pos == digits_per_limb) { - pos -= pos_incr; - if (radix_bits == 0) { - v = get_limbz(a, pos); - limb_to_a(buf, v, radix, digits_per_limb); - } else { - v = get_bits(a->tab, a->len, pos); - limb_to_a2(buf, v, radix_bits, digits_per_limb); - } - buf_pos = first_buf_pos; - first_buf_pos = 0; - } - if (i < dot_pos) { - l = dot_pos; - } else { - if (i == dot_pos) - dbuf_putc(s, '.'); - l = n_digits; - } - l = bf_min(digits_per_limb - buf_pos, l - i); - dbuf_put(s, (uint8_t *)(buf + buf_pos), l); - buf_pos += l; - i += l; - } - done: - if (a != a1) - bf_delete(a); -} - -static void *bf_dbuf_realloc(void *opaque, void *ptr, size_t size) -{ - bf_context_t *s = opaque; - return bf_realloc(s, ptr, size); -} - -/* return the length in bytes. A trailing '\0' is added */ -static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix, - limb_t prec, bf_flags_t flags, BOOL is_dec) -{ - bf_context_t *ctx = a2->ctx; - DynBuf s_s, *s = &s_s; - int radix_bits; - - // bf_print_str("ftoa", a2); - // printf("radix=%d\n", radix); - dbuf_init2(s, ctx, bf_dbuf_realloc); - if (a2->expn == BF_EXP_NAN) { - dbuf_putstr(s, "NaN"); - } else { - if (a2->sign) - dbuf_putc(s, '-'); - if (a2->expn == BF_EXP_INF) { - if (flags & BF_FTOA_JS_QUIRKS) - dbuf_putstr(s, "Infinity"); - else - dbuf_putstr(s, "Inf"); - } else { - int fmt, ret; - slimb_t n_digits, n, i, n_max, n1; - bf_t a1_s, *a1 = &a1_s; - - if ((radix & (radix - 1)) != 0) - radix_bits = 0; - else - radix_bits = ceil_log2(radix); - - fmt = flags & BF_FTOA_FORMAT_MASK; - bf_init(ctx, a1); - if (fmt == BF_FTOA_FORMAT_FRAC) { - if (is_dec || radix_bits != 0) { - if (bf_set(a1, a2)) - goto fail1; -#ifdef USE_BF_DEC - if (is_dec) { - if (bfdec_round((bfdec_t *)a1, prec, (flags & BF_RND_MASK) | BF_FLAG_RADPNT_PREC) & BF_ST_MEM_ERROR) - goto fail1; - n = a1->expn; - } else -#endif - { - if (bf_round(a1, prec * radix_bits, (flags & BF_RND_MASK) | BF_FLAG_RADPNT_PREC) & BF_ST_MEM_ERROR) - goto fail1; - n = ceil_div(a1->expn, radix_bits); - } - if (flags & BF_FTOA_ADD_PREFIX) { - if (radix == 16) - dbuf_putstr(s, "0x"); - else if (radix == 8) - dbuf_putstr(s, "0o"); - else if (radix == 2) - dbuf_putstr(s, "0b"); - } - if (a1->expn == BF_EXP_ZERO) { - dbuf_putstr(s, "0"); - if (prec > 0) { - dbuf_putstr(s, "."); - for(i = 0; i < prec; i++) { - dbuf_putc(s, '0'); - } - } - } else { - n_digits = prec + n; - if (n <= 0) { - /* 0.x */ - dbuf_putstr(s, "0."); - for(i = 0; i < -n; i++) { - dbuf_putc(s, '0'); - } - if (n_digits > 0) { - output_digits(s, a1, radix, n_digits, n_digits, is_dec); - } - } else { - output_digits(s, a1, radix, n_digits, n, is_dec); - } - } - } else { - size_t pos, start; - bf_t a_s, *a = &a_s; - - /* make a positive number */ - a->tab = a2->tab; - a->len = a2->len; - a->expn = a2->expn; - a->sign = 0; - - /* one more digit for the rounding */ - n = 1 + bf_mul_log2_radix(bf_max(a->expn, 0), radix, TRUE, TRUE); - n_digits = n + prec; - n1 = n; - if (bf_convert_to_radix(a1, &n1, a, radix, n_digits, - flags & BF_RND_MASK, TRUE)) - goto fail1; - start = s->size; - output_digits(s, a1, radix, n_digits, n, is_dec); - /* remove leading zeros because we allocated one more digit */ - pos = start; - while ((pos + 1) < s->size && s->buf[pos] == '0' && - s->buf[pos + 1] != '.') - pos++; - if (pos > start) { - memmove(s->buf + start, s->buf + pos, s->size - pos); - s->size -= (pos - start); - } - } - } else { -#ifdef USE_BF_DEC - if (is_dec) { - if (bf_set(a1, a2)) - goto fail1; - if (fmt == BF_FTOA_FORMAT_FIXED) { - n_digits = prec; - n_max = n_digits; - if (bfdec_round((bfdec_t *)a1, prec, (flags & BF_RND_MASK)) & BF_ST_MEM_ERROR) - goto fail1; - } else { - /* prec is ignored */ - prec = n_digits = a1->len * LIMB_DIGITS; - /* remove the trailing zero digits */ - while (n_digits > 1 && - get_digit(a1->tab, a1->len, prec - n_digits) == 0) { - n_digits--; - } - n_max = n_digits + 4; - } - n = a1->expn; - } else -#endif - if (radix_bits != 0) { - if (bf_set(a1, a2)) - goto fail1; - if (fmt == BF_FTOA_FORMAT_FIXED) { - slimb_t prec_bits; - n_digits = prec; - n_max = n_digits; - /* align to the radix point */ - prec_bits = prec * radix_bits - - smod(-a1->expn, radix_bits); - if (bf_round(a1, prec_bits, - (flags & BF_RND_MASK)) & BF_ST_MEM_ERROR) - goto fail1; - } else { - limb_t digit_mask; - slimb_t pos; - /* position of the digit before the most - significant digit in bits */ - pos = a1->len * LIMB_BITS + - smod(-a1->expn, radix_bits); - n_digits = ceil_div(pos, radix_bits); - /* remove the trailing zero digits */ - digit_mask = ((limb_t)1 << radix_bits) - 1; - while (n_digits > 1 && - (get_bits(a1->tab, a1->len, pos - n_digits * radix_bits) & digit_mask) == 0) { - n_digits--; - } - n_max = n_digits + 4; - } - n = ceil_div(a1->expn, radix_bits); - } else { - bf_t a_s, *a = &a_s; - - /* make a positive number */ - a->tab = a2->tab; - a->len = a2->len; - a->expn = a2->expn; - a->sign = 0; - - if (fmt == BF_FTOA_FORMAT_FIXED) { - n_digits = prec; - n_max = n_digits; - } else { - slimb_t n_digits_max, n_digits_min; - - assert(prec != BF_PREC_INF); - n_digits = 1 + bf_mul_log2_radix(prec, radix, TRUE, TRUE); - /* max number of digits for non exponential - notation. The rational is to have the same rule - as JS i.e. n_max = 21 for 64 bit float in base 10. */ - n_max = n_digits + 4; - if (fmt == BF_FTOA_FORMAT_FREE_MIN) { - bf_t b_s, *b = &b_s; - - /* find the minimum number of digits by - dichotomy. */ - /* XXX: inefficient */ - n_digits_max = n_digits; - n_digits_min = 1; - bf_init(ctx, b); - while (n_digits_min < n_digits_max) { - n_digits = (n_digits_min + n_digits_max) / 2; - if (bf_convert_to_radix(a1, &n, a, radix, n_digits, - flags & BF_RND_MASK, FALSE)) { - bf_delete(b); - goto fail1; - } - /* convert back to a number and compare */ - ret = bf_mul_pow_radix(b, a1, radix, n - n_digits, - prec, - (flags & ~BF_RND_MASK) | - BF_RNDN); - if (ret & BF_ST_MEM_ERROR) { - bf_delete(b); - goto fail1; - } - if (bf_cmpu(b, a) == 0) { - n_digits_max = n_digits; - } else { - n_digits_min = n_digits + 1; - } - } - bf_delete(b); - n_digits = n_digits_max; - } - } - if (bf_convert_to_radix(a1, &n, a, radix, n_digits, - flags & BF_RND_MASK, FALSE)) { - fail1: - bf_delete(a1); - goto fail; - } - } - if (a1->expn == BF_EXP_ZERO && - fmt != BF_FTOA_FORMAT_FIXED && - !(flags & BF_FTOA_FORCE_EXP)) { - /* just output zero */ - dbuf_putstr(s, "0"); - } else { - if (flags & BF_FTOA_ADD_PREFIX) { - if (radix == 16) - dbuf_putstr(s, "0x"); - else if (radix == 8) - dbuf_putstr(s, "0o"); - else if (radix == 2) - dbuf_putstr(s, "0b"); - } - if (a1->expn == BF_EXP_ZERO) - n = 1; - if ((flags & BF_FTOA_FORCE_EXP) || - n <= -6 || n > n_max) { - const char *fmt; - /* exponential notation */ - output_digits(s, a1, radix, n_digits, 1, is_dec); - if (radix_bits != 0 && radix <= 16) { - if (flags & BF_FTOA_JS_QUIRKS) - fmt = "p%+" PRId_LIMB; - else - fmt = "p%" PRId_LIMB; - dbuf_printf(s, fmt, (n - 1) * radix_bits); - } else { - if (flags & BF_FTOA_JS_QUIRKS) - fmt = "%c%+" PRId_LIMB; - else - fmt = "%c%" PRId_LIMB; - dbuf_printf(s, fmt, - radix <= 10 ? 'e' : '@', n - 1); - } - } else if (n <= 0) { - /* 0.x */ - dbuf_putstr(s, "0."); - for(i = 0; i < -n; i++) { - dbuf_putc(s, '0'); - } - output_digits(s, a1, radix, n_digits, n_digits, is_dec); - } else { - if (n_digits <= n) { - /* no dot */ - output_digits(s, a1, radix, n_digits, n_digits, is_dec); - for(i = 0; i < (n - n_digits); i++) - dbuf_putc(s, '0'); - } else { - output_digits(s, a1, radix, n_digits, n, is_dec); - } - } - } - } - bf_delete(a1); - } - } - dbuf_putc(s, '\0'); - if (dbuf_error(s)) - goto fail; - if (plen) - *plen = s->size - 1; - return (char *)s->buf; - fail: - bf_free(ctx, s->buf); - if (plen) - *plen = 0; - return NULL; -} - -char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec, - bf_flags_t flags) -{ - return bf_ftoa_internal(plen, a, radix, prec, flags, FALSE); -} - -/***************************************************************/ -/* transcendental functions */ - -/* Note: the algorithm is from MPFR */ -static void bf_const_log2_rec(bf_t *T, bf_t *P, bf_t *Q, limb_t n1, - limb_t n2, BOOL need_P) -{ - bf_context_t *s = T->ctx; - if ((n2 - n1) == 1) { - if (n1 == 0) { - bf_set_ui(P, 3); - } else { - bf_set_ui(P, n1); - P->sign = 1; - } - bf_set_ui(Q, 2 * n1 + 1); - Q->expn += 2; - bf_set(T, P); - } else { - limb_t m; - bf_t T1_s, *T1 = &T1_s; - bf_t P1_s, *P1 = &P1_s; - bf_t Q1_s, *Q1 = &Q1_s; - - m = n1 + ((n2 - n1) >> 1); - bf_const_log2_rec(T, P, Q, n1, m, TRUE); - bf_init(s, T1); - bf_init(s, P1); - bf_init(s, Q1); - bf_const_log2_rec(T1, P1, Q1, m, n2, need_P); - bf_mul(T, T, Q1, BF_PREC_INF, BF_RNDZ); - bf_mul(T1, T1, P, BF_PREC_INF, BF_RNDZ); - bf_add(T, T, T1, BF_PREC_INF, BF_RNDZ); - if (need_P) - bf_mul(P, P, P1, BF_PREC_INF, BF_RNDZ); - bf_mul(Q, Q, Q1, BF_PREC_INF, BF_RNDZ); - bf_delete(T1); - bf_delete(P1); - bf_delete(Q1); - } -} - -/* compute log(2) with faithful rounding at precision 'prec' */ -static void bf_const_log2_internal(bf_t *T, limb_t prec) -{ - limb_t w, N; - bf_t P_s, *P = &P_s; - bf_t Q_s, *Q = &Q_s; - - w = prec + 15; - N = w / 3 + 1; - bf_init(T->ctx, P); - bf_init(T->ctx, Q); - bf_const_log2_rec(T, P, Q, 0, N, FALSE); - bf_div(T, T, Q, prec, BF_RNDN); - bf_delete(P); - bf_delete(Q); -} - -/* PI constant */ - -#define CHUD_A 13591409 -#define CHUD_B 545140134 -#define CHUD_C 640320 -#define CHUD_BITS_PER_TERM 47 - -static void chud_bs(bf_t *P, bf_t *Q, bf_t *G, int64_t a, int64_t b, int need_g, - limb_t prec) -{ - bf_context_t *s = P->ctx; - int64_t c; - - if (a == (b - 1)) { - bf_t T0, T1; - - bf_init(s, &T0); - bf_init(s, &T1); - bf_set_ui(G, 2 * b - 1); - bf_mul_ui(G, G, 6 * b - 1, prec, BF_RNDN); - bf_mul_ui(G, G, 6 * b - 5, prec, BF_RNDN); - bf_set_ui(&T0, CHUD_B); - bf_mul_ui(&T0, &T0, b, prec, BF_RNDN); - bf_set_ui(&T1, CHUD_A); - bf_add(&T0, &T0, &T1, prec, BF_RNDN); - bf_mul(P, G, &T0, prec, BF_RNDN); - P->sign = b & 1; - - bf_set_ui(Q, b); - bf_mul_ui(Q, Q, b, prec, BF_RNDN); - bf_mul_ui(Q, Q, b, prec, BF_RNDN); - bf_mul_ui(Q, Q, (uint64_t)CHUD_C * CHUD_C * CHUD_C / 24, prec, BF_RNDN); - bf_delete(&T0); - bf_delete(&T1); - } else { - bf_t P2, Q2, G2; - - bf_init(s, &P2); - bf_init(s, &Q2); - bf_init(s, &G2); - - c = (a + b) / 2; - chud_bs(P, Q, G, a, c, 1, prec); - chud_bs(&P2, &Q2, &G2, c, b, need_g, prec); - - /* Q = Q1 * Q2 */ - /* G = G1 * G2 */ - /* P = P1 * Q2 + P2 * G1 */ - bf_mul(&P2, &P2, G, prec, BF_RNDN); - if (!need_g) - bf_set_ui(G, 0); - bf_mul(P, P, &Q2, prec, BF_RNDN); - bf_add(P, P, &P2, prec, BF_RNDN); - bf_delete(&P2); - - bf_mul(Q, Q, &Q2, prec, BF_RNDN); - bf_delete(&Q2); - if (need_g) - bf_mul(G, G, &G2, prec, BF_RNDN); - bf_delete(&G2); - } -} - -/* compute Pi with faithful rounding at precision 'prec' using the - Chudnovsky formula */ -static void bf_const_pi_internal(bf_t *Q, limb_t prec) -{ - bf_context_t *s = Q->ctx; - int64_t n, prec1; - bf_t P, G; - - /* number of serie terms */ - n = prec / CHUD_BITS_PER_TERM + 1; - /* XXX: precision analysis */ - prec1 = prec + 32; - - bf_init(s, &P); - bf_init(s, &G); - - chud_bs(&P, Q, &G, 0, n, 0, BF_PREC_INF); - - bf_mul_ui(&G, Q, CHUD_A, prec1, BF_RNDN); - bf_add(&P, &G, &P, prec1, BF_RNDN); - bf_div(Q, Q, &P, prec1, BF_RNDF); - - bf_set_ui(&P, CHUD_C); - bf_sqrt(&G, &P, prec1, BF_RNDF); - bf_mul_ui(&G, &G, (uint64_t)CHUD_C / 12, prec1, BF_RNDF); - bf_mul(Q, Q, &G, prec, BF_RNDN); - bf_delete(&P); - bf_delete(&G); -} - -static int bf_const_get(bf_t *T, limb_t prec, bf_flags_t flags, - BFConstCache *c, - void (*func)(bf_t *res, limb_t prec), int sign) -{ - limb_t ziv_extra_bits, prec1; - - ziv_extra_bits = 32; - for(;;) { - prec1 = prec + ziv_extra_bits; - if (c->prec < prec1) { - if (c->val.len == 0) - bf_init(T->ctx, &c->val); - func(&c->val, prec1); - c->prec = prec1; - } else { - prec1 = c->prec; - } - bf_set(T, &c->val); - T->sign = sign; - if (!bf_can_round(T, prec, flags & BF_RND_MASK, prec1)) { - /* and more precision and retry */ - ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2); - } else { - break; - } - } - return bf_round(T, prec, flags); -} - -static void bf_const_free(BFConstCache *c) -{ - bf_delete(&c->val); - bzero(c, sizeof(*c)); -} - -int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags) -{ - bf_context_t *s = T->ctx; - return bf_const_get(T, prec, flags, &s->log2_cache, bf_const_log2_internal, 0); -} - -/* return rounded pi * (1 - 2 * sign) */ -static int bf_const_pi_signed(bf_t *T, int sign, limb_t prec, bf_flags_t flags) -{ - bf_context_t *s = T->ctx; - return bf_const_get(T, prec, flags, &s->pi_cache, bf_const_pi_internal, - sign); -} - -int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags) -{ - return bf_const_pi_signed(T, 0, prec, flags); -} - -void bf_clear_cache(bf_context_t *s) -{ -#ifdef USE_FFT_MUL - fft_clear_cache(s); -#endif - bf_const_free(&s->log2_cache); - bf_const_free(&s->pi_cache); -} - -/* ZivFunc should compute the result 'r' with faithful rounding at - precision 'prec'. For efficiency purposes, the final bf_round() - does not need to be done in the function. */ -typedef int ZivFunc(bf_t *r, const bf_t *a, limb_t prec, void *opaque); - -static int bf_ziv_rounding(bf_t *r, const bf_t *a, - limb_t prec, bf_flags_t flags, - ZivFunc *f, void *opaque) -{ - int rnd_mode, ret; - slimb_t prec1, ziv_extra_bits; - - rnd_mode = flags & BF_RND_MASK; - if (rnd_mode == BF_RNDF) { - /* no need to iterate */ - f(r, a, prec, opaque); - ret = 0; - } else { - ziv_extra_bits = 32; - for(;;) { - prec1 = prec + ziv_extra_bits; - ret = f(r, a, prec1, opaque); - if (ret & (BF_ST_OVERFLOW | BF_ST_UNDERFLOW | BF_ST_MEM_ERROR)) { - /* overflow or underflow should never happen because - it indicates the rounding cannot be done correctly, - but we do not catch all the cases */ - return ret; - } - /* if the result is exact, we can stop */ - if (!(ret & BF_ST_INEXACT)) { - ret = 0; - break; - } - if (bf_can_round(r, prec, rnd_mode, prec1)) { - ret = BF_ST_INEXACT; - break; - } - ziv_extra_bits = ziv_extra_bits * 2; - // printf("ziv_extra_bits=%" PRId64 "\n", (int64_t)ziv_extra_bits); - } - } - if (r->len == 0) - return ret; - else - return __bf_round(r, prec, flags, r->len, ret); -} - -/* add (1 - 2*e_sign) * 2^e */ -static int bf_add_epsilon(bf_t *r, const bf_t *a, slimb_t e, int e_sign, - limb_t prec, int flags) -{ - bf_t T_s, *T = &T_s; - int ret; - /* small argument case: result = 1 + epsilon * sign(x) */ - bf_init(a->ctx, T); - bf_set_ui(T, 1); - T->sign = e_sign; - T->expn += e; - ret = bf_add(r, r, T, prec, flags); - bf_delete(T); - return ret; -} - -/* Compute the exponential using faithful rounding at precision 'prec'. - Note: the algorithm is from MPFR */ -static int bf_exp_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) -{ - bf_context_t *s = r->ctx; - bf_t T_s, *T = &T_s; - slimb_t n, K, l, i, prec1; - - assert(r != a); - - /* argument reduction: - T = a - n*log(2) with 0 <= T < log(2) and n integer. - */ - bf_init(s, T); - if (a->expn <= -1) { - /* 0 <= abs(a) <= 0.5 */ - if (a->sign) - n = -1; - else - n = 0; - } else { - bf_const_log2(T, LIMB_BITS, BF_RNDZ); - bf_div(T, a, T, LIMB_BITS, BF_RNDD); - bf_get_limb(&n, T, 0); - } - - K = bf_isqrt((prec + 1) / 2); - l = (prec - 1) / K + 1; - /* XXX: precision analysis ? */ - prec1 = prec + (K + 2 * l + 18) + K + 8; - if (a->expn > 0) - prec1 += a->expn; - // printf("n=%ld K=%ld prec1=%ld\n", n, K, prec1); - - bf_const_log2(T, prec1, BF_RNDF); - bf_mul_si(T, T, n, prec1, BF_RNDN); - bf_sub(T, a, T, prec1, BF_RNDN); - - /* reduce the range of T */ - bf_mul_2exp(T, -K, BF_PREC_INF, BF_RNDZ); - - /* Taylor expansion around zero : - 1 + x + x^2/2 + ... + x^n/n! - = (1 + x * (1 + x/2 * (1 + ... (x/n)))) - */ - { - bf_t U_s, *U = &U_s; - - bf_init(s, U); - bf_set_ui(r, 1); - for(i = l ; i >= 1; i--) { - bf_set_ui(U, i); - bf_div(U, T, U, prec1, BF_RNDN); - bf_mul(r, r, U, prec1, BF_RNDN); - bf_add_si(r, r, 1, prec1, BF_RNDN); - } - bf_delete(U); - } - bf_delete(T); - - /* undo the range reduction */ - for(i = 0; i < K; i++) { - bf_mul(r, r, r, prec1, BF_RNDN | BF_FLAG_EXT_EXP); - } - - /* undo the argument reduction */ - bf_mul_2exp(r, n, BF_PREC_INF, BF_RNDZ | BF_FLAG_EXT_EXP); - - return BF_ST_INEXACT; -} - -/* crude overflow and underflow tests for exp(a). a_low <= a <= a_high */ -static int check_exp_underflow_overflow(bf_context_t *s, bf_t *r, - const bf_t *a_low, const bf_t *a_high, - limb_t prec, bf_flags_t flags) -{ - bf_t T_s, *T = &T_s; - bf_t log2_s, *log2 = &log2_s; - slimb_t e_min, e_max; - - if (a_high->expn <= 0) - return 0; - - e_max = (limb_t)1 << (bf_get_exp_bits(flags) - 1); - e_min = -e_max + 3; - if (flags & BF_FLAG_SUBNORMAL) - e_min -= (prec - 1); - - bf_init(s, T); - bf_init(s, log2); - bf_const_log2(log2, LIMB_BITS, BF_RNDU); - bf_mul_ui(T, log2, e_max, LIMB_BITS, BF_RNDU); - /* a_low > e_max * log(2) implies exp(a) > e_max */ - if (bf_cmp_lt(T, a_low) > 0) { - /* overflow */ - bf_delete(T); - bf_delete(log2); - return bf_set_overflow(r, 0, prec, flags); - } - /* a_high < (e_min - 2) * log(2) implies exp(a) < (e_min - 2) */ - bf_const_log2(log2, LIMB_BITS, BF_RNDD); - bf_mul_si(T, log2, e_min - 2, LIMB_BITS, BF_RNDD); - if (bf_cmp_lt(a_high, T)) { - int rnd_mode = flags & BF_RND_MASK; - - /* underflow */ - bf_delete(T); - bf_delete(log2); - if (rnd_mode == BF_RNDU) { - /* set the smallest value */ - bf_set_ui(r, 1); - r->expn = e_min; - } else { - bf_set_zero(r, 0); - } - return BF_ST_UNDERFLOW | BF_ST_INEXACT; - } - bf_delete(log2); - bf_delete(T); - return 0; -} - -int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) -{ - bf_context_t *s = r->ctx; - int ret; - assert(r != a); - if (a->len == 0) { - if (a->expn == BF_EXP_NAN) { - bf_set_nan(r); - } else if (a->expn == BF_EXP_INF) { - if (a->sign) - bf_set_zero(r, 0); - else - bf_set_inf(r, 0); - } else { - bf_set_ui(r, 1); - } - return 0; - } - - ret = check_exp_underflow_overflow(s, r, a, a, prec, flags); - if (ret) - return ret; - if (a->expn < 0 && (-a->expn) >= (prec + 2)) { - /* small argument case: result = 1 + epsilon * sign(x) */ - bf_set_ui(r, 1); - return bf_add_epsilon(r, r, -(prec + 2), a->sign, prec, flags); - } - - return bf_ziv_rounding(r, a, prec, flags, bf_exp_internal, NULL); -} - -static int bf_log_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) -{ - bf_context_t *s = r->ctx; - bf_t T_s, *T = &T_s; - bf_t U_s, *U = &U_s; - bf_t V_s, *V = &V_s; - slimb_t n, prec1, l, i, K; - - assert(r != a); - - bf_init(s, T); - /* argument reduction 1 */ - /* T=a*2^n with 2/3 <= T <= 4/3 */ - { - bf_t U_s, *U = &U_s; - bf_set(T, a); - n = T->expn; - T->expn = 0; - /* U= ~ 2/3 */ - bf_init(s, U); - bf_set_ui(U, 0xaaaaaaaa); - U->expn = 0; - if (bf_cmp_lt(T, U)) { - T->expn++; - n--; - } - bf_delete(U); - } - // printf("n=%ld\n", n); - // bf_print_str("T", T); - - /* XXX: precision analysis */ - /* number of iterations for argument reduction 2 */ - K = bf_isqrt((prec + 1) / 2); - /* order of Taylor expansion */ - l = prec / (2 * K) + 1; - /* precision of the intermediate computations */ - prec1 = prec + K + 2 * l + 32; - - bf_init(s, U); - bf_init(s, V); - - /* Note: cancellation occurs here, so we use more precision (XXX: - reduce the precision by computing the exact cancellation) */ - bf_add_si(T, T, -1, BF_PREC_INF, BF_RNDN); - - /* argument reduction 2 */ - for(i = 0; i < K; i++) { - /* T = T / (1 + sqrt(1 + T)) */ - bf_add_si(U, T, 1, prec1, BF_RNDN); - bf_sqrt(V, U, prec1, BF_RNDF); - bf_add_si(U, V, 1, prec1, BF_RNDN); - bf_div(T, T, U, prec1, BF_RNDN); - } - - { - bf_t Y_s, *Y = &Y_s; - bf_t Y2_s, *Y2 = &Y2_s; - bf_init(s, Y); - bf_init(s, Y2); - - /* compute ln(1+x) = ln((1+y)/(1-y)) with y=x/(2+x) - = y + y^3/3 + ... + y^(2*l + 1) / (2*l+1) - with Y=Y^2 - = y*(1+Y/3+Y^2/5+...) = y*(1+Y*(1/3+Y*(1/5 + ...))) - */ - bf_add_si(Y, T, 2, prec1, BF_RNDN); - bf_div(Y, T, Y, prec1, BF_RNDN); - - bf_mul(Y2, Y, Y, prec1, BF_RNDN); - bf_set_ui(r, 0); - for(i = l; i >= 1; i--) { - bf_set_ui(U, 1); - bf_set_ui(V, 2 * i + 1); - bf_div(U, U, V, prec1, BF_RNDN); - bf_add(r, r, U, prec1, BF_RNDN); - bf_mul(r, r, Y2, prec1, BF_RNDN); - } - bf_add_si(r, r, 1, prec1, BF_RNDN); - bf_mul(r, r, Y, prec1, BF_RNDN); - bf_delete(Y); - bf_delete(Y2); - } - bf_delete(V); - bf_delete(U); - - /* multiplication by 2 for the Taylor expansion and undo the - argument reduction 2*/ - bf_mul_2exp(r, K + 1, BF_PREC_INF, BF_RNDZ); - - /* undo the argument reduction 1 */ - bf_const_log2(T, prec1, BF_RNDF); - bf_mul_si(T, T, n, prec1, BF_RNDN); - bf_add(r, r, T, prec1, BF_RNDN); - - bf_delete(T); - return BF_ST_INEXACT; -} - -int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) -{ - bf_context_t *s = r->ctx; - bf_t T_s, *T = &T_s; - - assert(r != a); - if (a->len == 0) { - if (a->expn == BF_EXP_NAN) { - bf_set_nan(r); - return 0; - } else if (a->expn == BF_EXP_INF) { - if (a->sign) { - bf_set_nan(r); - return BF_ST_INVALID_OP; - } else { - bf_set_inf(r, 0); - return 0; - } - } else { - bf_set_inf(r, 1); - return 0; - } - } - if (a->sign) { - bf_set_nan(r); - return BF_ST_INVALID_OP; - } - bf_init(s, T); - bf_set_ui(T, 1); - if (bf_cmp_eq(a, T)) { - bf_set_zero(r, 0); - bf_delete(T); - return 0; - } - bf_delete(T); - - return bf_ziv_rounding(r, a, prec, flags, bf_log_internal, NULL); -} - -/* x and y finite and x > 0 */ -static int bf_pow_generic(bf_t *r, const bf_t *x, limb_t prec, void *opaque) -{ - bf_context_t *s = r->ctx; - const bf_t *y = opaque; - bf_t T_s, *T = &T_s; - limb_t prec1; - - bf_init(s, T); - /* XXX: proof for the added precision */ - prec1 = prec + 32; - bf_log(T, x, prec1, BF_RNDF | BF_FLAG_EXT_EXP); - bf_mul(T, T, y, prec1, BF_RNDF | BF_FLAG_EXT_EXP); - if (bf_is_nan(T)) - bf_set_nan(r); - else - bf_exp_internal(r, T, prec1, NULL); /* no overflow/underlow test needed */ - bf_delete(T); - return BF_ST_INEXACT; -} - -/* x and y finite, x > 0, y integer and y fits on one limb */ -static int bf_pow_int(bf_t *r, const bf_t *x, limb_t prec, void *opaque) -{ - bf_context_t *s = r->ctx; - const bf_t *y = opaque; - bf_t T_s, *T = &T_s; - limb_t prec1; - int ret; - slimb_t y1; - - bf_get_limb(&y1, y, 0); - if (y1 < 0) - y1 = -y1; - /* XXX: proof for the added precision */ - prec1 = prec + ceil_log2(y1) * 2 + 8; - ret = bf_pow_ui(r, x, y1 < 0 ? -y1 : y1, prec1, BF_RNDN | BF_FLAG_EXT_EXP); - if (y->sign) { - bf_init(s, T); - bf_set_ui(T, 1); - ret |= bf_div(r, T, r, prec1, BF_RNDN | BF_FLAG_EXT_EXP); - bf_delete(T); - } - return ret; -} - -/* x must be a finite non zero float. Return TRUE if there is a - floating point number r such as x=r^(2^n) and return this floating - point number 'r'. Otherwise return FALSE and r is undefined. */ -static BOOL check_exact_power2n(bf_t *r, const bf_t *x, slimb_t n) -{ - bf_context_t *s = r->ctx; - bf_t T_s, *T = &T_s; - slimb_t e, i, er; - limb_t v; - - /* x = m*2^e with m odd integer */ - e = bf_get_exp_min(x); - /* fast check on the exponent */ - if (n > (LIMB_BITS - 1)) { - if (e != 0) - return FALSE; - er = 0; - } else { - if ((e & (((limb_t)1 << n) - 1)) != 0) - return FALSE; - er = e >> n; - } - /* every perfect odd square = 1 modulo 8 */ - v = get_bits(x->tab, x->len, x->len * LIMB_BITS - x->expn + e); - if ((v & 7) != 1) - return FALSE; - - bf_init(s, T); - bf_set(T, x); - T->expn -= e; - for(i = 0; i < n; i++) { - if (i != 0) - bf_set(T, r); - if (bf_sqrtrem(r, NULL, T) != 0) - return FALSE; - } - r->expn += er; - return TRUE; -} - -/* prec = BF_PREC_INF is accepted for x and y integers and y >= 0 */ -int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags) -{ - bf_context_t *s = r->ctx; - bf_t T_s, *T = &T_s; - bf_t ytmp_s; - BOOL y_is_int, y_is_odd; - int r_sign, ret, rnd_mode; - slimb_t y_emin; - - if (x->len == 0 || y->len == 0) { - if (y->expn == BF_EXP_ZERO) { - /* pow(x, 0) = 1 */ - bf_set_ui(r, 1); - } else if (x->expn == BF_EXP_NAN) { - bf_set_nan(r); - } else { - int cmp_x_abs_1; - bf_set_ui(r, 1); - cmp_x_abs_1 = bf_cmpu(x, r); - if (cmp_x_abs_1 == 0 && (flags & BF_POW_JS_QUIRKS) && - (y->expn >= BF_EXP_INF)) { - bf_set_nan(r); - } else if (cmp_x_abs_1 == 0 && - (!x->sign || y->expn != BF_EXP_NAN)) { - /* pow(1, y) = 1 even if y = NaN */ - /* pow(-1, +/-inf) = 1 */ - } else if (y->expn == BF_EXP_NAN) { - bf_set_nan(r); - } else if (y->expn == BF_EXP_INF) { - if (y->sign == (cmp_x_abs_1 > 0)) { - bf_set_zero(r, 0); - } else { - bf_set_inf(r, 0); - } - } else { - y_emin = bf_get_exp_min(y); - y_is_odd = (y_emin == 0); - if (y->sign == (x->expn == BF_EXP_ZERO)) { - bf_set_inf(r, y_is_odd & x->sign); - if (y->sign) { - /* pow(0, y) with y < 0 */ - return BF_ST_DIVIDE_ZERO; - } - } else { - bf_set_zero(r, y_is_odd & x->sign); - } - } - } - return 0; - } - bf_init(s, T); - bf_set(T, x); - y_emin = bf_get_exp_min(y); - y_is_int = (y_emin >= 0); - rnd_mode = flags & BF_RND_MASK; - if (x->sign) { - if (!y_is_int) { - bf_set_nan(r); - bf_delete(T); - return BF_ST_INVALID_OP; - } - y_is_odd = (y_emin == 0); - r_sign = y_is_odd; - /* change the directed rounding mode if the sign of the result - is changed */ - if (r_sign && (rnd_mode == BF_RNDD || rnd_mode == BF_RNDU)) - flags ^= 1; - bf_neg(T); - } else { - r_sign = 0; - } - - bf_set_ui(r, 1); - if (bf_cmp_eq(T, r)) { - /* abs(x) = 1: nothing more to do */ - ret = 0; - } else { - /* check the overflow/underflow cases */ - { - bf_t al_s, *al = &al_s; - bf_t ah_s, *ah = &ah_s; - limb_t precl = LIMB_BITS; - - bf_init(s, al); - bf_init(s, ah); - /* compute bounds of log(abs(x)) * y with a low precision */ - /* XXX: compute bf_log() once */ - /* XXX: add a fast test before this slow test */ - bf_log(al, T, precl, BF_RNDD); - bf_log(ah, T, precl, BF_RNDU); - bf_mul(al, al, y, precl, BF_RNDD ^ y->sign); - bf_mul(ah, ah, y, precl, BF_RNDU ^ y->sign); - ret = check_exp_underflow_overflow(s, r, al, ah, prec, flags); - bf_delete(al); - bf_delete(ah); - if (ret) - goto done; - } - - if (y_is_int) { - slimb_t T_bits, e; - int_pow: - T_bits = T->expn - bf_get_exp_min(T); - if (T_bits == 1) { - /* pow(2^b, y) = 2^(b*y) */ - bf_mul_si(T, y, T->expn - 1, LIMB_BITS, BF_RNDZ); - bf_get_limb(&e, T, 0); - bf_set_ui(r, 1); - ret = bf_mul_2exp(r, e, prec, flags); - } else if (prec == BF_PREC_INF) { - slimb_t y1; - /* specific case for infinite precision (integer case) */ - bf_get_limb(&y1, y, 0); - assert(!y->sign); - /* x must be an integer, so abs(x) >= 2 */ - if (y1 >= ((slimb_t)1 << BF_EXP_BITS_MAX)) { - bf_delete(T); - return bf_set_overflow(r, 0, BF_PREC_INF, flags); - } - ret = bf_pow_ui(r, T, y1, BF_PREC_INF, BF_RNDZ); - } else { - if (y->expn <= 31) { - /* small enough power: use exponentiation in all cases */ - } else if (y->sign) { - /* cannot be exact */ - goto general_case; - } else { - if (rnd_mode == BF_RNDF) - goto general_case; /* no need to track exact results */ - /* see if the result has a chance to be exact: - if x=a*2^b (a odd), x^y=a^y*2^(b*y) - x^y needs a precision of at least floor_log2(a)*y bits - */ - bf_mul_si(r, y, T_bits - 1, LIMB_BITS, BF_RNDZ); - bf_get_limb(&e, r, 0); - if (prec < e) - goto general_case; - } - ret = bf_ziv_rounding(r, T, prec, flags, bf_pow_int, (void *)y); - } - } else { - if (rnd_mode != BF_RNDF) { - bf_t *y1; - if (y_emin < 0 && check_exact_power2n(r, T, -y_emin)) { - /* the problem is reduced to a power to an integer */ -#if 0 - printf("\nn=%" PRId64 "\n", -(int64_t)y_emin); - bf_print_str("T", T); - bf_print_str("r", r); -#endif - bf_set(T, r); - y1 = &ytmp_s; - y1->tab = y->tab; - y1->len = y->len; - y1->sign = y->sign; - y1->expn = y->expn - y_emin; - y = y1; - goto int_pow; - } - } - general_case: - ret = bf_ziv_rounding(r, T, prec, flags, bf_pow_generic, (void *)y); - } - } - done: - bf_delete(T); - r->sign = r_sign; - return ret; -} - -/* compute sqrt(-2*x-x^2) to get |sin(x)| from cos(x) - 1. */ -static void bf_sqrt_sin(bf_t *r, const bf_t *x, limb_t prec1) -{ - bf_context_t *s = r->ctx; - bf_t T_s, *T = &T_s; - bf_init(s, T); - bf_set(T, x); - bf_mul(r, T, T, prec1, BF_RNDN); - bf_mul_2exp(T, 1, BF_PREC_INF, BF_RNDZ); - bf_add(T, T, r, prec1, BF_RNDN); - bf_neg(T); - bf_sqrt(r, T, prec1, BF_RNDF); - bf_delete(T); -} - -static int bf_sincos(bf_t *s, bf_t *c, const bf_t *a, limb_t prec) -{ - bf_context_t *s1 = a->ctx; - bf_t T_s, *T = &T_s; - bf_t U_s, *U = &U_s; - bf_t r_s, *r = &r_s; - slimb_t K, prec1, i, l, mod, prec2; - int is_neg; - - assert(c != a && s != a); - - bf_init(s1, T); - bf_init(s1, U); - bf_init(s1, r); - - /* XXX: precision analysis */ - K = bf_isqrt(prec / 2); - l = prec / (2 * K) + 1; - prec1 = prec + 2 * K + l + 8; - - /* after the modulo reduction, -pi/4 <= T <= pi/4 */ - if (a->expn <= -1) { - /* abs(a) <= 0.25: no modulo reduction needed */ - bf_set(T, a); - mod = 0; - } else { - slimb_t cancel; - cancel = 0; - for(;;) { - prec2 = prec1 + a->expn + cancel; - bf_const_pi(U, prec2, BF_RNDF); - bf_mul_2exp(U, -1, BF_PREC_INF, BF_RNDZ); - bf_remquo(&mod, T, a, U, prec2, BF_RNDN, BF_RNDN); - // printf("T.expn=%ld prec2=%ld\n", T->expn, prec2); - if (mod == 0 || (T->expn != BF_EXP_ZERO && - (T->expn + prec2) >= (prec1 - 1))) - break; - /* increase the number of bits until the precision is good enough */ - cancel = bf_max(-T->expn, (cancel + 1) * 3 / 2); - } - mod &= 3; - } - - is_neg = T->sign; - - /* compute cosm1(x) = cos(x) - 1 */ - bf_mul(T, T, T, prec1, BF_RNDN); - bf_mul_2exp(T, -2 * K, BF_PREC_INF, BF_RNDZ); - - /* Taylor expansion: - -x^2/2 + x^4/4! - x^6/6! + ... - */ - bf_set_ui(r, 1); - for(i = l ; i >= 1; i--) { - bf_set_ui(U, 2 * i - 1); - bf_mul_ui(U, U, 2 * i, BF_PREC_INF, BF_RNDZ); - bf_div(U, T, U, prec1, BF_RNDN); - bf_mul(r, r, U, prec1, BF_RNDN); - bf_neg(r); - if (i != 1) - bf_add_si(r, r, 1, prec1, BF_RNDN); - } - bf_delete(U); - - /* undo argument reduction: - cosm1(2*x)= 2*(2*cosm1(x)+cosm1(x)^2) - */ - for(i = 0; i < K; i++) { - bf_mul(T, r, r, prec1, BF_RNDN); - bf_mul_2exp(r, 1, BF_PREC_INF, BF_RNDZ); - bf_add(r, r, T, prec1, BF_RNDN); - bf_mul_2exp(r, 1, BF_PREC_INF, BF_RNDZ); - } - bf_delete(T); - - if (c) { - if ((mod & 1) == 0) { - bf_add_si(c, r, 1, prec1, BF_RNDN); - } else { - bf_sqrt_sin(c, r, prec1); - c->sign = is_neg ^ 1; - } - c->sign ^= mod >> 1; - } - if (s) { - if ((mod & 1) == 0) { - bf_sqrt_sin(s, r, prec1); - s->sign = is_neg; - } else { - bf_add_si(s, r, 1, prec1, BF_RNDN); - } - s->sign ^= mod >> 1; - } - bf_delete(r); - return BF_ST_INEXACT; -} - -static int bf_cos_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) -{ - return bf_sincos(NULL, r, a, prec); -} - -int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) -{ - if (a->len == 0) { - if (a->expn == BF_EXP_NAN) { - bf_set_nan(r); - return 0; - } else if (a->expn == BF_EXP_INF) { - bf_set_nan(r); - return BF_ST_INVALID_OP; - } else { - bf_set_ui(r, 1); - return 0; - } - } - - /* small argument case: result = 1+r(x) with r(x) = -x^2/2 + - O(X^4). We assume r(x) < 2^(2*EXP(x) - 1). */ - if (a->expn < 0) { - slimb_t e; - e = 2 * a->expn - 1; - if (e < -(prec + 2)) { - bf_set_ui(r, 1); - return bf_add_epsilon(r, r, e, 1, prec, flags); - } - } - - return bf_ziv_rounding(r, a, prec, flags, bf_cos_internal, NULL); -} - -static int bf_sin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) -{ - return bf_sincos(r, NULL, a, prec); -} - -int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) -{ - if (a->len == 0) { - if (a->expn == BF_EXP_NAN) { - bf_set_nan(r); - return 0; - } else if (a->expn == BF_EXP_INF) { - bf_set_nan(r); - return BF_ST_INVALID_OP; - } else { - bf_set_zero(r, a->sign); - return 0; - } - } - - /* small argument case: result = x+r(x) with r(x) = -x^3/6 + - O(X^5). We assume r(x) < 2^(3*EXP(x) - 2). */ - if (a->expn < 0) { - slimb_t e; - e = sat_add(2 * a->expn, a->expn - 2); - if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) { - bf_set(r, a); - return bf_add_epsilon(r, r, e, 1 - a->sign, prec, flags); - } - } - - return bf_ziv_rounding(r, a, prec, flags, bf_sin_internal, NULL); -} - -static int bf_tan_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) -{ - bf_context_t *s = r->ctx; - bf_t T_s, *T = &T_s; - limb_t prec1; - - /* XXX: precision analysis */ - prec1 = prec + 8; - bf_init(s, T); - bf_sincos(r, T, a, prec1); - bf_div(r, r, T, prec1, BF_RNDF); - bf_delete(T); - return BF_ST_INEXACT; -} - -int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) -{ - assert(r != a); - if (a->len == 0) { - if (a->expn == BF_EXP_NAN) { - bf_set_nan(r); - return 0; - } else if (a->expn == BF_EXP_INF) { - bf_set_nan(r); - return BF_ST_INVALID_OP; - } else { - bf_set_zero(r, a->sign); - return 0; - } - } - - /* small argument case: result = x+r(x) with r(x) = x^3/3 + - O(X^5). We assume r(x) < 2^(3*EXP(x) - 1). */ - if (a->expn < 0) { - slimb_t e; - e = sat_add(2 * a->expn, a->expn - 1); - if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) { - bf_set(r, a); - return bf_add_epsilon(r, r, e, a->sign, prec, flags); - } - } - - return bf_ziv_rounding(r, a, prec, flags, bf_tan_internal, NULL); -} - -/* if add_pi2 is true, add pi/2 to the result (used for acos(x) to - avoid cancellation) */ -static int bf_atan_internal(bf_t *r, const bf_t *a, limb_t prec, - void *opaque) -{ - bf_context_t *s = r->ctx; - BOOL add_pi2 = (BOOL)(intptr_t)opaque; - bf_t T_s, *T = &T_s; - bf_t U_s, *U = &U_s; - bf_t V_s, *V = &V_s; - bf_t X2_s, *X2 = &X2_s; - int cmp_1; - slimb_t prec1, i, K, l; - - /* XXX: precision analysis */ - K = bf_isqrt((prec + 1) / 2); - l = prec / (2 * K) + 1; - prec1 = prec + K + 2 * l + 32; - // printf("prec=%d K=%d l=%d prec1=%d\n", (int)prec, (int)K, (int)l, (int)prec1); - - bf_init(s, T); - cmp_1 = (a->expn >= 1); /* a >= 1 */ - if (cmp_1) { - bf_set_ui(T, 1); - bf_div(T, T, a, prec1, BF_RNDN); - } else { - bf_set(T, a); - } - - /* abs(T) <= 1 */ - - /* argument reduction */ - - bf_init(s, U); - bf_init(s, V); - bf_init(s, X2); - for(i = 0; i < K; i++) { - /* T = T / (1 + sqrt(1 + T^2)) */ - bf_mul(U, T, T, prec1, BF_RNDN); - bf_add_si(U, U, 1, prec1, BF_RNDN); - bf_sqrt(V, U, prec1, BF_RNDN); - bf_add_si(V, V, 1, prec1, BF_RNDN); - bf_div(T, T, V, prec1, BF_RNDN); - } - - /* Taylor series: - x - x^3/3 + ... + (-1)^ l * y^(2*l + 1) / (2*l+1) - */ - bf_mul(X2, T, T, prec1, BF_RNDN); - bf_set_ui(r, 0); - for(i = l; i >= 1; i--) { - bf_set_si(U, 1); - bf_set_ui(V, 2 * i + 1); - bf_div(U, U, V, prec1, BF_RNDN); - bf_neg(r); - bf_add(r, r, U, prec1, BF_RNDN); - bf_mul(r, r, X2, prec1, BF_RNDN); - } - bf_neg(r); - bf_add_si(r, r, 1, prec1, BF_RNDN); - bf_mul(r, r, T, prec1, BF_RNDN); - - /* undo the argument reduction */ - bf_mul_2exp(r, K, BF_PREC_INF, BF_RNDZ); - - bf_delete(U); - bf_delete(V); - bf_delete(X2); - - i = add_pi2; - if (cmp_1 > 0) { - /* undo the inversion : r = sign(a)*PI/2 - r */ - bf_neg(r); - i += 1 - 2 * a->sign; - } - /* add i*(pi/2) with -1 <= i <= 2 */ - if (i != 0) { - bf_const_pi(T, prec1, BF_RNDF); - if (i != 2) - bf_mul_2exp(T, -1, BF_PREC_INF, BF_RNDZ); - T->sign = (i < 0); - bf_add(r, T, r, prec1, BF_RNDN); - } - - bf_delete(T); - return BF_ST_INEXACT; -} - -int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) -{ - bf_context_t *s = r->ctx; - bf_t T_s, *T = &T_s; - int res; - - if (a->len == 0) { - if (a->expn == BF_EXP_NAN) { - bf_set_nan(r); - return 0; - } else if (a->expn == BF_EXP_INF) { - /* -PI/2 or PI/2 */ - bf_const_pi_signed(r, a->sign, prec, flags); - bf_mul_2exp(r, -1, BF_PREC_INF, BF_RNDZ); - return BF_ST_INEXACT; - } else { - bf_set_zero(r, a->sign); - return 0; - } - } - - bf_init(s, T); - bf_set_ui(T, 1); - res = bf_cmpu(a, T); - bf_delete(T); - if (res == 0) { - /* short cut: abs(a) == 1 -> +/-pi/4 */ - bf_const_pi_signed(r, a->sign, prec, flags); - bf_mul_2exp(r, -2, BF_PREC_INF, BF_RNDZ); - return BF_ST_INEXACT; - } - - /* small argument case: result = x+r(x) with r(x) = -x^3/3 + - O(X^5). We assume r(x) < 2^(3*EXP(x) - 1). */ - if (a->expn < 0) { - slimb_t e; - e = sat_add(2 * a->expn, a->expn - 1); - if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) { - bf_set(r, a); - return bf_add_epsilon(r, r, e, 1 - a->sign, prec, flags); - } - } - - return bf_ziv_rounding(r, a, prec, flags, bf_atan_internal, (void *)FALSE); -} - -static int bf_atan2_internal(bf_t *r, const bf_t *y, limb_t prec, void *opaque) -{ - bf_context_t *s = r->ctx; - const bf_t *x = opaque; - bf_t T_s, *T = &T_s; - limb_t prec1; - int ret; - - if (y->expn == BF_EXP_NAN || x->expn == BF_EXP_NAN) { - bf_set_nan(r); - return 0; - } - - /* compute atan(y/x) assumming inf/inf = 1 and 0/0 = 0 */ - bf_init(s, T); - prec1 = prec + 32; - if (y->expn == BF_EXP_INF && x->expn == BF_EXP_INF) { - bf_set_ui(T, 1); - T->sign = y->sign ^ x->sign; - } else if (y->expn == BF_EXP_ZERO && x->expn == BF_EXP_ZERO) { - bf_set_zero(T, y->sign ^ x->sign); - } else { - bf_div(T, y, x, prec1, BF_RNDF); - } - ret = bf_atan(r, T, prec1, BF_RNDF); - - if (x->sign) { - /* if x < 0 (it includes -0), return sign(y)*pi + atan(y/x) */ - bf_const_pi(T, prec1, BF_RNDF); - T->sign = y->sign; - bf_add(r, r, T, prec1, BF_RNDN); - ret |= BF_ST_INEXACT; - } - - bf_delete(T); - return ret; -} - -int bf_atan2(bf_t *r, const bf_t *y, const bf_t *x, - limb_t prec, bf_flags_t flags) -{ - return bf_ziv_rounding(r, y, prec, flags, bf_atan2_internal, (void *)x); -} - -static int bf_asin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) -{ - bf_context_t *s = r->ctx; - BOOL is_acos = (BOOL)(intptr_t)opaque; - bf_t T_s, *T = &T_s; - limb_t prec1, prec2; - - /* asin(x) = atan(x/sqrt(1-x^2)) - acos(x) = pi/2 - asin(x) */ - prec1 = prec + 8; - /* increase the precision in x^2 to compensate the cancellation in - (1-x^2) if x is close to 1 */ - /* XXX: use less precision when possible */ - if (a->expn >= 0) - prec2 = BF_PREC_INF; - else - prec2 = prec1; - bf_init(s, T); - bf_mul(T, a, a, prec2, BF_RNDN); - bf_neg(T); - bf_add_si(T, T, 1, prec2, BF_RNDN); - - bf_sqrt(r, T, prec1, BF_RNDN); - bf_div(T, a, r, prec1, BF_RNDN); - if (is_acos) - bf_neg(T); - bf_atan_internal(r, T, prec1, (void *)(intptr_t)is_acos); - bf_delete(T); - return BF_ST_INEXACT; -} - -int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) -{ - bf_context_t *s = r->ctx; - bf_t T_s, *T = &T_s; - int res; - - if (a->len == 0) { - if (a->expn == BF_EXP_NAN) { - bf_set_nan(r); - return 0; - } else if (a->expn == BF_EXP_INF) { - bf_set_nan(r); - return BF_ST_INVALID_OP; - } else { - bf_set_zero(r, a->sign); - return 0; - } - } - bf_init(s, T); - bf_set_ui(T, 1); - res = bf_cmpu(a, T); - bf_delete(T); - if (res > 0) { - bf_set_nan(r); - return BF_ST_INVALID_OP; - } - - /* small argument case: result = x+r(x) with r(x) = x^3/6 + - O(X^5). We assume r(x) < 2^(3*EXP(x) - 2). */ - if (a->expn < 0) { - slimb_t e; - e = sat_add(2 * a->expn, a->expn - 2); - if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) { - bf_set(r, a); - return bf_add_epsilon(r, r, e, a->sign, prec, flags); - } - } - - return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)FALSE); -} - -int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) -{ - bf_context_t *s = r->ctx; - bf_t T_s, *T = &T_s; - int res; - - if (a->len == 0) { - if (a->expn == BF_EXP_NAN) { - bf_set_nan(r); - return 0; - } else if (a->expn == BF_EXP_INF) { - bf_set_nan(r); - return BF_ST_INVALID_OP; - } else { - bf_const_pi(r, prec, flags); - bf_mul_2exp(r, -1, BF_PREC_INF, BF_RNDZ); - return BF_ST_INEXACT; - } - } - bf_init(s, T); - bf_set_ui(T, 1); - res = bf_cmpu(a, T); - bf_delete(T); - if (res > 0) { - bf_set_nan(r); - return BF_ST_INVALID_OP; - } else if (res == 0 && a->sign == 0) { - bf_set_zero(r, 0); - return 0; - } - - return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)TRUE); -} - -/***************************************************************/ -/* decimal floating point numbers */ - -#ifdef USE_BF_DEC - -#define adddq(r1, r0, a1, a0) \ - do { \ - limb_t __t = r0; \ - r0 += (a0); \ - r1 += (a1) + (r0 < __t); \ - } while (0) - -#define subdq(r1, r0, a1, a0) \ - do { \ - limb_t __t = r0; \ - r0 -= (a0); \ - r1 -= (a1) + (r0 > __t); \ - } while (0) - -#if LIMB_BITS == 64 - -/* Note: we assume __int128 is available */ -#define muldq(r1, r0, a, b) \ - do { \ - unsigned __int128 __t; \ - __t = (unsigned __int128)(a) * (unsigned __int128)(b); \ - r0 = __t; \ - r1 = __t >> 64; \ - } while (0) - -#define divdq(q, r, a1, a0, b) \ - do { \ - unsigned __int128 __t; \ - limb_t __b = (b); \ - __t = ((unsigned __int128)(a1) << 64) | (a0); \ - q = __t / __b; \ - r = __t % __b; \ - } while (0) - -#else - -#define muldq(r1, r0, a, b) \ - do { \ - uint64_t __t; \ - __t = (uint64_t)(a) * (uint64_t)(b); \ - r0 = __t; \ - r1 = __t >> 32; \ - } while (0) - -#define divdq(q, r, a1, a0, b) \ - do { \ - uint64_t __t; \ - limb_t __b = (b); \ - __t = ((uint64_t)(a1) << 32) | (a0); \ - q = __t / __b; \ - r = __t % __b; \ - } while (0) - -#endif /* LIMB_BITS != 64 */ - -static inline __maybe_unused limb_t shrd(limb_t low, limb_t high, long shift) -{ - if (shift != 0) - low = (low >> shift) | (high << (LIMB_BITS - shift)); - return low; -} - -static inline __maybe_unused limb_t shld(limb_t a1, limb_t a0, long shift) -{ - if (shift != 0) - return (a1 << shift) | (a0 >> (LIMB_BITS - shift)); - else - return a1; -} - -#if LIMB_DIGITS == 19 - -/* WARNING: hardcoded for b = 1e19. It is assumed that: - 0 <= a1 < 2^63 */ -#define divdq_base(q, r, a1, a0)\ -do {\ - uint64_t __a0, __a1, __t0, __t1, __b = BF_DEC_BASE; \ - __a0 = a0;\ - __a1 = a1;\ - __t0 = __a1;\ - __t0 = shld(__t0, __a0, 1);\ - muldq(q, __t1, __t0, UINT64_C(17014118346046923173)); \ - muldq(__t1, __t0, q, __b);\ - subdq(__a1, __a0, __t1, __t0);\ - subdq(__a1, __a0, 1, __b * 2); \ - __t0 = (slimb_t)__a1 >> 1; \ - q += 2 + __t0;\ - adddq(__a1, __a0, 0, __b & __t0);\ - q += __a1; \ - __a0 += __b & __a1; \ - r = __a0;\ -} while(0) - -#elif LIMB_DIGITS == 9 - -/* WARNING: hardcoded for b = 1e9. It is assumed that: - 0 <= a1 < 2^29 */ -#define divdq_base(q, r, a1, a0)\ -do {\ - uint32_t __t0, __t1, __b = BF_DEC_BASE; \ - __t0 = a1;\ - __t1 = a0;\ - __t0 = (__t0 << 3) | (__t1 >> (32 - 3)); \ - muldq(q, __t1, __t0, 2305843009U);\ - r = a0 - q * __b;\ - __t1 = (r >= __b);\ - q += __t1;\ - if (__t1)\ - r -= __b;\ -} while(0) - -#endif - -/* fast integer division by a fixed constant */ - -typedef struct FastDivData { - limb_t m1; /* multiplier */ - int8_t shift1; - int8_t shift2; -} FastDivData; - -/* From "Division by Invariant Integers using Multiplication" by - Torborn Granlund and Peter L. Montgomery */ -/* d must be != 0 */ -static inline __maybe_unused void fast_udiv_init(FastDivData *s, limb_t d) -{ - int l; - limb_t q, r, m1; - if (d == 1) - l = 0; - else - l = 64 - clz64(d - 1); - divdq(q, r, ((limb_t)1 << l) - d, 0, d); - (void)r; - m1 = q + 1; - // printf("d=%lu l=%d m1=0x%016lx\n", d, l, m1); - s->m1 = m1; - s->shift1 = l; - if (s->shift1 > 1) - s->shift1 = 1; - s->shift2 = l - 1; - if (s->shift2 < 0) - s->shift2 = 0; -} - -static inline limb_t fast_udiv(limb_t a, const FastDivData *s) -{ - limb_t t0, t1; - muldq(t1, t0, s->m1, a); - t0 = (a - t1) >> s->shift1; - return (t1 + t0) >> s->shift2; -} - -/* contains 10^i */ -const limb_t mp_pow_dec[LIMB_DIGITS + 1] = { - 1U, - 10U, - 100U, - 1000U, - 10000U, - 100000U, - 1000000U, - 10000000U, - 100000000U, - 1000000000U, -#if LIMB_BITS == 64 - 10000000000U, - 100000000000U, - 1000000000000U, - 10000000000000U, - 100000000000000U, - 1000000000000000U, - 10000000000000000U, - 100000000000000000U, - 1000000000000000000U, - 10000000000000000000U, -#endif -}; - -/* precomputed from fast_udiv_init(10^i) */ -static const FastDivData mp_pow_div[LIMB_DIGITS + 1] = { -#if LIMB_BITS == 32 - { 0x00000001, 0, 0 }, - { 0x9999999a, 1, 3 }, - { 0x47ae147b, 1, 6 }, - { 0x0624dd30, 1, 9 }, - { 0xa36e2eb2, 1, 13 }, - { 0x4f8b588f, 1, 16 }, - { 0x0c6f7a0c, 1, 19 }, - { 0xad7f29ac, 1, 23 }, - { 0x5798ee24, 1, 26 }, - { 0x12e0be83, 1, 29 }, -#else - { 0x0000000000000001, 0, 0 }, - { 0x999999999999999a, 1, 3 }, - { 0x47ae147ae147ae15, 1, 6 }, - { 0x0624dd2f1a9fbe77, 1, 9 }, - { 0xa36e2eb1c432ca58, 1, 13 }, - { 0x4f8b588e368f0847, 1, 16 }, - { 0x0c6f7a0b5ed8d36c, 1, 19 }, - { 0xad7f29abcaf48579, 1, 23 }, - { 0x5798ee2308c39dfa, 1, 26 }, - { 0x12e0be826d694b2f, 1, 29 }, - { 0xb7cdfd9d7bdbab7e, 1, 33 }, - { 0x5fd7fe17964955fe, 1, 36 }, - { 0x19799812dea11198, 1, 39 }, - { 0xc25c268497681c27, 1, 43 }, - { 0x6849b86a12b9b01f, 1, 46 }, - { 0x203af9ee756159b3, 1, 49 }, - { 0xcd2b297d889bc2b7, 1, 53 }, - { 0x70ef54646d496893, 1, 56 }, - { 0x2725dd1d243aba0f, 1, 59 }, - { 0xd83c94fb6d2ac34d, 1, 63 }, -#endif -}; - -/* divide by 10^shift with 0 <= shift <= LIMB_DIGITS */ -static inline limb_t fast_shr_dec(limb_t a, int shift) -{ - return fast_udiv(a, &mp_pow_div[shift]); -} - -/* division and remainder by 10^shift */ -#define fast_shr_rem_dec(q, r, a, shift) q = fast_shr_dec(a, shift), r = a - q * mp_pow_dec[shift] - -limb_t mp_add_dec(limb_t *res, const limb_t *op1, const limb_t *op2, - mp_size_t n, limb_t carry) -{ - limb_t base = BF_DEC_BASE; - mp_size_t i; - limb_t k, a, v; - - k=carry; - for(i=0;i v; - if (k) - a += base; - res[i] = a; - } - return k; -} - -limb_t mp_sub_ui_dec(limb_t *tab, limb_t b, mp_size_t n) -{ - limb_t base = BF_DEC_BASE; - mp_size_t i; - limb_t k, v, a; - - k=b; - for(i=0;i v; - if (k) - a += base; - tab[i]=a; - if (k == 0) - break; - } - return k; -} - -/* taba[] = taba[] * b + l. 0 <= b, l <= base - 1. Return the high carry */ -limb_t mp_mul1_dec(limb_t *tabr, const limb_t *taba, mp_size_t n, - limb_t b, limb_t l) -{ - mp_size_t i; - limb_t t0, t1, r; - - for(i = 0; i < n; i++) { - muldq(t1, t0, taba[i], b); - adddq(t1, t0, 0, l); - divdq_base(l, r, t1, t0); - tabr[i] = r; - } - return l; -} - -/* tabr[] += taba[] * b. 0 <= b <= base - 1. Return the value to add - to the high word */ -limb_t mp_add_mul1_dec(limb_t *tabr, const limb_t *taba, mp_size_t n, - limb_t b) -{ - mp_size_t i; - limb_t l, t0, t1, r; - - l = 0; - for(i = 0; i < n; i++) { - muldq(t1, t0, taba[i], b); - adddq(t1, t0, 0, l); - adddq(t1, t0, 0, tabr[i]); - divdq_base(l, r, t1, t0); - tabr[i] = r; - } - return l; -} - -/* tabr[] -= taba[] * b. 0 <= b <= base - 1. Return the value to - substract to the high word. */ -limb_t mp_sub_mul1_dec(limb_t *tabr, const limb_t *taba, mp_size_t n, - limb_t b) -{ - limb_t base = BF_DEC_BASE; - mp_size_t i; - limb_t l, t0, t1, r, a, v, c; - - /* XXX: optimize */ - l = 0; - for(i = 0; i < n; i++) { - muldq(t1, t0, taba[i], b); - adddq(t1, t0, 0, l); - divdq_base(l, r, t1, t0); - v = tabr[i]; - a = v - r; - c = a > v; - if (c) - a += base; - /* never bigger than base because r = 0 when l = base - 1 */ - l += c; - tabr[i] = a; - } - return l; -} - -/* size of the result : op1_size + op2_size. */ -void mp_mul_basecase_dec(limb_t *result, - const limb_t *op1, mp_size_t op1_size, - const limb_t *op2, mp_size_t op2_size) -{ - mp_size_t i; - limb_t r; - - result[op1_size] = mp_mul1_dec(result, op1, op1_size, op2[0], 0); - - for(i=1;i> 1; - if (r) - r = base_div2; - for(i = na - 1; i >= 0; i--) { - t0 = taba[i]; - tabr[i] = (t0 >> 1) + r; - r = 0; - if (t0 & 1) - r = base_div2; - } - if (r) - r = 1; - } else -#endif - if (na >= UDIV1NORM_THRESHOLD) { - shift = clz(b); - if (shift == 0) { - /* normalized case: b >= 2^(LIMB_BITS-1) */ - limb_t b_inv; - b_inv = udiv1norm_init(b); - for(i = na - 1; i >= 0; i--) { - muldq(t1, t0, r, base); - adddq(t1, t0, 0, taba[i]); - q = udiv1norm(&r, t1, t0, b, b_inv); - tabr[i] = q; - } - } else { - limb_t b_inv; - b <<= shift; - b_inv = udiv1norm_init(b); - for(i = na - 1; i >= 0; i--) { - muldq(t1, t0, r, base); - adddq(t1, t0, 0, taba[i]); - t1 = (t1 << shift) | (t0 >> (LIMB_BITS - shift)); - t0 <<= shift; - q = udiv1norm(&r, t1, t0, b, b_inv); - r >>= shift; - tabr[i] = q; - } - } - } else { - for(i = na - 1; i >= 0; i--) { - muldq(t1, t0, r, base); - adddq(t1, t0, 0, taba[i]); - divdq(q, r, t1, t0, b); - tabr[i] = q; - } - } - return r; -} - -static __maybe_unused void mp_print_str_dec(const char *str, - const limb_t *tab, slimb_t n) -{ - slimb_t i; - printf("%s=", str); - for(i = n - 1; i >= 0; i--) { - if (i != n - 1) - printf("_"); - printf("%0*" PRIu_LIMB, LIMB_DIGITS, tab[i]); - } - printf("\n"); -} - -static __maybe_unused void mp_print_str_h_dec(const char *str, - const limb_t *tab, slimb_t n, - limb_t high) -{ - slimb_t i; - printf("%s=", str); - printf("%0*" PRIu_LIMB, LIMB_DIGITS, high); - for(i = n - 1; i >= 0; i--) { - printf("_"); - printf("%0*" PRIu_LIMB, LIMB_DIGITS, tab[i]); - } - printf("\n"); -} - -//#define DEBUG_DIV_SLOW - -#define DIV_STATIC_ALLOC_LEN 16 - -/* return q = a / b and r = a % b. - - taba[na] must be allocated if tabb1[nb - 1] < B / 2. tabb1[nb - 1] - must be != zero. na must be >= nb. 's' can be NULL if tabb1[nb - 1] - >= B / 2. - - The remainder is is returned in taba and contains nb libms. tabq - contains na - nb + 1 limbs. No overlap is permitted. - - Running time of the standard method: (na - nb + 1) * nb - Return 0 if OK, -1 if memory alloc error -*/ -/* XXX: optimize */ -static int mp_div_dec(bf_context_t *s, limb_t *tabq, - limb_t *taba, mp_size_t na, - const limb_t *tabb1, mp_size_t nb) -{ - limb_t base = BF_DEC_BASE; - limb_t r, mult, t0, t1, a, c, q, v, *tabb; - mp_size_t i, j; - limb_t static_tabb[DIV_STATIC_ALLOC_LEN]; - -#ifdef DEBUG_DIV_SLOW - mp_print_str_dec("a", taba, na); - mp_print_str_dec("b", tabb1, nb); -#endif - - /* normalize tabb */ - r = tabb1[nb - 1]; - assert(r != 0); - i = na - nb; - if (r >= BF_DEC_BASE / 2) { - mult = 1; - tabb = (limb_t *)tabb1; - q = 1; - for(j = nb - 1; j >= 0; j--) { - if (taba[i + j] != tabb[j]) { - if (taba[i + j] < tabb[j]) - q = 0; - break; - } - } - tabq[i] = q; - if (q) { - mp_sub_dec(taba + i, taba + i, tabb, nb, 0); - } - i--; - } else { - mult = base / (r + 1); - if (LIKELY(nb <= DIV_STATIC_ALLOC_LEN)) { - tabb = static_tabb; - } else { - tabb = bf_malloc(s, sizeof(limb_t) * nb); - if (!tabb) - return -1; - } - mp_mul1_dec(tabb, tabb1, nb, mult, 0); - taba[na] = mp_mul1_dec(taba, taba, na, mult, 0); - } - -#ifdef DEBUG_DIV_SLOW - printf("mult=" FMT_LIMB "\n", mult); - mp_print_str_dec("a_norm", taba, na + 1); - mp_print_str_dec("b_norm", tabb, nb); -#endif - - for(; i >= 0; i--) { - if (UNLIKELY(taba[i + nb] >= tabb[nb - 1])) { - /* XXX: check if it is really possible */ - q = base - 1; - } else { - muldq(t1, t0, taba[i + nb], base); - adddq(t1, t0, 0, taba[i + nb - 1]); - divdq(q, r, t1, t0, tabb[nb - 1]); - } - // printf("i=%d q1=%ld\n", i, q); - - r = mp_sub_mul1_dec(taba + i, tabb, nb, q); - // mp_dump("r1", taba + i, nb, bd); - // printf("r2=%ld\n", r); - - v = taba[i + nb]; - a = v - r; - c = a > v; - if (c) - a += base; - taba[i + nb] = a; - - if (c != 0) { - /* negative result */ - for(;;) { - q--; - c = mp_add_dec(taba + i, taba + i, tabb, nb, 0); - /* propagate carry and test if positive result */ - if (c != 0) { - if (++taba[i + nb] == base) { - break; - } - } - } - } - tabq[i] = q; - } - -#ifdef DEBUG_DIV_SLOW - mp_print_str_dec("q", tabq, na - nb + 1); - mp_print_str_dec("r", taba, nb); -#endif - - /* remove the normalization */ - if (mult != 1) { - mp_div1_dec(taba, taba, nb, mult, 0); - if (UNLIKELY(tabb != static_tabb)) - bf_free(s, tabb); - } - return 0; -} - -/* divide by 10^shift */ -static limb_t mp_shr_dec(limb_t *tab_r, const limb_t *tab, mp_size_t n, - limb_t shift, limb_t high) -{ - mp_size_t i; - limb_t l, a, q, r; - - assert(shift >= 1 && shift < LIMB_DIGITS); - l = high; - for(i = n - 1; i >= 0; i--) { - a = tab[i]; - fast_shr_rem_dec(q, r, a, shift); - tab_r[i] = q + l * mp_pow_dec[LIMB_DIGITS - shift]; - l = r; - } - return l; -} - -/* multiply by 10^shift */ -static limb_t mp_shl_dec(limb_t *tab_r, const limb_t *tab, mp_size_t n, - limb_t shift, limb_t low) -{ - mp_size_t i; - limb_t l, a, q, r; - - assert(shift >= 1 && shift < LIMB_DIGITS); - l = low; - for(i = 0; i < n; i++) { - a = tab[i]; - fast_shr_rem_dec(q, r, a, LIMB_DIGITS - shift); - tab_r[i] = r * mp_pow_dec[shift] + l; - l = q; - } - return l; -} - -static limb_t mp_sqrtrem2_dec(limb_t *tabs, limb_t *taba) -{ - int k; - dlimb_t a, b, r; - limb_t taba1[2], s, r0, r1; - - /* convert to binary and normalize */ - a = (dlimb_t)taba[1] * BF_DEC_BASE + taba[0]; - k = clz(a >> LIMB_BITS) & ~1; - b = a << k; - taba1[0] = b; - taba1[1] = b >> LIMB_BITS; - mp_sqrtrem2(&s, taba1); - s >>= (k >> 1); - /* convert the remainder back to decimal */ - r = a - (dlimb_t)s * (dlimb_t)s; - divdq_base(r1, r0, r >> LIMB_BITS, r); - taba[0] = r0; - tabs[0] = s; - return r1; -} - -//#define DEBUG_SQRTREM_DEC - -/* tmp_buf must contain (n / 2 + 1 limbs) */ -static limb_t mp_sqrtrem_rec_dec(limb_t *tabs, limb_t *taba, limb_t n, - limb_t *tmp_buf) -{ - limb_t l, h, rh, ql, qh, c, i; - - if (n == 1) - return mp_sqrtrem2_dec(tabs, taba); -#ifdef DEBUG_SQRTREM_DEC - mp_print_str_dec("a", taba, 2 * n); -#endif - l = n / 2; - h = n - l; - qh = mp_sqrtrem_rec_dec(tabs + l, taba + 2 * l, h, tmp_buf); -#ifdef DEBUG_SQRTREM_DEC - mp_print_str_dec("s1", tabs + l, h); - mp_print_str_h_dec("r1", taba + 2 * l, h, qh); - mp_print_str_h_dec("r2", taba + l, n, qh); -#endif - - /* the remainder is in taba + 2 * l. Its high bit is in qh */ - if (qh) { - mp_sub_dec(taba + 2 * l, taba + 2 * l, tabs + l, h, 0); - } - /* instead of dividing by 2*s, divide by s (which is normalized) - and update q and r */ - mp_div_dec(NULL, tmp_buf, taba + l, n, tabs + l, h); - qh += tmp_buf[l]; - for(i = 0; i < l; i++) - tabs[i] = tmp_buf[i]; - ql = mp_div1_dec(tabs, tabs, l, 2, qh & 1); - qh = qh >> 1; /* 0 or 1 */ - if (ql) - rh = mp_add_dec(taba + l, taba + l, tabs + l, h, 0); - else - rh = 0; -#ifdef DEBUG_SQRTREM_DEC - mp_print_str_h_dec("q", tabs, l, qh); - mp_print_str_h_dec("u", taba + l, h, rh); -#endif - - mp_add_ui_dec(tabs + l, qh, h); -#ifdef DEBUG_SQRTREM_DEC - mp_print_str_dec("s2", tabs, n); -#endif - - /* q = qh, tabs[l - 1 ... 0], r = taba[n - 1 ... l] */ - /* subtract q^2. if qh = 1 then q = B^l, so we can take shortcuts */ - if (qh) { - c = qh; - } else { - mp_mul_basecase_dec(taba + n, tabs, l, tabs, l); - c = mp_sub_dec(taba, taba, taba + n, 2 * l, 0); - } - rh -= mp_sub_ui_dec(taba + 2 * l, c, n - 2 * l); - if ((slimb_t)rh < 0) { - mp_sub_ui_dec(tabs, 1, n); - rh += mp_add_mul1_dec(taba, tabs, n, 2); - rh += mp_add_ui_dec(taba, 1, n); - } - return rh; -} - -/* 'taba' has 2*n limbs with n >= 1 and taba[2*n-1] >= B/4. Return (s, - r) with s=floor(sqrt(a)) and r=a-s^2. 0 <= r <= 2 * s. tabs has n - limbs. r is returned in the lower n limbs of taba. Its r[n] is the - returned value of the function. */ -int mp_sqrtrem_dec(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n) -{ - limb_t tmp_buf1[8]; - limb_t *tmp_buf; - mp_size_t n2; - n2 = n / 2 + 1; - if (n2 <= countof(tmp_buf1)) { - tmp_buf = tmp_buf1; - } else { - tmp_buf = bf_malloc(s, sizeof(limb_t) * n2); - if (!tmp_buf) - return -1; - } - taba[n] = mp_sqrtrem_rec_dec(tabs, taba, n, tmp_buf); - if (tmp_buf != tmp_buf1) - bf_free(s, tmp_buf); - return 0; -} - -/* return the number of leading zero digits, from 0 to LIMB_DIGITS */ -static int clz_dec(limb_t a) -{ - if (a == 0) - return LIMB_DIGITS; - switch(LIMB_BITS - 1 - clz(a)) { - case 0: /* 1-1 */ - return LIMB_DIGITS - 1; - case 1: /* 2-3 */ - return LIMB_DIGITS - 1; - case 2: /* 4-7 */ - return LIMB_DIGITS - 1; - case 3: /* 8-15 */ - if (a < 10) - return LIMB_DIGITS - 1; - else - return LIMB_DIGITS - 2; - case 4: /* 16-31 */ - return LIMB_DIGITS - 2; - case 5: /* 32-63 */ - return LIMB_DIGITS - 2; - case 6: /* 64-127 */ - if (a < 100) - return LIMB_DIGITS - 2; - else - return LIMB_DIGITS - 3; - case 7: /* 128-255 */ - return LIMB_DIGITS - 3; - case 8: /* 256-511 */ - return LIMB_DIGITS - 3; - case 9: /* 512-1023 */ - if (a < 1000) - return LIMB_DIGITS - 3; - else - return LIMB_DIGITS - 4; - case 10: /* 1024-2047 */ - return LIMB_DIGITS - 4; - case 11: /* 2048-4095 */ - return LIMB_DIGITS - 4; - case 12: /* 4096-8191 */ - return LIMB_DIGITS - 4; - case 13: /* 8192-16383 */ - if (a < 10000) - return LIMB_DIGITS - 4; - else - return LIMB_DIGITS - 5; - case 14: /* 16384-32767 */ - return LIMB_DIGITS - 5; - case 15: /* 32768-65535 */ - return LIMB_DIGITS - 5; - case 16: /* 65536-131071 */ - if (a < 100000) - return LIMB_DIGITS - 5; - else - return LIMB_DIGITS - 6; - case 17: /* 131072-262143 */ - return LIMB_DIGITS - 6; - case 18: /* 262144-524287 */ - return LIMB_DIGITS - 6; - case 19: /* 524288-1048575 */ - if (a < 1000000) - return LIMB_DIGITS - 6; - else - return LIMB_DIGITS - 7; - case 20: /* 1048576-2097151 */ - return LIMB_DIGITS - 7; - case 21: /* 2097152-4194303 */ - return LIMB_DIGITS - 7; - case 22: /* 4194304-8388607 */ - return LIMB_DIGITS - 7; - case 23: /* 8388608-16777215 */ - if (a < 10000000) - return LIMB_DIGITS - 7; - else - return LIMB_DIGITS - 8; - case 24: /* 16777216-33554431 */ - return LIMB_DIGITS - 8; - case 25: /* 33554432-67108863 */ - return LIMB_DIGITS - 8; - case 26: /* 67108864-134217727 */ - if (a < 100000000) - return LIMB_DIGITS - 8; - else - return LIMB_DIGITS - 9; -#if LIMB_BITS == 64 - case 27: /* 134217728-268435455 */ - return LIMB_DIGITS - 9; - case 28: /* 268435456-536870911 */ - return LIMB_DIGITS - 9; - case 29: /* 536870912-1073741823 */ - if (a < 1000000000) - return LIMB_DIGITS - 9; - else - return LIMB_DIGITS - 10; - case 30: /* 1073741824-2147483647 */ - return LIMB_DIGITS - 10; - case 31: /* 2147483648-4294967295 */ - return LIMB_DIGITS - 10; - case 32: /* 4294967296-8589934591 */ - return LIMB_DIGITS - 10; - case 33: /* 8589934592-17179869183 */ - if (a < 10000000000) - return LIMB_DIGITS - 10; - else - return LIMB_DIGITS - 11; - case 34: /* 17179869184-34359738367 */ - return LIMB_DIGITS - 11; - case 35: /* 34359738368-68719476735 */ - return LIMB_DIGITS - 11; - case 36: /* 68719476736-137438953471 */ - if (a < 100000000000) - return LIMB_DIGITS - 11; - else - return LIMB_DIGITS - 12; - case 37: /* 137438953472-274877906943 */ - return LIMB_DIGITS - 12; - case 38: /* 274877906944-549755813887 */ - return LIMB_DIGITS - 12; - case 39: /* 549755813888-1099511627775 */ - if (a < 1000000000000) - return LIMB_DIGITS - 12; - else - return LIMB_DIGITS - 13; - case 40: /* 1099511627776-2199023255551 */ - return LIMB_DIGITS - 13; - case 41: /* 2199023255552-4398046511103 */ - return LIMB_DIGITS - 13; - case 42: /* 4398046511104-8796093022207 */ - return LIMB_DIGITS - 13; - case 43: /* 8796093022208-17592186044415 */ - if (a < 10000000000000) - return LIMB_DIGITS - 13; - else - return LIMB_DIGITS - 14; - case 44: /* 17592186044416-35184372088831 */ - return LIMB_DIGITS - 14; - case 45: /* 35184372088832-70368744177663 */ - return LIMB_DIGITS - 14; - case 46: /* 70368744177664-140737488355327 */ - if (a < 100000000000000) - return LIMB_DIGITS - 14; - else - return LIMB_DIGITS - 15; - case 47: /* 140737488355328-281474976710655 */ - return LIMB_DIGITS - 15; - case 48: /* 281474976710656-562949953421311 */ - return LIMB_DIGITS - 15; - case 49: /* 562949953421312-1125899906842623 */ - if (a < 1000000000000000) - return LIMB_DIGITS - 15; - else - return LIMB_DIGITS - 16; - case 50: /* 1125899906842624-2251799813685247 */ - return LIMB_DIGITS - 16; - case 51: /* 2251799813685248-4503599627370495 */ - return LIMB_DIGITS - 16; - case 52: /* 4503599627370496-9007199254740991 */ - return LIMB_DIGITS - 16; - case 53: /* 9007199254740992-18014398509481983 */ - if (a < 10000000000000000) - return LIMB_DIGITS - 16; - else - return LIMB_DIGITS - 17; - case 54: /* 18014398509481984-36028797018963967 */ - return LIMB_DIGITS - 17; - case 55: /* 36028797018963968-72057594037927935 */ - return LIMB_DIGITS - 17; - case 56: /* 72057594037927936-144115188075855871 */ - if (a < 100000000000000000) - return LIMB_DIGITS - 17; - else - return LIMB_DIGITS - 18; - case 57: /* 144115188075855872-288230376151711743 */ - return LIMB_DIGITS - 18; - case 58: /* 288230376151711744-576460752303423487 */ - return LIMB_DIGITS - 18; - case 59: /* 576460752303423488-1152921504606846975 */ - if (a < 1000000000000000000) - return LIMB_DIGITS - 18; - else - return LIMB_DIGITS - 19; -#endif - default: - return 0; - } -} - -/* for debugging */ -void bfdec_print_str(const char *str, const bfdec_t *a) -{ - slimb_t i; - printf("%s=", str); - - if (a->expn == BF_EXP_NAN) { - printf("NaN"); - } else { - if (a->sign) - putchar('-'); - if (a->expn == BF_EXP_ZERO) { - putchar('0'); - } else if (a->expn == BF_EXP_INF) { - printf("Inf"); - } else { - printf("0."); - for(i = a->len - 1; i >= 0; i--) - printf("%0*" PRIu_LIMB, LIMB_DIGITS, a->tab[i]); - printf("e%" PRId_LIMB, a->expn); - } - } - printf("\n"); -} - -/* return != 0 if one digit between 0 and bit_pos inclusive is not zero. */ -static inline limb_t scan_digit_nz(const bfdec_t *r, slimb_t bit_pos) -{ - slimb_t pos; - limb_t v, q; - int shift; - - if (bit_pos < 0) - return 0; - pos = (limb_t)bit_pos / LIMB_DIGITS; - shift = (limb_t)bit_pos % LIMB_DIGITS; - fast_shr_rem_dec(q, v, r->tab[pos], shift + 1); - (void)q; - if (v != 0) - return 1; - pos--; - while (pos >= 0) { - if (r->tab[pos] != 0) - return 1; - pos--; - } - return 0; -} - -static limb_t get_digit(const limb_t *tab, limb_t len, slimb_t pos) -{ - slimb_t i; - int shift; - i = floor_div(pos, LIMB_DIGITS); - if (i < 0 || i >= len) - return 0; - shift = pos - i * LIMB_DIGITS; - return fast_shr_dec(tab[i], shift) % 10; -} - -#if 0 -static limb_t get_digits(const limb_t *tab, limb_t len, slimb_t pos) -{ - limb_t a0, a1; - int shift; - slimb_t i; - - i = floor_div(pos, LIMB_DIGITS); - shift = pos - i * LIMB_DIGITS; - if (i >= 0 && i < len) - a0 = tab[i]; - else - a0 = 0; - if (shift == 0) { - return a0; - } else { - i++; - if (i >= 0 && i < len) - a1 = tab[i]; - else - a1 = 0; - return fast_shr_dec(a0, shift) + - fast_urem(a1, &mp_pow_div[LIMB_DIGITS - shift]) * - mp_pow_dec[shift]; - } -} -#endif - -/* return the addend for rounding. Note that prec can be <= 0 for bf_rint() */ -static int bfdec_get_rnd_add(int *pret, const bfdec_t *r, limb_t l, - slimb_t prec, int rnd_mode) -{ - int add_one, inexact; - limb_t digit1, digit0; - - // bfdec_print_str("get_rnd_add", r); - if (rnd_mode == BF_RNDF) { - digit0 = 1; /* faithful rounding does not honor the INEXACT flag */ - } else { - /* starting limb for bit 'prec + 1' */ - digit0 = scan_digit_nz(r, l * LIMB_DIGITS - 1 - bf_max(0, prec + 1)); - } - - /* get the digit at 'prec' */ - digit1 = get_digit(r->tab, l, l * LIMB_DIGITS - 1 - prec); - inexact = (digit1 | digit0) != 0; - - add_one = 0; - switch(rnd_mode) { - case BF_RNDZ: - break; - case BF_RNDN: - if (digit1 == 5) { - if (digit0) { - add_one = 1; - } else { - /* round to even */ - add_one = - get_digit(r->tab, l, l * LIMB_DIGITS - 1 - (prec - 1)) & 1; - } - } else if (digit1 > 5) { - add_one = 1; - } - break; - case BF_RNDD: - case BF_RNDU: - if (r->sign == (rnd_mode == BF_RNDD)) - add_one = inexact; - break; - case BF_RNDNA: - case BF_RNDF: - add_one = (digit1 >= 5); - break; - case BF_RNDA: - add_one = inexact; - break; - default: - abort(); - } - - if (inexact) - *pret |= BF_ST_INEXACT; - return add_one; -} - -/* round to prec1 bits assuming 'r' is non zero and finite. 'r' is - assumed to have length 'l' (1 <= l <= r->len). prec1 can be - BF_PREC_INF. BF_FLAG_SUBNORMAL is not supported. Cannot fail with - BF_ST_MEM_ERROR. - */ -static int __bfdec_round(bfdec_t *r, limb_t prec1, bf_flags_t flags, limb_t l) -{ - int shift, add_one, rnd_mode, ret; - slimb_t i, bit_pos, pos, e_min, e_max, e_range, prec; - - /* XXX: align to IEEE 754 2008 for decimal numbers ? */ - e_range = (limb_t)1 << (bf_get_exp_bits(flags) - 1); - e_min = -e_range + 3; - e_max = e_range; - - if (flags & BF_FLAG_RADPNT_PREC) { - /* 'prec' is the precision after the decimal point */ - if (prec1 != BF_PREC_INF) - prec = r->expn + prec1; - else - prec = prec1; - } else if (UNLIKELY(r->expn < e_min) && (flags & BF_FLAG_SUBNORMAL)) { - /* restrict the precision in case of potentially subnormal - result */ - assert(prec1 != BF_PREC_INF); - prec = prec1 - (e_min - r->expn); - } else { - prec = prec1; - } - - /* round to prec bits */ - rnd_mode = flags & BF_RND_MASK; - ret = 0; - add_one = bfdec_get_rnd_add(&ret, r, l, prec, rnd_mode); - - if (prec <= 0) { - if (add_one) { - bfdec_resize(r, 1); /* cannot fail because r is non zero */ - r->tab[0] = BF_DEC_BASE / 10; - r->expn += 1 - prec; - ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT; - return ret; - } else { - goto underflow; - } - } else if (add_one) { - limb_t carry; - - /* add one starting at digit 'prec - 1' */ - bit_pos = l * LIMB_DIGITS - 1 - (prec - 1); - pos = bit_pos / LIMB_DIGITS; - carry = mp_pow_dec[bit_pos % LIMB_DIGITS]; - carry = mp_add_ui_dec(r->tab + pos, carry, l - pos); - if (carry) { - /* shift right by one digit */ - mp_shr_dec(r->tab + pos, r->tab + pos, l - pos, 1, 1); - r->expn++; - } - } - - /* check underflow */ - if (UNLIKELY(r->expn < e_min)) { - if (flags & BF_FLAG_SUBNORMAL) { - /* if inexact, also set the underflow flag */ - if (ret & BF_ST_INEXACT) - ret |= BF_ST_UNDERFLOW; - } else { - underflow: - bfdec_set_zero(r, r->sign); - ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT; - return ret; - } - } - - /* check overflow */ - if (UNLIKELY(r->expn > e_max)) { - bfdec_set_inf(r, r->sign); - ret |= BF_ST_OVERFLOW | BF_ST_INEXACT; - return ret; - } - - /* keep the bits starting at 'prec - 1' */ - bit_pos = l * LIMB_DIGITS - 1 - (prec - 1); - i = floor_div(bit_pos, LIMB_DIGITS); - if (i >= 0) { - shift = smod(bit_pos, LIMB_DIGITS); - if (shift != 0) { - r->tab[i] = fast_shr_dec(r->tab[i], shift) * - mp_pow_dec[shift]; - } - } else { - i = 0; - } - /* remove trailing zeros */ - while (r->tab[i] == 0) - i++; - if (i > 0) { - l -= i; - memmove(r->tab, r->tab + i, l * sizeof(limb_t)); - } - bfdec_resize(r, l); /* cannot fail */ - return ret; -} - -/* Cannot fail with BF_ST_MEM_ERROR. */ -int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags) -{ - if (r->len == 0) - return 0; - return __bfdec_round(r, prec, flags, r->len); -} - -/* 'r' must be a finite number. Cannot fail with BF_ST_MEM_ERROR. */ -int bfdec_normalize_and_round(bfdec_t *r, limb_t prec1, bf_flags_t flags) -{ - limb_t l, v; - int shift, ret; - - // bfdec_print_str("bf_renorm", r); - l = r->len; - while (l > 0 && r->tab[l - 1] == 0) - l--; - if (l == 0) { - /* zero */ - r->expn = BF_EXP_ZERO; - bfdec_resize(r, 0); /* cannot fail */ - ret = 0; - } else { - r->expn -= (r->len - l) * LIMB_DIGITS; - /* shift to have the MSB set to '1' */ - v = r->tab[l - 1]; - shift = clz_dec(v); - if (shift != 0) { - mp_shl_dec(r->tab, r->tab, l, shift, 0); - r->expn -= shift; - } - ret = __bfdec_round(r, prec1, flags, l); - } - // bf_print_str("r_final", r); - return ret; -} - -int bfdec_set_ui(bfdec_t *r, uint64_t v) -{ -#if LIMB_BITS == 32 - if (v >= BF_DEC_BASE * BF_DEC_BASE) { - if (bfdec_resize(r, 3)) - goto fail; - r->tab[0] = v % BF_DEC_BASE; - v /= BF_DEC_BASE; - r->tab[1] = v % BF_DEC_BASE; - r->tab[2] = v / BF_DEC_BASE; - r->expn = 3 * LIMB_DIGITS; - } else -#endif - if (v >= BF_DEC_BASE) { - if (bfdec_resize(r, 2)) - goto fail; - r->tab[0] = v % BF_DEC_BASE; - r->tab[1] = v / BF_DEC_BASE; - r->expn = 2 * LIMB_DIGITS; - } else { - if (bfdec_resize(r, 1)) - goto fail; - r->tab[0] = v; - r->expn = LIMB_DIGITS; - } - r->sign = 0; - return bfdec_normalize_and_round(r, BF_PREC_INF, 0); - fail: - bfdec_set_nan(r); - return BF_ST_MEM_ERROR; -} - -int bfdec_set_si(bfdec_t *r, int64_t v) -{ - int ret; - if (v < 0) { - ret = bfdec_set_ui(r, -v); - r->sign = 1; - } else { - ret = bfdec_set_ui(r, v); - } - return ret; -} - -static int bfdec_add_internal(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, bf_flags_t flags, int b_neg) -{ - bf_context_t *s = r->ctx; - int is_sub, cmp_res, a_sign, b_sign, ret; - - a_sign = a->sign; - b_sign = b->sign ^ b_neg; - is_sub = a_sign ^ b_sign; - cmp_res = bfdec_cmpu(a, b); - if (cmp_res < 0) { - const bfdec_t *tmp; - tmp = a; - a = b; - b = tmp; - a_sign = b_sign; /* b_sign is never used later */ - } - /* abs(a) >= abs(b) */ - if (cmp_res == 0 && is_sub && a->expn < BF_EXP_INF) { - /* zero result */ - bfdec_set_zero(r, (flags & BF_RND_MASK) == BF_RNDD); - ret = 0; - } else if (a->len == 0 || b->len == 0) { - ret = 0; - if (a->expn >= BF_EXP_INF) { - if (a->expn == BF_EXP_NAN) { - /* at least one operand is NaN */ - bfdec_set_nan(r); - ret = 0; - } else if (b->expn == BF_EXP_INF && is_sub) { - /* infinities with different signs */ - bfdec_set_nan(r); - ret = BF_ST_INVALID_OP; - } else { - bfdec_set_inf(r, a_sign); - } - } else { - /* at least one zero and not subtract */ - if (bfdec_set(r, a)) - return BF_ST_MEM_ERROR; - r->sign = a_sign; - goto renorm; - } - } else { - slimb_t d, a_offset, b_offset, i, r_len; - limb_t carry; - limb_t *b1_tab; - int b_shift; - mp_size_t b1_len; - - d = a->expn - b->expn; - - /* XXX: not efficient in time and memory if the precision is - not infinite */ - r_len = bf_max(a->len, b->len + (d + LIMB_DIGITS - 1) / LIMB_DIGITS); - if (bfdec_resize(r, r_len)) - goto fail; - r->sign = a_sign; - r->expn = a->expn; - - a_offset = r_len - a->len; - for(i = 0; i < a_offset; i++) - r->tab[i] = 0; - for(i = 0; i < a->len; i++) - r->tab[a_offset + i] = a->tab[i]; - - b_shift = d % LIMB_DIGITS; - if (b_shift == 0) { - b1_len = b->len; - b1_tab = (limb_t *)b->tab; - } else { - b1_len = b->len + 1; - b1_tab = bf_malloc(s, sizeof(limb_t) * b1_len); - if (!b1_tab) - goto fail; - b1_tab[0] = mp_shr_dec(b1_tab + 1, b->tab, b->len, b_shift, 0) * - mp_pow_dec[LIMB_DIGITS - b_shift]; - } - b_offset = r_len - (b->len + (d + LIMB_DIGITS - 1) / LIMB_DIGITS); - - if (is_sub) { - carry = mp_sub_dec(r->tab + b_offset, r->tab + b_offset, - b1_tab, b1_len, 0); - if (carry != 0) { - carry = mp_sub_ui_dec(r->tab + b_offset + b1_len, carry, - r_len - (b_offset + b1_len)); - assert(carry == 0); - } - } else { - carry = mp_add_dec(r->tab + b_offset, r->tab + b_offset, - b1_tab, b1_len, 0); - if (carry != 0) { - carry = mp_add_ui_dec(r->tab + b_offset + b1_len, carry, - r_len - (b_offset + b1_len)); - } - if (carry != 0) { - if (bfdec_resize(r, r_len + 1)) { - if (b_shift != 0) - bf_free(s, b1_tab); - goto fail; - } - r->tab[r_len] = 1; - r->expn += LIMB_DIGITS; - } - } - if (b_shift != 0) - bf_free(s, b1_tab); - renorm: - ret = bfdec_normalize_and_round(r, prec, flags); - } - return ret; - fail: - bfdec_set_nan(r); - return BF_ST_MEM_ERROR; -} - -static int __bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, - bf_flags_t flags) -{ - return bfdec_add_internal(r, a, b, prec, flags, 0); -} - -static int __bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, - bf_flags_t flags) -{ - return bfdec_add_internal(r, a, b, prec, flags, 1); -} - -int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, - bf_flags_t flags) -{ - return bf_op2((bf_t *)r, (bf_t *)a, (bf_t *)b, prec, flags, - (bf_op2_func_t *)__bfdec_add); -} - -int bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, - bf_flags_t flags) -{ - return bf_op2((bf_t *)r, (bf_t *)a, (bf_t *)b, prec, flags, - (bf_op2_func_t *)__bfdec_sub); -} - -int bfdec_mul(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, - bf_flags_t flags) -{ - int ret, r_sign; - - if (a->len < b->len) { - const bfdec_t *tmp = a; - a = b; - b = tmp; - } - r_sign = a->sign ^ b->sign; - /* here b->len <= a->len */ - if (b->len == 0) { - if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) { - bfdec_set_nan(r); - ret = 0; - } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_INF) { - if ((a->expn == BF_EXP_INF && b->expn == BF_EXP_ZERO) || - (a->expn == BF_EXP_ZERO && b->expn == BF_EXP_INF)) { - bfdec_set_nan(r); - ret = BF_ST_INVALID_OP; - } else { - bfdec_set_inf(r, r_sign); - ret = 0; - } - } else { - bfdec_set_zero(r, r_sign); - ret = 0; - } - } else { - bfdec_t tmp, *r1 = NULL; - limb_t a_len, b_len; - limb_t *a_tab, *b_tab; - - a_len = a->len; - b_len = b->len; - a_tab = a->tab; - b_tab = b->tab; - - if (r == a || r == b) { - bfdec_init(r->ctx, &tmp); - r1 = r; - r = &tmp; - } - if (bfdec_resize(r, a_len + b_len)) { - bfdec_set_nan(r); - ret = BF_ST_MEM_ERROR; - goto done; - } - mp_mul_basecase_dec(r->tab, a_tab, a_len, b_tab, b_len); - r->sign = r_sign; - r->expn = a->expn + b->expn; - ret = bfdec_normalize_and_round(r, prec, flags); - done: - if (r == &tmp) - bfdec_move(r1, &tmp); - } - return ret; -} - -int bfdec_mul_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec, - bf_flags_t flags) -{ - bfdec_t b; - int ret; - bfdec_init(r->ctx, &b); - ret = bfdec_set_si(&b, b1); - ret |= bfdec_mul(r, a, &b, prec, flags); - bfdec_delete(&b); - return ret; -} - -int bfdec_add_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec, - bf_flags_t flags) -{ - bfdec_t b; - int ret; - - bfdec_init(r->ctx, &b); - ret = bfdec_set_si(&b, b1); - ret |= bfdec_add(r, a, &b, prec, flags); - bfdec_delete(&b); - return ret; -} - -static int __bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, - limb_t prec, bf_flags_t flags) -{ - int ret, r_sign; - limb_t n, nb, precl; - - r_sign = a->sign ^ b->sign; - if (a->expn >= BF_EXP_INF || b->expn >= BF_EXP_INF) { - if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) { - bfdec_set_nan(r); - return 0; - } else if (a->expn == BF_EXP_INF && b->expn == BF_EXP_INF) { - bfdec_set_nan(r); - return BF_ST_INVALID_OP; - } else if (a->expn == BF_EXP_INF) { - bfdec_set_inf(r, r_sign); - return 0; - } else { - bfdec_set_zero(r, r_sign); - return 0; - } - } else if (a->expn == BF_EXP_ZERO) { - if (b->expn == BF_EXP_ZERO) { - bfdec_set_nan(r); - return BF_ST_INVALID_OP; - } else { - bfdec_set_zero(r, r_sign); - return 0; - } - } else if (b->expn == BF_EXP_ZERO) { - bfdec_set_inf(r, r_sign); - return BF_ST_DIVIDE_ZERO; - } - - nb = b->len; - if (prec == BF_PREC_INF) { - /* infinite precision: return BF_ST_INVALID_OP if not an exact - result */ - /* XXX: check */ - precl = nb + 1; - } else if (flags & BF_FLAG_RADPNT_PREC) { - /* number of digits after the decimal point */ - /* XXX: check (2 extra digits for rounding + 2 digits) */ - precl = (bf_max(a->expn - b->expn, 0) + 2 + - prec + 2 + LIMB_DIGITS - 1) / LIMB_DIGITS; - } else { - /* number of limbs of the quotient (2 extra digits for rounding) */ - precl = (prec + 2 + LIMB_DIGITS - 1) / LIMB_DIGITS; - } - n = bf_max(a->len, precl); - - { - limb_t *taba, na, i; - slimb_t d; - - na = n + nb; - taba = bf_malloc(r->ctx, (na + 1) * sizeof(limb_t)); - if (!taba) - goto fail; - d = na - a->len; - bzero(taba, d * sizeof(limb_t)); - memcpy(taba + d, a->tab, a->len * sizeof(limb_t)); - if (bfdec_resize(r, n + 1)) - goto fail1; - if (mp_div_dec(r->ctx, r->tab, taba, na, b->tab, nb)) { - fail1: - bf_free(r->ctx, taba); - goto fail; - } - /* see if non zero remainder */ - for(i = 0; i < nb; i++) { - if (taba[i] != 0) - break; - } - bf_free(r->ctx, taba); - if (i != nb) { - if (prec == BF_PREC_INF) { - bfdec_set_nan(r); - return BF_ST_INVALID_OP; - } else { - r->tab[0] |= 1; - } - } - r->expn = a->expn - b->expn + LIMB_DIGITS; - r->sign = r_sign; - ret = bfdec_normalize_and_round(r, prec, flags); - } - return ret; - fail: - bfdec_set_nan(r); - return BF_ST_MEM_ERROR; -} - -int bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, - bf_flags_t flags) -{ - return bf_op2((bf_t *)r, (bf_t *)a, (bf_t *)b, prec, flags, - (bf_op2_func_t *)__bfdec_div); -} - -/* a and b must be finite numbers with a >= 0 and b > 0. 'q' is the - integer defined as floor(a/b) and r = a - q * b. */ -static void bfdec_tdivremu(bf_context_t *s, bfdec_t *q, bfdec_t *r, - const bfdec_t *a, const bfdec_t *b) -{ - if (bfdec_cmpu(a, b) < 0) { - bfdec_set_ui(q, 0); - bfdec_set(r, a); - } else { - bfdec_div(q, a, b, 0, BF_RNDZ | BF_FLAG_RADPNT_PREC); - bfdec_mul(r, q, b, BF_PREC_INF, BF_RNDZ); - bfdec_sub(r, a, r, BF_PREC_INF, BF_RNDZ); - } -} - -/* division and remainder. - - rnd_mode is the rounding mode for the quotient. The additional - rounding mode BF_RND_EUCLIDIAN is supported. - - 'q' is an integer. 'r' is rounded with prec and flags (prec can be - BF_PREC_INF). -*/ -int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b, - limb_t prec, bf_flags_t flags, int rnd_mode) -{ - bf_context_t *s = q->ctx; - bfdec_t a1_s, *a1 = &a1_s; - bfdec_t b1_s, *b1 = &b1_s; - bfdec_t r1_s, *r1 = &r1_s; - int q_sign, res; - BOOL is_ceil, is_rndn; - - assert(q != a && q != b); - assert(r != a && r != b); - assert(q != r); - - if (a->len == 0 || b->len == 0) { - bfdec_set_zero(q, 0); - if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) { - bfdec_set_nan(r); - return 0; - } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_ZERO) { - bfdec_set_nan(r); - return BF_ST_INVALID_OP; - } else { - bfdec_set(r, a); - return bfdec_round(r, prec, flags); - } - } - - q_sign = a->sign ^ b->sign; - is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA); - switch(rnd_mode) { - default: - case BF_RNDZ: - case BF_RNDN: - case BF_RNDNA: - is_ceil = FALSE; - break; - case BF_RNDD: - is_ceil = q_sign; - break; - case BF_RNDU: - is_ceil = q_sign ^ 1; - break; - case BF_RNDA: - is_ceil = TRUE; - break; - case BF_DIVREM_EUCLIDIAN: - is_ceil = a->sign; - break; - } - - a1->expn = a->expn; - a1->tab = a->tab; - a1->len = a->len; - a1->sign = 0; - - b1->expn = b->expn; - b1->tab = b->tab; - b1->len = b->len; - b1->sign = 0; - - // bfdec_print_str("a1", a1); - // bfdec_print_str("b1", b1); - /* XXX: could improve to avoid having a large 'q' */ - bfdec_tdivremu(s, q, r, a1, b1); - if (bfdec_is_nan(q) || bfdec_is_nan(r)) - goto fail; - // bfdec_print_str("q", q); - // bfdec_print_str("r", r); - - if (r->len != 0) { - if (is_rndn) { - bfdec_init(s, r1); - if (bfdec_set(r1, r)) - goto fail; - if (bfdec_mul_si(r1, r1, 2, BF_PREC_INF, BF_RNDZ)) { - bfdec_delete(r1); - goto fail; - } - res = bfdec_cmpu(r1, b); - bfdec_delete(r1); - if (res > 0 || - (res == 0 && - (rnd_mode == BF_RNDNA || - (get_digit(q->tab, q->len, q->len * LIMB_DIGITS - q->expn) & 1) != 0))) { - goto do_sub_r; - } - } else if (is_ceil) { - do_sub_r: - res = bfdec_add_si(q, q, 1, BF_PREC_INF, BF_RNDZ); - res |= bfdec_sub(r, r, b1, BF_PREC_INF, BF_RNDZ); - if (res & BF_ST_MEM_ERROR) - goto fail; - } - } - - r->sign ^= a->sign; - q->sign = q_sign; - return bfdec_round(r, prec, flags); - fail: - bfdec_set_nan(q); - bfdec_set_nan(r); - return BF_ST_MEM_ERROR; -} - -int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, - bf_flags_t flags, int rnd_mode) -{ - bfdec_t q_s, *q = &q_s; - int ret; - - bfdec_init(r->ctx, q); - ret = bfdec_divrem(q, r, a, b, prec, flags, rnd_mode); - bfdec_delete(q); - return ret; -} - -/* convert to integer (infinite precision) */ -int bfdec_rint(bfdec_t *r, int rnd_mode) -{ - return bfdec_round(r, 0, rnd_mode | BF_FLAG_RADPNT_PREC); -} - -int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags) -{ - bf_context_t *s = a->ctx; - int ret, k; - limb_t *a1, v; - slimb_t n, n1, prec1; - limb_t res; - - assert(r != a); - - if (a->len == 0) { - if (a->expn == BF_EXP_NAN) { - bfdec_set_nan(r); - } else if (a->expn == BF_EXP_INF && a->sign) { - goto invalid_op; - } else { - bfdec_set(r, a); - } - ret = 0; - } else if (a->sign || prec == BF_PREC_INF) { - invalid_op: - bfdec_set_nan(r); - ret = BF_ST_INVALID_OP; - } else { - if (flags & BF_FLAG_RADPNT_PREC) { - prec1 = bf_max(floor_div(a->expn + 1, 2) + prec, 1); - } else { - prec1 = prec; - } - /* convert the mantissa to an integer with at least 2 * - prec + 4 digits */ - n = (2 * (prec1 + 2) + 2 * LIMB_DIGITS - 1) / (2 * LIMB_DIGITS); - if (bfdec_resize(r, n)) - goto fail; - a1 = bf_malloc(s, sizeof(limb_t) * 2 * n); - if (!a1) - goto fail; - n1 = bf_min(2 * n, a->len); - bzero(a1, (2 * n - n1) * sizeof(limb_t)); - memcpy(a1 + 2 * n - n1, a->tab + a->len - n1, n1 * sizeof(limb_t)); - if (a->expn & 1) { - res = mp_shr_dec(a1, a1, 2 * n, 1, 0); - } else { - res = 0; - } - /* normalize so that a1 >= B^(2*n)/4. Not need for n = 1 - because mp_sqrtrem2_dec already does it */ - k = 0; - if (n > 1) { - v = a1[2 * n - 1]; - while (v < BF_DEC_BASE / 4) { - k++; - v *= 4; - } - if (k != 0) - mp_mul1_dec(a1, a1, 2 * n, 1 << (2 * k), 0); - } - if (mp_sqrtrem_dec(s, r->tab, a1, n)) { - bf_free(s, a1); - goto fail; - } - if (k != 0) - mp_div1_dec(r->tab, r->tab, n, 1 << k, 0); - if (!res) { - res = mp_scan_nz(a1, n + 1); - } - bf_free(s, a1); - if (!res) { - res = mp_scan_nz(a->tab, a->len - n1); - } - if (res != 0) - r->tab[0] |= 1; - r->sign = 0; - r->expn = (a->expn + 1) >> 1; - ret = bfdec_round(r, prec, flags); - } - return ret; - fail: - bfdec_set_nan(r); - return BF_ST_MEM_ERROR; -} - -/* The rounding mode is always BF_RNDZ. Return BF_ST_OVERFLOW if there - is an overflow and 0 otherwise. No memory error is possible. */ -int bfdec_get_int32(int *pres, const bfdec_t *a) -{ - uint32_t v; - int ret; - if (a->expn >= BF_EXP_INF) { - ret = 0; - if (a->expn == BF_EXP_INF) { - v = (uint32_t)INT32_MAX + a->sign; - /* XXX: return overflow ? */ - } else { - v = INT32_MAX; - } - } else if (a->expn <= 0) { - v = 0; - ret = 0; - } else if (a->expn <= 9) { - v = fast_shr_dec(a->tab[a->len - 1], LIMB_DIGITS - a->expn); - if (a->sign) - v = -v; - ret = 0; - } else if (a->expn == 10) { - uint64_t v1; - uint32_t v_max; -#if LIMB_BITS == 64 - v1 = fast_shr_dec(a->tab[a->len - 1], LIMB_DIGITS - a->expn); -#else - v1 = (uint64_t)a->tab[a->len - 1] * 10 + - get_digit(a->tab, a->len, (a->len - 1) * LIMB_DIGITS - 1); -#endif - v_max = (uint32_t)INT32_MAX + a->sign; - if (v1 > v_max) { - v = v_max; - ret = BF_ST_OVERFLOW; - } else { - v = v1; - if (a->sign) - v = -v; - ret = 0; - } - } else { - v = (uint32_t)INT32_MAX + a->sign; - ret = BF_ST_OVERFLOW; - } - *pres = v; - return ret; -} - -/* power to an integer with infinite precision */ -int bfdec_pow_ui(bfdec_t *r, const bfdec_t *a, limb_t b) -{ - int ret, n_bits, i; - - assert(r != a); - if (b == 0) - return bfdec_set_ui(r, 1); - ret = bfdec_set(r, a); - n_bits = LIMB_BITS - clz(b); - for(i = n_bits - 2; i >= 0; i--) { - ret |= bfdec_mul(r, r, r, BF_PREC_INF, BF_RNDZ); - if ((b >> i) & 1) - ret |= bfdec_mul(r, r, a, BF_PREC_INF, BF_RNDZ); - } - return ret; -} - -char *bfdec_ftoa(size_t *plen, const bfdec_t *a, limb_t prec, bf_flags_t flags) -{ - return bf_ftoa_internal(plen, (const bf_t *)a, 10, prec, flags, TRUE); -} - -int bfdec_atof(bfdec_t *r, const char *str, const char **pnext, - limb_t prec, bf_flags_t flags) -{ - slimb_t dummy_exp; - return bf_atof_internal((bf_t *)r, &dummy_exp, str, pnext, 10, prec, - flags, TRUE); -} - -#endif /* USE_BF_DEC */ - -#ifdef USE_FFT_MUL -/***************************************************************/ -/* Integer multiplication with FFT */ - -/* or LIMB_BITS at bit position 'pos' in tab */ -static inline void put_bits(limb_t *tab, limb_t len, slimb_t pos, limb_t val) -{ - limb_t i; - int p; - - i = pos >> LIMB_LOG2_BITS; - p = pos & (LIMB_BITS - 1); - if (i < len) - tab[i] |= val << p; - if (p != 0) { - i++; - if (i < len) { - tab[i] |= val >> (LIMB_BITS - p); - } - } -} - -#if defined(__AVX2__) - -forceinline __m256d _mm256_set_pd(double __A, double __B, double __C, double __D) { - return (__m256d){ __D, __C, __B, __A }; -} - -forceinline __m256d _mm256_set1_pd(double x) { - return (__m256d){x, x, x, x}; -} - -forceinline __m256d _mm256_setr_pd(double __A, double __B, double __C, double __D) { - return _mm256_set_pd(__D, __C, __B, __A); -} - -forceinline __m256d _mm256_blendv_pd(__m256d __X, __m256d __Y, __m256d __M) { - return (__m256d) __builtin_ia32_blendvpd256((__v4df)__X, (__v4df)__Y, (__v4df)__M); -} - -forceinline __m256d _mm256_round_pd(__m256d __V, const int __M) { - return (__m256d) __builtin_ia32_roundpd256((__v4df)__V, __M); -} - -forceinline __m256d _mm256_fmsub_pd(__m256d __A, __m256d __B, __m256d __C) { - return (__m256d)__builtin_ia32_vfmsubpd256((__v4df)__A, (__v4df)__B, (__v4df)__C); -} - -forceinline __m256d _mm256_load_pd(double const *__P) { - return *(__m256d *)__P; -} - -forceinline void _mm256_store_pd(double *__P, __m256d __A) { - *(__m256d *)__P = __A; -} - -forceinline __m256d _mm256_permute2f128_pd(__m256d __X, __m256d __Y, const int __C) { - return (__m256d) __builtin_ia32_vperm2f128_pd256((__v4df)__X, (__v4df)__Y, __C); -} - -forceinline __m256d _mm256_permute4x64_pd(__m256d __X, const int __M) { - return (__m256d) __builtin_ia32_permdf256((__v4df)__X, __M); -} - -typedef double NTTLimb; - -/* we must have: modulo >= 1 << NTT_MOD_LOG2_MIN */ -#define NTT_MOD_LOG2_MIN 50 -#define NTT_MOD_LOG2_MAX 51 -#define NB_MODS 5 -#define NTT_PROOT_2EXP 39 -static const int ntt_int_bits[NB_MODS] = { 254, 203, 152, 101, 50, }; - -static const limb_t ntt_mods[NB_MODS] = { 0x00073a8000000001, 0x0007858000000001, 0x0007a38000000001, 0x0007a68000000001, 0x0007fd8000000001, -}; - -static const limb_t ntt_proot[2][NB_MODS] = { - { 0x00056198d44332c8, 0x0002eb5d640aad39, 0x00047e31eaa35fd0, 0x0005271ac118a150, 0x00075e0ce8442bd5, }, - { 0x000461169761bcc5, 0x0002dac3cb2da688, 0x0004abc97751e3bf, 0x000656778fc8c485, 0x0000dc6469c269fa, }, -}; - -static const limb_t ntt_mods_cr[NB_MODS * (NB_MODS - 1) / 2] = { - 0x00020e4da740da8e, 0x0004c3dc09c09c1d, 0x000063bd097b4271, 0x000799d8f18f18fd, - 0x0005384222222264, 0x000572b07c1f07fe, 0x00035cd08888889a, - 0x00066015555557e3, 0x000725960b60b623, - 0x0002fc1fa1d6ce12, -}; - -#else - -typedef limb_t NTTLimb; - -#if LIMB_BITS == 64 - -#define NTT_MOD_LOG2_MIN 61 -#define NTT_MOD_LOG2_MAX 62 -#define NB_MODS 5 -#define NTT_PROOT_2EXP 51 -static const int ntt_int_bits[NB_MODS] = { 307, 246, 185, 123, 61, }; - -static const limb_t ntt_mods[NB_MODS] = { 0x28d8000000000001, 0x2a88000000000001, 0x2ed8000000000001, 0x3508000000000001, 0x3aa8000000000001, -}; - -static const limb_t ntt_proot[2][NB_MODS] = { - { 0x1b8ea61034a2bea7, 0x21a9762de58206fb, 0x02ca782f0756a8ea, 0x278384537a3e50a1, 0x106e13fee74ce0ab, }, - { 0x233513af133e13b8, 0x1d13140d1c6f75f1, 0x12cde57f97e3eeda, 0x0d6149e23cbe654f, 0x36cd204f522a1379, }, -}; - -static const limb_t ntt_mods_cr[NB_MODS * (NB_MODS - 1) / 2] = { - 0x08a9ed097b425eea, 0x18a44aaaaaaaaab3, 0x2493f57f57f57f5d, 0x126b8d0649a7f8d4, - 0x09d80ed7303b5ccc, 0x25b8bcf3cf3cf3d5, 0x2ce6ce63398ce638, - 0x0e31fad40a57eb59, 0x02a3529fd4a7f52f, - 0x3a5493e93e93e94a, -}; - -#elif LIMB_BITS == 32 - -/* we must have: modulo >= 1 << NTT_MOD_LOG2_MIN */ -#define NTT_MOD_LOG2_MIN 29 -#define NTT_MOD_LOG2_MAX 30 -#define NB_MODS 5 -#define NTT_PROOT_2EXP 20 -static const int ntt_int_bits[NB_MODS] = { 148, 119, 89, 59, 29, }; - -static const limb_t ntt_mods[NB_MODS] = { 0x0000000032b00001, 0x0000000033700001, 0x0000000036d00001, 0x0000000037300001, 0x000000003e500001, -}; - -static const limb_t ntt_proot[2][NB_MODS] = { - { 0x0000000032525f31, 0x0000000005eb3b37, 0x00000000246eda9f, 0x0000000035f25901, 0x00000000022f5768, }, - { 0x00000000051eba1a, 0x00000000107be10e, 0x000000001cd574e0, 0x00000000053806e6, 0x000000002cd6bf98, }, -}; - -static const limb_t ntt_mods_cr[NB_MODS * (NB_MODS - 1) / 2] = { - 0x000000000449559a, 0x000000001eba6ca9, 0x000000002ec18e46, 0x000000000860160b, - 0x000000000d321307, 0x000000000bf51120, 0x000000000f662938, - 0x000000000932ab3e, 0x000000002f40eef8, - 0x000000002e760905, -}; - -#endif /* LIMB_BITS */ - -#endif /* !AVX2 */ - -#if defined(__AVX2__) -#define NTT_TRIG_K_MAX 18 -#else -#define NTT_TRIG_K_MAX 19 -#endif - -typedef struct BFNTTState { - bf_context_t *ctx; - - /* used for mul_mod_fast() */ - limb_t ntt_mods_div[NB_MODS]; - - limb_t ntt_proot_pow[NB_MODS][2][NTT_PROOT_2EXP + 1]; - limb_t ntt_proot_pow_inv[NB_MODS][2][NTT_PROOT_2EXP + 1]; - NTTLimb *ntt_trig[NB_MODS][2][NTT_TRIG_K_MAX + 1]; - /* 1/2^n mod m */ - limb_t ntt_len_inv[NB_MODS][NTT_PROOT_2EXP + 1][2]; -#if defined(__AVX2__) - __m256d ntt_mods_cr_vec[NB_MODS * (NB_MODS - 1) / 2]; - __m256d ntt_mods_vec[NB_MODS]; - __m256d ntt_mods_inv_vec[NB_MODS]; -#else - limb_t ntt_mods_cr_inv[NB_MODS * (NB_MODS - 1) / 2]; -#endif -} BFNTTState; - -static NTTLimb *get_trig(BFNTTState *s, int k, int inverse, int m_idx); - -/* add modulo with up to (LIMB_BITS-1) bit modulo */ -static inline limb_t add_mod(limb_t a, limb_t b, limb_t m) -{ - limb_t r; - r = a + b; - if (r >= m) - r -= m; - return r; -} - -/* sub modulo with up to LIMB_BITS bit modulo */ -static inline limb_t sub_mod(limb_t a, limb_t b, limb_t m) -{ - limb_t r; - r = a - b; - if (r > a) - r += m; - return r; -} - -/* return (r0+r1*B) mod m - precondition: 0 <= r0+r1*B < 2^(64+NTT_MOD_LOG2_MIN) -*/ -static inline limb_t mod_fast(dlimb_t r, - limb_t m, limb_t m_inv) -{ - limb_t a1, q, t0, r1, r0; - - a1 = r >> NTT_MOD_LOG2_MIN; - - q = ((dlimb_t)a1 * m_inv) >> LIMB_BITS; - r = r - (dlimb_t)q * m - m * 2; - r1 = r >> LIMB_BITS; - t0 = (slimb_t)r1 >> 1; - r += m & t0; - r0 = r; - r1 = r >> LIMB_BITS; - r0 += m & r1; - return r0; -} - -/* faster version using precomputed modulo inverse. - precondition: 0 <= a * b < 2^(64+NTT_MOD_LOG2_MIN) */ -static inline limb_t mul_mod_fast(limb_t a, limb_t b, - limb_t m, limb_t m_inv) -{ - dlimb_t r; - r = (dlimb_t)a * (dlimb_t)b; - return mod_fast(r, m, m_inv); -} - -static inline limb_t init_mul_mod_fast(limb_t m) -{ - dlimb_t t; - assert(m < (limb_t)1 << NTT_MOD_LOG2_MAX); - assert(m >= (limb_t)1 << NTT_MOD_LOG2_MIN); - t = (dlimb_t)1 << (LIMB_BITS + NTT_MOD_LOG2_MIN); - return t / m; -} - -/* Faster version used when the multiplier is constant. 0 <= a < 2^64, - 0 <= b < m. */ -static inline limb_t mul_mod_fast2(limb_t a, limb_t b, - limb_t m, limb_t b_inv) -{ - limb_t r, q; - - q = ((dlimb_t)a * (dlimb_t)b_inv) >> LIMB_BITS; - r = a * b - q * m; - if (r >= m) - r -= m; - return r; -} - -/* Faster version used when the multiplier is constant. 0 <= a < 2^64, - 0 <= b < m. Let r = a * b mod m. The return value is 'r' or 'r + - m'. */ -static inline limb_t mul_mod_fast3(limb_t a, limb_t b, - limb_t m, limb_t b_inv) -{ - limb_t r, q; - - q = ((dlimb_t)a * (dlimb_t)b_inv) >> LIMB_BITS; - r = a * b - q * m; - return r; -} - -static inline limb_t init_mul_mod_fast2(limb_t b, limb_t m) -{ - return ((dlimb_t)b << LIMB_BITS) / m; -} - -#ifdef __AVX2__ - -static inline limb_t ntt_limb_to_int(NTTLimb a, limb_t m) -{ - slimb_t v; - v = a; - if (v < 0) - v += m; - if (v >= m) - v -= m; - return v; -} - -static inline NTTLimb int_to_ntt_limb(limb_t a, limb_t m) -{ - return (slimb_t)a; -} - -static inline NTTLimb int_to_ntt_limb2(limb_t a, limb_t m) -{ - if (a >= (m / 2)) - a -= m; - return (slimb_t)a; -} - -/* return r + m if r < 0 otherwise r. */ -static inline __m256d ntt_mod1(__m256d r, __m256d m) -{ - return _mm256_blendv_pd(r, r + m, r); -} - -/* input: abs(r) < 2 * m. Output: abs(r) < m */ -static inline __m256d ntt_mod(__m256d r, __m256d mf, __m256d m2f) -{ - return _mm256_blendv_pd(r, r + m2f, r) - mf; -} - -/* input: abs(a*b) < 2 * m^2, output: abs(r) < m */ -static inline __m256d ntt_mul_mod(__m256d a, __m256d b, __m256d mf, - __m256d m_inv) -{ - __m256d r, q, ab1, ab0, qm0, qm1; - ab1 = a * b; - q = _mm256_round_pd(ab1 * m_inv, 0); /* round to nearest */ - qm1 = q * mf; - qm0 = _mm256_fmsub_pd(q, mf, qm1); /* low part */ - ab0 = _mm256_fmsub_pd(a, b, ab1); /* low part */ - r = (ab1 - qm1) + (ab0 - qm0); - return r; -} - -static void *bf_aligned_malloc(bf_context_t *s, size_t size, size_t align) -{ - void *ptr; - void **ptr1; - ptr = bf_malloc(s, size + sizeof(void *) + align - 1); - if (!ptr) - return NULL; - ptr1 = (void **)(((uintptr_t)ptr + sizeof(void *) + align - 1) & - ~(align - 1)); - ptr1[-1] = ptr; - return ptr1; -} - -static void bf_aligned_free(bf_context_t *s, void *ptr) -{ - if (!ptr) - return; - bf_free(s, ((void **)ptr)[-1]); -} - -static void *ntt_malloc(BFNTTState *s, size_t size) -{ - return bf_aligned_malloc(s->ctx, size, 64); -} - -static void ntt_free(BFNTTState *s, void *ptr) -{ - bf_aligned_free(s->ctx, ptr); -} - -static dontinline int ntt_fft(BFNTTState *s, - NTTLimb *out_buf, NTTLimb *in_buf, - NTTLimb *tmp_buf, int fft_len_log2, - int inverse, int m_idx) -{ - limb_t nb_blocks, fft_per_block, p, k, n, stride_in, i, j; - NTTLimb *tab_in, *tab_out, *tmp, *trig; - __m256d m_inv, mf, m2f, c, a0, a1, b0, b1; - limb_t m; - int l; - - m = ntt_mods[m_idx]; - - m_inv = _mm256_set1_pd(1.0 / (double)m); - mf = _mm256_set1_pd(m); - m2f = _mm256_set1_pd(m * 2); - - n = (limb_t)1 << fft_len_log2; - assert(n >= 8); - stride_in = n / 2; - - tab_in = in_buf; - tab_out = tmp_buf; - trig = get_trig(s, fft_len_log2, inverse, m_idx); - if (!trig) - return -1; - p = 0; - for(k = 0; k < stride_in; k += 4) { - a0 = _mm256_load_pd(&tab_in[k]); - a1 = _mm256_load_pd(&tab_in[k + stride_in]); - c = _mm256_load_pd(trig); - trig += 4; - b0 = ntt_mod(a0 + a1, mf, m2f); - b1 = ntt_mul_mod(a0 - a1, c, mf, m_inv); - a0 = _mm256_permute2f128_pd(b0, b1, 0x20); - a1 = _mm256_permute2f128_pd(b0, b1, 0x31); - a0 = _mm256_permute4x64_pd(a0, 0xd8); - a1 = _mm256_permute4x64_pd(a1, 0xd8); - _mm256_store_pd(&tab_out[p], a0); - _mm256_store_pd(&tab_out[p + 4], a1); - p += 2 * 4; - } - tmp = tab_in; - tab_in = tab_out; - tab_out = tmp; - - trig = get_trig(s, fft_len_log2 - 1, inverse, m_idx); - if (!trig) - return -1; - p = 0; - for(k = 0; k < stride_in; k += 4) { - a0 = _mm256_load_pd(&tab_in[k]); - a1 = _mm256_load_pd(&tab_in[k + stride_in]); - c = _mm256_setr_pd(trig[0], trig[0], trig[1], trig[1]); - trig += 2; - b0 = ntt_mod(a0 + a1, mf, m2f); - b1 = ntt_mul_mod(a0 - a1, c, mf, m_inv); - a0 = _mm256_permute2f128_pd(b0, b1, 0x20); - a1 = _mm256_permute2f128_pd(b0, b1, 0x31); - _mm256_store_pd(&tab_out[p], a0); - _mm256_store_pd(&tab_out[p + 4], a1); - p += 2 * 4; - } - tmp = tab_in; - tab_in = tab_out; - tab_out = tmp; - - nb_blocks = n / 4; - fft_per_block = 4; - - l = fft_len_log2 - 2; - while (nb_blocks != 2) { - nb_blocks >>= 1; - p = 0; - k = 0; - trig = get_trig(s, l, inverse, m_idx); - if (!trig) - return -1; - for(i = 0; i < nb_blocks; i++) { - c = _mm256_set1_pd(trig[0]); - trig++; - for(j = 0; j < fft_per_block; j += 4) { - a0 = _mm256_load_pd(&tab_in[k + j]); - a1 = _mm256_load_pd(&tab_in[k + j + stride_in]); - b0 = ntt_mod(a0 + a1, mf, m2f); - b1 = ntt_mul_mod(a0 - a1, c, mf, m_inv); - _mm256_store_pd(&tab_out[p + j], b0); - _mm256_store_pd(&tab_out[p + j + fft_per_block], b1); - } - k += fft_per_block; - p += 2 * fft_per_block; - } - fft_per_block <<= 1; - l--; - tmp = tab_in; - tab_in = tab_out; - tab_out = tmp; - } - - tab_out = out_buf; - for(k = 0; k < stride_in; k += 4) { - a0 = _mm256_load_pd(&tab_in[k]); - a1 = _mm256_load_pd(&tab_in[k + stride_in]); - b0 = ntt_mod(a0 + a1, mf, m2f); - b1 = ntt_mod(a0 - a1, mf, m2f); - _mm256_store_pd(&tab_out[k], b0); - _mm256_store_pd(&tab_out[k + stride_in], b1); - } - return 0; -} - -static void ntt_vec_mul(BFNTTState *s, - NTTLimb *tab1, NTTLimb *tab2, limb_t fft_len_log2, - int k_tot, int m_idx) -{ - limb_t i, c_inv, n, m; - __m256d m_inv, mf, a, b, c; - - m = ntt_mods[m_idx]; - c_inv = s->ntt_len_inv[m_idx][k_tot][0]; - m_inv = _mm256_set1_pd(1.0 / (double)m); - mf = _mm256_set1_pd(m); - c = _mm256_set1_pd(int_to_ntt_limb(c_inv, m)); - n = (limb_t)1 << fft_len_log2; - for(i = 0; i < n; i += 4) { - a = _mm256_load_pd(&tab1[i]); - b = _mm256_load_pd(&tab2[i]); - a = ntt_mul_mod(a, b, mf, m_inv); - a = ntt_mul_mod(a, c, mf, m_inv); - _mm256_store_pd(&tab1[i], a); - } -} - -static dontinline void mul_trig(NTTLimb *buf, - limb_t n, limb_t c1, limb_t m, limb_t m_inv1) -{ - limb_t i, c2, c3, c4; - __m256d c, c_mul, a0, mf, m_inv; - assert(n >= 2); - - mf = _mm256_set1_pd(m); - m_inv = _mm256_set1_pd(1.0 / (double)m); - - c2 = mul_mod_fast(c1, c1, m, m_inv1); - c3 = mul_mod_fast(c2, c1, m, m_inv1); - c4 = mul_mod_fast(c2, c2, m, m_inv1); - c = _mm256_setr_pd(1, int_to_ntt_limb(c1, m), - int_to_ntt_limb(c2, m), int_to_ntt_limb(c3, m)); - c_mul = _mm256_set1_pd(int_to_ntt_limb(c4, m)); - for(i = 0; i < n; i += 4) { - a0 = *(__m256d *)(buf + i); - a0 = ntt_mul_mod(a0, c, mf, m_inv); - *(__m256d *)(buf+i) = a0; - c = ntt_mul_mod(c, c_mul, mf, m_inv); - } -} - -#else - -static void *ntt_malloc(BFNTTState *s, size_t size) -{ - return bf_malloc(s->ctx, size); -} - -static void ntt_free(BFNTTState *s, void *ptr) -{ - bf_free(s->ctx, ptr); -} - -static inline limb_t ntt_limb_to_int(NTTLimb a, limb_t m) -{ - if (a >= m) - a -= m; - return a; -} - -static inline NTTLimb int_to_ntt_limb(slimb_t a, limb_t m) -{ - return a; -} - -static dontinline int ntt_fft(BFNTTState *s, NTTLimb *out_buf, NTTLimb *in_buf, - NTTLimb *tmp_buf, int fft_len_log2, - int inverse, int m_idx) -{ - limb_t nb_blocks, fft_per_block, p, k, n, stride_in, i, j, m, m2; - NTTLimb *tab_in, *tab_out, *tmp, a0, a1, b0, b1, c, *trig, c_inv; - int l; - - m = ntt_mods[m_idx]; - m2 = 2 * m; - n = (limb_t)1 << fft_len_log2; - nb_blocks = n; - fft_per_block = 1; - stride_in = n / 2; - tab_in = in_buf; - tab_out = tmp_buf; - l = fft_len_log2; - while (nb_blocks != 2) { - nb_blocks >>= 1; - p = 0; - k = 0; - trig = get_trig(s, l, inverse, m_idx); - if (!trig) - return -1; - for(i = 0; i < nb_blocks; i++) { - c = trig[0]; - c_inv = trig[1]; - trig += 2; - for(j = 0; j < fft_per_block; j++) { - a0 = tab_in[k + j]; - a1 = tab_in[k + j + stride_in]; - b0 = add_mod(a0, a1, m2); - b1 = a0 - a1 + m2; - b1 = mul_mod_fast3(b1, c, m, c_inv); - tab_out[p + j] = b0; - tab_out[p + j + fft_per_block] = b1; - } - k += fft_per_block; - p += 2 * fft_per_block; - } - fft_per_block <<= 1; - l--; - tmp = tab_in; - tab_in = tab_out; - tab_out = tmp; - } - /* no twiddle in last step */ - tab_out = out_buf; - for(k = 0; k < stride_in; k++) { - a0 = tab_in[k]; - a1 = tab_in[k + stride_in]; - b0 = add_mod(a0, a1, m2); - b1 = sub_mod(a0, a1, m2); - tab_out[k] = b0; - tab_out[k + stride_in] = b1; - } - return 0; -} - -static void ntt_vec_mul(BFNTTState *s, - NTTLimb *tab1, NTTLimb *tab2, int fft_len_log2, - int k_tot, int m_idx) -{ - limb_t i, norm, norm_inv, a, n, m, m_inv; - - m = ntt_mods[m_idx]; - m_inv = s->ntt_mods_div[m_idx]; - norm = s->ntt_len_inv[m_idx][k_tot][0]; - norm_inv = s->ntt_len_inv[m_idx][k_tot][1]; - n = (limb_t)1 << fft_len_log2; - for(i = 0; i < n; i++) { - a = tab1[i]; - /* need to reduce the range so that the product is < - 2^(LIMB_BITS+NTT_MOD_LOG2_MIN) */ - if (a >= m) - a -= m; - a = mul_mod_fast(a, tab2[i], m, m_inv); - a = mul_mod_fast3(a, norm, m, norm_inv); - tab1[i] = a; - } -} - -static dontinline void mul_trig(NTTLimb *buf, - limb_t n, limb_t c_mul, limb_t m, limb_t m_inv) -{ - limb_t i, c0, c_mul_inv; - - c0 = 1; - c_mul_inv = init_mul_mod_fast2(c_mul, m); - for(i = 0; i < n; i++) { - buf[i] = mul_mod_fast(buf[i], c0, m, m_inv); - c0 = mul_mod_fast2(c0, c_mul, m, c_mul_inv); - } -} - -#endif /* !AVX2 */ - -static dontinline NTTLimb *get_trig(BFNTTState *s, - int k, int inverse, int m_idx) -{ - NTTLimb *tab; - limb_t i, n2, c, c_mul, m, c_mul_inv; - - if (k > NTT_TRIG_K_MAX) - return NULL; - - tab = s->ntt_trig[m_idx][inverse][k]; - if (tab) - return tab; - n2 = (limb_t)1 << (k - 1); - m = ntt_mods[m_idx]; -#ifdef __AVX2__ - tab = ntt_malloc(s, sizeof(NTTLimb) * n2); -#else - tab = ntt_malloc(s, sizeof(NTTLimb) * n2 * 2); -#endif - if (!tab) - return NULL; - c = 1; - c_mul = s->ntt_proot_pow[m_idx][inverse][k]; - c_mul_inv = s->ntt_proot_pow_inv[m_idx][inverse][k]; - for(i = 0; i < n2; i++) { -#ifdef __AVX2__ - tab[i] = int_to_ntt_limb2(c, m); -#else - tab[2 * i] = int_to_ntt_limb(c, m); - tab[2 * i + 1] = init_mul_mod_fast2(c, m); -#endif - c = mul_mod_fast2(c, c_mul, m, c_mul_inv); - } - s->ntt_trig[m_idx][inverse][k] = tab; - return tab; -} - -void fft_clear_cache(bf_context_t *s1) -{ - int m_idx, inverse, k; - BFNTTState *s = s1->ntt_state; - if (s) { - for(m_idx = 0; m_idx < NB_MODS; m_idx++) { - for(inverse = 0; inverse < 2; inverse++) { - for(k = 0; k < NTT_TRIG_K_MAX + 1; k++) { - if (s->ntt_trig[m_idx][inverse][k]) { - ntt_free(s, s->ntt_trig[m_idx][inverse][k]); - s->ntt_trig[m_idx][inverse][k] = NULL; - } - } - } - } -#if defined(__AVX2__) - bf_aligned_free(s1, s); -#else - bf_free(s1, s); -#endif - s1->ntt_state = NULL; - } -} - -#define STRIP_LEN 16 - -/* dst = buf1, src = buf2 */ -static int ntt_fft_partial(BFNTTState *s, NTTLimb *buf1, - int k1, int k2, limb_t n1, limb_t n2, int inverse, - limb_t m_idx) -{ - limb_t i, j, c_mul, c0, m, m_inv, strip_len, l; - NTTLimb *buf2, *buf3; - - buf2 = NULL; - buf3 = ntt_malloc(s, sizeof(NTTLimb) * n1); - if (!buf3) - goto fail; - if (k2 == 0) { - if (ntt_fft(s, buf1, buf1, buf3, k1, inverse, m_idx)) - goto fail; - } else { - strip_len = STRIP_LEN; - buf2 = ntt_malloc(s, sizeof(NTTLimb) * n1 * strip_len); - if (!buf2) - goto fail; - m = ntt_mods[m_idx]; - m_inv = s->ntt_mods_div[m_idx]; - c0 = s->ntt_proot_pow[m_idx][inverse][k1 + k2]; - c_mul = 1; - assert((n2 % strip_len) == 0); - for(j = 0; j < n2; j += strip_len) { - for(i = 0; i < n1; i++) { - for(l = 0; l < strip_len; l++) { - buf2[i + l * n1] = buf1[i * n2 + (j + l)]; - } - } - for(l = 0; l < strip_len; l++) { - if (inverse) - mul_trig(buf2 + l * n1, n1, c_mul, m, m_inv); - if (ntt_fft(s, buf2 + l * n1, buf2 + l * n1, buf3, k1, inverse, m_idx)) - goto fail; - if (!inverse) - mul_trig(buf2 + l * n1, n1, c_mul, m, m_inv); - c_mul = mul_mod_fast(c_mul, c0, m, m_inv); - } - - for(i = 0; i < n1; i++) { - for(l = 0; l < strip_len; l++) { - buf1[i * n2 + (j + l)] = buf2[i + l *n1]; - } - } - } - ntt_free(s, buf2); - } - ntt_free(s, buf3); - return 0; - fail: - ntt_free(s, buf2); - ntt_free(s, buf3); - return -1; -} - - -/* dst = buf1, src = buf2, tmp = buf3 */ -static int ntt_conv(BFNTTState *s, NTTLimb *buf1, NTTLimb *buf2, - int k, int k_tot, limb_t m_idx) -{ - limb_t n1, n2, i; - int k1, k2; - - if (k <= NTT_TRIG_K_MAX) { - k1 = k; - } else { - /* recursive split of the FFT */ - k1 = bf_min(k / 2, NTT_TRIG_K_MAX); - } - k2 = k - k1; - n1 = (limb_t)1 << k1; - n2 = (limb_t)1 << k2; - - if (ntt_fft_partial(s, buf1, k1, k2, n1, n2, 0, m_idx)) - return -1; - if (ntt_fft_partial(s, buf2, k1, k2, n1, n2, 0, m_idx)) - return -1; - if (k2 == 0) { - ntt_vec_mul(s, buf1, buf2, k, k_tot, m_idx); - } else { - for(i = 0; i < n1; i++) { - ntt_conv(s, buf1 + i * n2, buf2 + i * n2, k2, k_tot, m_idx); - } - } - if (ntt_fft_partial(s, buf1, k1, k2, n1, n2, 1, m_idx)) - return -1; - return 0; -} - - -static dontinline void limb_to_ntt(BFNTTState *s, - NTTLimb *tabr, limb_t fft_len, - const limb_t *taba, limb_t a_len, int dpl, - int first_m_idx, int nb_mods) -{ - slimb_t i, n; - dlimb_t a, b; - int j, shift; - limb_t base_mask1, a0, a1, a2, r, m, m_inv; - -#if 0 - for(i = 0; i < a_len; i++) { - printf("%" PRId64 ": " FMT_LIMB "\n", - (int64_t)i, taba[i]); - } -#endif - bzero(tabr, sizeof(NTTLimb) * fft_len * nb_mods); - shift = dpl & (LIMB_BITS - 1); - if (shift == 0) - base_mask1 = -1; - else - base_mask1 = ((limb_t)1 << shift) - 1; - n = bf_min(fft_len, (a_len * LIMB_BITS + dpl - 1) / dpl); - for(i = 0; i < n; i++) { - a0 = get_bits(taba, a_len, i * dpl); - if (dpl <= LIMB_BITS) { - a0 &= base_mask1; - a = a0; - } else { - a1 = get_bits(taba, a_len, i * dpl + LIMB_BITS); - if (dpl <= (LIMB_BITS + NTT_MOD_LOG2_MIN)) { - a = a0 | ((dlimb_t)(a1 & base_mask1) << LIMB_BITS); - } else { - if (dpl > 2 * LIMB_BITS) { - a2 = get_bits(taba, a_len, i * dpl + LIMB_BITS * 2) & - base_mask1; - } else { - a1 &= base_mask1; - a2 = 0; - } - // printf("a=0x%016lx%016lx%016lx\n", a2, a1, a0); - a = (a0 >> (LIMB_BITS - NTT_MOD_LOG2_MAX + NTT_MOD_LOG2_MIN)) | - ((dlimb_t)a1 << (NTT_MOD_LOG2_MAX - NTT_MOD_LOG2_MIN)) | - ((dlimb_t)a2 << (LIMB_BITS + NTT_MOD_LOG2_MAX - NTT_MOD_LOG2_MIN)); - a0 &= ((limb_t)1 << (LIMB_BITS - NTT_MOD_LOG2_MAX + NTT_MOD_LOG2_MIN)) - 1; - } - } - for(j = 0; j < nb_mods; j++) { - m = ntt_mods[first_m_idx + j]; - m_inv = s->ntt_mods_div[first_m_idx + j]; - r = mod_fast(a, m, m_inv); - if (dpl > (LIMB_BITS + NTT_MOD_LOG2_MIN)) { - b = ((dlimb_t)r << (LIMB_BITS - NTT_MOD_LOG2_MAX + NTT_MOD_LOG2_MIN)) | a0; - r = mod_fast(b, m, m_inv); - } - tabr[i + j * fft_len] = int_to_ntt_limb(r, m); - } - } -} - -#if defined(__AVX2__) - -#define VEC_LEN 4 - -typedef union { - __m256d v; - double d[4]; -} VecUnion; - -static dontinline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len, - const NTTLimb *buf, int fft_len_log2, int dpl, - int nb_mods) -{ - const limb_t *mods = ntt_mods + NB_MODS - nb_mods; - const __m256d *mods_cr_vec, *mf, *m_inv; - VecUnion y[NB_MODS]; - limb_t u[NB_MODS], carry[NB_MODS], fft_len, base_mask1, r; - slimb_t i, len, pos; - int j, k, l, shift, n_limb1, p; - dlimb_t t; - - j = NB_MODS * (NB_MODS - 1) / 2 - nb_mods * (nb_mods - 1) / 2; - mods_cr_vec = s->ntt_mods_cr_vec + j; - mf = s->ntt_mods_vec + NB_MODS - nb_mods; - m_inv = s->ntt_mods_inv_vec + NB_MODS - nb_mods; - - shift = dpl & (LIMB_BITS - 1); - if (shift == 0) - base_mask1 = -1; - else - base_mask1 = ((limb_t)1 << shift) - 1; - n_limb1 = ((unsigned)dpl - 1) / LIMB_BITS; - for(j = 0; j < NB_MODS; j++) - carry[j] = 0; - for(j = 0; j < NB_MODS; j++) - u[j] = 0; /* avoid warnings */ - bzero(tabr, sizeof(limb_t) * r_len); - fft_len = (limb_t)1 << fft_len_log2; - len = bf_min(fft_len, (r_len * LIMB_BITS + dpl - 1) / dpl); - len = (len + VEC_LEN - 1) & ~(VEC_LEN - 1); - i = 0; - while (i < len) { - for(j = 0; j < nb_mods; j++) - y[j].v = *(__m256d *)&buf[i + fft_len * j]; - - /* Chinese remainder to get mixed radix representation */ - l = 0; - for(j = 0; j < nb_mods - 1; j++) { - y[j].v = ntt_mod1(y[j].v, mf[j]); - for(k = j + 1; k < nb_mods; k++) { - y[k].v = ntt_mul_mod(y[k].v - y[j].v, - mods_cr_vec[l], mf[k], m_inv[k]); - l++; - } - } - y[j].v = ntt_mod1(y[j].v, mf[j]); - - for(p = 0; p < VEC_LEN; p++) { - /* back to normal representation */ - u[0] = (int64_t)y[nb_mods - 1].d[p]; - l = 1; - for(j = nb_mods - 2; j >= 1; j--) { - r = (int64_t)y[j].d[p]; - for(k = 0; k < l; k++) { - t = (dlimb_t)u[k] * mods[j] + r; - r = t >> LIMB_BITS; - u[k] = t; - } - u[l] = r; - l++; - } - /* XXX: for nb_mods = 5, l should be 4 */ - - /* last step adds the carry */ - r = (int64_t)y[0].d[p]; - for(k = 0; k < l; k++) { - t = (dlimb_t)u[k] * mods[j] + r + carry[k]; - r = t >> LIMB_BITS; - u[k] = t; - } - u[l] = r + carry[l]; - -#if 0 - printf("%" PRId64 ": ", i); - for(j = nb_mods - 1; j >= 0; j--) { - printf(" %019" PRIu64, u[j]); - } - printf("\n"); -#endif - - /* write the digits */ - pos = i * dpl; - for(j = 0; j < n_limb1; j++) { - put_bits(tabr, r_len, pos, u[j]); - pos += LIMB_BITS; - } - put_bits(tabr, r_len, pos, u[n_limb1] & base_mask1); - /* shift by dpl digits and set the carry */ - if (shift == 0) { - for(j = n_limb1 + 1; j < nb_mods; j++) - carry[j - (n_limb1 + 1)] = u[j]; - } else { - for(j = n_limb1; j < nb_mods - 1; j++) { - carry[j - n_limb1] = (u[j] >> shift) | - (u[j + 1] << (LIMB_BITS - shift)); - } - carry[nb_mods - 1 - n_limb1] = u[nb_mods - 1] >> shift; - } - i++; - } - } -} -#else -static dontinline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len, - const NTTLimb *buf, int fft_len_log2, int dpl, - int nb_mods) -{ - const limb_t *mods = ntt_mods + NB_MODS - nb_mods; - const limb_t *mods_cr, *mods_cr_inv; - limb_t y[NB_MODS], u[NB_MODS], carry[NB_MODS], fft_len, base_mask1, r; - slimb_t i, len, pos; - int j, k, l, shift, n_limb1; - dlimb_t t; - - j = NB_MODS * (NB_MODS - 1) / 2 - nb_mods * (nb_mods - 1) / 2; - mods_cr = ntt_mods_cr + j; - mods_cr_inv = s->ntt_mods_cr_inv + j; - - shift = dpl & (LIMB_BITS - 1); - if (shift == 0) - base_mask1 = -1; - else - base_mask1 = ((limb_t)1 << shift) - 1; - n_limb1 = ((unsigned)dpl - 1) / LIMB_BITS; - for(j = 0; j < NB_MODS; j++) - carry[j] = 0; - for(j = 0; j < NB_MODS; j++) - u[j] = 0; /* avoid warnings */ - bzero(tabr, sizeof(limb_t) * r_len); - fft_len = (limb_t)1 << fft_len_log2; - len = bf_min(fft_len, (r_len * LIMB_BITS + dpl - 1) / dpl); - for(i = 0; i < len; i++) { - for(j = 0; j < nb_mods; j++) { - y[j] = ntt_limb_to_int(buf[i + fft_len * j], mods[j]); - } - - /* Chinese remainder to get mixed radix representation */ - l = 0; - for(j = 0; j < nb_mods - 1; j++) { - for(k = j + 1; k < nb_mods; k++) { - limb_t m; - m = mods[k]; - /* Note: there is no overflow in the sub_mod() because - the modulos are sorted by increasing order */ - y[k] = mul_mod_fast2(y[k] - y[j] + m, - mods_cr[l], m, mods_cr_inv[l]); - l++; - } - } - - /* back to normal representation */ - u[0] = y[nb_mods - 1]; - l = 1; - for(j = nb_mods - 2; j >= 1; j--) { - r = y[j]; - for(k = 0; k < l; k++) { - t = (dlimb_t)u[k] * mods[j] + r; - r = t >> LIMB_BITS; - u[k] = t; - } - u[l] = r; - l++; - } - - /* last step adds the carry */ - r = y[0]; - for(k = 0; k < l; k++) { - t = (dlimb_t)u[k] * mods[j] + r + carry[k]; - r = t >> LIMB_BITS; - u[k] = t; - } - u[l] = r + carry[l]; - -#if 0 - printf("%" PRId64 ": ", (int64_t)i); - for(j = nb_mods - 1; j >= 0; j--) { - printf(" " FMT_LIMB, u[j]); - } - printf("\n"); -#endif - - /* write the digits */ - pos = i * dpl; - for(j = 0; j < n_limb1; j++) { - put_bits(tabr, r_len, pos, u[j]); - pos += LIMB_BITS; - } - put_bits(tabr, r_len, pos, u[n_limb1] & base_mask1); - /* shift by dpl digits and set the carry */ - if (shift == 0) { - for(j = n_limb1 + 1; j < nb_mods; j++) - carry[j - (n_limb1 + 1)] = u[j]; - } else { - for(j = n_limb1; j < nb_mods - 1; j++) { - carry[j - n_limb1] = (u[j] >> shift) | - (u[j + 1] << (LIMB_BITS - shift)); - } - carry[nb_mods - 1 - n_limb1] = u[nb_mods - 1] >> shift; - } - } -} -#endif - -static int ntt_static_init(bf_context_t *s1) -{ - BFNTTState *s; - int inverse, i, j, k, l; - limb_t c, c_inv, c_inv2, m, m_inv; - - if (s1->ntt_state) - return 0; -#if defined(__AVX2__) - s = bf_aligned_malloc(s1, sizeof(*s), 64); -#else - s = bf_malloc(s1, sizeof(*s)); -#endif - if (!s) - return -1; - bzero(s, sizeof(*s)); - s1->ntt_state = s; - s->ctx = s1; - - for(j = 0; j < NB_MODS; j++) { - m = ntt_mods[j]; - m_inv = init_mul_mod_fast(m); - s->ntt_mods_div[j] = m_inv; -#if defined(__AVX2__) - s->ntt_mods_vec[j] = (__m256d){m, m, m, m}; - s->ntt_mods_inv_vec[j] = (__m256d){1./m, 1./m, 1./m, 1./m}; -#endif - c_inv2 = (m + 1) / 2; /* 1/2 */ - c_inv = 1; - for(i = 0; i <= NTT_PROOT_2EXP; i++) { - s->ntt_len_inv[j][i][0] = c_inv; - s->ntt_len_inv[j][i][1] = init_mul_mod_fast2(c_inv, m); - c_inv = mul_mod_fast(c_inv, c_inv2, m, m_inv); - } - - for(inverse = 0; inverse < 2; inverse++) { - c = ntt_proot[inverse][j]; - for(i = 0; i < NTT_PROOT_2EXP; i++) { - s->ntt_proot_pow[j][inverse][NTT_PROOT_2EXP - i] = c; - s->ntt_proot_pow_inv[j][inverse][NTT_PROOT_2EXP - i] = - init_mul_mod_fast2(c, m); - c = mul_mod_fast(c, c, m, m_inv); - } - } - } - - l = 0; - for(j = 0; j < NB_MODS - 1; j++) { - for(k = j + 1; k < NB_MODS; k++) { -#if defined(__AVX2__) - NTTLimb x = int_to_ntt_limb2(ntt_mods_cr[l], - ntt_mods[k]); - s->ntt_mods_cr_vec[l] = (__m256d){x, x, x, x}; -#else - s->ntt_mods_cr_inv[l] = init_mul_mod_fast2(ntt_mods_cr[l], - ntt_mods[k]); -#endif - l++; - } - } - return 0; -} - -int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len) -{ - int dpl, fft_len_log2, n_bits, nb_mods, dpl_found, fft_len_log2_found; - int int_bits, nb_mods_found; - limb_t cost, min_cost; - - min_cost = -1; - dpl_found = 0; - nb_mods_found = 4; - fft_len_log2_found = 0; - for(nb_mods = 3; nb_mods <= NB_MODS; nb_mods++) { - int_bits = ntt_int_bits[NB_MODS - nb_mods]; - dpl = bf_min((int_bits - 4) / 2, - 2 * LIMB_BITS + 2 * NTT_MOD_LOG2_MIN - NTT_MOD_LOG2_MAX); - for(;;) { - fft_len_log2 = ceil_log2((len * LIMB_BITS + dpl - 1) / dpl); - if (fft_len_log2 > NTT_PROOT_2EXP) - goto next; - n_bits = fft_len_log2 + 2 * dpl; - if (n_bits <= int_bits) { - cost = ((limb_t)(fft_len_log2 + 1) << fft_len_log2) * nb_mods; - // printf("n=%d dpl=%d: cost=%" PRId64 "\n", nb_mods, dpl, (int64_t)cost); - if (cost < min_cost) { - min_cost = cost; - dpl_found = dpl; - nb_mods_found = nb_mods; - fft_len_log2_found = fft_len_log2; - } - break; - } - dpl--; - if (dpl == 0) - break; - } - next: ; - } - if (!dpl_found) - abort(); - /* limit dpl if possible to reduce fixed cost of limb/NTT conversion */ - if (dpl_found > (LIMB_BITS + NTT_MOD_LOG2_MIN) && - ((limb_t)(LIMB_BITS + NTT_MOD_LOG2_MIN) << fft_len_log2_found) >= - len * LIMB_BITS) { - dpl_found = LIMB_BITS + NTT_MOD_LOG2_MIN; - } - *pnb_mods = nb_mods_found; - *pdpl = dpl_found; - return fft_len_log2_found; -} - -/* return 0 if OK, -1 if memory error */ -static dontinline int fft_mul(bf_context_t *s1, - bf_t *res, limb_t *a_tab, limb_t a_len, - limb_t *b_tab, limb_t b_len, int mul_flags) -{ - BFNTTState *s; - int dpl, fft_len_log2, j, nb_mods, reduced_mem; - slimb_t len, fft_len; - NTTLimb *buf1, *buf2, *ptr; -#if defined(USE_MUL_CHECK) - limb_t ha, hb, hr, h_ref; -#endif - - if (ntt_static_init(s1)) - return -1; - s = s1->ntt_state; - - /* find the optimal number of digits per limb (dpl) */ - len = a_len + b_len; - fft_len_log2 = bf_get_fft_size(&dpl, &nb_mods, len); - fft_len = (uint64_t)1 << fft_len_log2; - // printf("len=%" PRId64 " fft_len_log2=%d dpl=%d\n", len, fft_len_log2, dpl); -#if defined(USE_MUL_CHECK) - ha = mp_mod1(a_tab, a_len, BF_CHKSUM_MOD, 0); - hb = mp_mod1(b_tab, b_len, BF_CHKSUM_MOD, 0); -#endif - if ((mul_flags & (FFT_MUL_R_OVERLAP_A | FFT_MUL_R_OVERLAP_B)) == 0) { - if (!(mul_flags & FFT_MUL_R_NORESIZE)) - bf_resize(res, 0); - } else if (mul_flags & FFT_MUL_R_OVERLAP_B) { - limb_t *tmp_tab, tmp_len; - /* it is better to free 'b' first */ - tmp_tab = a_tab; - a_tab = b_tab; - b_tab = tmp_tab; - tmp_len = a_len; - a_len = b_len; - b_len = tmp_len; - } - buf1 = ntt_malloc(s, sizeof(NTTLimb) * fft_len * nb_mods); - if (!buf1) - return -1; - limb_to_ntt(s, buf1, fft_len, a_tab, a_len, dpl, - NB_MODS - nb_mods, nb_mods); - if ((mul_flags & (FFT_MUL_R_OVERLAP_A | FFT_MUL_R_OVERLAP_B)) == - FFT_MUL_R_OVERLAP_A) { - if (!(mul_flags & FFT_MUL_R_NORESIZE)) - bf_resize(res, 0); - } - reduced_mem = (fft_len_log2 >= 14); - if (!reduced_mem) { - buf2 = ntt_malloc(s, sizeof(NTTLimb) * fft_len * nb_mods); - if (!buf2) - goto fail; - limb_to_ntt(s, buf2, fft_len, b_tab, b_len, dpl, - NB_MODS - nb_mods, nb_mods); - if (!(mul_flags & FFT_MUL_R_NORESIZE)) - bf_resize(res, 0); /* in case res == b */ - } else { - buf2 = ntt_malloc(s, sizeof(NTTLimb) * fft_len); - if (!buf2) - goto fail; - } - for(j = 0; j < nb_mods; j++) { - if (reduced_mem) { - limb_to_ntt(s, buf2, fft_len, b_tab, b_len, dpl, - NB_MODS - nb_mods + j, 1); - ptr = buf2; - } else { - ptr = buf2 + fft_len * j; - } - if (ntt_conv(s, buf1 + fft_len * j, ptr, - fft_len_log2, fft_len_log2, j + NB_MODS - nb_mods)) - goto fail; - } - if (!(mul_flags & FFT_MUL_R_NORESIZE)) - bf_resize(res, 0); /* in case res == b and reduced mem */ - ntt_free(s, buf2); - buf2 = NULL; - if (!(mul_flags & FFT_MUL_R_NORESIZE)) { - if (bf_resize(res, len)) - goto fail; - } - ntt_to_limb(s, res->tab, len, buf1, fft_len_log2, dpl, nb_mods); - ntt_free(s, buf1); -#if defined(USE_MUL_CHECK) - hr = mp_mod1(res->tab, len, BF_CHKSUM_MOD, 0); - h_ref = mul_mod(ha, hb, BF_CHKSUM_MOD); - if (hr != h_ref) { - printf("ntt_mul_error: len=%" PRId_LIMB " fft_len_log2=%d dpl=%d nb_mods=%d\n", - len, fft_len_log2, dpl, nb_mods); - // printf("ha=0x" FMT_LIMB" hb=0x" FMT_LIMB " hr=0x" FMT_LIMB " expected=0x" FMT_LIMB "\n", ha, hb, hr, h_ref); - exit(1); - } -#endif - return 0; - fail: - ntt_free(s, buf1); - ntt_free(s, buf2); - return -1; -} - -#else /* USE_FFT_MUL */ - -int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len) -{ - return 0; -} - -#endif /* !USE_FFT_MUL */ diff --git a/third_party/quickjs/libbf.h b/third_party/quickjs/libbf.h deleted file mode 100644 index ab5a56e7d..000000000 --- a/third_party/quickjs/libbf.h +++ /dev/null @@ -1,514 +0,0 @@ -#ifndef COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBBF_H_ -#define COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBBF_H_ -#include "libc/limits.h" -#include "libc/literal.h" -COSMOPOLITAN_C_START_ - -#if INTPTR_MAX >= INT64_MAX -#define LIMB_LOG2_BITS 6 -#else -#define LIMB_LOG2_BITS 5 -#endif - -#define LIMB_BITS (1 << LIMB_LOG2_BITS) - -#if LIMB_BITS == 64 -typedef __int128 int128_t; -typedef unsigned __int128 uint128_t; -typedef int64_t slimb_t; -typedef uint64_t limb_t; -typedef uint128_t dlimb_t; -#define BF_RAW_EXP_MIN INT64_MIN -#define BF_RAW_EXP_MAX INT64_MAX - -#define LIMB_DIGITS 19 -#define BF_DEC_BASE UINT64_C(10000000000000000000) - -#else - -typedef int32_t slimb_t; -typedef uint32_t limb_t; -typedef uint64_t dlimb_t; -#define BF_RAW_EXP_MIN INT32_MIN -#define BF_RAW_EXP_MAX INT32_MAX - -#define LIMB_DIGITS 9 -#define BF_DEC_BASE 1000000000U - -#endif - -/* in bits */ -/* minimum number of bits for the exponent */ -#define BF_EXP_BITS_MIN 3 -/* maximum number of bits for the exponent */ -#define BF_EXP_BITS_MAX (LIMB_BITS - 3) -/* extended range for exponent, used internally */ -#define BF_EXT_EXP_BITS_MAX (BF_EXP_BITS_MAX + 1) -/* minimum possible precision */ -#define BF_PREC_MIN 2 -/* minimum possible precision */ -#define BF_PREC_MAX (((limb_t)1 << (LIMB_BITS - 2)) - 2) -/* some operations support infinite precision */ -#define BF_PREC_INF (BF_PREC_MAX + 1) /* infinite precision */ - -#if LIMB_BITS == 64 -#define BF_CHKSUM_MOD (UINT64_C(975620677) * UINT64_C(9795002197)) -#else -#define BF_CHKSUM_MOD 975620677U -#endif - -#define BF_EXP_ZERO BF_RAW_EXP_MIN -#define BF_EXP_INF (BF_RAW_EXP_MAX - 1) -#define BF_EXP_NAN BF_RAW_EXP_MAX - -/* +/-zero is represented with expn = BF_EXP_ZERO and len = 0, - +/-infinity is represented with expn = BF_EXP_INF and len = 0, - NaN is represented with expn = BF_EXP_NAN and len = 0 (sign is ignored) - */ -typedef struct { - struct bf_context_t *ctx; - int sign; - slimb_t expn; - limb_t len; - limb_t *tab; -} bf_t; - -typedef struct { - /* must be kept identical to bf_t */ - struct bf_context_t *ctx; - int sign; - slimb_t expn; - limb_t len; - limb_t *tab; -} bfdec_t; - -typedef enum { - BF_RNDN, /* round to nearest, ties to even */ - BF_RNDZ, /* round to zero */ - BF_RNDD, /* round to -inf (the code relies on (BF_RNDD xor BF_RNDU) = 1) */ - BF_RNDU, /* round to +inf */ - BF_RNDNA, /* round to nearest, ties away from zero */ - BF_RNDA, /* round away from zero */ - BF_RNDF, /* faithful rounding (nondeterministic, either RNDD or RNDU, - inexact flag is always set) */ -} bf_rnd_t; - -/* allow subnormal numbers. Only available if the number of exponent - bits is <= BF_EXP_BITS_USER_MAX and prec != BF_PREC_INF. */ -#define BF_FLAG_SUBNORMAL (1 << 3) -/* 'prec' is the precision after the radix point instead of the whole - mantissa. Can only be used with bf_round() and - bfdec_[add|sub|mul|div|sqrt|round](). */ -#define BF_FLAG_RADPNT_PREC (1 << 4) - -#define BF_RND_MASK 0x7 -#define BF_EXP_BITS_SHIFT 5 -#define BF_EXP_BITS_MASK 0x3f - -/* shortcut for bf_set_exp_bits(BF_EXT_EXP_BITS_MAX) */ -#define BF_FLAG_EXT_EXP (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT) - -/* contains the rounding mode and number of exponents bits */ -typedef uint32_t bf_flags_t; - -typedef void *bf_realloc_func_t(void *opaque, void *ptr, size_t size); - -typedef struct { - bf_t val; - limb_t prec; -} BFConstCache; - -typedef struct bf_context_t { - void *realloc_opaque; - bf_realloc_func_t *realloc_func; - BFConstCache log2_cache; - BFConstCache pi_cache; - struct BFNTTState *ntt_state; -} bf_context_t; - -static inline int bf_get_exp_bits(bf_flags_t flags) -{ - int e; - e = (flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK; - if (e == BF_EXP_BITS_MASK) - return BF_EXP_BITS_MAX + 1; - else - return BF_EXP_BITS_MAX - e; -} - -static inline bf_flags_t bf_set_exp_bits(int n) -{ - return ((BF_EXP_BITS_MAX - n) & BF_EXP_BITS_MASK) << BF_EXP_BITS_SHIFT; -} - -/* returned status */ -#define BF_ST_INVALID_OP (1 << 0) -#define BF_ST_DIVIDE_ZERO (1 << 1) -#define BF_ST_OVERFLOW (1 << 2) -#define BF_ST_UNDERFLOW (1 << 3) -#define BF_ST_INEXACT (1 << 4) -/* indicate that a memory allocation error occured. NaN is returned */ -#define BF_ST_MEM_ERROR (1 << 5) - -#define BF_RADIX_MAX 36 /* maximum radix for bf_atof() and bf_ftoa() */ - -static inline slimb_t bf_max(slimb_t a, slimb_t b) -{ - if (a > b) - return a; - else - return b; -} - -static inline slimb_t bf_min(slimb_t a, slimb_t b) -{ - if (a < b) - return a; - else - return b; -} - -void bf_context_init(bf_context_t *s, bf_realloc_func_t *realloc_func, - void *realloc_opaque); -void bf_context_end(bf_context_t *s); -/* free memory allocated for the bf cache data */ -void bf_clear_cache(bf_context_t *s); - -static inline void *bf_realloc(bf_context_t *s, void *ptr, size_t size) -{ - return s->realloc_func(s->realloc_opaque, ptr, size); -} - -/* 'size' must be != 0 */ -static inline void *bf_malloc(bf_context_t *s, size_t size) -{ - return bf_realloc(s, NULL, size); -} - -static inline void bf_free(bf_context_t *s, void *ptr) -{ - /* must test ptr otherwise equivalent to malloc(0) */ - if (ptr) - bf_realloc(s, ptr, 0); -} - -void bf_init(bf_context_t *s, bf_t *r); - -static inline void bf_delete(bf_t *r) -{ - bf_context_t *s = r->ctx; - /* we accept to delete a zeroed bf_t structure */ - if (s && r->tab) { - bf_realloc(s, r->tab, 0); - } -} - -static inline void bf_neg(bf_t *r) -{ - r->sign ^= 1; -} - -static inline int bf_is_finite(const bf_t *a) -{ - return (a->expn < BF_EXP_INF); -} - -static inline int bf_is_nan(const bf_t *a) -{ - return (a->expn == BF_EXP_NAN); -} - -static inline int bf_is_zero(const bf_t *a) -{ - return (a->expn == BF_EXP_ZERO); -} - -static inline void bf_memcpy(bf_t *r, const bf_t *a) -{ - *r = *a; -} - -int bf_set_ui(bf_t *r, uint64_t a); -int bf_set_si(bf_t *r, int64_t a); -void bf_set_nan(bf_t *r); -void bf_set_zero(bf_t *r, int is_neg); -void bf_set_inf(bf_t *r, int is_neg); -int bf_set(bf_t *r, const bf_t *a); -void bf_move(bf_t *r, bf_t *a); -int bf_get_float64(const bf_t *a, double *pres, bf_rnd_t rnd_mode); -int bf_set_float64(bf_t *a, double d); - -int bf_cmpu(const bf_t *a, const bf_t *b); -int bf_cmp_full(const bf_t *a, const bf_t *b); -int bf_cmp(const bf_t *a, const bf_t *b); -static inline int bf_cmp_eq(const bf_t *a, const bf_t *b) -{ - return bf_cmp(a, b) == 0; -} - -static inline int bf_cmp_le(const bf_t *a, const bf_t *b) -{ - return bf_cmp(a, b) <= 0; -} - -static inline int bf_cmp_lt(const bf_t *a, const bf_t *b) -{ - return bf_cmp(a, b) < 0; -} - -int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); -int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); -int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags); -int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); -int bf_mul_ui(bf_t *r, const bf_t *a, uint64_t b1, limb_t prec, bf_flags_t flags); -int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, - bf_flags_t flags); -int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags); -int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); -#define BF_DIVREM_EUCLIDIAN BF_RNDF -int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b, - limb_t prec, bf_flags_t flags, int rnd_mode); -int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, - bf_flags_t flags, int rnd_mode); -int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, - bf_flags_t flags, int rnd_mode); -/* round to integer with infinite precision */ -int bf_rint(bf_t *r, int rnd_mode); -int bf_round(bf_t *r, limb_t prec, bf_flags_t flags); -int bf_sqrtrem(bf_t *r, bf_t *rem1, const bf_t *a); -int bf_sqrt(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); -slimb_t bf_get_exp_min(const bf_t *a); -int bf_logic_or(bf_t *r, const bf_t *a, const bf_t *b); -int bf_logic_xor(bf_t *r, const bf_t *a, const bf_t *b); -int bf_logic_and(bf_t *r, const bf_t *a, const bf_t *b); - -/* additional flags for bf_atof */ -/* do not accept hex radix prefix (0x or 0X) if radix = 0 or radix = 16 */ -#define BF_ATOF_NO_HEX (1 << 16) -/* accept binary (0b or 0B) or octal (0o or 0O) radix prefix if radix = 0 */ -#define BF_ATOF_BIN_OCT (1 << 17) -/* Do not parse NaN or Inf */ -#define BF_ATOF_NO_NAN_INF (1 << 18) -/* return the exponent separately */ -#define BF_ATOF_EXPONENT (1 << 19) - -int bf_atof(bf_t *a, const char *str, const char **pnext, int radix, - limb_t prec, bf_flags_t flags); -/* this version accepts prec = BF_PREC_INF and returns the radix - exponent */ -int bf_atof2(bf_t *r, slimb_t *pexponent, - const char *str, const char **pnext, int radix, - limb_t prec, bf_flags_t flags); -int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix, - slimb_t expn, limb_t prec, bf_flags_t flags); - - -/* Conversion of floating point number to string. Return a null - terminated string or NULL if memory error. *plen contains its - length if plen != NULL. The exponent letter is "e" for base 10, - "p" for bases 2, 8, 16 with a binary exponent and "@" for the other - bases. */ - -#define BF_FTOA_FORMAT_MASK (3 << 16) - -/* fixed format: prec significant digits rounded with (flags & - BF_RND_MASK). Exponential notation is used if too many zeros are - needed.*/ -#define BF_FTOA_FORMAT_FIXED (0 << 16) -/* fractional format: prec digits after the decimal point rounded with - (flags & BF_RND_MASK) */ -#define BF_FTOA_FORMAT_FRAC (1 << 16) -/* free format: - - For binary radices with bf_ftoa() and for bfdec_ftoa(): use the minimum - number of digits to represent 'a'. The precision and the rounding - mode are ignored. - - For the non binary radices with bf_ftoa(): use as many digits as - necessary so that bf_atof() return the same number when using - precision 'prec', rounding to nearest and the subnormal - configuration of 'flags'. The result is meaningful only if 'a' is - already rounded to 'prec' bits. If the subnormal flag is set, the - exponent in 'flags' must also be set to the desired exponent range. -*/ -#define BF_FTOA_FORMAT_FREE (2 << 16) -/* same as BF_FTOA_FORMAT_FREE but uses the minimum number of digits - (takes more computation time). Identical to BF_FTOA_FORMAT_FREE for - binary radices with bf_ftoa() and for bfdec_ftoa(). */ -#define BF_FTOA_FORMAT_FREE_MIN (3 << 16) - -/* force exponential notation for fixed or free format */ -#define BF_FTOA_FORCE_EXP (1 << 20) -/* add 0x prefix for base 16, 0o prefix for base 8 or 0b prefix for - base 2 if non zero value */ -#define BF_FTOA_ADD_PREFIX (1 << 21) -/* return "Infinity" instead of "Inf" and add a "+" for positive - exponents */ -#define BF_FTOA_JS_QUIRKS (1 << 22) - -char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec, - bf_flags_t flags); - -/* modulo 2^n instead of saturation. NaN and infinity return 0 */ -#define BF_GET_INT_MOD (1 << 0) -int bf_get_int32(int *pres, const bf_t *a, int flags); -int bf_get_int64(int64_t *pres, const bf_t *a, int flags); -int bf_get_uint64(uint64_t *pres, const bf_t *a); - -/* the following functions are exported for testing only. */ -void mp_print_str(const char *str, const limb_t *tab, limb_t n); -void bf_print_str(const char *str, const bf_t *a); -int bf_resize(bf_t *r, limb_t len); -int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len); -int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags); -int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k); -slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv, - int is_ceil1); -int mp_mul(bf_context_t *s, limb_t *result, - const limb_t *op1, limb_t op1_size, - const limb_t *op2, limb_t op2_size); -limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2, - limb_t n, limb_t carry); -limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n); -int mp_sqrtrem(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n); -int mp_recip(bf_context_t *s, limb_t *tabr, const limb_t *taba, limb_t n); -limb_t bf_isqrt(limb_t a); - -/* transcendental functions */ -int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags); -int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags); -int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); -int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); -#define BF_POW_JS_QUIRKS (1 << 16) /* (+/-1)^(+/-Inf) = NaN, 1^NaN = NaN */ -int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags); -int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); -int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); -int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); -int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); -int bf_atan2(bf_t *r, const bf_t *y, const bf_t *x, - limb_t prec, bf_flags_t flags); -int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); -int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); - -/* decimal floating point */ - -static inline void bfdec_init(bf_context_t *s, bfdec_t *r) -{ - bf_init(s, (bf_t *)r); -} -static inline void bfdec_delete(bfdec_t *r) -{ - bf_delete((bf_t *)r); -} - -static inline void bfdec_neg(bfdec_t *r) -{ - r->sign ^= 1; -} - -static inline int bfdec_is_finite(const bfdec_t *a) -{ - return (a->expn < BF_EXP_INF); -} - -static inline int bfdec_is_nan(const bfdec_t *a) -{ - return (a->expn == BF_EXP_NAN); -} - -static inline int bfdec_is_zero(const bfdec_t *a) -{ - return (a->expn == BF_EXP_ZERO); -} - -static inline void bfdec_memcpy(bfdec_t *r, const bfdec_t *a) -{ - bf_memcpy((bf_t *)r, (const bf_t *)a); -} - -int bfdec_set_ui(bfdec_t *r, uint64_t a); -int bfdec_set_si(bfdec_t *r, int64_t a); - -static inline void bfdec_set_nan(bfdec_t *r) -{ - bf_set_nan((bf_t *)r); -} -static inline void bfdec_set_zero(bfdec_t *r, int is_neg) -{ - bf_set_zero((bf_t *)r, is_neg); -} -static inline void bfdec_set_inf(bfdec_t *r, int is_neg) -{ - bf_set_inf((bf_t *)r, is_neg); -} -static inline int bfdec_set(bfdec_t *r, const bfdec_t *a) -{ - return bf_set((bf_t *)r, (bf_t *)a); -} -static inline void bfdec_move(bfdec_t *r, bfdec_t *a) -{ - bf_move((bf_t *)r, (bf_t *)a); -} -static inline int bfdec_cmpu(const bfdec_t *a, const bfdec_t *b) -{ - return bf_cmpu((const bf_t *)a, (const bf_t *)b); -} -static inline int bfdec_cmp_full(const bfdec_t *a, const bfdec_t *b) -{ - return bf_cmp_full((const bf_t *)a, (const bf_t *)b); -} -static inline int bfdec_cmp(const bfdec_t *a, const bfdec_t *b) -{ - return bf_cmp((const bf_t *)a, (const bf_t *)b); -} -static inline int bfdec_cmp_eq(const bfdec_t *a, const bfdec_t *b) -{ - return bfdec_cmp(a, b) == 0; -} -static inline int bfdec_cmp_le(const bfdec_t *a, const bfdec_t *b) -{ - return bfdec_cmp(a, b) <= 0; -} -static inline int bfdec_cmp_lt(const bfdec_t *a, const bfdec_t *b) -{ - return bfdec_cmp(a, b) < 0; -} - -int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, - bf_flags_t flags); -int bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, - bf_flags_t flags); -int bfdec_add_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec, - bf_flags_t flags); -int bfdec_mul(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, - bf_flags_t flags); -int bfdec_mul_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec, - bf_flags_t flags); -int bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, - bf_flags_t flags); -int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b, - limb_t prec, bf_flags_t flags, int rnd_mode); -int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, - bf_flags_t flags, int rnd_mode); -int bfdec_rint(bfdec_t *r, int rnd_mode); -int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags); -int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags); -int bfdec_get_int32(int *pres, const bfdec_t *a); -int bfdec_pow_ui(bfdec_t *r, const bfdec_t *a, limb_t b); - -char *bfdec_ftoa(size_t *plen, const bfdec_t *a, limb_t prec, bf_flags_t flags); -int bfdec_atof(bfdec_t *r, const char *str, const char **pnext, - limb_t prec, bf_flags_t flags); - -/* the following functions are exported for testing only. */ -extern const limb_t mp_pow_dec[LIMB_DIGITS + 1]; -void bfdec_print_str(const char *str, const bfdec_t *a); -static inline int bfdec_resize(bfdec_t *r, limb_t len) -{ - return bf_resize((bf_t *)r, len); -} -int bfdec_normalize_and_round(bfdec_t *r, limb_t prec1, bf_flags_t flags); - -/* clang-format on */ -COSMOPOLITAN_C_END_ -#endif /* COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBBF_H_ */ diff --git a/third_party/quickjs/libregexp-opcode.inc b/third_party/quickjs/libregexp-opcode.inc deleted file mode 100644 index 794668935..000000000 --- a/third_party/quickjs/libregexp-opcode.inc +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Regular Expression Engine - * - * Copyright (c) 2017-2018 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - - -#ifdef DEF - -DEF(invalid, 1) /* never used */ -DEF(char, 3) -DEF(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/third_party/quickjs/libregexp.c b/third_party/quickjs/libregexp.c deleted file mode 100644 index aa4b2d546..000000000 --- a/third_party/quickjs/libregexp.c +++ /dev/null @@ -1,2618 +0,0 @@ -/* - * Regular Expression Engine - * - * Copyright (c) 2017-2018 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/assert.h" -#include "libc/intrin/likely.h" -#include "libc/limits.h" -#include "libc/mem/alloca.h" -#include "libc/runtime/runtime.h" -#include "libc/stdio/stdio.h" -#include "libc/str/str.h" -#include "third_party/quickjs/cutils.h" -#include "third_party/quickjs/libregexp.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - - -/* - 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 "third_party/quickjs/libregexp-opcode.inc" -#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 *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 "third_party/quickjs/libregexp-opcode.inc" -#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->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 'e': - c = '\e'; /* [jart] love this */ - 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': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - c -= '0'; - if (allow_utf16 == 2) { - /* only accept \0 not followed by digit */ - if (c != 0 || is_digit(*p)) - return -1; - } else { - /* parse a legacy octal sequence */ - uint32_t v; - v = *p - '0'; - if (v > 7) - break; - c = (c << 3) | v; - p++; - if (c >= 32) - break; - v = *p - '0'; - if (v > 7) - break; - c = (c << 3) | v; - p++; - } - break; - default: - return -2; - } - *pp = p; - return c; -} - -#ifdef CONFIG_ALL_UNICODE -/* XXX: we use the same chars for name and value */ -static BOOL is_unicode_char(int c) -{ - return ((c >= '0' && c <= '9') || - (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') || - (c == '_')); -} - -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->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->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->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->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; - bzero(capture_bitmap, 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++; - if (capture_index >= CAPTURE_COUNT_MAX) - goto done; - } - } else { - capture_index++; - if (capture_index >= CAPTURE_COUNT_MAX) - goto done; - } - break; - case '\\': - p++; - break; - case '[': - for (p += 1 + (*p == ']'); p < s->buf_end && *p != ']'; p++) { - if (*p == '\\') - p++; - } - break; - } - } - done: - if (capture_name) - return -1; - else - return capture_index; -} - -static int re_count_captures(REParseState *s) -{ - if (s->total_capture_count < 0) { - s->total_capture_count = re_parse_captures(s, &s->has_named_captures, - NULL); - } - return s->total_capture_count; -} - -static BOOL re_has_named_captures(REParseState *s) -{ - if (s->has_named_captures < 0) - re_count_captures(s); - return s->has_named_captures; -} - -static int find_group_name(REParseState *s, const char *name) -{ - const char *p, *buf_end; - size_t len, name_len; - int capture_index; - - 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': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': - case '9': - { - const uint8_t *q = ++p; - - c = parse_digits(&p, FALSE); - if (c < 0 || (c >= s->capture_count && c >= re_count_captures(s))) { - if (!s->is_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 regular expression"); - } - emit_back_reference: - last_atom_start = s->byte_code.size; - last_capture_count = s->capture_count; - re_emit_op_u8(s, REOP_back_reference + 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; - - if (lre_check_stack_overflow(s->opaque, 0)) - return re_parse_error(s, "stack overflow"); - - start = s->byte_code.size; - if (re_parse_alternative(s, is_backward_dir)) - return -1; - while (*s->buf_ptr == '|') { - s->buf_ptr++; - - len = s->byte_code.size - start; - - /* insert a split before the first alternative */ - if (dbuf_insert(&s->byte_code, start, 5)) { - return re_parse_out_of_memory(s); - } - s->byte_code.buf[start] = REOP_split_next_first; - put_u32(s->byte_code.buf + start + 1, len + 5); - - pos = re_emit_op_u32(s, REOP_goto, 0); - - if (re_parse_alternative(s, is_backward_dir)) - return -1; - - /* patch the goto */ - len = s->byte_code.size - (pos + 4); - put_u32(s->byte_code.buf + pos, len); - } - return 0; -} - -/* the control flow is recursive so the analysis can be linear */ -static int compute_stack_size(const uint8_t *bc_buf, int bc_buf_len) -{ - int stack_size, stack_size_max, pos, opcode, len; - uint32_t val; - - stack_size = 0; - stack_size_max = 0; - bc_buf += RE_HEADER_LEN; - bc_buf_len -= RE_HEADER_LEN; - pos = 0; - while (pos < bc_buf_len) { - opcode = bc_buf[pos]; - len = reopcode_info[opcode].size; - assert(opcode < REOP_COUNT); - assert((pos + len) <= bc_buf_len); - switch(opcode) { - case REOP_push_i32: - case REOP_push_char_pos: - stack_size++; - if (stack_size > stack_size_max) { - if (stack_size > STACK_SIZE_MAX) - return -1; - stack_size_max = stack_size; - } - break; - case REOP_drop: - case REOP_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; - - bzero(s, sizeof(*s)); - s->opaque = opaque; - s->buf_ptr = (const uint8_t *)buf; - s->buf_end = s->buf_ptr + buf_len; - s->buf_start = s->buf_ptr; - s->re_flags = re_flags; - s->is_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]; -} - -/* Return NULL if no group names. Otherwise, return a pointer to - 'capture_count - 1' zero terminated UTF-8 strings. */ -const char *lre_get_groupnames(const uint8_t *bc_buf) -{ - uint32_t re_bytecode_len; - if ((lre_get_flags(bc_buf) & LRE_FLAG_NAMED_GROUPS) == 0) - return NULL; - re_bytecode_len = get_u32(bc_buf + 3); - return (const char *)(bc_buf + 7 + re_bytecode_len); -} - -#ifdef TEST - -BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size) -{ - return FALSE; -} - -void *lre_realloc(void *opaque, void *ptr, size_t size) -{ - return realloc(ptr, size); -} - -int main(int argc, char **argv) -{ - int len, 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/third_party/quickjs/libregexp.h b/third_party/quickjs/libregexp.h deleted file mode 100644 index bf7e2350c..000000000 --- a/third_party/quickjs/libregexp.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBREGEXP_H_ -#define COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBREGEXP_H_ -#include "third_party/quickjs/libunicode.h" -COSMOPOLITAN_C_START_ - -#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); -const char *lre_get_groupnames(const uint8_t *bc_buf); -int lre_exec(uint8_t **capture, - const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen, - int cbuf_type, void *opaque); - -int lre_parse_escape(const uint8_t **pp, int allow_utf16); -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 - -/* clang-format on */ -COSMOPOLITAN_C_END_ -#endif /* COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBREGEXP_H_ */ diff --git a/third_party/quickjs/libunicode-table.inc b/third_party/quickjs/libunicode-table.inc deleted file mode 100644 index 5c37dee38..000000000 --- a/third_party/quickjs/libunicode-table.inc +++ /dev/null @@ -1,4447 +0,0 @@ -/* Compressed unicode tables */ -/* Automatically generated file - do not edit */ - -static const uint32_t case_conv_table1[370] = { - 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, 0x16003031, - 0x16183001, 0x16300240, 0x16310130, 0x16318130, - 0x16320130, 0x16328100, 0x16330100, 0x16338640, - 0x16368130, 0x16370130, 0x16378130, 0x16380130, - 0x16390240, 0x163a8240, 0x163f0230, 0x16406440, - 0x16758440, 0x16790240, 0x16802600, 0x16938100, - 0x16968100, 0x53202e40, 0x53401c40, 0x53910e40, - 0x53993e40, 0x53bc8440, 0x53be8130, 0x53bf0a40, - 0x53c58240, 0x53c68130, 0x53c80440, 0x53ca0101, - 0x53cb1440, 0x53d50130, 0x53d58130, 0x53d60130, - 0x53d68130, 0x53d70130, 0x53d80130, 0x53d88130, - 0x53d90130, 0x53d98131, 0x53da1040, 0x53e20131, - 0x53e28130, 0x53e30130, 0x53e38440, 0x53e80240, - 0x53eb0440, 0x53fa8240, 0x55a98101, 0x55b85020, - 0x7d8001b2, 0x7d8081b2, 0x7d8101b2, 0x7d8181da, - 0x7d8201da, 0x7d8281b3, 0x7d8301b3, 0x7d8981bb, - 0x7d8a01bb, 0x7d8a81bb, 0x7d8b01bc, 0x7d8b81bb, - 0x7f909a31, 0x7fa09a01, 0x82002831, 0x82142801, - 0x82582431, 0x826c2401, 0x82b80b31, 0x82be0f31, - 0x82c60731, 0x82ca0231, 0x82cb8b01, 0x82d18f01, - 0x82d98701, 0x82dd8201, 0x86403331, 0x86603301, - 0x8c502031, 0x8c602001, 0xb7202031, 0xb7302001, - 0xf4802231, 0xf4912201, -}; - -static const uint8_t case_conv_table2[370] = { - 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, 0x48, - 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, - 0x4f, 0xaa, 0xa9, 0x12, 0x14, 0x1e, 0x21, 0x22, - 0x22, 0x2a, 0x34, 0x35, 0xa6, 0xa7, 0x36, 0x1f, - 0x49, 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, 0x47, 0x00, 0x5b, 0x56, 0x58, - 0x60, 0x5e, 0x70, 0x69, 0x6f, 0x4e, 0x00, 0x3b, - 0x67, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x45, 0xa8, - 0x8a, 0x8b, 0x8c, 0xab, 0xac, 0x58, 0x58, 0xaf, - 0x94, 0xb0, 0x6f, 0xb2, 0x5d, 0x5c, 0x5f, 0x5e, - 0x61, 0x60, 0x66, 0x67, 0x68, 0x69, 0x62, 0x63, - 0x64, 0x65, 0x6b, 0x6a, 0x6d, 0x6c, 0x6f, 0x6e, - 0x71, 0x70, -}; - -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[188] = { - 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, 0xa2, 0x00, 0x80, 0xa1, - 0x82, 0x43, 0x34, 0xa2, 0x06, 0x80, 0x8c, 0x60, - 0x5c, 0x16, 0x01, 0x10, 0xa9, 0x80, 0x88, 0x60, - 0xcc, 0x44, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, - 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, - 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, - 0x80, 0x41, 0x53, 0x81, 0x98, 0x80, 0x98, 0x80, - 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, - 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07, - 0x47, 0x33, 0x89, 0x80, 0x93, 0x52, 0x10, 0x99, - 0x85, 0x99, 0x85, 0x99, -}; - -static const uint8_t unicode_prop_Cased1_index[18] = { - 0xb9, 0x02, 0xe0, 0xa0, 0x1e, 0x40, 0x9e, 0xa6, - 0x40, 0x55, 0xd4, 0x61, 0xfb, 0xd6, 0x21, 0x8a, - 0xf1, 0x01, -}; - -static const uint8_t unicode_prop_Case_Ignorable_table[720] = { - 0xa6, 0x05, 0x80, 0x8a, 0x80, 0xa2, 0x00, 0x80, - 0xc6, 0x03, 0x00, 0x03, 0x01, 0x81, 0x41, 0xf6, - 0x40, 0xbf, 0x19, 0x18, 0x88, 0x08, 0x80, 0x40, - 0xfa, 0x86, 0x40, 0xce, 0x04, 0x80, 0xb0, 0xac, - 0x00, 0x01, 0x01, 0x00, 0xab, 0x80, 0x8a, 0x85, - 0x89, 0x8a, 0x00, 0xa2, 0x80, 0x89, 0x94, 0x8f, - 0x80, 0xe4, 0x38, 0x89, 0x03, 0xa0, 0x00, 0x80, - 0x9d, 0x9a, 0xda, 0x8a, 0xb9, 0x8a, 0x18, 0x08, - 0x97, 0x97, 0xaa, 0x82, 0xab, 0x06, 0x0d, 0x87, - 0xa8, 0xb9, 0xb6, 0x00, 0x03, 0x3b, 0x02, 0x86, - 0x89, 0x81, 0x8c, 0x80, 0x8e, 0x80, 0xb9, 0x03, - 0x1f, 0x80, 0x93, 0x81, 0x99, 0x01, 0x81, 0xb8, - 0x03, 0x0b, 0x09, 0x12, 0x80, 0x9d, 0x0a, 0x80, - 0x8a, 0x81, 0xb8, 0x03, 0x20, 0x0b, 0x80, 0x93, - 0x81, 0x95, 0x28, 0x80, 0xb9, 0x01, 0x00, 0x1f, - 0x06, 0x81, 0x8a, 0x81, 0x9d, 0x80, 0xbc, 0x80, - 0x8b, 0x80, 0xb1, 0x02, 0x80, 0xb6, 0x00, 0x14, - 0x10, 0x1e, 0x81, 0x8a, 0x81, 0x9c, 0x80, 0xb9, - 0x01, 0x05, 0x04, 0x81, 0x93, 0x81, 0x9b, 0x81, - 0xb8, 0x0b, 0x1f, 0x80, 0x93, 0x81, 0x9c, 0x80, - 0xc7, 0x06, 0x10, 0x80, 0xd9, 0x01, 0x86, 0x8a, - 0x88, 0xe1, 0x01, 0x88, 0x88, 0x00, 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, - 0x81, 0x9d, 0x81, 0x9d, 0x81, 0xbf, 0x08, 0x37, - 0x01, 0x8a, 0x10, 0x20, 0xac, 0x84, 0xb2, 0x80, - 0xc0, 0x81, 0xa1, 0x80, 0xf5, 0x13, 0x81, 0x88, - 0x05, 0x82, 0x40, 0xda, 0x09, 0x80, 0xb9, 0x00, - 0x30, 0x00, 0x01, 0x3d, 0x89, 0x08, 0xa6, 0x07, - 0x9e, 0xb0, 0x83, 0xaf, 0x00, 0x20, 0x04, 0x80, - 0xa7, 0x88, 0x8b, 0x81, 0x9f, 0x19, 0x08, 0x82, - 0xb7, 0x00, 0x0a, 0x00, 0x82, 0xb9, 0x39, 0x81, - 0xbf, 0x85, 0xd1, 0x10, 0x8c, 0x06, 0x18, 0x28, - 0x11, 0xb1, 0xbe, 0x8c, 0x80, 0xa1, 0xe4, 0x41, - 0xbc, 0x00, 0x82, 0x8a, 0x82, 0x8c, 0x82, 0x8c, - 0x82, 0x8c, 0x81, 0x8b, 0x27, 0x81, 0x89, 0x01, - 0x01, 0x84, 0xb0, 0x20, 0x89, 0x00, 0x8c, 0x80, - 0x8f, 0x8c, 0xb2, 0xa0, 0x4b, 0x8a, 0x81, 0xf0, - 0x82, 0xfc, 0x80, 0x8e, 0x80, 0xdf, 0x9f, 0xae, - 0x80, 0x41, 0xd4, 0x80, 0xa3, 0x1a, 0x24, 0x80, - 0xdc, 0x85, 0xdc, 0x82, 0x60, 0x6f, 0x15, 0x80, - 0x44, 0xe1, 0x85, 0x41, 0x0d, 0x80, 0xe1, 0x18, - 0x89, 0x00, 0x9b, 0x83, 0xcf, 0x81, 0x8d, 0xa1, - 0xcd, 0x80, 0x96, 0x82, 0xe6, 0x12, 0x0f, 0x02, - 0x03, 0x80, 0x98, 0x0c, 0x80, 0x40, 0x96, 0x81, - 0x99, 0x91, 0x8c, 0x80, 0xa5, 0x87, 0x98, 0x8a, - 0xad, 0x82, 0xaf, 0x01, 0x19, 0x81, 0x90, 0x80, - 0x94, 0x81, 0xc1, 0x29, 0x09, 0x81, 0x8b, 0x07, - 0x80, 0xa2, 0x80, 0x8a, 0x80, 0xb2, 0x00, 0x11, - 0x0c, 0x08, 0x80, 0x9a, 0x80, 0x8d, 0x0c, 0x08, - 0x80, 0xe3, 0x84, 0x88, 0x82, 0xf8, 0x01, 0x03, - 0x80, 0x60, 0x4f, 0x2f, 0x80, 0x40, 0x92, 0x90, - 0x42, 0x3c, 0x8f, 0x10, 0x8b, 0x8f, 0xa1, 0x01, - 0x80, 0x40, 0xa8, 0x06, 0x05, 0x80, 0x8a, 0x80, - 0xa2, 0x00, 0x80, 0xae, 0x80, 0xac, 0x81, 0xc2, - 0x80, 0x94, 0x82, 0x42, 0x00, 0x80, 0x40, 0xe1, - 0x80, 0x40, 0x94, 0x84, 0x44, 0x04, 0x28, 0xa9, - 0x80, 0x88, 0x42, 0x45, 0x10, 0x0c, 0x83, 0xa7, - 0x13, 0x80, 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x83, - 0x41, 0x82, 0x81, 0x40, 0x98, 0x8a, 0xb0, 0x83, - 0xfa, 0x80, 0xb5, 0x8e, 0xa8, 0x01, 0x81, 0x89, - 0x82, 0xb0, 0x19, 0x09, 0x03, 0x80, 0x89, 0x80, - 0xb1, 0x82, 0xa3, 0x20, 0x87, 0xbd, 0x80, 0x8b, - 0x81, 0xb3, 0x88, 0x89, 0x19, 0x80, 0xde, 0x11, - 0x00, 0x0d, 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, 0x40, 0x0a, 0x18, 0x30, - 0x81, 0x4c, 0x9d, 0x08, 0x83, 0x52, 0x5b, 0xad, - 0x81, 0x96, 0x42, 0x1f, 0x82, 0x88, 0x8f, 0x0e, - 0x9d, 0x83, 0x40, 0x93, 0x82, 0x47, 0xba, 0xb6, - 0x83, 0xb1, 0x38, 0x8d, 0x80, 0x95, 0x20, 0x8e, - 0x45, 0x4f, 0x30, 0x90, 0x0e, 0x01, 0x04, 0x41, - 0x04, 0x8d, 0x41, 0x6f, 0x80, 0xbc, 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[69] = { - 0xbe, 0x05, 0x00, 0xfe, 0x07, 0x00, 0x52, 0x0a, - 0xa0, 0xc1, 0x0b, 0x00, 0x82, 0x0d, 0x00, 0x3f, - 0x10, 0x80, 0xd4, 0x17, 0x40, 0xcf, 0x1a, 0x20, - 0xf5, 0x1c, 0x00, 0x80, 0x20, 0x00, 0x16, 0xa0, - 0x00, 0xc6, 0xa8, 0x00, 0xc2, 0xaa, 0x60, 0x56, - 0xfe, 0x20, 0xb1, 0x07, 0x01, 0x82, 0x10, 0x21, - 0x02, 0x13, 0x21, 0xb8, 0x16, 0x61, 0x97, 0x1a, - 0x01, 0x37, 0x6b, 0x21, 0x8c, 0xd1, 0x01, 0xd7, - 0xe8, 0x41, 0xf0, 0x01, 0x0e, -}; - -static const uint8_t unicode_prop_ID_Start_table[1079] = { - 0xc0, 0x99, 0x85, 0x99, 0xae, 0x80, 0x89, 0x03, - 0x04, 0x96, 0x80, 0x9e, 0x80, 0x41, 0xc9, 0x83, - 0x8b, 0x8d, 0x26, 0x00, 0x80, 0x40, 0x80, 0x20, - 0x09, 0x18, 0x05, 0x00, 0x10, 0x00, 0x93, 0x80, - 0xd2, 0x80, 0x40, 0x8a, 0x87, 0x40, 0xa5, 0x80, - 0xa5, 0x08, 0x85, 0xa8, 0xc6, 0x9a, 0x1b, 0xac, - 0xaa, 0xa2, 0x08, 0xe2, 0x00, 0x8e, 0x0e, 0x81, - 0x89, 0x11, 0x80, 0x8f, 0x00, 0x9d, 0x9c, 0xd8, - 0x8a, 0x80, 0x97, 0xa0, 0x88, 0x0b, 0x04, 0x95, - 0x18, 0x88, 0x02, 0x80, 0x96, 0x98, 0x86, 0x8a, - 0x84, 0x97, 0x05, 0x90, 0xa9, 0xb9, 0xb5, 0x10, - 0x91, 0x06, 0x89, 0x8e, 0x8f, 0x1f, 0x09, 0x81, - 0x95, 0x06, 0x00, 0x13, 0x10, 0x8f, 0x80, 0x8c, - 0x08, 0x82, 0x8d, 0x81, 0x89, 0x07, 0x2b, 0x09, - 0x95, 0x06, 0x01, 0x01, 0x01, 0x9e, 0x18, 0x80, - 0x92, 0x82, 0x8f, 0x88, 0x02, 0x80, 0x95, 0x06, - 0x01, 0x04, 0x10, 0x91, 0x80, 0x8e, 0x81, 0x96, - 0x80, 0x8a, 0x39, 0x09, 0x95, 0x06, 0x01, 0x04, - 0x10, 0x9d, 0x08, 0x82, 0x8e, 0x80, 0x90, 0x00, - 0x2a, 0x10, 0x1a, 0x08, 0x00, 0x0a, 0x0a, 0x12, - 0x8b, 0x95, 0x80, 0xb3, 0x38, 0x10, 0x96, 0x80, - 0x8f, 0x10, 0x99, 0x11, 0x01, 0x81, 0x9d, 0x03, - 0x38, 0x10, 0x96, 0x80, 0x89, 0x04, 0x10, 0x9e, - 0x08, 0x81, 0x8e, 0x81, 0x90, 0x88, 0x02, 0x80, - 0xa8, 0x08, 0x8f, 0x04, 0x17, 0x82, 0x97, 0x2c, - 0x91, 0x82, 0x97, 0x80, 0x88, 0x00, 0x0e, 0xb9, - 0xaf, 0x01, 0x8b, 0x86, 0xb9, 0x08, 0x00, 0x20, - 0x97, 0x00, 0x80, 0x89, 0x01, 0x88, 0x01, 0x20, - 0x80, 0x94, 0x83, 0x9f, 0x80, 0xbe, 0x38, 0xa3, - 0x9a, 0x84, 0xf2, 0xaa, 0x93, 0x80, 0x8f, 0x2b, - 0x1a, 0x02, 0x0e, 0x13, 0x8c, 0x8b, 0x80, 0x90, - 0xa5, 0x00, 0x20, 0x81, 0xaa, 0x80, 0x41, 0x4c, - 0x03, 0x0e, 0x00, 0x03, 0x81, 0xa8, 0x03, 0x81, - 0xa0, 0x03, 0x0e, 0x00, 0x03, 0x81, 0x8e, 0x80, - 0xb8, 0x03, 0x81, 0xc2, 0xa4, 0x8f, 0x8f, 0xd5, - 0x0d, 0x82, 0x42, 0x6b, 0x81, 0x90, 0x80, 0x99, - 0x84, 0xca, 0x82, 0x8a, 0x86, 0x91, 0x8c, 0x92, - 0x8d, 0x91, 0x8d, 0x8c, 0x02, 0x8e, 0xb3, 0xa2, - 0x03, 0x80, 0xc2, 0xd8, 0x86, 0xa8, 0x00, 0x84, - 0xc5, 0x89, 0x9e, 0xb0, 0x9d, 0x0c, 0x8a, 0xab, - 0x83, 0x99, 0xb5, 0x96, 0x88, 0xb4, 0xd1, 0x80, - 0xdc, 0xae, 0x90, 0x87, 0xb5, 0x9d, 0x8c, 0x81, - 0x89, 0xab, 0x99, 0xa3, 0xa8, 0x82, 0x89, 0xa3, - 0x81, 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, 0x40, 0xe4, 0x2b, - 0x11, 0x8b, 0xa5, 0x00, 0x20, 0x81, 0xb7, 0x30, - 0x8f, 0x96, 0x88, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x86, 0x42, 0x25, 0x82, 0x98, 0x88, - 0x34, 0x0c, 0x83, 0xd5, 0x1c, 0x80, 0xd9, 0x03, - 0x84, 0xaa, 0x80, 0xdd, 0x90, 0x9f, 0xaf, 0x8f, - 0x41, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x56, 0x8c, - 0xc2, 0xad, 0x81, 0x41, 0x0c, 0x82, 0x8f, 0x89, - 0x81, 0x93, 0xae, 0x8f, 0x9e, 0x81, 0xcf, 0xa6, - 0x88, 0x81, 0xe6, 0x81, 0xbf, 0x21, 0x00, 0x04, - 0x97, 0x8f, 0x02, 0x03, 0x80, 0x96, 0x9c, 0xb3, - 0x8d, 0xb1, 0xbd, 0x2a, 0x00, 0x81, 0x8a, 0x9b, - 0x89, 0x96, 0x98, 0x9c, 0x86, 0xae, 0x9b, 0x80, - 0x8f, 0x20, 0x89, 0x89, 0x20, 0xa8, 0x96, 0x10, - 0x87, 0x93, 0x96, 0x10, 0x82, 0xb1, 0x00, 0x11, - 0x0c, 0x08, 0x00, 0x97, 0x11, 0x8a, 0x32, 0x8b, - 0x29, 0x29, 0x85, 0x88, 0x30, 0x30, 0xaa, 0x80, - 0x8d, 0x85, 0xf2, 0x9c, 0x60, 0x2b, 0xa3, 0x8b, - 0x96, 0x83, 0xb0, 0x60, 0x21, 0x03, 0x41, 0x6d, - 0x81, 0xe9, 0xa5, 0x86, 0x8b, 0x24, 0x00, 0x89, - 0x80, 0x8c, 0x04, 0x00, 0x01, 0x01, 0x80, 0xeb, - 0xa0, 0x41, 0x6a, 0x91, 0xbf, 0x81, 0xb5, 0xa7, - 0x8b, 0xf3, 0x20, 0x40, 0x86, 0xa3, 0x99, 0x85, - 0x99, 0x8a, 0xd8, 0x15, 0x0d, 0x0d, 0x0a, 0xa2, - 0x8b, 0x80, 0x99, 0x80, 0x92, 0x01, 0x80, 0x8e, - 0x81, 0x8d, 0xa1, 0xfa, 0xc4, 0xb4, 0x41, 0x0a, - 0x9c, 0x82, 0xb0, 0xae, 0x9f, 0x8c, 0x9d, 0x84, - 0xa5, 0x89, 0x9d, 0x81, 0xa3, 0x1f, 0x04, 0xa9, - 0x40, 0x9d, 0x91, 0xa3, 0x83, 0xa3, 0x83, 0xa7, - 0x87, 0xb3, 0x8b, 0x8a, 0x80, 0x8e, 0x06, 0x01, - 0x80, 0x8a, 0x80, 0x8e, 0x06, 0x01, 0xc2, 0x41, - 0x36, 0x88, 0x95, 0x89, 0x87, 0x97, 0x28, 0xa9, - 0x80, 0x88, 0xc4, 0x29, 0x00, 0xab, 0x01, 0x10, - 0x81, 0x96, 0x89, 0x96, 0x88, 0x9e, 0xc0, 0x92, - 0x01, 0x89, 0x95, 0x89, 0x99, 0xc5, 0xb7, 0x29, - 0xbf, 0x80, 0x8e, 0x18, 0x10, 0x9c, 0xa9, 0x9c, - 0x82, 0x9c, 0xa2, 0x38, 0x9b, 0x9a, 0xb5, 0x89, - 0x95, 0x89, 0x92, 0x8c, 0x91, 0xed, 0xc8, 0xb6, - 0xb2, 0x8c, 0xb2, 0x8c, 0xa3, 0x41, 0x5b, 0xa9, - 0x29, 0xcd, 0x9c, 0x89, 0x07, 0x95, 0xa9, 0x91, - 0xad, 0x94, 0x9a, 0x96, 0x8b, 0xb4, 0xb8, 0x09, - 0x80, 0x8c, 0xac, 0x9f, 0x98, 0x99, 0xa3, 0x9c, - 0x01, 0x07, 0xa2, 0x10, 0x8b, 0xaf, 0x8d, 0x83, - 0x94, 0x00, 0x80, 0xa2, 0x91, 0x80, 0x98, 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, 0xa4, - 0x86, 0x40, 0xb8, 0xab, 0xf3, 0xbf, 0x9e, 0x39, - 0x01, 0x38, 0x08, 0x97, 0x8e, 0x00, 0x80, 0xdd, - 0x39, 0xa6, 0x8f, 0x00, 0x80, 0x9b, 0x80, 0x89, - 0xa7, 0x30, 0x94, 0x80, 0x8a, 0xad, 0x92, 0x80, - 0x91, 0xc8, 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, 0x4b, 0xe0, - 0x8e, 0x44, 0x2e, 0x4f, 0xd0, 0x42, 0x46, 0x60, - 0x21, 0xb8, 0x42, 0x38, 0x86, 0x9e, 0x90, 0xce, - 0x90, 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, 0xe6, - 0x18, 0x30, 0x08, 0x41, 0x22, 0xac, 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, 0x47, 0x33, 0x9e, 0x41, - 0xe0, 0xac, 0x89, 0x86, 0x8f, 0x80, 0x41, 0x40, - 0x9d, 0x91, 0xab, 0x44, 0xf3, 0x30, 0x18, 0x08, - 0x8e, 0x80, 0x40, 0xc4, 0xba, 0xc3, 0x30, 0x44, - 0xb3, 0x18, 0x9a, 0x01, 0x00, 0x08, 0x80, 0x89, - 0x03, 0x00, 0x00, 0x28, 0x18, 0x00, 0x00, 0x02, - 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00, 0x80, 0x89, - 0x80, 0x90, 0x22, 0x04, 0x80, 0x90, 0x51, 0x43, - 0x60, 0xa6, 0xdf, 0x9f, 0x50, 0x38, 0x86, 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[102] = { - 0xf6, 0x03, 0x20, 0xa6, 0x07, 0x00, 0xa9, 0x09, - 0x20, 0xb1, 0x0a, 0x00, 0xba, 0x0b, 0x20, 0x3b, - 0x0d, 0x20, 0xc7, 0x0e, 0x20, 0x49, 0x12, 0x00, - 0x9b, 0x16, 0x00, 0xac, 0x19, 0x00, 0xc0, 0x1d, - 0x80, 0x80, 0x20, 0x20, 0x70, 0x2d, 0x00, 0x00, - 0x32, 0x00, 0xda, 0xa7, 0x00, 0x4c, 0xaa, 0x20, - 0xc7, 0xd7, 0x20, 0xfc, 0xfd, 0x20, 0x9d, 0x02, - 0x21, 0x96, 0x05, 0x01, 0xf3, 0x08, 0x01, 0xb3, - 0x0c, 0x21, 0x73, 0x11, 0x61, 0x3e, 0x13, 0x01, - 0x47, 0x17, 0x21, 0x9e, 0x1a, 0x01, 0x9a, 0x23, - 0x01, 0x78, 0x6b, 0x01, 0xfc, 0xb2, 0x61, 0x3a, - 0xd5, 0x01, 0x2d, 0xe1, 0x41, 0x33, 0xee, 0x01, - 0xe0, 0xa6, 0x62, 0x4b, 0x13, 0x03, -}; - -static const uint8_t unicode_prop_ID_Continue1_table[640] = { - 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, 0xbb, 0x87, 0xa9, 0x97, 0x80, - 0xa0, 0xb5, 0x10, 0x91, 0x06, 0x89, 0x09, 0x89, - 0x90, 0x82, 0xb7, 0x00, 0x31, 0x09, 0x82, 0x88, - 0x80, 0x89, 0x09, 0x89, 0x8d, 0x01, 0x82, 0xb7, - 0x00, 0x23, 0x09, 0x12, 0x80, 0x93, 0x8b, 0x10, - 0x8a, 0x82, 0xb7, 0x00, 0x38, 0x10, 0x82, 0x93, - 0x09, 0x89, 0x89, 0x28, 0x82, 0xb7, 0x00, 0x31, - 0x09, 0x16, 0x82, 0x89, 0x09, 0x89, 0x91, 0x80, - 0xba, 0x22, 0x10, 0x83, 0x88, 0x80, 0x8d, 0x89, - 0x8f, 0x84, 0xb6, 0x00, 0x30, 0x10, 0x1e, 0x81, - 0x8a, 0x09, 0x89, 0x90, 0x82, 0xb7, 0x00, 0x30, - 0x10, 0x1e, 0x81, 0x8a, 0x09, 0x89, 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, 0x83, 0x9b, 0x82, - 0x9c, 0x81, 0x9d, 0x81, 0xbf, 0x9f, 0x88, 0x01, - 0x89, 0xa0, 0x10, 0x8a, 0x40, 0x8e, 0x80, 0xf5, - 0x8b, 0x83, 0x8b, 0x89, 0x89, 0xff, 0x8a, 0xbb, - 0x84, 0xb8, 0x89, 0x80, 0x9c, 0x81, 0x8a, 0x85, - 0x89, 0x95, 0x8d, 0x80, 0x8f, 0xb0, 0x84, 0xae, - 0x90, 0x8a, 0x89, 0x90, 0x88, 0x8b, 0x82, 0x9d, - 0x8c, 0x81, 0x89, 0xab, 0x8d, 0xaf, 0x93, 0x87, - 0x89, 0x85, 0x89, 0xf5, 0x10, 0x94, 0x18, 0x28, - 0x0a, 0x40, 0xc5, 0xbf, 0x42, 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, 0xb0, 0x83, - 0xf9, 0x82, 0xb4, 0x8e, 0x9e, 0x8a, 0x09, 0x89, - 0x83, 0xac, 0x8a, 0x30, 0xac, 0x89, 0x2a, 0xa3, - 0x8d, 0x80, 0x89, 0x21, 0xab, 0x80, 0x8b, 0x82, - 0xaf, 0x8d, 0x3b, 0x80, 0x8b, 0xd1, 0x8b, 0x28, - 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, 0xd5, 0x89, - 0xa5, 0x84, 0xba, 0x86, 0x98, 0x89, 0x43, 0xf4, - 0x00, 0xb6, 0x33, 0xd0, 0x80, 0x8a, 0x81, 0x60, - 0x4c, 0xaa, 0x81, 0x52, 0x60, 0xad, 0x81, 0x96, - 0x42, 0x1d, 0x22, 0x2f, 0x39, 0x86, 0x9d, 0x83, - 0x40, 0x93, 0x82, 0x45, 0x88, 0xb1, 0x41, 0xff, - 0xb6, 0x83, 0xb1, 0x38, 0x8d, 0x80, 0x95, 0x20, - 0x8e, 0x45, 0x4f, 0x30, 0x90, 0x0e, 0x01, 0x04, - 0x41, 0x04, 0x86, 0x88, 0x89, 0x41, 0x63, 0x80, - 0xbc, 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, 0x70, 0x09, 0x00, 0xf0, 0x0a, - 0x40, 0x57, 0x0c, 0x00, 0xf0, 0x0d, 0x40, 0xc7, - 0x0f, 0x00, 0xea, 0x17, 0x20, 0x45, 0x1b, 0x20, - 0x55, 0x20, 0x20, 0x0c, 0xa8, 0x60, 0x37, 0xaa, - 0x00, 0x50, 0xfe, 0x00, 0x3a, 0x0d, 0x01, 0x83, - 0x11, 0x01, 0xc4, 0x14, 0x21, 0x44, 0x19, 0x21, - 0x5a, 0x1d, 0x41, 0x9f, 0xbc, 0x61, 0xb0, 0xda, - 0x21, 0xf0, 0x01, 0x0e, -}; - -#ifdef CONFIG_ALL_UNICODE - -static const uint8_t unicode_cc_table[881] = { - 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, 0x0b, 0xc0, 0x02, 0xdc, - 0xc3, 0xa9, 0xc4, 0x04, 0xdc, 0xcd, 0x80, 0x00, - 0xdc, 0xc1, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xc2, - 0x02, 0xdc, 0x42, 0x1b, 0xc2, 0x00, 0xdc, 0xc1, - 0x01, 0xdc, 0xc4, 0xb0, 0x0b, 0x00, 0x07, 0x8f, - 0x00, 0x09, 0x82, 0xc0, 0x00, 0xdc, 0xc1, 0xb0, - 0x36, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xaf, 0xc0, - 0xb0, 0x0c, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0, - 0x3d, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0, 0x3d, - 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0, 0x4e, 0x00, - 0x09, 0xb0, 0x3d, 0x00, 0x07, 0x8f, 0x00, 0x09, - 0x86, 0x00, 0x54, 0x00, 0x5b, 0xb0, 0x34, 0x00, - 0x07, 0x8f, 0x00, 0x09, 0xb0, 0x3c, 0x01, 0x09, - 0x8f, 0x00, 0x09, 0xb0, 0x4b, 0x00, 0x09, 0xb0, - 0x3c, 0x01, 0x67, 0x00, 0x09, 0x8c, 0x03, 0x6b, - 0xb0, 0x3b, 0x01, 0x76, 0x00, 0x09, 0x8c, 0x03, - 0x7a, 0xb0, 0x1b, 0x01, 0xdc, 0x9a, 0x00, 0xdc, - 0x80, 0x00, 0xdc, 0x80, 0x00, 0xd8, 0xb0, 0x06, - 0x41, 0x81, 0x80, 0x00, 0x84, 0x84, 0x03, 0x82, - 0x81, 0x00, 0x82, 0x80, 0xc1, 0x00, 0x09, 0x80, - 0xc1, 0xb0, 0x0d, 0x00, 0xdc, 0xb0, 0x3f, 0x00, - 0x07, 0x80, 0x01, 0x09, 0xb0, 0x21, 0x00, 0xdc, - 0xb2, 0x9e, 0xc2, 0xb3, 0x83, 0x01, 0x09, 0x9d, - 0x00, 0x09, 0xb0, 0x6c, 0x00, 0x09, 0x89, 0xc0, - 0xb0, 0x9a, 0x00, 0xe4, 0xb0, 0x5e, 0x00, 0xde, - 0xc0, 0x00, 0xdc, 0xb0, 0xaa, 0xc0, 0x00, 0xdc, - 0xb0, 0x16, 0x00, 0x09, 0x93, 0xc7, 0x81, 0x00, - 0xdc, 0xaf, 0xc4, 0x05, 0xdc, 0xc1, 0x00, 0xdc, - 0x80, 0x01, 0xdc, 0xc1, 0x01, 0xdc, 0xc4, 0x00, - 0xdc, 0xc3, 0xb0, 0x34, 0x00, 0x07, 0x8e, 0x00, - 0x09, 0xa5, 0xc0, 0x00, 0xdc, 0xc6, 0xb0, 0x05, - 0x01, 0x09, 0xb0, 0x09, 0x00, 0x07, 0x8a, 0x01, - 0x09, 0xb0, 0x12, 0x00, 0x07, 0xb0, 0x67, 0xc2, - 0x41, 0x00, 0x04, 0xdc, 0xc1, 0x03, 0xdc, 0xc0, - 0x41, 0x00, 0x05, 0x01, 0x83, 0x00, 0xdc, 0x85, - 0xc0, 0x82, 0xc1, 0xb0, 0x95, 0xc1, 0x00, 0xdc, - 0xc6, 0x00, 0xdc, 0xc1, 0x00, 0xea, 0x00, 0xd6, - 0x00, 0xdc, 0x00, 0xca, 0xe4, 0x00, 0xe8, 0x01, - 0xe4, 0x00, 0xdc, 0x00, 0xda, 0xc0, 0x00, 0xe9, - 0x00, 0xdc, 0xc0, 0x00, 0xdc, 0xb2, 0x9f, 0xc1, - 0x01, 0x01, 0xc3, 0x02, 0x01, 0xc1, 0x83, 0xc0, - 0x82, 0x01, 0x01, 0xc0, 0x00, 0xdc, 0xc0, 0x01, - 0x01, 0x03, 0xdc, 0xc0, 0xb8, 0x03, 0xcd, 0xc2, - 0xb0, 0x5c, 0x00, 0x09, 0xb0, 0x2f, 0xdf, 0xb1, - 0xf9, 0x00, 0xda, 0x00, 0xe4, 0x00, 0xe8, 0x00, - 0xde, 0x01, 0xe0, 0xb0, 0x38, 0x01, 0x08, 0xb8, - 0x6d, 0xa3, 0xc0, 0x83, 0xc9, 0x9f, 0xc1, 0xb0, - 0x1f, 0xc1, 0xb0, 0xe3, 0x00, 0x09, 0xa4, 0x00, - 0x09, 0xb0, 0x66, 0x00, 0x09, 0x9a, 0xd1, 0xb0, - 0x08, 0x02, 0xdc, 0xa4, 0x00, 0x09, 0xb0, 0x2e, - 0x00, 0x07, 0x8b, 0x00, 0x09, 0xb0, 0xbe, 0xc0, - 0x80, 0xc1, 0x00, 0xdc, 0x81, 0xc1, 0x84, 0xc1, - 0x80, 0xc0, 0xb0, 0x03, 0x00, 0x09, 0xb0, 0xc5, - 0x00, 0x09, 0xb8, 0x46, 0xff, 0x00, 0x1a, 0xb2, - 0xd0, 0xc6, 0x06, 0xdc, 0xc1, 0xb3, 0x9c, 0x00, - 0xdc, 0xb0, 0xb1, 0x00, 0xdc, 0xb0, 0x64, 0xc4, - 0xb6, 0x61, 0x00, 0xdc, 0x80, 0xc0, 0xa7, 0xc0, - 0x00, 0x01, 0x00, 0xdc, 0x83, 0x00, 0x09, 0xb0, - 0x74, 0xc0, 0x00, 0xdc, 0xb2, 0x0c, 0xc3, 0xb1, - 0x52, 0xc1, 0xb0, 0x68, 0x01, 0xdc, 0xc2, 0x00, - 0xdc, 0xc0, 0x03, 0xdc, 0xb0, 0x00, 0xc0, 0x00, - 0xdc, 0xc0, 0x00, 0xdc, 0xb0, 0x8f, 0x00, 0x09, - 0xa8, 0x00, 0x09, 0x8d, 0x00, 0x09, 0xb0, 0x08, - 0x00, 0x09, 0x00, 0x07, 0xb0, 0x14, 0xc2, 0xaf, - 0x01, 0x09, 0xb0, 0x0d, 0x00, 0x07, 0xb0, 0x1b, - 0x00, 0x09, 0x88, 0x00, 0x07, 0xb0, 0x39, 0x00, - 0x09, 0x00, 0x07, 0xb0, 0x81, 0x00, 0x07, 0x00, - 0x09, 0xb0, 0x1f, 0x01, 0x07, 0x8f, 0x00, 0x09, - 0x97, 0xc6, 0x82, 0xc4, 0xb0, 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, 0x46, 0xc0, 0xb0, 0x0c, 0xc3, - 0xb5, 0xaf, 0x06, 0xdc, 0xb0, 0x3c, 0xc5, 0x00, - 0x07, -}; - -static const uint8_t unicode_cc_index[84] = { - 0x4d, 0x03, 0x00, 0x97, 0x05, 0x20, 0xc6, 0x05, - 0x00, 0xe7, 0x06, 0x00, 0x45, 0x07, 0x00, 0x9c, - 0x08, 0x00, 0x4d, 0x09, 0x00, 0x3c, 0x0b, 0x00, - 0x3d, 0x0d, 0x00, 0x36, 0x0f, 0x00, 0x38, 0x10, - 0x20, 0x3a, 0x19, 0x00, 0xcb, 0x1a, 0x20, 0xd3, - 0x1c, 0x00, 0xcf, 0x1d, 0x00, 0xe2, 0x20, 0x00, - 0x2e, 0x30, 0x20, 0x2b, 0xa9, 0x20, 0xed, 0xab, - 0x00, 0x39, 0x0a, 0x01, 0x84, 0x0f, 0x21, 0xc0, - 0x11, 0x01, 0x43, 0x14, 0x01, 0x39, 0x18, 0x21, - 0x42, 0x1d, 0x21, 0x67, 0xd1, 0x01, 0x30, 0xe1, - 0x21, 0x4b, 0xe9, 0x01, -}; - -static const uint32_t unicode_decomp_table1[693] = { - 0x00280081, 0x002a0097, 0x002a8081, 0x002bc097, - 0x002c8115, 0x002d0097, 0x002d4081, 0x002e0097, - 0x002e4115, 0x002f0199, 0x00302016, 0x00400842, - 0x00448a42, 0x004a0442, 0x004c0096, 0x004c8117, - 0x004d0242, 0x004e4342, 0x004fc12f, 0x0050c342, - 0x005240bf, 0x00530342, 0x00550942, 0x005a0842, - 0x005e0096, 0x005e4342, 0x005fc081, 0x00680142, - 0x006bc142, 0x00710185, 0x0071c317, 0x00734844, - 0x00778344, 0x00798342, 0x007b02be, 0x007c4197, - 0x007d0142, 0x007e0444, 0x00800e42, 0x00878142, - 0x00898744, 0x00ac0483, 0x00b60317, 0x00b80283, - 0x00d00214, 0x00d10096, 0x00dd0080, 0x00de8097, - 0x00df8080, 0x00e10097, 0x00e1413e, 0x00e1c080, - 0x00e204be, 0x00ea83ae, 0x00f282ae, 0x00f401ad, - 0x00f4c12e, 0x00f54103, 0x00fc0303, 0x00fe4081, - 0x0100023e, 0x0101c0be, 0x010301be, 0x010640be, - 0x010e40be, 0x0114023e, 0x0115c0be, 0x011701be, - 0x011d8144, 0x01304144, 0x01340244, 0x01358144, - 0x01368344, 0x01388344, 0x013a8644, 0x013e0144, - 0x0161c085, 0x018882ae, 0x019d422f, 0x01b00184, - 0x01b4c084, 0x024a4084, 0x024c4084, 0x024d0084, - 0x0256042e, 0x0272c12e, 0x02770120, 0x0277c084, - 0x028cc084, 0x028d8084, 0x029641ae, 0x02978084, - 0x02d20084, 0x02d2c12e, 0x02d70120, 0x02e50084, - 0x02f281ae, 0x03120084, 0x03300084, 0x0331c122, - 0x0332812e, 0x035281ae, 0x03768084, 0x037701ae, - 0x038cc085, 0x03acc085, 0x03b7012f, 0x03c30081, - 0x03d0c084, 0x03d34084, 0x03d48084, 0x03d5c084, - 0x03d70084, 0x03da4084, 0x03dcc084, 0x03dd412e, - 0x03ddc085, 0x03de0084, 0x03de4085, 0x03e04084, - 0x03e4c084, 0x03e74084, 0x03e88084, 0x03e9c084, - 0x03eb0084, 0x03ee4084, 0x04098084, 0x043f0081, - 0x06c18484, 0x06c48084, 0x06cec184, 0x06d00120, - 0x06d0c084, 0x074b0383, 0x074cc41f, 0x074f1783, - 0x075e0081, 0x0766d283, 0x07801d44, 0x078e8942, - 0x07931844, 0x079f0d42, 0x07a58216, 0x07a68085, - 0x07a6c0be, 0x07a80d44, 0x07aea044, 0x07c00122, - 0x07c08344, 0x07c20122, 0x07c28344, 0x07c40122, - 0x07c48244, 0x07c60122, 0x07c68244, 0x07c8113e, - 0x07d08244, 0x07d20122, 0x07d28244, 0x07d40122, - 0x07d48344, 0x07d64c3e, 0x07dc4080, 0x07dc80be, - 0x07dcc080, 0x07dd00be, 0x07dd4080, 0x07dd80be, - 0x07ddc080, 0x07de00be, 0x07de4080, 0x07de80be, - 0x07dec080, 0x07df00be, 0x07df4080, 0x07e00820, - 0x07e40820, 0x07e80820, 0x07ec05be, 0x07eec080, - 0x07ef00be, 0x07ef4097, 0x07ef8080, 0x07efc117, - 0x07f0443e, 0x07f24080, 0x07f280be, 0x07f2c080, - 0x07f303be, 0x07f4c080, 0x07f582ae, 0x07f6c080, - 0x07f7433e, 0x07f8c080, 0x07f903ae, 0x07fac080, - 0x07fb013e, 0x07fb8102, 0x07fc83be, 0x07fe4080, - 0x07fe80be, 0x07fec080, 0x07ff00be, 0x07ff4080, - 0x07ff8097, 0x0800011e, 0x08008495, 0x08044081, - 0x0805c097, 0x08090081, 0x08094097, 0x08098099, - 0x080bc081, 0x080cc085, 0x080d00b1, 0x080d8085, - 0x080dc0b1, 0x080f0197, 0x0811c197, 0x0815c0b3, - 0x0817c081, 0x081c0595, 0x081ec081, 0x081f0215, - 0x0820051f, 0x08228583, 0x08254415, 0x082a0097, - 0x08400119, 0x08408081, 0x0840c0bf, 0x08414119, - 0x0841c081, 0x084240bf, 0x0842852d, 0x08454081, - 0x08458097, 0x08464295, 0x08480097, 0x08484099, - 0x08488097, 0x08490081, 0x08498080, 0x084a0081, - 0x084a8102, 0x084b0495, 0x084d421f, 0x084e4081, - 0x084ec099, 0x084f0283, 0x08514295, 0x08540119, - 0x0854809b, 0x0854c619, 0x0857c097, 0x08580081, - 0x08584097, 0x08588099, 0x0858c097, 0x08590081, - 0x08594097, 0x08598099, 0x0859c09b, 0x085a0097, - 0x085a4081, 0x085a8097, 0x085ac099, 0x085b0295, - 0x085c4097, 0x085c8099, 0x085cc097, 0x085d0081, - 0x085d4097, 0x085d8099, 0x085dc09b, 0x085e0097, - 0x085e4081, 0x085e8097, 0x085ec099, 0x085f0215, - 0x08624099, 0x0866813e, 0x086b80be, 0x087341be, - 0x088100be, 0x088240be, 0x088300be, 0x088901be, - 0x088b0085, 0x088b40b1, 0x088bc085, 0x088c00b1, - 0x089040be, 0x089100be, 0x0891c1be, 0x089801be, - 0x089b42be, 0x089d0144, 0x089e0144, 0x08a00144, - 0x08a10144, 0x08a20144, 0x08ab023e, 0x08b80244, - 0x08ba8220, 0x08ca411e, 0x0918049f, 0x091a4523, - 0x091cc097, 0x091d04a5, 0x091f452b, 0x0921c09b, - 0x092204a1, 0x09244525, 0x0926c099, 0x09270d25, - 0x092d8d1f, 0x09340d1f, 0x093a8081, 0x0a8300b3, - 0x0a9d0099, 0x0a9d4097, 0x0a9d8099, 0x0ab700be, - 0x0b1f0115, 0x0b5bc081, 0x0ba7c081, 0x0bbcc081, - 0x0bc004ad, 0x0bc244ad, 0x0bc484ad, 0x0bc6f383, - 0x0be0852d, 0x0be31d03, 0x0bf1882d, 0x0c000081, - 0x0c0d8283, 0x0c130b84, 0x0c194284, 0x0c1c0122, - 0x0c1cc122, 0x0c1d8122, 0x0c1e4122, 0x0c1f0122, - 0x0c250084, 0x0c26c123, 0x0c278084, 0x0c27c085, - 0x0c2b0b84, 0x0c314284, 0x0c340122, 0x0c34c122, - 0x0c358122, 0x0c364122, 0x0c370122, 0x0c3d0084, - 0x0c3dc220, 0x0c3f8084, 0x0c3fc085, 0x0c4c4a2d, - 0x0c51451f, 0x0c53ca9f, 0x0c5915ad, 0x0c648703, - 0x0c800741, 0x0c838089, 0x0c83c129, 0x0c8441a9, - 0x0c850089, 0x0c854129, 0x0c85c2a9, 0x0c870089, - 0x0c87408f, 0x0c87808d, 0x0c881241, 0x0c910203, - 0x0c940099, 0x0c9444a3, 0x0c968323, 0x0c98072d, - 0x0c9b84af, 0x0c9dc2a1, 0x0c9f00b5, 0x0c9f40b3, - 0x0c9f8085, 0x0ca01883, 0x0cac4223, 0x0cad4523, - 0x0cafc097, 0x0cb004a1, 0x0cb241a5, 0x0cb30097, - 0x0cb34099, 0x0cb38097, 0x0cb3c099, 0x0cb417ad, - 0x0cbfc085, 0x0cc001b3, 0x0cc0c0b1, 0x0cc100b3, - 0x0cc14131, 0x0cc1c0b5, 0x0cc200b3, 0x0cc241b1, - 0x0cc30133, 0x0cc38131, 0x0cc40085, 0x0cc440b1, - 0x0cc48133, 0x0cc50085, 0x0cc540b5, 0x0cc580b7, - 0x0cc5c0b5, 0x0cc600b1, 0x0cc64135, 0x0cc6c0b3, - 0x0cc701b1, 0x0cc7c0b3, 0x0cc800b5, 0x0cc840b3, - 0x0cc881b1, 0x0cc9422f, 0x0cca4131, 0x0ccac0b5, - 0x0ccb00b1, 0x0ccb40b3, 0x0ccb80b5, 0x0ccbc0b1, - 0x0ccc012f, 0x0ccc80b5, 0x0cccc0b3, 0x0ccd00b5, - 0x0ccd40b1, 0x0ccd80b5, 0x0ccdc085, 0x0cce02b1, - 0x0ccf40b3, 0x0ccf80b1, 0x0ccfc085, 0x0cd001b1, - 0x0cd0c0b3, 0x0cd101b1, 0x0cd1c0b5, 0x0cd200b3, - 0x0cd24085, 0x0cd280b5, 0x0cd2c085, 0x0cd30133, - 0x0cd381b1, 0x0cd440b3, 0x0cd48085, 0x0cd4c0b1, - 0x0cd500b3, 0x0cd54085, 0x0cd580b5, 0x0cd5c0b1, - 0x0cd60521, 0x0cd88525, 0x0cdb02a5, 0x0cdc4099, - 0x0cdc8117, 0x0cdd0099, 0x0cdd4197, 0x0cde0127, - 0x0cde8285, 0x0cdfc089, 0x0ce0043f, 0x0ce20099, - 0x0ce2409b, 0x0ce283bf, 0x0ce44219, 0x0ce54205, - 0x0ce6433f, 0x0ce7c131, 0x0ce84085, 0x0ce881b1, - 0x0ce94085, 0x0ce98107, 0x0cea0089, 0x0cea4097, - 0x0cea8219, 0x0ceb809d, 0x0cebc08d, 0x0cec083f, - 0x0cf00105, 0x0cf0809b, 0x0cf0c197, 0x0cf1809b, - 0x0cf1c099, 0x0cf20517, 0x0cf48099, 0x0cf4c117, - 0x0cf54119, 0x0cf5c097, 0x0cf6009b, 0x0cf64099, - 0x0cf68217, 0x0cf78119, 0x0cf804a1, 0x0cfa4525, - 0x0cfcc525, 0x0cff4125, 0x0cffc099, 0x29a70103, - 0x29dc0081, 0x29fc8195, 0x29fe0103, 0x2ad70203, - 0x2ada4081, 0x3e401482, 0x3e4a7f82, 0x3e6a3f82, - 0x3e8aa102, 0x3e9b0110, 0x3e9c2f82, 0x3eb3c590, - 0x3ec00197, 0x3ec0c119, 0x3ec1413f, 0x3ec4c2af, - 0x3ec74184, 0x3ec804ad, 0x3eca4081, 0x3eca8304, - 0x3ecc03a0, 0x3ece02a0, 0x3ecf8084, 0x3ed00120, - 0x3ed0c120, 0x3ed184ae, 0x3ed3c085, 0x3ed4312d, - 0x3ef4cbad, 0x3efa892f, 0x3eff022d, 0x3f002f2f, - 0x3f1782a5, 0x3f18c0b1, 0x3f1907af, 0x3f1cffaf, - 0x3f3c81a5, 0x3f3d64af, 0x3f542031, 0x3f649b31, - 0x3f7c0131, 0x3f7c83b3, 0x3f7e40b1, 0x3f7e80bd, - 0x3f7ec0bb, 0x3f7f00b3, 0x3f840503, 0x3f8c01ad, - 0x3f8cc315, 0x3f8e462d, 0x3f91cc03, 0x3f97c695, - 0x3f9c01af, 0x3f9d0085, 0x3f9d852f, 0x3fa03aad, - 0x3fbd442f, 0x3fc06f1f, 0x3fd7c11f, 0x3fd85fad, - 0x3fe80081, 0x3fe84f1f, 0x3ff0831f, 0x3ff2831f, - 0x3ff4831f, 0x3ff6819f, 0x3ff80783, 0x41e04d83, - 0x41e70f91, 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[693] = { - 0x0020, 0x0000, 0x0061, 0x0002, 0x0004, 0x0006, 0x03bc, 0x0008, - 0x000a, 0x000c, 0x0015, 0x0095, 0x00a5, 0x00b9, 0x00c1, 0x00c3, - 0x00c7, 0x00cb, 0x00d1, 0x00d7, 0x00dd, 0x00e0, 0x00e6, 0x00f8, - 0x0108, 0x010a, 0x0073, 0x0110, 0x0112, 0x0114, 0x0120, 0x012c, - 0x0144, 0x014d, 0x0153, 0x0162, 0x0168, 0x016a, 0x0176, 0x0192, - 0x0194, 0x01a9, 0x01bb, 0x01c7, 0x01d1, 0x01d5, 0x02b9, 0x01d7, - 0x003b, 0x01d9, 0x01db, 0x00b7, 0x01e1, 0x01fc, 0x020c, 0x0218, - 0x021d, 0x0223, 0x0227, 0x03a3, 0x0233, 0x023f, 0x0242, 0x024b, - 0x024e, 0x0251, 0x025d, 0x0260, 0x0269, 0x026c, 0x026f, 0x0275, - 0x0278, 0x0281, 0x028a, 0x029c, 0x029f, 0x02a3, 0x02af, 0x02b9, - 0x02c5, 0x02c9, 0x02cd, 0x02d1, 0x02d5, 0x02e7, 0x02ed, 0x02f1, - 0x02f5, 0x02f9, 0x02fd, 0x0305, 0x0309, 0x030d, 0x0313, 0x0317, - 0x031b, 0x0323, 0x0327, 0x032b, 0x032f, 0x0335, 0x033d, 0x0341, - 0x0349, 0x034d, 0x0351, 0x0f0b, 0x0357, 0x035b, 0x035f, 0x0363, - 0x0367, 0x036b, 0x036f, 0x0373, 0x0379, 0x037d, 0x0381, 0x0385, - 0x0389, 0x038d, 0x0391, 0x0395, 0x0399, 0x039d, 0x03a1, 0x10dc, - 0x03a5, 0x03c9, 0x03cd, 0x03d9, 0x03dd, 0x03e1, 0x03ef, 0x03f1, - 0x043d, 0x044f, 0x0499, 0x04f0, 0x0502, 0x054a, 0x0564, 0x056c, - 0x0570, 0x0573, 0x059a, 0x05fa, 0x05fe, 0x0607, 0x060b, 0x0614, - 0x0618, 0x061e, 0x0622, 0x0628, 0x068e, 0x0694, 0x0698, 0x069e, - 0x06a2, 0x06ab, 0x03ac, 0x06f3, 0x03ad, 0x06f6, 0x03ae, 0x06f9, - 0x03af, 0x06fc, 0x03cc, 0x06ff, 0x03cd, 0x0702, 0x03ce, 0x0705, - 0x0709, 0x070d, 0x0711, 0x0386, 0x0732, 0x0735, 0x03b9, 0x0737, - 0x073b, 0x0388, 0x0753, 0x0389, 0x0756, 0x0390, 0x076b, 0x038a, - 0x0777, 0x03b0, 0x0789, 0x038e, 0x0799, 0x079f, 0x07a3, 0x038c, - 0x07b8, 0x038f, 0x07bb, 0x00b4, 0x07be, 0x07c0, 0x07c2, 0x2010, - 0x07cb, 0x002e, 0x07cd, 0x07cf, 0x0020, 0x07d2, 0x07d6, 0x07db, - 0x07df, 0x07e4, 0x07ea, 0x07f0, 0x0020, 0x07f6, 0x2212, 0x0801, - 0x0805, 0x0807, 0x081d, 0x0825, 0x0827, 0x0043, 0x082d, 0x0830, - 0x0190, 0x0836, 0x0839, 0x004e, 0x0845, 0x0847, 0x084c, 0x084e, - 0x0851, 0x005a, 0x03a9, 0x005a, 0x0853, 0x0857, 0x0860, 0x0069, - 0x0862, 0x0865, 0x086f, 0x0874, 0x087a, 0x087e, 0x08a2, 0x0049, - 0x08a4, 0x08a6, 0x08a9, 0x0056, 0x08ab, 0x08ad, 0x08b0, 0x08b4, - 0x0058, 0x08b6, 0x08b8, 0x08bb, 0x08c0, 0x08c2, 0x08c5, 0x0076, - 0x08c7, 0x08c9, 0x08cc, 0x08d0, 0x0078, 0x08d2, 0x08d4, 0x08d7, - 0x08db, 0x08de, 0x08e4, 0x08e7, 0x08f0, 0x08f3, 0x08f6, 0x08f9, - 0x0902, 0x0906, 0x090b, 0x090f, 0x0914, 0x0917, 0x091a, 0x0923, - 0x092c, 0x093b, 0x093e, 0x0941, 0x0944, 0x0947, 0x094a, 0x0956, - 0x095c, 0x0960, 0x0962, 0x0964, 0x0968, 0x096a, 0x0970, 0x0978, - 0x097c, 0x0980, 0x0986, 0x0989, 0x098f, 0x0991, 0x0030, 0x0993, - 0x0999, 0x099c, 0x099e, 0x09a1, 0x09a4, 0x2d61, 0x6bcd, 0x9f9f, - 0x09a6, 0x09b1, 0x09bc, 0x09c7, 0x0a95, 0x0aa1, 0x0b15, 0x0020, - 0x0b27, 0x0b31, 0x0b8d, 0x0ba1, 0x0ba5, 0x0ba9, 0x0bad, 0x0bb1, - 0x0bb5, 0x0bb9, 0x0bbd, 0x0bc1, 0x0bc5, 0x0c21, 0x0c35, 0x0c39, - 0x0c3d, 0x0c41, 0x0c45, 0x0c49, 0x0c4d, 0x0c51, 0x0c55, 0x0c59, - 0x0c6f, 0x0c71, 0x0c73, 0x0ca0, 0x0cbc, 0x0cdc, 0x0ce4, 0x0cec, - 0x0cf4, 0x0cfc, 0x0d04, 0x0d0c, 0x0d14, 0x0d22, 0x0d2e, 0x0d7a, - 0x0d82, 0x0d85, 0x0d89, 0x0d8d, 0x0d9d, 0x0db1, 0x0db5, 0x0dbc, - 0x0dc2, 0x0dc6, 0x0e28, 0x0e2c, 0x0e30, 0x0e32, 0x0e36, 0x0e3c, - 0x0e3e, 0x0e41, 0x0e43, 0x0e46, 0x0e77, 0x0e7b, 0x0e89, 0x0e8e, - 0x0e94, 0x0e9c, 0x0ea3, 0x0ea9, 0x0eb4, 0x0ebe, 0x0ec6, 0x0eca, - 0x0ecf, 0x0ed9, 0x0edd, 0x0ee4, 0x0eec, 0x0ef3, 0x0ef8, 0x0f04, - 0x0f0a, 0x0f15, 0x0f1b, 0x0f22, 0x0f28, 0x0f33, 0x0f3d, 0x0f45, - 0x0f4c, 0x0f51, 0x0f57, 0x0f5e, 0x0f63, 0x0f69, 0x0f70, 0x0f76, - 0x0f7d, 0x0f82, 0x0f89, 0x0f8d, 0x0f9e, 0x0fa4, 0x0fa9, 0x0fad, - 0x0fb8, 0x0fbe, 0x0fc9, 0x0fd0, 0x0fd6, 0x0fda, 0x0fe1, 0x0fe5, - 0x0fef, 0x0ffa, 0x1000, 0x1004, 0x1009, 0x100f, 0x1013, 0x101a, - 0x101f, 0x1023, 0x1029, 0x102f, 0x1032, 0x1036, 0x1039, 0x103f, - 0x1045, 0x1059, 0x1061, 0x1079, 0x107c, 0x1080, 0x1095, 0x10a1, - 0x10b1, 0x10c3, 0x10cb, 0x10cf, 0x10da, 0x10de, 0x10ea, 0x10f2, - 0x10f4, 0x1100, 0x1105, 0x1111, 0x1141, 0x1149, 0x114d, 0x1153, - 0x1157, 0x115a, 0x116e, 0x1171, 0x1175, 0x117b, 0x117d, 0x1181, - 0x1184, 0x118c, 0x1192, 0x1196, 0x119c, 0x11a2, 0x11a8, 0x11ab, - 0xa76f, 0x11af, 0x11b2, 0x11b6, 0x028d, 0x11be, 0x1210, 0x130e, - 0x140c, 0x1490, 0x1495, 0x1553, 0x156c, 0x1572, 0x1578, 0x157e, - 0x158a, 0x1596, 0x002b, 0x15a1, 0x15b9, 0x15bd, 0x15c1, 0x15c5, - 0x15c9, 0x15cd, 0x15e1, 0x15e5, 0x1649, 0x1662, 0x1688, 0x168e, - 0x174c, 0x1752, 0x1757, 0x1777, 0x1877, 0x187d, 0x1911, 0x19d3, - 0x1a77, 0x1a7f, 0x1a9d, 0x1aa2, 0x1ab6, 0x1ac0, 0x1ac6, 0x1ada, - 0x1adf, 0x1ae5, 0x1af3, 0x1b23, 0x1b30, 0x1b38, 0x1b3c, 0x1b52, - 0x1bc9, 0x1bdb, 0x1bdd, 0x1bdf, 0x3164, 0x1c20, 0x1c22, 0x1c24, - 0x1c26, 0x1c28, 0x1c2a, 0x1c48, 0x1c7e, 0x1cc4, 0x1cd2, 0x1cd7, - 0x1ce0, 0x1ce9, 0x1cfb, 0x1d04, 0x1d09, 0x1d29, 0x1d44, 0x1d46, - 0x1d48, 0x1d4a, 0x1d4c, 0x1d4e, 0x1d50, 0x1d52, 0x1d72, 0x1d74, - 0x1d76, 0x1d78, 0x1d7a, 0x1d81, 0x1d83, 0x1d85, 0x1d87, 0x1d96, - 0x1d98, 0x1d9a, 0x1d9c, 0x1d9e, 0x1da0, 0x1da2, 0x1da4, 0x1da6, - 0x1da8, 0x1daa, 0x1dac, 0x1dae, 0x1db0, 0x1db2, 0x1db6, 0x03f4, - 0x1db8, 0x2207, 0x1dba, 0x2202, 0x1dbc, 0x1dc4, 0x03f4, 0x1dc6, - 0x2207, 0x1dc8, 0x2202, 0x1dca, 0x1dd2, 0x03f4, 0x1dd4, 0x2207, - 0x1dd6, 0x2202, 0x1dd8, 0x1de0, 0x03f4, 0x1de2, 0x2207, 0x1de4, - 0x2202, 0x1de6, 0x1dee, 0x03f4, 0x1df0, 0x2207, 0x1df2, 0x2202, - 0x1df4, 0x1dfe, 0x1e00, 0x1e02, 0x1e04, 0x1e06, 0x1e08, 0x1e0e, - 0x1e2b, 0x062d, 0x1e33, 0x1e3f, 0x062c, 0x1e4f, 0x1ebf, 0x1ecb, - 0x1ede, 0x1ef0, 0x1f03, 0x1f05, 0x1f09, 0x1f0f, 0x1f15, 0x1f17, - 0x1f1b, 0x1f1d, 0x1f25, 0x1f28, 0x1f2a, 0x1f30, 0x1f32, 0x30b5, - 0x1f38, 0x1f90, 0x1fa6, 0x1faa, 0x1fac, 0x1fb1, 0x1ffe, 0x200f, - 0x2110, 0x2120, 0x2126, 0x2220, 0x233e, -}; - -static const uint8_t unicode_decomp_data[9292] = { - 0x20, 0x88, 0x20, 0x84, 0x32, 0x33, 0x20, 0x81, - 0x20, 0xa7, 0x31, 0x6f, 0x31, 0xd0, 0x34, 0x31, - 0xd0, 0x32, 0x33, 0xd0, 0x34, 0x41, 0x80, 0x41, - 0x81, 0x41, 0x82, 0x41, 0x83, 0x41, 0x88, 0x41, - 0x8a, 0x00, 0x00, 0x43, 0xa7, 0x45, 0x80, 0x45, - 0x81, 0x45, 0x82, 0x45, 0x88, 0x49, 0x80, 0x49, - 0x81, 0x49, 0x82, 0x49, 0x88, 0x00, 0x00, 0x4e, - 0x83, 0x4f, 0x80, 0x4f, 0x81, 0x4f, 0x82, 0x4f, - 0x83, 0x4f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x55, - 0x80, 0x55, 0x81, 0x55, 0x82, 0x55, 0x88, 0x59, - 0x81, 0x00, 0x00, 0x00, 0x00, 0x61, 0x80, 0x61, - 0x81, 0x61, 0x82, 0x61, 0x83, 0x61, 0x88, 0x61, - 0x8a, 0x00, 0x00, 0x63, 0xa7, 0x65, 0x80, 0x65, - 0x81, 0x65, 0x82, 0x65, 0x88, 0x69, 0x80, 0x69, - 0x81, 0x69, 0x82, 0x69, 0x88, 0x00, 0x00, 0x6e, - 0x83, 0x6f, 0x80, 0x6f, 0x81, 0x6f, 0x82, 0x6f, - 0x83, 0x6f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x75, - 0x80, 0x75, 0x81, 0x75, 0x82, 0x75, 0x88, 0x79, - 0x81, 0x00, 0x00, 0x79, 0x88, 0x41, 0x84, 0x41, - 0x86, 0x41, 0xa8, 0x43, 0x81, 0x43, 0x82, 0x43, - 0x87, 0x43, 0x8c, 0x44, 0x8c, 0x45, 0x84, 0x45, - 0x86, 0x45, 0x87, 0x45, 0xa8, 0x45, 0x8c, 0x47, - 0x82, 0x47, 0x86, 0x47, 0x87, 0x47, 0xa7, 0x48, - 0x82, 0x49, 0x83, 0x49, 0x84, 0x49, 0x86, 0x49, - 0xa8, 0x49, 0x87, 0x49, 0x4a, 0x69, 0x6a, 0x4a, - 0x82, 0x4b, 0xa7, 0x4c, 0x81, 0x4c, 0xa7, 0x4c, - 0x8c, 0x4c, 0x00, 0x00, 0x6b, 0x20, 0x6b, 0x4e, - 0x81, 0x4e, 0xa7, 0x4e, 0x8c, 0xbc, 0x02, 0x6e, - 0x4f, 0x84, 0x4f, 0x86, 0x4f, 0x8b, 0x52, 0x81, - 0x52, 0xa7, 0x52, 0x8c, 0x53, 0x81, 0x53, 0x82, - 0x53, 0xa7, 0x53, 0x8c, 0x54, 0xa7, 0x54, 0x8c, - 0x55, 0x83, 0x55, 0x84, 0x55, 0x86, 0x55, 0x8a, - 0x55, 0x8b, 0x55, 0xa8, 0x57, 0x82, 0x59, 0x82, - 0x59, 0x88, 0x5a, 0x81, 0x5a, 0x87, 0x5a, 0x8c, - 0x4f, 0x9b, 0x55, 0x9b, 0x44, 0x00, 0x7d, 0x01, - 0x44, 0x00, 0x7e, 0x01, 0x64, 0x00, 0x7e, 0x01, - 0x4c, 0x4a, 0x4c, 0x6a, 0x6c, 0x6a, 0x4e, 0x4a, - 0x4e, 0x6a, 0x6e, 0x6a, 0x41, 0x00, 0x8c, 0x49, - 0x00, 0x8c, 0x4f, 0x00, 0x8c, 0x55, 0x00, 0x8c, - 0xdc, 0x00, 0x84, 0xdc, 0x00, 0x81, 0xdc, 0x00, - 0x8c, 0xdc, 0x00, 0x80, 0xc4, 0x00, 0x84, 0x26, - 0x02, 0x84, 0xc6, 0x00, 0x84, 0x47, 0x8c, 0x4b, - 0x8c, 0x4f, 0xa8, 0xea, 0x01, 0x84, 0xeb, 0x01, - 0x84, 0xb7, 0x01, 0x8c, 0x92, 0x02, 0x8c, 0x6a, - 0x00, 0x8c, 0x44, 0x5a, 0x44, 0x7a, 0x64, 0x7a, - 0x47, 0x81, 0x4e, 0x00, 0x80, 0xc5, 0x00, 0x81, - 0xc6, 0x00, 0x81, 0xd8, 0x00, 0x81, 0x41, 0x8f, - 0x41, 0x91, 0x45, 0x8f, 0x45, 0x91, 0x49, 0x8f, - 0x49, 0x91, 0x4f, 0x8f, 0x4f, 0x91, 0x52, 0x8f, - 0x52, 0x91, 0x55, 0x8f, 0x55, 0x91, 0x53, 0xa6, - 0x54, 0xa6, 0x48, 0x8c, 0x41, 0x00, 0x87, 0x45, - 0x00, 0xa7, 0xd6, 0x00, 0x84, 0xd5, 0x00, 0x84, - 0x4f, 0x00, 0x87, 0x2e, 0x02, 0x84, 0x59, 0x00, - 0x84, 0x68, 0x00, 0x66, 0x02, 0x6a, 0x00, 0x72, - 0x00, 0x79, 0x02, 0x7b, 0x02, 0x81, 0x02, 0x77, - 0x00, 0x79, 0x00, 0x20, 0x86, 0x20, 0x87, 0x20, - 0x8a, 0x20, 0xa8, 0x20, 0x83, 0x20, 0x8b, 0x63, - 0x02, 0x6c, 0x00, 0x73, 0x00, 0x78, 0x00, 0x95, - 0x02, 0x80, 0x81, 0x00, 0x93, 0x88, 0x81, 0x20, - 0xc5, 0x20, 0x81, 0xa8, 0x00, 0x81, 0x91, 0x03, - 0x81, 0x95, 0x03, 0x81, 0x97, 0x03, 0x81, 0x99, - 0x03, 0x81, 0x00, 0x00, 0x00, 0x9f, 0x03, 0x81, - 0x00, 0x00, 0x00, 0xa5, 0x03, 0x81, 0xa9, 0x03, - 0x81, 0xca, 0x03, 0x81, 0x01, 0x03, 0x98, 0x07, - 0xa4, 0x07, 0xb0, 0x00, 0xb4, 0x00, 0xb6, 0x00, - 0xb8, 0x00, 0xca, 0x00, 0x01, 0x03, 0xb8, 0x07, - 0xc4, 0x07, 0xbe, 0x00, 0xc4, 0x00, 0xc8, 0x00, - 0xa5, 0x03, 0x0d, 0x13, 0x00, 0x01, 0x03, 0xd1, - 0x00, 0xd1, 0x07, 0xc6, 0x03, 0xc0, 0x03, 0xba, - 0x03, 0xc1, 0x03, 0xc2, 0x03, 0x00, 0x00, 0x98, - 0x03, 0xb5, 0x03, 0x15, 0x04, 0x80, 0x15, 0x04, - 0x88, 0x00, 0x00, 0x00, 0x13, 0x04, 0x81, 0x06, - 0x04, 0x88, 0x1a, 0x04, 0x81, 0x18, 0x04, 0x80, - 0x23, 0x04, 0x86, 0x18, 0x04, 0x86, 0x38, 0x04, - 0x86, 0x35, 0x04, 0x80, 0x35, 0x04, 0x88, 0x00, - 0x00, 0x00, 0x33, 0x04, 0x81, 0x56, 0x04, 0x88, - 0x3a, 0x04, 0x81, 0x38, 0x04, 0x80, 0x43, 0x04, - 0x86, 0x74, 0x04, 0x8f, 0x16, 0x04, 0x86, 0x10, - 0x04, 0x86, 0x10, 0x04, 0x88, 0x15, 0x04, 0x86, - 0xd8, 0x04, 0x88, 0x16, 0x04, 0x88, 0x17, 0x04, - 0x88, 0x18, 0x04, 0x84, 0x18, 0x04, 0x88, 0x1e, - 0x04, 0x88, 0xe8, 0x04, 0x88, 0x2d, 0x04, 0x88, - 0x23, 0x04, 0x84, 0x23, 0x04, 0x88, 0x23, 0x04, - 0x8b, 0x27, 0x04, 0x88, 0x2b, 0x04, 0x88, 0x65, - 0x05, 0x82, 0x05, 0x27, 0x06, 0x00, 0x2c, 0x00, - 0x2d, 0x21, 0x2d, 0x00, 0x2e, 0x23, 0x2d, 0x27, - 0x06, 0x00, 0x4d, 0x21, 0x4d, 0xa0, 0x4d, 0x23, - 0x4d, 0xd5, 0x06, 0x54, 0x06, 0x00, 0x00, 0x00, - 0x00, 0xc1, 0x06, 0x54, 0x06, 0xd2, 0x06, 0x54, - 0x06, 0x28, 0x09, 0x3c, 0x09, 0x30, 0x09, 0x3c, - 0x09, 0x33, 0x09, 0x3c, 0x09, 0x15, 0x09, 0x00, - 0x27, 0x01, 0x27, 0x02, 0x27, 0x07, 0x27, 0x0c, - 0x27, 0x0d, 0x27, 0x16, 0x27, 0x1a, 0x27, 0xbe, - 0x09, 0x09, 0x00, 0x09, 0x19, 0xa1, 0x09, 0xbc, - 0x09, 0xaf, 0x09, 0xbc, 0x09, 0x32, 0x0a, 0x3c, - 0x0a, 0x38, 0x0a, 0x3c, 0x0a, 0x16, 0x0a, 0x00, - 0x26, 0x01, 0x26, 0x06, 0x26, 0x2b, 0x0a, 0x3c, - 0x0a, 0x47, 0x0b, 0x56, 0x0b, 0x3e, 0x0b, 0x09, - 0x00, 0x09, 0x19, 0x21, 0x0b, 0x3c, 0x0b, 0x92, - 0x0b, 0xd7, 0x0b, 0xbe, 0x0b, 0x08, 0x00, 0x09, - 0x00, 0x08, 0x19, 0x46, 0x0c, 0x56, 0x0c, 0xbf, - 0x0c, 0xd5, 0x0c, 0xc6, 0x0c, 0xd5, 0x0c, 0xc2, - 0x0c, 0x04, 0x00, 0x08, 0x13, 0x3e, 0x0d, 0x08, - 0x00, 0x09, 0x00, 0x08, 0x19, 0xd9, 0x0d, 0xca, - 0x0d, 0xca, 0x0d, 0x0f, 0x05, 0x12, 0x00, 0x0f, - 0x15, 0x4d, 0x0e, 0x32, 0x0e, 0xcd, 0x0e, 0xb2, - 0x0e, 0x99, 0x0e, 0x12, 0x00, 0x12, 0x08, 0x42, - 0x0f, 0xb7, 0x0f, 0x4c, 0x0f, 0xb7, 0x0f, 0x51, - 0x0f, 0xb7, 0x0f, 0x56, 0x0f, 0xb7, 0x0f, 0x5b, - 0x0f, 0xb7, 0x0f, 0x40, 0x0f, 0xb5, 0x0f, 0x71, - 0x0f, 0x72, 0x0f, 0x71, 0x0f, 0x00, 0x03, 0x41, - 0x0f, 0xb2, 0x0f, 0x81, 0x0f, 0xb3, 0x0f, 0x80, - 0x0f, 0xb3, 0x0f, 0x81, 0x0f, 0x71, 0x0f, 0x80, - 0x0f, 0x92, 0x0f, 0xb7, 0x0f, 0x9c, 0x0f, 0xb7, - 0x0f, 0xa1, 0x0f, 0xb7, 0x0f, 0xa6, 0x0f, 0xb7, - 0x0f, 0xab, 0x0f, 0xb7, 0x0f, 0x90, 0x0f, 0xb5, - 0x0f, 0x25, 0x10, 0x2e, 0x10, 0x05, 0x1b, 0x35, - 0x1b, 0x00, 0x00, 0x00, 0x00, 0x07, 0x1b, 0x35, - 0x1b, 0x00, 0x00, 0x00, 0x00, 0x09, 0x1b, 0x35, - 0x1b, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x1b, 0x35, - 0x1b, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x1b, 0x35, - 0x1b, 0x11, 0x1b, 0x35, 0x1b, 0x3a, 0x1b, 0x35, - 0x1b, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1b, 0x35, - 0x1b, 0x3e, 0x1b, 0x35, 0x1b, 0x42, 0x1b, 0x35, - 0x1b, 0x41, 0x00, 0xc6, 0x00, 0x42, 0x00, 0x00, - 0x00, 0x44, 0x00, 0x45, 0x00, 0x8e, 0x01, 0x47, - 0x00, 0x4f, 0x00, 0x22, 0x02, 0x50, 0x00, 0x52, - 0x00, 0x54, 0x00, 0x55, 0x00, 0x57, 0x00, 0x61, - 0x00, 0x50, 0x02, 0x51, 0x02, 0x02, 0x1d, 0x62, - 0x00, 0x64, 0x00, 0x65, 0x00, 0x59, 0x02, 0x5b, - 0x02, 0x5c, 0x02, 0x67, 0x00, 0x00, 0x00, 0x6b, - 0x00, 0x6d, 0x00, 0x4b, 0x01, 0x6f, 0x00, 0x54, - 0x02, 0x16, 0x1d, 0x17, 0x1d, 0x70, 0x00, 0x74, - 0x00, 0x75, 0x00, 0x1d, 0x1d, 0x6f, 0x02, 0x76, - 0x00, 0x25, 0x1d, 0xb2, 0x03, 0xb3, 0x03, 0xb4, - 0x03, 0xc6, 0x03, 0xc7, 0x03, 0x69, 0x00, 0x72, - 0x00, 0x75, 0x00, 0x76, 0x00, 0xb2, 0x03, 0xb3, - 0x03, 0xc1, 0x03, 0xc6, 0x03, 0xc7, 0x03, 0x52, - 0x02, 0x63, 0x00, 0x55, 0x02, 0xf0, 0x00, 0x5c, - 0x02, 0x66, 0x00, 0x5f, 0x02, 0x61, 0x02, 0x65, - 0x02, 0x68, 0x02, 0x69, 0x02, 0x6a, 0x02, 0x7b, - 0x1d, 0x9d, 0x02, 0x6d, 0x02, 0x85, 0x1d, 0x9f, - 0x02, 0x71, 0x02, 0x70, 0x02, 0x72, 0x02, 0x73, - 0x02, 0x74, 0x02, 0x75, 0x02, 0x78, 0x02, 0x82, - 0x02, 0x83, 0x02, 0xab, 0x01, 0x89, 0x02, 0x8a, - 0x02, 0x1c, 0x1d, 0x8b, 0x02, 0x8c, 0x02, 0x7a, - 0x00, 0x90, 0x02, 0x91, 0x02, 0x92, 0x02, 0xb8, - 0x03, 0x41, 0x00, 0xa5, 0x42, 0x00, 0x87, 0x42, - 0x00, 0xa3, 0x42, 0x00, 0xb1, 0xc7, 0x00, 0x81, - 0x44, 0x00, 0x87, 0x44, 0x00, 0xa3, 0x44, 0x00, - 0xb1, 0x44, 0x00, 0xa7, 0x44, 0x00, 0xad, 0x12, - 0x01, 0x80, 0x12, 0x01, 0x81, 0x45, 0x00, 0xad, - 0x45, 0x00, 0xb0, 0x28, 0x02, 0x86, 0x46, 0x00, - 0x87, 0x47, 0x00, 0x84, 0x48, 0x00, 0x87, 0x48, - 0x00, 0xa3, 0x48, 0x00, 0x88, 0x48, 0x00, 0xa7, - 0x48, 0x00, 0xae, 0x49, 0x00, 0xb0, 0xcf, 0x00, - 0x81, 0x4b, 0x00, 0x81, 0x4b, 0x00, 0xa3, 0x4b, - 0x00, 0xb1, 0x4c, 0x00, 0xa3, 0x36, 0x1e, 0x84, - 0x4c, 0xb1, 0x4c, 0xad, 0x4d, 0x81, 0x4d, 0x87, - 0x4d, 0xa3, 0x4e, 0x87, 0x4e, 0xa3, 0x4e, 0xb1, - 0x4e, 0xad, 0xd5, 0x00, 0x81, 0xd5, 0x00, 0x88, - 0x4c, 0x01, 0x80, 0x4c, 0x01, 0x81, 0x50, 0x00, - 0x81, 0x50, 0x00, 0x87, 0x52, 0x00, 0x87, 0x52, - 0x00, 0xa3, 0x5a, 0x1e, 0x84, 0x52, 0x00, 0xb1, - 0x53, 0x00, 0x87, 0x53, 0x00, 0xa3, 0x5a, 0x01, - 0x87, 0x60, 0x01, 0x87, 0x62, 0x1e, 0x87, 0x54, - 0x00, 0x87, 0x54, 0x00, 0xa3, 0x54, 0x00, 0xb1, - 0x54, 0x00, 0xad, 0x55, 0x00, 0xa4, 0x55, 0x00, - 0xb0, 0x55, 0x00, 0xad, 0x68, 0x01, 0x81, 0x6a, - 0x01, 0x88, 0x56, 0x83, 0x56, 0xa3, 0x57, 0x80, - 0x57, 0x81, 0x57, 0x88, 0x57, 0x87, 0x57, 0xa3, - 0x58, 0x87, 0x58, 0x88, 0x59, 0x87, 0x5a, 0x82, - 0x5a, 0xa3, 0x5a, 0xb1, 0x68, 0xb1, 0x74, 0x88, - 0x77, 0x8a, 0x79, 0x8a, 0x61, 0x00, 0xbe, 0x02, - 0x7f, 0x01, 0x87, 0x41, 0x00, 0xa3, 0x41, 0x00, - 0x89, 0xc2, 0x00, 0x81, 0xc2, 0x00, 0x80, 0xc2, - 0x00, 0x89, 0xc2, 0x00, 0x83, 0xa0, 0x1e, 0x82, - 0x02, 0x01, 0x81, 0x02, 0x01, 0x80, 0x02, 0x01, - 0x89, 0x02, 0x01, 0x83, 0xa0, 0x1e, 0x86, 0x45, - 0x00, 0xa3, 0x45, 0x00, 0x89, 0x45, 0x00, 0x83, - 0xca, 0x00, 0x81, 0xca, 0x00, 0x80, 0xca, 0x00, - 0x89, 0xca, 0x00, 0x83, 0xb8, 0x1e, 0x82, 0x49, - 0x00, 0x89, 0x49, 0x00, 0xa3, 0x4f, 0x00, 0xa3, - 0x4f, 0x00, 0x89, 0xd4, 0x00, 0x81, 0xd4, 0x00, - 0x80, 0xd4, 0x00, 0x89, 0xd4, 0x00, 0x83, 0xcc, - 0x1e, 0x82, 0xa0, 0x01, 0x81, 0xa0, 0x01, 0x80, - 0xa0, 0x01, 0x89, 0xa0, 0x01, 0x83, 0xa0, 0x01, - 0xa3, 0x55, 0x00, 0xa3, 0x55, 0x00, 0x89, 0xaf, - 0x01, 0x81, 0xaf, 0x01, 0x80, 0xaf, 0x01, 0x89, - 0xaf, 0x01, 0x83, 0xaf, 0x01, 0xa3, 0x59, 0x00, - 0x80, 0x59, 0x00, 0xa3, 0x59, 0x00, 0x89, 0x59, - 0x00, 0x83, 0xb1, 0x03, 0x13, 0x03, 0x00, 0x1f, - 0x80, 0x00, 0x1f, 0x81, 0x00, 0x1f, 0xc2, 0x91, - 0x03, 0x13, 0x03, 0x08, 0x1f, 0x80, 0x08, 0x1f, - 0x81, 0x08, 0x1f, 0xc2, 0xb5, 0x03, 0x13, 0x03, - 0x10, 0x1f, 0x80, 0x10, 0x1f, 0x81, 0x95, 0x03, - 0x13, 0x03, 0x18, 0x1f, 0x80, 0x18, 0x1f, 0x81, - 0xb7, 0x03, 0x93, 0xb7, 0x03, 0x94, 0x20, 0x1f, - 0x80, 0x21, 0x1f, 0x80, 0x20, 0x1f, 0x81, 0x21, - 0x1f, 0x81, 0x20, 0x1f, 0xc2, 0x21, 0x1f, 0xc2, - 0x97, 0x03, 0x93, 0x97, 0x03, 0x94, 0x28, 0x1f, - 0x80, 0x29, 0x1f, 0x80, 0x28, 0x1f, 0x81, 0x29, - 0x1f, 0x81, 0x28, 0x1f, 0xc2, 0x29, 0x1f, 0xc2, - 0xb9, 0x03, 0x93, 0xb9, 0x03, 0x94, 0x30, 0x1f, - 0x80, 0x31, 0x1f, 0x80, 0x30, 0x1f, 0x81, 0x31, - 0x1f, 0x81, 0x30, 0x1f, 0xc2, 0x31, 0x1f, 0xc2, - 0x99, 0x03, 0x93, 0x99, 0x03, 0x94, 0x38, 0x1f, - 0x80, 0x39, 0x1f, 0x80, 0x38, 0x1f, 0x81, 0x39, - 0x1f, 0x81, 0x38, 0x1f, 0xc2, 0x39, 0x1f, 0xc2, - 0xbf, 0x03, 0x93, 0xbf, 0x03, 0x94, 0x40, 0x1f, - 0x80, 0x40, 0x1f, 0x81, 0x9f, 0x03, 0x13, 0x03, - 0x48, 0x1f, 0x80, 0x48, 0x1f, 0x81, 0xc5, 0x03, - 0x13, 0x03, 0x50, 0x1f, 0x80, 0x50, 0x1f, 0x81, - 0x50, 0x1f, 0xc2, 0xa5, 0x03, 0x94, 0x00, 0x00, - 0x00, 0x59, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x59, - 0x1f, 0x81, 0x00, 0x00, 0x00, 0x59, 0x1f, 0xc2, - 0xc9, 0x03, 0x93, 0xc9, 0x03, 0x94, 0x60, 0x1f, - 0x80, 0x61, 0x1f, 0x80, 0x60, 0x1f, 0x81, 0x61, - 0x1f, 0x81, 0x60, 0x1f, 0xc2, 0x61, 0x1f, 0xc2, - 0xa9, 0x03, 0x93, 0xa9, 0x03, 0x94, 0x68, 0x1f, - 0x80, 0x69, 0x1f, 0x80, 0x68, 0x1f, 0x81, 0x69, - 0x1f, 0x81, 0x68, 0x1f, 0xc2, 0x69, 0x1f, 0xc2, - 0xb1, 0x03, 0x80, 0xb5, 0x03, 0x80, 0xb7, 0x03, - 0x80, 0xb9, 0x03, 0x80, 0xbf, 0x03, 0x80, 0xc5, - 0x03, 0x80, 0xc9, 0x03, 0x80, 0x00, 0x1f, 0x45, - 0x03, 0x20, 0x1f, 0x45, 0x03, 0x60, 0x1f, 0x45, - 0x03, 0xb1, 0x03, 0x86, 0xb1, 0x03, 0x84, 0x70, - 0x1f, 0xc5, 0xb1, 0x03, 0xc5, 0xac, 0x03, 0xc5, - 0x00, 0x00, 0x00, 0xb1, 0x03, 0xc2, 0xb6, 0x1f, - 0xc5, 0x91, 0x03, 0x86, 0x91, 0x03, 0x84, 0x91, - 0x03, 0x80, 0x91, 0x03, 0xc5, 0x20, 0x93, 0x20, - 0x93, 0x20, 0xc2, 0xa8, 0x00, 0xc2, 0x74, 0x1f, - 0xc5, 0xb7, 0x03, 0xc5, 0xae, 0x03, 0xc5, 0x00, - 0x00, 0x00, 0xb7, 0x03, 0xc2, 0xc6, 0x1f, 0xc5, - 0x95, 0x03, 0x80, 0x97, 0x03, 0x80, 0x97, 0x03, - 0xc5, 0xbf, 0x1f, 0x80, 0xbf, 0x1f, 0x81, 0xbf, - 0x1f, 0xc2, 0xb9, 0x03, 0x86, 0xb9, 0x03, 0x84, - 0xca, 0x03, 0x80, 0x00, 0x03, 0xb9, 0x42, 0xca, - 0x42, 0x99, 0x06, 0x99, 0x04, 0x99, 0x00, 0xfe, - 0x1f, 0x80, 0xfe, 0x1f, 0x81, 0xfe, 0x1f, 0xc2, - 0xc5, 0x03, 0x86, 0xc5, 0x03, 0x84, 0xcb, 0x03, - 0x80, 0x00, 0x03, 0xc1, 0x13, 0xc1, 0x14, 0xc5, - 0x42, 0xcb, 0x42, 0xa5, 0x06, 0xa5, 0x04, 0xa5, - 0x00, 0xa1, 0x03, 0x94, 0xa8, 0x00, 0x80, 0x85, - 0x03, 0x60, 0x00, 0x7c, 0x1f, 0xc5, 0xc9, 0x03, - 0xc5, 0xce, 0x03, 0xc5, 0x00, 0x00, 0x00, 0xc9, - 0x03, 0xc2, 0xf6, 0x1f, 0xc5, 0x9f, 0x03, 0x80, - 0xa9, 0x03, 0x80, 0xa9, 0x03, 0xc5, 0x20, 0x94, - 0x02, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0xb3, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x32, 0x20, 0x32, 0x20, 0x32, 0x20, - 0x00, 0x00, 0x00, 0x35, 0x20, 0x35, 0x20, 0x35, - 0x20, 0x00, 0x00, 0x00, 0x21, 0x21, 0x00, 0x00, - 0x20, 0x85, 0x3f, 0x3f, 0x3f, 0x21, 0x21, 0x3f, - 0x32, 0x20, 0x00, 0x00, 0x00, 0x00, 0x30, 0x69, - 0x00, 0x00, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x2b, 0x3d, 0x28, 0x29, 0x6e, 0x30, 0x00, 0x2b, - 0x00, 0x12, 0x22, 0x3d, 0x00, 0x28, 0x00, 0x29, - 0x00, 0x00, 0x00, 0x61, 0x00, 0x65, 0x00, 0x6f, - 0x00, 0x78, 0x00, 0x59, 0x02, 0x68, 0x6b, 0x6c, - 0x6d, 0x6e, 0x70, 0x73, 0x74, 0x52, 0x73, 0x61, - 0x2f, 0x63, 0x61, 0x2f, 0x73, 0xb0, 0x00, 0x43, - 0x63, 0x2f, 0x6f, 0x63, 0x2f, 0x75, 0xb0, 0x00, - 0x46, 0x48, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, - 0xdf, 0x01, 0x01, 0x04, 0x24, 0x4e, 0x6f, 0x50, - 0x51, 0x52, 0x52, 0x52, 0x53, 0x4d, 0x54, 0x45, - 0x4c, 0x54, 0x4d, 0x4b, 0x00, 0xc5, 0x00, 0x42, - 0x43, 0x00, 0x65, 0x45, 0x46, 0x00, 0x4d, 0x6f, - 0xd0, 0x05, 0x46, 0x41, 0x58, 0xc0, 0x03, 0xb3, - 0x03, 0x93, 0x03, 0xa0, 0x03, 0x11, 0x22, 0x44, - 0x64, 0x65, 0x69, 0x6a, 0x31, 0xd0, 0x37, 0x31, - 0xd0, 0x39, 0x31, 0xd0, 0x31, 0x30, 0x31, 0xd0, - 0x33, 0x32, 0xd0, 0x33, 0x31, 0xd0, 0x35, 0x32, - 0xd0, 0x35, 0x33, 0xd0, 0x35, 0x34, 0xd0, 0x35, - 0x31, 0xd0, 0x36, 0x35, 0xd0, 0x36, 0x31, 0xd0, - 0x38, 0x33, 0xd0, 0x38, 0x35, 0xd0, 0x38, 0x37, - 0xd0, 0x38, 0x31, 0xd0, 0x49, 0x49, 0x49, 0x49, - 0x49, 0x49, 0x56, 0x56, 0x49, 0x56, 0x49, 0x49, - 0x56, 0x49, 0x49, 0x49, 0x49, 0x58, 0x58, 0x49, - 0x58, 0x49, 0x49, 0x4c, 0x43, 0x44, 0x4d, 0x69, - 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x76, 0x76, - 0x69, 0x76, 0x69, 0x69, 0x76, 0x69, 0x69, 0x69, - 0x69, 0x78, 0x78, 0x69, 0x78, 0x69, 0x69, 0x6c, - 0x63, 0x64, 0x6d, 0x30, 0xd0, 0x33, 0x90, 0x21, - 0xb8, 0x92, 0x21, 0xb8, 0x94, 0x21, 0xb8, 0xd0, - 0x21, 0xb8, 0xd4, 0x21, 0xb8, 0xd2, 0x21, 0xb8, - 0x03, 0x22, 0xb8, 0x08, 0x22, 0xb8, 0x0b, 0x22, - 0xb8, 0x23, 0x22, 0xb8, 0x00, 0x00, 0x00, 0x25, - 0x22, 0xb8, 0x2b, 0x22, 0x2b, 0x22, 0x2b, 0x22, - 0x00, 0x00, 0x00, 0x2e, 0x22, 0x2e, 0x22, 0x2e, - 0x22, 0x00, 0x00, 0x00, 0x3c, 0x22, 0xb8, 0x43, - 0x22, 0xb8, 0x45, 0x22, 0xb8, 0x00, 0x00, 0x00, - 0x48, 0x22, 0xb8, 0x3d, 0x00, 0xb8, 0x00, 0x00, - 0x00, 0x61, 0x22, 0xb8, 0x4d, 0x22, 0xb8, 0x3c, - 0x00, 0xb8, 0x3e, 0x00, 0xb8, 0x64, 0x22, 0xb8, - 0x65, 0x22, 0xb8, 0x72, 0x22, 0xb8, 0x76, 0x22, - 0xb8, 0x7a, 0x22, 0xb8, 0x82, 0x22, 0xb8, 0x86, - 0x22, 0xb8, 0xa2, 0x22, 0xb8, 0xa8, 0x22, 0xb8, - 0xa9, 0x22, 0xb8, 0xab, 0x22, 0xb8, 0x7c, 0x22, - 0xb8, 0x91, 0x22, 0xb8, 0xb2, 0x22, 0x38, 0x03, - 0x08, 0x30, 0x31, 0x00, 0x31, 0x00, 0x30, 0x00, - 0x32, 0x30, 0x28, 0x00, 0x31, 0x00, 0x29, 0x00, - 0x28, 0x00, 0x31, 0x00, 0x30, 0x00, 0x29, 0x00, - 0x28, 0x32, 0x30, 0x29, 0x31, 0x00, 0x2e, 0x00, - 0x31, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x32, 0x30, - 0x2e, 0x28, 0x00, 0x61, 0x00, 0x29, 0x00, 0x41, - 0x00, 0x61, 0x00, 0x2b, 0x22, 0x00, 0x00, 0x00, - 0x00, 0x3a, 0x3a, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0xdd, 0x2a, 0xb8, 0x6a, 0x56, 0x00, 0x4e, - 0x00, 0x28, 0x36, 0x3f, 0x59, 0x85, 0x8c, 0xa0, - 0xba, 0x3f, 0x51, 0x00, 0x26, 0x2c, 0x43, 0x57, - 0x6c, 0xa1, 0xb6, 0xc1, 0x9b, 0x52, 0x00, 0x5e, - 0x7a, 0x7f, 0x9d, 0xa6, 0xc1, 0xce, 0xe7, 0xb6, - 0x53, 0xc8, 0x53, 0xe3, 0x53, 0xd7, 0x56, 0x1f, - 0x57, 0xeb, 0x58, 0x02, 0x59, 0x0a, 0x59, 0x15, - 0x59, 0x27, 0x59, 0x73, 0x59, 0x50, 0x5b, 0x80, - 0x5b, 0xf8, 0x5b, 0x0f, 0x5c, 0x22, 0x5c, 0x38, - 0x5c, 0x6e, 0x5c, 0x71, 0x5c, 0xdb, 0x5d, 0xe5, - 0x5d, 0xf1, 0x5d, 0xfe, 0x5d, 0x72, 0x5e, 0x7a, - 0x5e, 0x7f, 0x5e, 0xf4, 0x5e, 0xfe, 0x5e, 0x0b, - 0x5f, 0x13, 0x5f, 0x50, 0x5f, 0x61, 0x5f, 0x73, - 0x5f, 0xc3, 0x5f, 0x08, 0x62, 0x36, 0x62, 0x4b, - 0x62, 0x2f, 0x65, 0x34, 0x65, 0x87, 0x65, 0x97, - 0x65, 0xa4, 0x65, 0xb9, 0x65, 0xe0, 0x65, 0xe5, - 0x65, 0xf0, 0x66, 0x08, 0x67, 0x28, 0x67, 0x20, - 0x6b, 0x62, 0x6b, 0x79, 0x6b, 0xb3, 0x6b, 0xcb, - 0x6b, 0xd4, 0x6b, 0xdb, 0x6b, 0x0f, 0x6c, 0x14, - 0x6c, 0x34, 0x6c, 0x6b, 0x70, 0x2a, 0x72, 0x36, - 0x72, 0x3b, 0x72, 0x3f, 0x72, 0x47, 0x72, 0x59, - 0x72, 0x5b, 0x72, 0xac, 0x72, 0x84, 0x73, 0x89, - 0x73, 0xdc, 0x74, 0xe6, 0x74, 0x18, 0x75, 0x1f, - 0x75, 0x28, 0x75, 0x30, 0x75, 0x8b, 0x75, 0x92, - 0x75, 0x76, 0x76, 0x7d, 0x76, 0xae, 0x76, 0xbf, - 0x76, 0xee, 0x76, 0xdb, 0x77, 0xe2, 0x77, 0xf3, - 0x77, 0x3a, 0x79, 0xb8, 0x79, 0xbe, 0x79, 0x74, - 0x7a, 0xcb, 0x7a, 0xf9, 0x7a, 0x73, 0x7c, 0xf8, - 0x7c, 0x36, 0x7f, 0x51, 0x7f, 0x8a, 0x7f, 0xbd, - 0x7f, 0x01, 0x80, 0x0c, 0x80, 0x12, 0x80, 0x33, - 0x80, 0x7f, 0x80, 0x89, 0x80, 0xe3, 0x81, 0x00, - 0x07, 0x10, 0x19, 0x29, 0x38, 0x3c, 0x8b, 0x8f, - 0x95, 0x4d, 0x86, 0x6b, 0x86, 0x40, 0x88, 0x4c, - 0x88, 0x63, 0x88, 0x7e, 0x89, 0x8b, 0x89, 0xd2, - 0x89, 0x00, 0x8a, 0x37, 0x8c, 0x46, 0x8c, 0x55, - 0x8c, 0x78, 0x8c, 0x9d, 0x8c, 0x64, 0x8d, 0x70, - 0x8d, 0xb3, 0x8d, 0xab, 0x8e, 0xca, 0x8e, 0x9b, - 0x8f, 0xb0, 0x8f, 0xb5, 0x8f, 0x91, 0x90, 0x49, - 0x91, 0xc6, 0x91, 0xcc, 0x91, 0xd1, 0x91, 0x77, - 0x95, 0x80, 0x95, 0x1c, 0x96, 0xb6, 0x96, 0xb9, - 0x96, 0xe8, 0x96, 0x51, 0x97, 0x5e, 0x97, 0x62, - 0x97, 0x69, 0x97, 0xcb, 0x97, 0xed, 0x97, 0xf3, - 0x97, 0x01, 0x98, 0xa8, 0x98, 0xdb, 0x98, 0xdf, - 0x98, 0x96, 0x99, 0x99, 0x99, 0xac, 0x99, 0xa8, - 0x9a, 0xd8, 0x9a, 0xdf, 0x9a, 0x25, 0x9b, 0x2f, - 0x9b, 0x32, 0x9b, 0x3c, 0x9b, 0x5a, 0x9b, 0xe5, - 0x9c, 0x75, 0x9e, 0x7f, 0x9e, 0xa5, 0x9e, 0x00, - 0x16, 0x1e, 0x28, 0x2c, 0x54, 0x58, 0x69, 0x6e, - 0x7b, 0x96, 0xa5, 0xad, 0xe8, 0xf7, 0xfb, 0x12, - 0x30, 0x00, 0x00, 0x41, 0x53, 0x44, 0x53, 0x45, - 0x53, 0x4b, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x4d, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x4f, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x51, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x53, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x55, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x57, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x59, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x5b, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x5d, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x5f, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x61, 0x30, 0x99, 0x30, 0x64, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x66, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x68, 0x30, 0x99, - 0x30, 0x6f, 0x30, 0x99, 0x30, 0x72, 0x30, 0x99, - 0x30, 0x75, 0x30, 0x99, 0x30, 0x78, 0x30, 0x99, - 0x30, 0x7b, 0x30, 0x99, 0x30, 0x46, 0x30, 0x99, - 0x30, 0x20, 0x00, 0x99, 0x30, 0x9d, 0x30, 0x99, - 0x30, 0x88, 0x30, 0x8a, 0x30, 0xab, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xad, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xb5, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x30, 0x99, - 0x30, 0xc4, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0xc6, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0xc8, 0x30, 0x99, 0x30, 0xcf, 0x30, 0x99, - 0x30, 0xd2, 0x30, 0x99, 0x30, 0xd5, 0x30, 0x99, - 0x30, 0xd8, 0x30, 0x99, 0x30, 0xdb, 0x30, 0x99, - 0x30, 0xa6, 0x30, 0x99, 0x30, 0xef, 0x30, 0x99, - 0x30, 0xfd, 0x30, 0x99, 0x30, 0xb3, 0x30, 0xc8, - 0x30, 0x00, 0x11, 0x00, 0x01, 0xaa, 0x02, 0xac, - 0xad, 0x03, 0x04, 0x05, 0xb0, 0xb1, 0xb2, 0xb3, - 0xb4, 0xb5, 0x1a, 0x06, 0x07, 0x08, 0x21, 0x09, - 0x11, 0x61, 0x11, 0x14, 0x11, 0x4c, 0x00, 0x01, - 0xb3, 0xb4, 0xb8, 0xba, 0xbf, 0xc3, 0xc5, 0x08, - 0xc9, 0xcb, 0x09, 0x0a, 0x0c, 0x0e, 0x0f, 0x13, - 0x15, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x22, - 0x2c, 0x33, 0x38, 0xdd, 0xde, 0x43, 0x44, 0x45, - 0x70, 0x71, 0x74, 0x7d, 0x7e, 0x80, 0x8a, 0x8d, - 0x00, 0x4e, 0x8c, 0x4e, 0x09, 0x4e, 0xdb, 0x56, - 0x0a, 0x4e, 0x2d, 0x4e, 0x0b, 0x4e, 0x32, 0x75, - 0x59, 0x4e, 0x19, 0x4e, 0x01, 0x4e, 0x29, 0x59, - 0x30, 0x57, 0xba, 0x4e, 0x28, 0x00, 0x29, 0x00, - 0x00, 0x11, 0x02, 0x11, 0x03, 0x11, 0x05, 0x11, - 0x06, 0x11, 0x07, 0x11, 0x09, 0x11, 0x0b, 0x11, - 0x0c, 0x11, 0x0e, 0x11, 0x0f, 0x11, 0x10, 0x11, - 0x11, 0x11, 0x12, 0x11, 0x28, 0x00, 0x00, 0x11, - 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x02, 0x11, - 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x05, 0x11, - 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x09, 0x11, - 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11, - 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0e, 0x11, - 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0c, 0x11, - 0x6e, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11, - 0x69, 0x11, 0x0c, 0x11, 0x65, 0x11, 0xab, 0x11, - 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11, 0x69, 0x11, - 0x12, 0x11, 0x6e, 0x11, 0x29, 0x00, 0x28, 0x00, - 0x29, 0x00, 0x00, 0x4e, 0x8c, 0x4e, 0x09, 0x4e, - 0xdb, 0x56, 0x94, 0x4e, 0x6d, 0x51, 0x03, 0x4e, - 0x6b, 0x51, 0x5d, 0x4e, 0x41, 0x53, 0x08, 0x67, - 0x6b, 0x70, 0x34, 0x6c, 0x28, 0x67, 0xd1, 0x91, - 0x1f, 0x57, 0xe5, 0x65, 0x2a, 0x68, 0x09, 0x67, - 0x3e, 0x79, 0x0d, 0x54, 0x79, 0x72, 0xa1, 0x8c, - 0x5d, 0x79, 0xb4, 0x52, 0xe3, 0x4e, 0x7c, 0x54, - 0x66, 0x5b, 0xe3, 0x76, 0x01, 0x4f, 0xc7, 0x8c, - 0x54, 0x53, 0x6d, 0x79, 0x11, 0x4f, 0xea, 0x81, - 0xf3, 0x81, 0x4f, 0x55, 0x7c, 0x5e, 0x87, 0x65, - 0x8f, 0x7b, 0x50, 0x54, 0x45, 0x32, 0x00, 0x31, - 0x00, 0x33, 0x00, 0x30, 0x00, 0x00, 0x11, 0x00, - 0x02, 0x03, 0x05, 0x06, 0x07, 0x09, 0x0b, 0x0c, - 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x00, 0x11, 0x00, - 0x61, 0x02, 0x61, 0x03, 0x61, 0x05, 0x61, 0x06, - 0x61, 0x07, 0x61, 0x09, 0x61, 0x0b, 0x61, 0x0c, - 0x61, 0x0e, 0x11, 0x61, 0x11, 0x00, 0x11, 0x0e, - 0x61, 0xb7, 0x00, 0x69, 0x0b, 0x11, 0x01, 0x63, - 0x00, 0x69, 0x0b, 0x11, 0x6e, 0x11, 0x00, 0x4e, - 0x8c, 0x4e, 0x09, 0x4e, 0xdb, 0x56, 0x94, 0x4e, - 0x6d, 0x51, 0x03, 0x4e, 0x6b, 0x51, 0x5d, 0x4e, - 0x41, 0x53, 0x08, 0x67, 0x6b, 0x70, 0x34, 0x6c, - 0x28, 0x67, 0xd1, 0x91, 0x1f, 0x57, 0xe5, 0x65, - 0x2a, 0x68, 0x09, 0x67, 0x3e, 0x79, 0x0d, 0x54, - 0x79, 0x72, 0xa1, 0x8c, 0x5d, 0x79, 0xb4, 0x52, - 0xd8, 0x79, 0x37, 0x75, 0x73, 0x59, 0x69, 0x90, - 0x2a, 0x51, 0x70, 0x53, 0xe8, 0x6c, 0x05, 0x98, - 0x11, 0x4f, 0x99, 0x51, 0x63, 0x6b, 0x0a, 0x4e, - 0x2d, 0x4e, 0x0b, 0x4e, 0xe6, 0x5d, 0xf3, 0x53, - 0x3b, 0x53, 0x97, 0x5b, 0x66, 0x5b, 0xe3, 0x76, - 0x01, 0x4f, 0xc7, 0x8c, 0x54, 0x53, 0x1c, 0x59, - 0x33, 0x00, 0x36, 0x00, 0x34, 0x00, 0x30, 0x00, - 0x35, 0x30, 0x31, 0x00, 0x08, 0x67, 0x31, 0x00, - 0x30, 0x00, 0x08, 0x67, 0x48, 0x67, 0x65, 0x72, - 0x67, 0x65, 0x56, 0x4c, 0x54, 0x44, 0xa2, 0x30, - 0x00, 0x02, 0x04, 0x06, 0x08, 0x09, 0x0b, 0x0d, - 0x0f, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1b, 0x1d, - 0x1f, 0x22, 0x24, 0x26, 0x28, 0x29, 0x2a, 0x2b, - 0x2c, 0x2d, 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3d, - 0x3e, 0x3f, 0x40, 0x42, 0x44, 0x46, 0x47, 0x48, - 0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0xe4, - 0x4e, 0x8c, 0x54, 0xa1, 0x30, 0x01, 0x30, 0x5b, - 0x27, 0x01, 0x4a, 0x34, 0x00, 0x01, 0x52, 0x39, - 0x01, 0xa2, 0x30, 0x00, 0x5a, 0x49, 0xa4, 0x30, - 0x00, 0x27, 0x4f, 0x0c, 0xa4, 0x30, 0x00, 0x4f, - 0x1d, 0x02, 0x05, 0x4f, 0xa8, 0x30, 0x00, 0x11, - 0x07, 0x54, 0x21, 0xa8, 0x30, 0x00, 0x54, 0x03, - 0x54, 0xa4, 0x30, 0x06, 0x4f, 0x15, 0x06, 0x58, - 0x3c, 0x07, 0x00, 0x46, 0xab, 0x30, 0x00, 0x3e, - 0x18, 0x1d, 0x00, 0x42, 0x3f, 0x51, 0xac, 0x30, - 0x00, 0x41, 0x47, 0x00, 0x47, 0x32, 0xae, 0x30, - 0xac, 0x30, 0xae, 0x30, 0x00, 0x1d, 0x4e, 0xad, - 0x30, 0x00, 0x38, 0x3d, 0x4f, 0x01, 0x3e, 0x13, - 0x4f, 0xad, 0x30, 0xed, 0x30, 0xad, 0x30, 0x00, - 0x40, 0x03, 0x3c, 0x33, 0xad, 0x30, 0x00, 0x40, - 0x34, 0x4f, 0x1b, 0x3e, 0xad, 0x30, 0x00, 0x40, - 0x42, 0x16, 0x1b, 0xb0, 0x30, 0x00, 0x39, 0x30, - 0xa4, 0x30, 0x0c, 0x45, 0x3c, 0x24, 0x4f, 0x0b, - 0x47, 0x18, 0x00, 0x49, 0xaf, 0x30, 0x00, 0x3e, - 0x4d, 0x1e, 0xb1, 0x30, 0x00, 0x4b, 0x08, 0x02, - 0x3a, 0x19, 0x02, 0x4b, 0x2c, 0xa4, 0x30, 0x11, - 0x00, 0x0b, 0x47, 0xb5, 0x30, 0x00, 0x3e, 0x0c, - 0x47, 0x2b, 0xb0, 0x30, 0x07, 0x3a, 0x43, 0x00, - 0xb9, 0x30, 0x02, 0x3a, 0x08, 0x02, 0x3a, 0x0f, - 0x07, 0x43, 0x00, 0xb7, 0x30, 0x10, 0x00, 0x12, - 0x34, 0x11, 0x3c, 0x13, 0x17, 0xa4, 0x30, 0x2a, - 0x1f, 0x24, 0x2b, 0x00, 0x20, 0xbb, 0x30, 0x16, - 0x41, 0x00, 0x38, 0x0d, 0xc4, 0x30, 0x0d, 0x38, - 0x00, 0xd0, 0x30, 0x00, 0x2c, 0x1c, 0x1b, 0xa2, - 0x30, 0x32, 0x00, 0x17, 0x26, 0x49, 0xaf, 0x30, - 0x25, 0x00, 0x3c, 0xb3, 0x30, 0x21, 0x00, 0x20, - 0x38, 0xa1, 0x30, 0x34, 0x00, 0x48, 0x22, 0x28, - 0xa3, 0x30, 0x32, 0x00, 0x59, 0x25, 0xa7, 0x30, - 0x2f, 0x1c, 0x10, 0x00, 0x44, 0xd5, 0x30, 0x00, - 0x14, 0x1e, 0xaf, 0x30, 0x29, 0x00, 0x10, 0x4d, - 0x3c, 0xda, 0x30, 0xbd, 0x30, 0xb8, 0x30, 0x22, - 0x13, 0x1a, 0x20, 0x33, 0x0c, 0x22, 0x3b, 0x01, - 0x22, 0x44, 0x00, 0x21, 0x44, 0x07, 0xa4, 0x30, - 0x39, 0x00, 0x4f, 0x24, 0xc8, 0x30, 0x14, 0x23, - 0x00, 0xdb, 0x30, 0xf3, 0x30, 0xc9, 0x30, 0x14, - 0x2a, 0x00, 0x12, 0x33, 0x22, 0x12, 0x33, 0x2a, - 0xa4, 0x30, 0x3a, 0x00, 0x0b, 0x49, 0xa4, 0x30, - 0x3a, 0x00, 0x47, 0x3a, 0x1f, 0x2b, 0x3a, 0x47, - 0x0b, 0xb7, 0x30, 0x27, 0x3c, 0x00, 0x30, 0x3c, - 0xaf, 0x30, 0x30, 0x00, 0x3e, 0x44, 0xdf, 0x30, - 0xea, 0x30, 0xd0, 0x30, 0x0f, 0x1a, 0x00, 0x2c, - 0x1b, 0xe1, 0x30, 0xac, 0x30, 0xac, 0x30, 0x35, - 0x00, 0x1c, 0x47, 0x35, 0x50, 0x1c, 0x3f, 0xa2, - 0x30, 0x42, 0x5a, 0x27, 0x42, 0x5a, 0x49, 0x44, - 0x00, 0x51, 0xc3, 0x30, 0x27, 0x00, 0x05, 0x28, - 0xea, 0x30, 0xe9, 0x30, 0xd4, 0x30, 0x17, 0x00, - 0x28, 0xd6, 0x30, 0x15, 0x26, 0x00, 0x15, 0xec, - 0x30, 0xe0, 0x30, 0xb2, 0x30, 0x3a, 0x41, 0x16, - 0x00, 0x41, 0xc3, 0x30, 0x2c, 0x00, 0x05, 0x30, - 0x00, 0xb9, 0x70, 0x31, 0x00, 0x30, 0x00, 0xb9, - 0x70, 0x32, 0x00, 0x30, 0x00, 0xb9, 0x70, 0x68, - 0x50, 0x61, 0x64, 0x61, 0x41, 0x55, 0x62, 0x61, - 0x72, 0x6f, 0x56, 0x70, 0x63, 0x64, 0x6d, 0x64, - 0x00, 0x6d, 0x00, 0xb2, 0x00, 0x49, 0x00, 0x55, - 0x00, 0x73, 0x5e, 0x10, 0x62, 0x2d, 0x66, 0x8c, - 0x54, 0x27, 0x59, 0x63, 0x6b, 0x0e, 0x66, 0xbb, - 0x6c, 0x2a, 0x68, 0x0f, 0x5f, 0x1a, 0x4f, 0x3e, - 0x79, 0x70, 0x00, 0x41, 0x6e, 0x00, 0x41, 0xbc, - 0x03, 0x41, 0x6d, 0x00, 0x41, 0x6b, 0x00, 0x41, - 0x4b, 0x00, 0x42, 0x4d, 0x00, 0x42, 0x47, 0x00, - 0x42, 0x63, 0x61, 0x6c, 0x6b, 0x63, 0x61, 0x6c, - 0x70, 0x00, 0x46, 0x6e, 0x00, 0x46, 0xbc, 0x03, - 0x46, 0xbc, 0x03, 0x67, 0x6d, 0x00, 0x67, 0x6b, - 0x00, 0x67, 0x48, 0x00, 0x7a, 0x6b, 0x48, 0x7a, - 0x4d, 0x48, 0x7a, 0x47, 0x48, 0x7a, 0x54, 0x48, - 0x7a, 0xbc, 0x03, 0x13, 0x21, 0x6d, 0x00, 0x13, - 0x21, 0x64, 0x00, 0x13, 0x21, 0x6b, 0x00, 0x13, - 0x21, 0x66, 0x00, 0x6d, 0x6e, 0x00, 0x6d, 0xbc, - 0x03, 0x6d, 0x6d, 0x00, 0x6d, 0x63, 0x00, 0x6d, - 0x6b, 0x00, 0x6d, 0x63, 0x00, 0x0a, 0x0a, 0x4f, - 0x00, 0x0a, 0x4f, 0x6d, 0x00, 0xb2, 0x00, 0x63, - 0x00, 0x08, 0x0a, 0x4f, 0x0a, 0x0a, 0x50, 0x00, - 0x0a, 0x50, 0x6d, 0x00, 0xb3, 0x00, 0x6b, 0x00, - 0x6d, 0x00, 0xb3, 0x00, 0x6d, 0x00, 0x15, 0x22, - 0x73, 0x00, 0x6d, 0x00, 0x15, 0x22, 0x73, 0x00, - 0xb2, 0x00, 0x50, 0x61, 0x6b, 0x50, 0x61, 0x4d, - 0x50, 0x61, 0x47, 0x50, 0x61, 0x72, 0x61, 0x64, - 0x72, 0x61, 0x64, 0xd1, 0x73, 0x72, 0x00, 0x61, - 0x00, 0x64, 0x00, 0x15, 0x22, 0x73, 0x00, 0xb2, - 0x00, 0x70, 0x00, 0x73, 0x6e, 0x00, 0x73, 0xbc, - 0x03, 0x73, 0x6d, 0x00, 0x73, 0x70, 0x00, 0x56, - 0x6e, 0x00, 0x56, 0xbc, 0x03, 0x56, 0x6d, 0x00, - 0x56, 0x6b, 0x00, 0x56, 0x4d, 0x00, 0x56, 0x70, - 0x00, 0x57, 0x6e, 0x00, 0x57, 0xbc, 0x03, 0x57, - 0x6d, 0x00, 0x57, 0x6b, 0x00, 0x57, 0x4d, 0x00, - 0x57, 0x6b, 0x00, 0xa9, 0x03, 0x4d, 0x00, 0xa9, - 0x03, 0x61, 0x2e, 0x6d, 0x2e, 0x42, 0x71, 0x63, - 0x63, 0x63, 0x64, 0x43, 0xd1, 0x6b, 0x67, 0x43, - 0x6f, 0x2e, 0x64, 0x42, 0x47, 0x79, 0x68, 0x61, - 0x48, 0x50, 0x69, 0x6e, 0x4b, 0x4b, 0x4b, 0x4d, - 0x6b, 0x74, 0x6c, 0x6d, 0x6c, 0x6e, 0x6c, 0x6f, - 0x67, 0x6c, 0x78, 0x6d, 0x62, 0x6d, 0x69, 0x6c, - 0x6d, 0x6f, 0x6c, 0x50, 0x48, 0x70, 0x2e, 0x6d, - 0x2e, 0x50, 0x50, 0x4d, 0x50, 0x52, 0x73, 0x72, - 0x53, 0x76, 0x57, 0x62, 0x56, 0xd1, 0x6d, 0x41, - 0xd1, 0x6d, 0x31, 0x00, 0xe5, 0x65, 0x31, 0x00, - 0x30, 0x00, 0xe5, 0x65, 0x32, 0x00, 0x30, 0x00, - 0xe5, 0x65, 0x33, 0x00, 0x30, 0x00, 0xe5, 0x65, - 0x67, 0x61, 0x6c, 0x4a, 0x04, 0x4c, 0x04, 0x43, - 0x46, 0x51, 0x26, 0x01, 0x53, 0x01, 0x27, 0xa7, - 0x37, 0xab, 0x6b, 0x02, 0x52, 0xab, 0x48, 0x8c, - 0xf4, 0x66, 0xca, 0x8e, 0xc8, 0x8c, 0xd1, 0x6e, - 0x32, 0x4e, 0xe5, 0x53, 0x9c, 0x9f, 0x9c, 0x9f, - 0x51, 0x59, 0xd1, 0x91, 0x87, 0x55, 0x48, 0x59, - 0xf6, 0x61, 0x69, 0x76, 0x85, 0x7f, 0x3f, 0x86, - 0xba, 0x87, 0xf8, 0x88, 0x8f, 0x90, 0x02, 0x6a, - 0x1b, 0x6d, 0xd9, 0x70, 0xde, 0x73, 0x3d, 0x84, - 0x6a, 0x91, 0xf1, 0x99, 0x82, 0x4e, 0x75, 0x53, - 0x04, 0x6b, 0x1b, 0x72, 0x2d, 0x86, 0x1e, 0x9e, - 0x50, 0x5d, 0xeb, 0x6f, 0xcd, 0x85, 0x64, 0x89, - 0xc9, 0x62, 0xd8, 0x81, 0x1f, 0x88, 0xca, 0x5e, - 0x17, 0x67, 0x6a, 0x6d, 0xfc, 0x72, 0xce, 0x90, - 0x86, 0x4f, 0xb7, 0x51, 0xde, 0x52, 0xc4, 0x64, - 0xd3, 0x6a, 0x10, 0x72, 0xe7, 0x76, 0x01, 0x80, - 0x06, 0x86, 0x5c, 0x86, 0xef, 0x8d, 0x32, 0x97, - 0x6f, 0x9b, 0xfa, 0x9d, 0x8c, 0x78, 0x7f, 0x79, - 0xa0, 0x7d, 0xc9, 0x83, 0x04, 0x93, 0x7f, 0x9e, - 0xd6, 0x8a, 0xdf, 0x58, 0x04, 0x5f, 0x60, 0x7c, - 0x7e, 0x80, 0x62, 0x72, 0xca, 0x78, 0xc2, 0x8c, - 0xf7, 0x96, 0xd8, 0x58, 0x62, 0x5c, 0x13, 0x6a, - 0xda, 0x6d, 0x0f, 0x6f, 0x2f, 0x7d, 0x37, 0x7e, - 0x4b, 0x96, 0xd2, 0x52, 0x8b, 0x80, 0xdc, 0x51, - 0xcc, 0x51, 0x1c, 0x7a, 0xbe, 0x7d, 0xf1, 0x83, - 0x75, 0x96, 0x80, 0x8b, 0xcf, 0x62, 0x02, 0x6a, - 0xfe, 0x8a, 0x39, 0x4e, 0xe7, 0x5b, 0x12, 0x60, - 0x87, 0x73, 0x70, 0x75, 0x17, 0x53, 0xfb, 0x78, - 0xbf, 0x4f, 0xa9, 0x5f, 0x0d, 0x4e, 0xcc, 0x6c, - 0x78, 0x65, 0x22, 0x7d, 0xc3, 0x53, 0x5e, 0x58, - 0x01, 0x77, 0x49, 0x84, 0xaa, 0x8a, 0xba, 0x6b, - 0xb0, 0x8f, 0x88, 0x6c, 0xfe, 0x62, 0xe5, 0x82, - 0xa0, 0x63, 0x65, 0x75, 0xae, 0x4e, 0x69, 0x51, - 0xc9, 0x51, 0x81, 0x68, 0xe7, 0x7c, 0x6f, 0x82, - 0xd2, 0x8a, 0xcf, 0x91, 0xf5, 0x52, 0x42, 0x54, - 0x73, 0x59, 0xec, 0x5e, 0xc5, 0x65, 0xfe, 0x6f, - 0x2a, 0x79, 0xad, 0x95, 0x6a, 0x9a, 0x97, 0x9e, - 0xce, 0x9e, 0x9b, 0x52, 0xc6, 0x66, 0x77, 0x6b, - 0x62, 0x8f, 0x74, 0x5e, 0x90, 0x61, 0x00, 0x62, - 0x9a, 0x64, 0x23, 0x6f, 0x49, 0x71, 0x89, 0x74, - 0xca, 0x79, 0xf4, 0x7d, 0x6f, 0x80, 0x26, 0x8f, - 0xee, 0x84, 0x23, 0x90, 0x4a, 0x93, 0x17, 0x52, - 0xa3, 0x52, 0xbd, 0x54, 0xc8, 0x70, 0xc2, 0x88, - 0xaa, 0x8a, 0xc9, 0x5e, 0xf5, 0x5f, 0x7b, 0x63, - 0xae, 0x6b, 0x3e, 0x7c, 0x75, 0x73, 0xe4, 0x4e, - 0xf9, 0x56, 0xe7, 0x5b, 0xba, 0x5d, 0x1c, 0x60, - 0xb2, 0x73, 0x69, 0x74, 0x9a, 0x7f, 0x46, 0x80, - 0x34, 0x92, 0xf6, 0x96, 0x48, 0x97, 0x18, 0x98, - 0x8b, 0x4f, 0xae, 0x79, 0xb4, 0x91, 0xb8, 0x96, - 0xe1, 0x60, 0x86, 0x4e, 0xda, 0x50, 0xee, 0x5b, - 0x3f, 0x5c, 0x99, 0x65, 0x02, 0x6a, 0xce, 0x71, - 0x42, 0x76, 0xfc, 0x84, 0x7c, 0x90, 0x8d, 0x9f, - 0x88, 0x66, 0x2e, 0x96, 0x89, 0x52, 0x7b, 0x67, - 0xf3, 0x67, 0x41, 0x6d, 0x9c, 0x6e, 0x09, 0x74, - 0x59, 0x75, 0x6b, 0x78, 0x10, 0x7d, 0x5e, 0x98, - 0x6d, 0x51, 0x2e, 0x62, 0x78, 0x96, 0x2b, 0x50, - 0x19, 0x5d, 0xea, 0x6d, 0x2a, 0x8f, 0x8b, 0x5f, - 0x44, 0x61, 0x17, 0x68, 0x87, 0x73, 0x86, 0x96, - 0x29, 0x52, 0x0f, 0x54, 0x65, 0x5c, 0x13, 0x66, - 0x4e, 0x67, 0xa8, 0x68, 0xe5, 0x6c, 0x06, 0x74, - 0xe2, 0x75, 0x79, 0x7f, 0xcf, 0x88, 0xe1, 0x88, - 0xcc, 0x91, 0xe2, 0x96, 0x3f, 0x53, 0xba, 0x6e, - 0x1d, 0x54, 0xd0, 0x71, 0x98, 0x74, 0xfa, 0x85, - 0xa3, 0x96, 0x57, 0x9c, 0x9f, 0x9e, 0x97, 0x67, - 0xcb, 0x6d, 0xe8, 0x81, 0xcb, 0x7a, 0x20, 0x7b, - 0x92, 0x7c, 0xc0, 0x72, 0x99, 0x70, 0x58, 0x8b, - 0xc0, 0x4e, 0x36, 0x83, 0x3a, 0x52, 0x07, 0x52, - 0xa6, 0x5e, 0xd3, 0x62, 0xd6, 0x7c, 0x85, 0x5b, - 0x1e, 0x6d, 0xb4, 0x66, 0x3b, 0x8f, 0x4c, 0x88, - 0x4d, 0x96, 0x8b, 0x89, 0xd3, 0x5e, 0x40, 0x51, - 0xc0, 0x55, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x58, - 0x00, 0x00, 0x74, 0x66, 0x00, 0x00, 0x00, 0x00, - 0xde, 0x51, 0x2a, 0x73, 0xca, 0x76, 0x3c, 0x79, - 0x5e, 0x79, 0x65, 0x79, 0x8f, 0x79, 0x56, 0x97, - 0xbe, 0x7c, 0xbd, 0x7f, 0x00, 0x00, 0x12, 0x86, - 0x00, 0x00, 0xf8, 0x8a, 0x00, 0x00, 0x00, 0x00, - 0x38, 0x90, 0xfd, 0x90, 0xef, 0x98, 0xfc, 0x98, - 0x28, 0x99, 0xb4, 0x9d, 0xde, 0x90, 0xb7, 0x96, - 0xae, 0x4f, 0xe7, 0x50, 0x4d, 0x51, 0xc9, 0x52, - 0xe4, 0x52, 0x51, 0x53, 0x9d, 0x55, 0x06, 0x56, - 0x68, 0x56, 0x40, 0x58, 0xa8, 0x58, 0x64, 0x5c, - 0x6e, 0x5c, 0x94, 0x60, 0x68, 0x61, 0x8e, 0x61, - 0xf2, 0x61, 0x4f, 0x65, 0xe2, 0x65, 0x91, 0x66, - 0x85, 0x68, 0x77, 0x6d, 0x1a, 0x6e, 0x22, 0x6f, - 0x6e, 0x71, 0x2b, 0x72, 0x22, 0x74, 0x91, 0x78, - 0x3e, 0x79, 0x49, 0x79, 0x48, 0x79, 0x50, 0x79, - 0x56, 0x79, 0x5d, 0x79, 0x8d, 0x79, 0x8e, 0x79, - 0x40, 0x7a, 0x81, 0x7a, 0xc0, 0x7b, 0xf4, 0x7d, - 0x09, 0x7e, 0x41, 0x7e, 0x72, 0x7f, 0x05, 0x80, - 0xed, 0x81, 0x79, 0x82, 0x79, 0x82, 0x57, 0x84, - 0x10, 0x89, 0x96, 0x89, 0x01, 0x8b, 0x39, 0x8b, - 0xd3, 0x8c, 0x08, 0x8d, 0xb6, 0x8f, 0x38, 0x90, - 0xe3, 0x96, 0xff, 0x97, 0x3b, 0x98, 0x75, 0x60, - 0xee, 0x42, 0x18, 0x82, 0x02, 0x26, 0x4e, 0xb5, - 0x51, 0x68, 0x51, 0x80, 0x4f, 0x45, 0x51, 0x80, - 0x51, 0xc7, 0x52, 0xfa, 0x52, 0x9d, 0x55, 0x55, - 0x55, 0x99, 0x55, 0xe2, 0x55, 0x5a, 0x58, 0xb3, - 0x58, 0x44, 0x59, 0x54, 0x59, 0x62, 0x5a, 0x28, - 0x5b, 0xd2, 0x5e, 0xd9, 0x5e, 0x69, 0x5f, 0xad, - 0x5f, 0xd8, 0x60, 0x4e, 0x61, 0x08, 0x61, 0x8e, - 0x61, 0x60, 0x61, 0xf2, 0x61, 0x34, 0x62, 0xc4, - 0x63, 0x1c, 0x64, 0x52, 0x64, 0x56, 0x65, 0x74, - 0x66, 0x17, 0x67, 0x1b, 0x67, 0x56, 0x67, 0x79, - 0x6b, 0xba, 0x6b, 0x41, 0x6d, 0xdb, 0x6e, 0xcb, - 0x6e, 0x22, 0x6f, 0x1e, 0x70, 0x6e, 0x71, 0xa7, - 0x77, 0x35, 0x72, 0xaf, 0x72, 0x2a, 0x73, 0x71, - 0x74, 0x06, 0x75, 0x3b, 0x75, 0x1d, 0x76, 0x1f, - 0x76, 0xca, 0x76, 0xdb, 0x76, 0xf4, 0x76, 0x4a, - 0x77, 0x40, 0x77, 0xcc, 0x78, 0xb1, 0x7a, 0xc0, - 0x7b, 0x7b, 0x7c, 0x5b, 0x7d, 0xf4, 0x7d, 0x3e, - 0x7f, 0x05, 0x80, 0x52, 0x83, 0xef, 0x83, 0x79, - 0x87, 0x41, 0x89, 0x86, 0x89, 0x96, 0x89, 0xbf, - 0x8a, 0xf8, 0x8a, 0xcb, 0x8a, 0x01, 0x8b, 0xfe, - 0x8a, 0xed, 0x8a, 0x39, 0x8b, 0x8a, 0x8b, 0x08, - 0x8d, 0x38, 0x8f, 0x72, 0x90, 0x99, 0x91, 0x76, - 0x92, 0x7c, 0x96, 0xe3, 0x96, 0x56, 0x97, 0xdb, - 0x97, 0xff, 0x97, 0x0b, 0x98, 0x3b, 0x98, 0x12, - 0x9b, 0x9c, 0x9f, 0x4a, 0x28, 0x44, 0x28, 0xd5, - 0x33, 0x9d, 0x3b, 0x18, 0x40, 0x39, 0x40, 0x49, - 0x52, 0xd0, 0x5c, 0xd3, 0x7e, 0x43, 0x9f, 0x8e, - 0x9f, 0x2a, 0xa0, 0x02, 0x66, 0x66, 0x66, 0x69, - 0x66, 0x6c, 0x66, 0x66, 0x69, 0x66, 0x66, 0x6c, - 0x7f, 0x01, 0x74, 0x73, 0x00, 0x74, 0x65, 0x05, - 0x0f, 0x11, 0x0f, 0x00, 0x0f, 0x06, 0x19, 0x11, - 0x0f, 0x08, 0xd9, 0x05, 0xb4, 0x05, 0x00, 0x00, - 0x00, 0x00, 0xf2, 0x05, 0xb7, 0x05, 0xd0, 0x05, - 0x12, 0x00, 0x03, 0x04, 0x0b, 0x0c, 0x0d, 0x18, - 0x1a, 0xe9, 0x05, 0xc1, 0x05, 0xe9, 0x05, 0xc2, - 0x05, 0x49, 0xfb, 0xc1, 0x05, 0x49, 0xfb, 0xc2, - 0x05, 0xd0, 0x05, 0xb7, 0x05, 0xd0, 0x05, 0xb8, - 0x05, 0xd0, 0x05, 0xbc, 0x05, 0xd8, 0x05, 0xbc, - 0x05, 0xde, 0x05, 0xbc, 0x05, 0xe0, 0x05, 0xbc, - 0x05, 0xe3, 0x05, 0xbc, 0x05, 0xb9, 0x05, 0x2d, - 0x03, 0x2e, 0x03, 0x2f, 0x03, 0x30, 0x03, 0x31, - 0x03, 0x1c, 0x00, 0x18, 0x06, 0x22, 0x06, 0x2b, - 0x06, 0xd0, 0x05, 0xdc, 0x05, 0x71, 0x06, 0x00, - 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0f, 0x0f, 0x0f, 0x0f, 0x09, 0x09, 0x09, - 0x09, 0x0e, 0x0e, 0x0e, 0x0e, 0x08, 0x08, 0x08, - 0x08, 0x33, 0x33, 0x33, 0x33, 0x35, 0x35, 0x35, - 0x35, 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, 0x12, - 0x12, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, - 0x16, 0x1c, 0x1c, 0x1b, 0x1b, 0x1d, 0x1d, 0x17, - 0x17, 0x27, 0x27, 0x20, 0x20, 0x38, 0x38, 0x38, - 0x38, 0x3e, 0x3e, 0x3e, 0x3e, 0x42, 0x42, 0x42, - 0x42, 0x40, 0x40, 0x40, 0x40, 0x49, 0x49, 0x4a, - 0x4a, 0x4a, 0x4a, 0x4f, 0x4f, 0x50, 0x50, 0x50, - 0x50, 0x4d, 0x4d, 0x4d, 0x4d, 0x61, 0x61, 0x62, - 0x62, 0x49, 0x06, 0x64, 0x64, 0x64, 0x64, 0x7e, - 0x7e, 0x7d, 0x7d, 0x7f, 0x7f, 0x2e, 0x82, 0x82, - 0x7c, 0x7c, 0x80, 0x80, 0x87, 0x87, 0x87, 0x87, - 0x00, 0x00, 0x26, 0x06, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xaf, 0x00, 0xaf, 0x00, 0x22, 0x00, 0x22, - 0x00, 0xa1, 0x00, 0xa1, 0x00, 0xa0, 0x00, 0xa0, - 0x00, 0xa2, 0x00, 0xa2, 0x00, 0xaa, 0x00, 0xaa, - 0x00, 0xaa, 0x00, 0x23, 0x00, 0x23, 0x00, 0x23, - 0xcc, 0x06, 0x00, 0x00, 0x00, 0x00, 0x26, 0x06, - 0x00, 0x06, 0x00, 0x07, 0x00, 0x1f, 0x00, 0x23, - 0x00, 0x24, 0x02, 0x06, 0x02, 0x07, 0x02, 0x08, - 0x02, 0x1f, 0x02, 0x23, 0x02, 0x24, 0x04, 0x06, - 0x04, 0x07, 0x04, 0x08, 0x04, 0x1f, 0x04, 0x23, - 0x04, 0x24, 0x05, 0x06, 0x05, 0x1f, 0x05, 0x23, - 0x05, 0x24, 0x06, 0x07, 0x06, 0x1f, 0x07, 0x06, - 0x07, 0x1f, 0x08, 0x06, 0x08, 0x07, 0x08, 0x1f, - 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x08, 0x0d, 0x1f, - 0x0f, 0x07, 0x0f, 0x1f, 0x10, 0x06, 0x10, 0x07, - 0x10, 0x08, 0x10, 0x1f, 0x11, 0x07, 0x11, 0x1f, - 0x12, 0x1f, 0x13, 0x06, 0x13, 0x1f, 0x14, 0x06, - 0x14, 0x1f, 0x1b, 0x06, 0x1b, 0x07, 0x1b, 0x08, - 0x1b, 0x1f, 0x1b, 0x23, 0x1b, 0x24, 0x1c, 0x07, - 0x1c, 0x1f, 0x1c, 0x23, 0x1c, 0x24, 0x1d, 0x01, - 0x1d, 0x06, 0x1d, 0x07, 0x1d, 0x08, 0x1d, 0x1e, - 0x1d, 0x1f, 0x1d, 0x23, 0x1d, 0x24, 0x1e, 0x06, - 0x1e, 0x07, 0x1e, 0x08, 0x1e, 0x1f, 0x1e, 0x23, - 0x1e, 0x24, 0x1f, 0x06, 0x1f, 0x07, 0x1f, 0x08, - 0x1f, 0x1f, 0x1f, 0x23, 0x1f, 0x24, 0x20, 0x06, - 0x20, 0x07, 0x20, 0x08, 0x20, 0x1f, 0x20, 0x23, - 0x20, 0x24, 0x21, 0x06, 0x21, 0x1f, 0x21, 0x23, - 0x21, 0x24, 0x24, 0x06, 0x24, 0x07, 0x24, 0x08, - 0x24, 0x1f, 0x24, 0x23, 0x24, 0x24, 0x0a, 0x4a, - 0x0b, 0x4a, 0x23, 0x4a, 0x20, 0x00, 0x4c, 0x06, - 0x51, 0x06, 0x51, 0x06, 0xff, 0x00, 0x1f, 0x26, - 0x06, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x1f, 0x00, - 0x20, 0x00, 0x23, 0x00, 0x24, 0x02, 0x0b, 0x02, - 0x0c, 0x02, 0x1f, 0x02, 0x20, 0x02, 0x23, 0x02, - 0x24, 0x04, 0x0b, 0x04, 0x0c, 0x04, 0x1f, 0x26, - 0x06, 0x04, 0x20, 0x04, 0x23, 0x04, 0x24, 0x05, - 0x0b, 0x05, 0x0c, 0x05, 0x1f, 0x05, 0x20, 0x05, - 0x23, 0x05, 0x24, 0x1b, 0x23, 0x1b, 0x24, 0x1c, - 0x23, 0x1c, 0x24, 0x1d, 0x01, 0x1d, 0x1e, 0x1d, - 0x1f, 0x1d, 0x23, 0x1d, 0x24, 0x1e, 0x1f, 0x1e, - 0x23, 0x1e, 0x24, 0x1f, 0x01, 0x1f, 0x1f, 0x20, - 0x0b, 0x20, 0x0c, 0x20, 0x1f, 0x20, 0x20, 0x20, - 0x23, 0x20, 0x24, 0x23, 0x4a, 0x24, 0x0b, 0x24, - 0x0c, 0x24, 0x1f, 0x24, 0x20, 0x24, 0x23, 0x24, - 0x24, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, - 0x1f, 0x00, 0x21, 0x02, 0x06, 0x02, 0x07, 0x02, - 0x08, 0x02, 0x1f, 0x02, 0x21, 0x04, 0x06, 0x04, - 0x07, 0x04, 0x08, 0x04, 0x1f, 0x04, 0x21, 0x05, - 0x1f, 0x06, 0x07, 0x06, 0x1f, 0x07, 0x06, 0x07, - 0x1f, 0x08, 0x06, 0x08, 0x1f, 0x0d, 0x06, 0x0d, - 0x07, 0x0d, 0x08, 0x0d, 0x1f, 0x0f, 0x07, 0x0f, - 0x08, 0x0f, 0x1f, 0x10, 0x06, 0x10, 0x07, 0x10, - 0x08, 0x10, 0x1f, 0x11, 0x07, 0x12, 0x1f, 0x13, - 0x06, 0x13, 0x1f, 0x14, 0x06, 0x14, 0x1f, 0x1b, - 0x06, 0x1b, 0x07, 0x1b, 0x08, 0x1b, 0x1f, 0x1c, - 0x07, 0x1c, 0x1f, 0x1d, 0x06, 0x1d, 0x07, 0x1d, - 0x08, 0x1d, 0x1e, 0x1d, 0x1f, 0x1e, 0x06, 0x1e, - 0x07, 0x1e, 0x08, 0x1e, 0x1f, 0x1e, 0x21, 0x1f, - 0x06, 0x1f, 0x07, 0x1f, 0x08, 0x1f, 0x1f, 0x20, - 0x06, 0x20, 0x07, 0x20, 0x08, 0x20, 0x1f, 0x20, - 0x21, 0x21, 0x06, 0x21, 0x1f, 0x21, 0x4a, 0x24, - 0x06, 0x24, 0x07, 0x24, 0x08, 0x24, 0x1f, 0x24, - 0x21, 0x00, 0x1f, 0x00, 0x21, 0x02, 0x1f, 0x02, - 0x21, 0x04, 0x1f, 0x04, 0x21, 0x05, 0x1f, 0x05, - 0x21, 0x0d, 0x1f, 0x0d, 0x21, 0x0e, 0x1f, 0x0e, - 0x21, 0x1d, 0x1e, 0x1d, 0x1f, 0x1e, 0x1f, 0x20, - 0x1f, 0x20, 0x21, 0x24, 0x1f, 0x24, 0x21, 0x40, - 0x06, 0x4e, 0x06, 0x51, 0x06, 0x27, 0x06, 0x10, - 0x22, 0x10, 0x23, 0x12, 0x22, 0x12, 0x23, 0x13, - 0x22, 0x13, 0x23, 0x0c, 0x22, 0x0c, 0x23, 0x0d, - 0x22, 0x0d, 0x23, 0x06, 0x22, 0x06, 0x23, 0x05, - 0x22, 0x05, 0x23, 0x07, 0x22, 0x07, 0x23, 0x0e, - 0x22, 0x0e, 0x23, 0x0f, 0x22, 0x0f, 0x23, 0x0d, - 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e, 0x0d, - 0x0a, 0x0c, 0x0a, 0x0e, 0x0a, 0x0f, 0x0a, 0x10, - 0x22, 0x10, 0x23, 0x12, 0x22, 0x12, 0x23, 0x13, - 0x22, 0x13, 0x23, 0x0c, 0x22, 0x0c, 0x23, 0x0d, - 0x22, 0x0d, 0x23, 0x06, 0x22, 0x06, 0x23, 0x05, - 0x22, 0x05, 0x23, 0x07, 0x22, 0x07, 0x23, 0x0e, - 0x22, 0x0e, 0x23, 0x0f, 0x22, 0x0f, 0x23, 0x0d, - 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e, 0x0d, - 0x0a, 0x0c, 0x0a, 0x0e, 0x0a, 0x0f, 0x0a, 0x0d, - 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e, 0x0c, - 0x20, 0x0d, 0x20, 0x10, 0x1e, 0x0c, 0x05, 0x0c, - 0x06, 0x0c, 0x07, 0x0d, 0x05, 0x0d, 0x06, 0x0d, - 0x07, 0x10, 0x1e, 0x11, 0x1e, 0x00, 0x24, 0x00, - 0x24, 0x2a, 0x06, 0x00, 0x02, 0x1b, 0x00, 0x03, - 0x02, 0x00, 0x03, 0x02, 0x00, 0x03, 0x1b, 0x00, - 0x04, 0x1b, 0x00, 0x1b, 0x02, 0x00, 0x1b, 0x03, - 0x00, 0x1b, 0x04, 0x02, 0x1b, 0x03, 0x02, 0x1b, - 0x03, 0x03, 0x1b, 0x20, 0x03, 0x1b, 0x1f, 0x09, - 0x03, 0x02, 0x09, 0x02, 0x03, 0x09, 0x02, 0x1f, - 0x09, 0x1b, 0x03, 0x09, 0x1b, 0x03, 0x09, 0x1b, - 0x02, 0x09, 0x1b, 0x1b, 0x09, 0x1b, 0x1b, 0x0b, - 0x03, 0x03, 0x0b, 0x03, 0x03, 0x0b, 0x1b, 0x1b, - 0x0a, 0x03, 0x1b, 0x0a, 0x03, 0x1b, 0x0a, 0x02, - 0x20, 0x0a, 0x1b, 0x04, 0x0a, 0x1b, 0x04, 0x0a, - 0x1b, 0x1b, 0x0a, 0x1b, 0x1b, 0x0c, 0x03, 0x1f, - 0x0c, 0x04, 0x1b, 0x0c, 0x04, 0x1b, 0x0d, 0x1b, - 0x03, 0x0d, 0x1b, 0x03, 0x0d, 0x1b, 0x1b, 0x0d, - 0x1b, 0x20, 0x0f, 0x02, 0x1b, 0x0f, 0x1b, 0x1b, - 0x0f, 0x1b, 0x1b, 0x0f, 0x1b, 0x1f, 0x10, 0x1b, - 0x1b, 0x10, 0x1b, 0x20, 0x10, 0x1b, 0x1f, 0x17, - 0x04, 0x1b, 0x17, 0x04, 0x1b, 0x18, 0x1b, 0x03, - 0x18, 0x1b, 0x1b, 0x1a, 0x03, 0x1b, 0x1a, 0x03, - 0x20, 0x1a, 0x03, 0x1f, 0x1a, 0x02, 0x02, 0x1a, - 0x02, 0x02, 0x1a, 0x04, 0x1b, 0x1a, 0x04, 0x1b, - 0x1a, 0x1b, 0x03, 0x1a, 0x1b, 0x03, 0x1b, 0x03, - 0x02, 0x1b, 0x03, 0x1b, 0x1b, 0x03, 0x20, 0x1b, - 0x02, 0x03, 0x1b, 0x02, 0x1b, 0x1b, 0x04, 0x02, - 0x1b, 0x04, 0x1b, 0x28, 0x06, 0x1d, 0x04, 0x06, - 0x1f, 0x1d, 0x04, 0x1f, 0x1d, 0x1d, 0x1e, 0x05, - 0x1d, 0x1e, 0x05, 0x21, 0x1e, 0x04, 0x1d, 0x1e, - 0x04, 0x1d, 0x1e, 0x04, 0x21, 0x1e, 0x1d, 0x22, - 0x1e, 0x1d, 0x21, 0x22, 0x1d, 0x1d, 0x22, 0x1d, - 0x1d, 0x00, 0x06, 0x22, 0x02, 0x04, 0x22, 0x02, - 0x04, 0x21, 0x02, 0x06, 0x22, 0x02, 0x06, 0x21, - 0x02, 0x1d, 0x22, 0x02, 0x1d, 0x21, 0x04, 0x1d, - 0x22, 0x04, 0x05, 0x21, 0x04, 0x1d, 0x21, 0x0b, - 0x06, 0x21, 0x0d, 0x05, 0x22, 0x0c, 0x05, 0x22, - 0x0e, 0x05, 0x22, 0x1c, 0x04, 0x22, 0x1c, 0x1d, - 0x22, 0x22, 0x05, 0x22, 0x22, 0x04, 0x22, 0x22, - 0x1d, 0x22, 0x1d, 0x1d, 0x22, 0x1a, 0x1d, 0x22, - 0x1e, 0x05, 0x22, 0x1a, 0x1d, 0x05, 0x1c, 0x05, - 0x1d, 0x11, 0x1d, 0x22, 0x1b, 0x1d, 0x22, 0x1e, - 0x04, 0x05, 0x1d, 0x06, 0x22, 0x1c, 0x04, 0x1d, - 0x1b, 0x1d, 0x1d, 0x1c, 0x04, 0x1d, 0x1e, 0x04, - 0x05, 0x04, 0x05, 0x22, 0x05, 0x04, 0x22, 0x1d, - 0x04, 0x22, 0x19, 0x1d, 0x22, 0x00, 0x05, 0x22, - 0x1b, 0x1d, 0x1d, 0x11, 0x04, 0x1d, 0x0d, 0x1d, - 0x1d, 0x0b, 0x06, 0x22, 0x1e, 0x04, 0x22, 0x35, - 0x06, 0x00, 0x0f, 0x9d, 0x0d, 0x0f, 0x9d, 0x27, - 0x06, 0x00, 0x1d, 0x1d, 0x20, 0x00, 0x1c, 0x01, - 0x0a, 0x1e, 0x06, 0x1e, 0x08, 0x0e, 0x1d, 0x12, - 0x1e, 0x0a, 0x0c, 0x21, 0x1d, 0x12, 0x1d, 0x23, - 0x20, 0x21, 0x0c, 0x1d, 0x1e, 0x35, 0x06, 0x00, - 0x0f, 0x14, 0x27, 0x06, 0x0e, 0x1d, 0x22, 0xff, - 0x00, 0x1d, 0x1d, 0x20, 0xff, 0x12, 0x1d, 0x23, - 0x20, 0xff, 0x21, 0x0c, 0x1d, 0x1e, 0x27, 0x06, - 0x05, 0x1d, 0xff, 0x05, 0x1d, 0x00, 0x1d, 0x20, - 0x27, 0x06, 0x0a, 0xa5, 0x00, 0x1d, 0x2c, 0x00, - 0x01, 0x30, 0x02, 0x30, 0x3a, 0x00, 0x3b, 0x00, - 0x21, 0x00, 0x3f, 0x00, 0x16, 0x30, 0x17, 0x30, - 0x26, 0x20, 0x13, 0x20, 0x12, 0x01, 0x00, 0x5f, - 0x5f, 0x28, 0x29, 0x7b, 0x7d, 0x08, 0x30, 0x0c, - 0x0d, 0x08, 0x09, 0x02, 0x03, 0x00, 0x01, 0x04, - 0x05, 0x06, 0x07, 0x5b, 0x00, 0x5d, 0x00, 0x3e, - 0x20, 0x3e, 0x20, 0x3e, 0x20, 0x3e, 0x20, 0x5f, - 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x2c, 0x00, 0x01, - 0x30, 0x2e, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x3a, - 0x00, 0x3f, 0x00, 0x21, 0x00, 0x14, 0x20, 0x28, - 0x00, 0x29, 0x00, 0x7b, 0x00, 0x7d, 0x00, 0x14, - 0x30, 0x15, 0x30, 0x23, 0x26, 0x2a, 0x2b, 0x2d, - 0x3c, 0x3e, 0x3d, 0x00, 0x5c, 0x24, 0x25, 0x40, - 0x40, 0x06, 0xff, 0x0b, 0x00, 0x0b, 0xff, 0x0c, - 0x20, 0x00, 0x4d, 0x06, 0x40, 0x06, 0xff, 0x0e, - 0x00, 0x0e, 0xff, 0x0f, 0x00, 0x0f, 0xff, 0x10, - 0x00, 0x10, 0xff, 0x11, 0x00, 0x11, 0xff, 0x12, - 0x00, 0x12, 0x21, 0x06, 0x00, 0x01, 0x01, 0x02, - 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x05, - 0x05, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, - 0x08, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, - 0x0f, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x12, - 0x12, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, - 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, - 0x16, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, - 0x18, 0x19, 0x19, 0x19, 0x19, 0x20, 0x20, 0x20, - 0x20, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, - 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, - 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26, - 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29, 0x29, - 0x29, 0x22, 0x06, 0x22, 0x00, 0x22, 0x00, 0x22, - 0x01, 0x22, 0x01, 0x22, 0x03, 0x22, 0x03, 0x22, - 0x05, 0x22, 0x05, 0x21, 0x00, 0x85, 0x29, 0x01, - 0x30, 0x01, 0x0b, 0x0c, 0x00, 0xfa, 0xf1, 0xa0, - 0xa2, 0xa4, 0xa6, 0xa8, 0xe2, 0xe4, 0xe6, 0xc2, - 0xfb, 0xa1, 0xa3, 0xa5, 0xa7, 0xa9, 0xaa, 0xac, - 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, - 0xbe, 0xc0, 0xc3, 0xc5, 0xc7, 0xc9, 0xca, 0xcb, - 0xcc, 0xcd, 0xce, 0xd1, 0xd4, 0xd7, 0xda, 0xdd, - 0xde, 0xdf, 0xe0, 0xe1, 0xe3, 0xe5, 0xe7, 0xe8, - 0xe9, 0xea, 0xeb, 0xec, 0xee, 0xf2, 0x98, 0x99, - 0x31, 0x31, 0x4f, 0x31, 0x55, 0x31, 0x5b, 0x31, - 0x61, 0x31, 0xa2, 0x00, 0xa3, 0x00, 0xac, 0x00, - 0xaf, 0x00, 0xa6, 0x00, 0xa5, 0x00, 0xa9, 0x20, - 0x00, 0x00, 0x02, 0x25, 0x90, 0x21, 0x91, 0x21, - 0x92, 0x21, 0x93, 0x21, 0xa0, 0x25, 0xcb, 0x25, - 0xd0, 0x02, 0xd1, 0x02, 0xe6, 0x00, 0x99, 0x02, - 0x53, 0x02, 0x00, 0x00, 0xa3, 0x02, 0x66, 0xab, - 0xa5, 0x02, 0xa4, 0x02, 0x56, 0x02, 0x57, 0x02, - 0x91, 0x1d, 0x58, 0x02, 0x5e, 0x02, 0xa9, 0x02, - 0x64, 0x02, 0x62, 0x02, 0x60, 0x02, 0x9b, 0x02, - 0x27, 0x01, 0x9c, 0x02, 0x67, 0x02, 0x84, 0x02, - 0xaa, 0x02, 0xab, 0x02, 0x6c, 0x02, 0x04, 0xdf, - 0x8e, 0xa7, 0x6e, 0x02, 0x05, 0xdf, 0x8e, 0x02, - 0x06, 0xdf, 0xf8, 0x00, 0x76, 0x02, 0x77, 0x02, - 0x71, 0x00, 0x7a, 0x02, 0x08, 0xdf, 0x7d, 0x02, - 0x7e, 0x02, 0x80, 0x02, 0xa8, 0x02, 0xa6, 0x02, - 0x67, 0xab, 0xa7, 0x02, 0x88, 0x02, 0x71, 0x2c, - 0x00, 0x00, 0x8f, 0x02, 0xa1, 0x02, 0xa2, 0x02, - 0x98, 0x02, 0xc0, 0x01, 0xc1, 0x01, 0xc2, 0x01, - 0x0a, 0xdf, 0x1e, 0xdf, 0x41, 0x04, 0x40, 0x00, - 0x00, 0x00, 0x00, 0x14, 0x99, 0x10, 0xba, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x9b, 0x10, 0xba, 0x10, - 0x05, 0x05, 0xa5, 0x10, 0xba, 0x10, 0x05, 0x31, - 0x11, 0x27, 0x11, 0x32, 0x11, 0x27, 0x11, 0x55, - 0x47, 0x13, 0x3e, 0x13, 0x47, 0x13, 0x57, 0x13, - 0x55, 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, 0x8f40, 0x8f42, 0x8f80, 0x8fc0, - 0x8fc1, 0x9000, 0x9001, 0x9041, 0x9040, 0x9043, 0x9080, 0x9081, - 0x90c0, -}; - -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[3897] = { - 0xfa, 0x18, 0x17, 0x56, 0x0d, 0x56, 0x12, 0x13, - 0x16, 0x0c, 0x16, 0x11, 0x36, 0xe9, 0x02, 0x36, - 0x4c, 0x36, 0xe1, 0x12, 0x12, 0x16, 0x13, 0x0e, - 0x10, 0x0e, 0xe2, 0x12, 0x12, 0x0c, 0x13, 0x0c, - 0xfa, 0x19, 0x17, 0x16, 0x6d, 0x0f, 0x16, 0x0e, - 0x0f, 0x05, 0x14, 0x0c, 0x1b, 0x0f, 0x0e, 0x0f, - 0x0c, 0x2b, 0x0e, 0x02, 0x36, 0x0e, 0x0b, 0x05, - 0x15, 0x4b, 0x16, 0xe1, 0x0f, 0x0c, 0xc1, 0xe2, - 0x10, 0x0c, 0xe2, 0x00, 0xff, 0x30, 0x02, 0xff, - 0x08, 0x02, 0xff, 0x27, 0xbf, 0x22, 0x21, 0x02, - 0x5f, 0x5f, 0x21, 0x22, 0x61, 0x02, 0x21, 0x02, - 0x41, 0x42, 0x21, 0x02, 0x21, 0x02, 0x9f, 0x7f, - 0x02, 0x5f, 0x5f, 0x21, 0x02, 0x5f, 0x3f, 0x02, - 0x05, 0x3f, 0x22, 0x65, 0x01, 0x03, 0x02, 0x01, - 0x03, 0x02, 0x01, 0x03, 0x02, 0xff, 0x08, 0x02, - 0xff, 0x0a, 0x02, 0x01, 0x03, 0x02, 0x5f, 0x21, - 0x02, 0xff, 0x32, 0xa2, 0x21, 0x02, 0x21, 0x22, - 0x5f, 0x41, 0x02, 0xff, 0x00, 0xe2, 0x3c, 0x05, - 0xe2, 0x13, 0xe4, 0x0a, 0x6e, 0xe4, 0x04, 0xee, - 0x06, 0x84, 0xce, 0x04, 0x0e, 0x04, 0xee, 0x09, - 0xe6, 0x68, 0x7f, 0x04, 0x0e, 0x3f, 0x20, 0x04, - 0x42, 0x16, 0x01, 0x60, 0x2e, 0x01, 0x16, 0x41, - 0x00, 0x01, 0x00, 0x21, 0x02, 0xe1, 0x09, 0x00, - 0xe1, 0x01, 0xe2, 0x1b, 0x3f, 0x02, 0x41, 0x42, - 0xff, 0x10, 0x62, 0x3f, 0x0c, 0x5f, 0x3f, 0x02, - 0xe1, 0x2b, 0xe2, 0x28, 0xff, 0x1a, 0x0f, 0x86, - 0x28, 0xff, 0x2f, 0xff, 0x06, 0x02, 0xff, 0x58, - 0x00, 0xe1, 0x1e, 0x20, 0x04, 0xb6, 0xe2, 0x21, - 0x16, 0x11, 0x20, 0x2f, 0x0d, 0x00, 0xe6, 0x25, - 0x11, 0x06, 0x16, 0x26, 0x16, 0x26, 0x16, 0x06, - 0xe0, 0x00, 0xe5, 0x13, 0x60, 0x65, 0x36, 0xe0, - 0x03, 0xbb, 0x4c, 0x36, 0x0d, 0x36, 0x2f, 0xe6, - 0x03, 0x16, 0x1b, 0x56, 0xe5, 0x18, 0x04, 0xe5, - 0x02, 0xe6, 0x0d, 0xe9, 0x02, 0x76, 0x25, 0x06, - 0xe5, 0x5b, 0x16, 0x05, 0xc6, 0x1b, 0x0f, 0xa6, - 0x24, 0x26, 0x0f, 0x66, 0x25, 0xe9, 0x02, 0x45, - 0x2f, 0x05, 0xf6, 0x06, 0x00, 0x1b, 0x05, 0x06, - 0xe5, 0x16, 0xe6, 0x13, 0x20, 0xe5, 0x51, 0xe6, - 0x03, 0x05, 0xe0, 0x06, 0xe9, 0x02, 0xe5, 0x19, - 0xe6, 0x01, 0x24, 0x0f, 0x56, 0x04, 0x20, 0x06, - 0x2d, 0xe5, 0x0e, 0x66, 0x04, 0xe6, 0x01, 0x04, - 0x46, 0x04, 0x86, 0x20, 0xf6, 0x07, 0x00, 0xe5, - 0x11, 0x46, 0x20, 0x16, 0x00, 0xe5, 0x03, 0x80, - 0xe5, 0x10, 0x0e, 0xa5, 0x00, 0x3b, 0xa0, 0xe6, - 0x00, 0xe5, 0x21, 0x04, 0xe6, 0x10, 0x1b, 0xe6, - 0x18, 0x07, 0xe5, 0x2e, 0x06, 0x07, 0x06, 0x05, - 0x47, 0xe6, 0x00, 0x67, 0x06, 0x27, 0x05, 0xc6, - 0xe5, 0x02, 0x26, 0x36, 0xe9, 0x02, 0x16, 0x04, - 0xe5, 0x07, 0x06, 0x27, 0x00, 0xe5, 0x00, 0x20, - 0x25, 0x20, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x05, - 0x40, 0x65, 0x20, 0x06, 0x05, 0x47, 0x66, 0x20, - 0x27, 0x20, 0x27, 0x06, 0x05, 0xe0, 0x00, 0x07, - 0x60, 0x25, 0x00, 0x45, 0x26, 0x20, 0xe9, 0x02, - 0x25, 0x2d, 0xab, 0x0f, 0x0d, 0x05, 0x16, 0x06, - 0x20, 0x26, 0x07, 0x00, 0xa5, 0x60, 0x25, 0x20, - 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00, 0x25, - 0x00, 0x25, 0x20, 0x06, 0x00, 0x47, 0x26, 0x60, - 0x26, 0x20, 0x46, 0x40, 0x06, 0xc0, 0x65, 0x00, - 0x05, 0xc0, 0xe9, 0x02, 0x26, 0x45, 0x06, 0x16, - 0xe0, 0x02, 0x26, 0x07, 0x00, 0xe5, 0x01, 0x00, - 0x45, 0x00, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, - 0x00, 0x85, 0x20, 0x06, 0x05, 0x47, 0x86, 0x00, - 0x26, 0x07, 0x00, 0x27, 0x06, 0x20, 0x05, 0xe0, - 0x07, 0x25, 0x26, 0x20, 0xe9, 0x02, 0x16, 0x0d, - 0xc0, 0x05, 0xa6, 0x00, 0x06, 0x27, 0x00, 0xe5, - 0x00, 0x20, 0x25, 0x20, 0xe5, 0x0e, 0x00, 0xc5, - 0x00, 0x25, 0x00, 0x85, 0x20, 0x06, 0x05, 0x07, - 0x06, 0x07, 0x66, 0x20, 0x27, 0x20, 0x27, 0x06, - 0xc0, 0x26, 0x07, 0x60, 0x25, 0x00, 0x45, 0x26, - 0x20, 0xe9, 0x02, 0x0f, 0x05, 0xab, 0xe0, 0x02, - 0x06, 0x05, 0x00, 0xa5, 0x40, 0x45, 0x00, 0x65, - 0x40, 0x25, 0x00, 0x05, 0x00, 0x25, 0x40, 0x25, - 0x40, 0x45, 0x40, 0xe5, 0x04, 0x60, 0x27, 0x06, - 0x27, 0x40, 0x47, 0x00, 0x47, 0x06, 0x20, 0x05, - 0xa0, 0x07, 0xe0, 0x06, 0xe9, 0x02, 0x4b, 0xaf, - 0x0d, 0x0f, 0x80, 0x06, 0x47, 0x06, 0xe5, 0x00, - 0x00, 0x45, 0x00, 0xe5, 0x0f, 0x00, 0xe5, 0x08, - 0x20, 0x06, 0x05, 0x46, 0x67, 0x00, 0x46, 0x00, - 0x66, 0xc0, 0x26, 0x00, 0x45, 0x20, 0x05, 0x20, - 0x25, 0x26, 0x20, 0xe9, 0x02, 0xc0, 0x16, 0xcb, - 0x0f, 0x05, 0x06, 0x27, 0x16, 0xe5, 0x00, 0x00, - 0x45, 0x00, 0xe5, 0x0f, 0x00, 0xe5, 0x02, 0x00, - 0x85, 0x20, 0x06, 0x05, 0x07, 0x06, 0x87, 0x00, - 0x06, 0x27, 0x00, 0x27, 0x26, 0xc0, 0x27, 0xa0, - 0x25, 0x00, 0x25, 0x26, 0x20, 0xe9, 0x02, 0x00, - 0x25, 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, 0x0a, 0x46, 0x07, 0xe0, - 0x01, 0xe5, 0x0b, 0x26, 0x07, 0x36, 0xe0, 0x01, - 0xe5, 0x0a, 0x26, 0xe0, 0x04, 0xe5, 0x05, 0x00, - 0x45, 0x00, 0x26, 0xe0, 0x04, 0xe5, 0x2c, 0x26, - 0x07, 0xc6, 0xe7, 0x00, 0x06, 0x27, 0xe6, 0x03, - 0x56, 0x04, 0x56, 0x0d, 0x05, 0x06, 0x20, 0xe9, - 0x02, 0xa0, 0xeb, 0x02, 0xa0, 0xb6, 0x11, 0x76, - 0x46, 0x1b, 0x06, 0xe9, 0x02, 0xa0, 0xe5, 0x1b, - 0x04, 0xe5, 0x2d, 0xc0, 0x85, 0x26, 0xe5, 0x1a, - 0x06, 0x05, 0x80, 0xe5, 0x3e, 0xe0, 0x02, 0xe5, - 0x17, 0x00, 0x46, 0x67, 0x26, 0x47, 0x60, 0x27, - 0x06, 0xa7, 0x46, 0x60, 0x0f, 0x40, 0x36, 0xe9, - 0x02, 0xe5, 0x16, 0x20, 0x85, 0xe0, 0x03, 0xe5, - 0x24, 0x60, 0xe5, 0x12, 0xa0, 0xe9, 0x02, 0x0b, - 0x40, 0xef, 0x1a, 0xe5, 0x0f, 0x26, 0x27, 0x06, - 0x20, 0x36, 0xe5, 0x2d, 0x07, 0x06, 0x07, 0xc6, - 0x00, 0x06, 0x07, 0x06, 0x27, 0xe6, 0x00, 0xa7, - 0xe6, 0x02, 0x20, 0x06, 0xe9, 0x02, 0xa0, 0xe9, - 0x02, 0xa0, 0xd6, 0x04, 0xb6, 0x20, 0xe6, 0x06, - 0x08, 0xe6, 0x08, 0xe0, 0x29, 0x66, 0x07, 0xe5, - 0x27, 0x06, 0x07, 0x86, 0x07, 0x06, 0x87, 0x06, - 0x27, 0xe5, 0x00, 0x40, 0xe9, 0x02, 0xd6, 0xef, - 0x02, 0xe6, 0x01, 0xef, 0x01, 0x36, 0x00, 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, 0x38, 0xff, 0x80, 0x0e, 0xe2, - 0x00, 0xff, 0x5a, 0xe2, 0x00, 0xe1, 0x00, 0xa2, - 0x20, 0xa1, 0x20, 0xe2, 0x00, 0xe1, 0x00, 0xe2, - 0x00, 0xe1, 0x00, 0xa2, 0x20, 0xa1, 0x20, 0xe2, - 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x3f, 0xc2, 0xe1, 0x00, 0xe2, 0x06, 0x20, 0xe2, - 0x00, 0xe3, 0x00, 0xe2, 0x00, 0xe3, 0x00, 0xe2, - 0x00, 0xe3, 0x00, 0x82, 0x00, 0x22, 0x61, 0x03, - 0x0e, 0x02, 0x4e, 0x42, 0x00, 0x22, 0x61, 0x03, - 0x4e, 0x62, 0x20, 0x22, 0x61, 0x00, 0x4e, 0xe2, - 0x00, 0x81, 0x4e, 0x20, 0x42, 0x00, 0x22, 0x61, - 0x03, 0x2e, 0x00, 0xf7, 0x03, 0x9b, 0xb1, 0x36, - 0x14, 0x15, 0x12, 0x34, 0x15, 0x12, 0x14, 0xf6, - 0x00, 0x18, 0x19, 0x9b, 0x17, 0xf6, 0x01, 0x14, - 0x15, 0x76, 0x30, 0x56, 0x0c, 0x12, 0x13, 0xf6, - 0x03, 0x0c, 0x16, 0x10, 0xf6, 0x02, 0x17, 0x9b, - 0x00, 0xfb, 0x02, 0x0b, 0x04, 0x20, 0xab, 0x4c, - 0x12, 0x13, 0x04, 0xeb, 0x02, 0x4c, 0x12, 0x13, - 0x00, 0xe4, 0x05, 0x40, 0xed, 0x19, 0xe0, 0x07, - 0xe6, 0x05, 0x68, 0x06, 0x48, 0xe6, 0x04, 0xe0, - 0x07, 0x2f, 0x01, 0x6f, 0x01, 0x2f, 0x02, 0x41, - 0x22, 0x41, 0x02, 0x0f, 0x01, 0x2f, 0x0c, 0x81, - 0xaf, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x61, - 0x0f, 0x02, 0x61, 0x02, 0x65, 0x02, 0x2f, 0x22, - 0x21, 0x8c, 0x3f, 0x42, 0x0f, 0x0c, 0x2f, 0x02, - 0x0f, 0xeb, 0x08, 0xea, 0x1b, 0x3f, 0x6a, 0x0b, - 0x2f, 0x60, 0x8c, 0x8f, 0x2c, 0x6f, 0x0c, 0x2f, - 0x0c, 0x2f, 0x0c, 0xcf, 0x0c, 0xef, 0x17, 0x2c, - 0x2f, 0x0c, 0x0f, 0x0c, 0xef, 0x17, 0xec, 0x80, - 0x84, 0xef, 0x00, 0x12, 0x13, 0x12, 0x13, 0xef, - 0x0c, 0x2c, 0xcf, 0x12, 0x13, 0xef, 0x49, 0x0c, - 0xef, 0x16, 0xec, 0x11, 0xef, 0x20, 0xac, 0xef, - 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, - 0x28, 0xe2, 0x28, 0x5f, 0x21, 0x22, 0xdf, 0x41, - 0x02, 0x3f, 0x02, 0x3f, 0x82, 0x24, 0x41, 0x02, - 0xff, 0x5a, 0x02, 0xaf, 0x7f, 0x46, 0x3f, 0x80, - 0x76, 0x0b, 0x36, 0xe2, 0x1e, 0x00, 0x02, 0x80, - 0x02, 0x20, 0xe5, 0x30, 0xc0, 0x04, 0x16, 0xe0, - 0x06, 0x06, 0xe5, 0x0f, 0xe0, 0x01, 0xc5, 0x00, - 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, - 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xe6, 0x18, - 0x36, 0x14, 0x15, 0x14, 0x15, 0x56, 0x14, 0x15, - 0x16, 0x14, 0x15, 0xf6, 0x01, 0x11, 0x36, 0x11, - 0x16, 0x14, 0x15, 0x36, 0x14, 0x15, 0x12, 0x13, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x96, 0x04, - 0xf6, 0x02, 0x31, 0x76, 0x11, 0x16, 0x12, 0xf6, - 0x05, 0x2f, 0x56, 0x12, 0x13, 0x12, 0x13, 0x12, - 0x13, 0x12, 0x13, 0x11, 0xe0, 0x1a, 0xef, 0x12, - 0x00, 0xef, 0x51, 0xe0, 0x04, 0xef, 0x80, 0x4e, - 0xe0, 0x12, 0xef, 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, 0x8d, 0x04, - 0xe5, 0x83, 0xef, 0x40, 0xef, 0x2f, 0xe0, 0x01, - 0xe5, 0x20, 0xa4, 0x36, 0xe5, 0x80, 0x84, 0x04, - 0x56, 0xe5, 0x08, 0xe9, 0x02, 0x25, 0xe0, 0x0c, - 0xff, 0x26, 0x05, 0x06, 0x48, 0x16, 0xe6, 0x02, - 0x16, 0x04, 0xff, 0x14, 0x24, 0x26, 0xe5, 0x3e, - 0xea, 0x02, 0x26, 0xb6, 0xe0, 0x00, 0xee, 0x0f, - 0xe4, 0x01, 0x2e, 0xff, 0x06, 0x22, 0xff, 0x36, - 0x04, 0xe2, 0x00, 0x9f, 0xff, 0x02, 0x04, 0x2e, - 0x7f, 0x05, 0x7f, 0x22, 0xff, 0x0d, 0x61, 0x02, - 0x81, 0x02, 0xff, 0x07, 0x41, 0x02, 0x3f, 0x80, - 0x3f, 0x00, 0x02, 0x00, 0x02, 0x7f, 0xe0, 0x10, - 0x44, 0x3f, 0x05, 0x24, 0x02, 0xc5, 0x06, 0x45, - 0x06, 0x65, 0x06, 0xe5, 0x0f, 0x27, 0x26, 0x07, - 0x6f, 0x06, 0x40, 0xab, 0x2f, 0x0d, 0x0f, 0xa0, - 0xe5, 0x2c, 0x76, 0xe0, 0x00, 0x27, 0xe5, 0x2a, - 0xe7, 0x08, 0x26, 0xe0, 0x00, 0x36, 0xe9, 0x02, - 0xa0, 0xe6, 0x0a, 0xa5, 0x56, 0x05, 0x16, 0x25, - 0x06, 0xe9, 0x02, 0xe5, 0x14, 0xe6, 0x00, 0x36, - 0xe5, 0x0f, 0xe6, 0x03, 0x27, 0xe0, 0x03, 0x16, - 0xe5, 0x15, 0x40, 0x46, 0x07, 0xe5, 0x27, 0x06, - 0x27, 0x66, 0x27, 0x26, 0x47, 0xf6, 0x05, 0x00, - 0x04, 0xe9, 0x02, 0x60, 0x36, 0x85, 0x06, 0x04, - 0xe5, 0x01, 0xe9, 0x02, 0x85, 0x00, 0xe5, 0x21, - 0xa6, 0x27, 0x26, 0x27, 0x26, 0xe0, 0x01, 0x45, - 0x06, 0xe5, 0x00, 0x06, 0x07, 0x20, 0xe9, 0x02, - 0x20, 0x76, 0xe5, 0x08, 0x04, 0xa5, 0x4f, 0x05, - 0x07, 0x06, 0x07, 0xe5, 0x2a, 0x06, 0x05, 0x46, - 0x25, 0x26, 0x85, 0x26, 0x05, 0x06, 0x05, 0xe0, - 0x10, 0x25, 0x04, 0x36, 0xe5, 0x03, 0x07, 0x26, - 0x27, 0x36, 0x05, 0x24, 0x07, 0x06, 0xe0, 0x02, - 0xa5, 0x20, 0xa5, 0x20, 0xa5, 0xe0, 0x01, 0xc5, - 0x00, 0xc5, 0x00, 0xe2, 0x23, 0x0e, 0x64, 0xe2, - 0x01, 0x04, 0x2e, 0x60, 0xe2, 0x48, 0xe5, 0x1b, - 0x27, 0x06, 0x27, 0x06, 0x27, 0x16, 0x07, 0x06, - 0x20, 0xe9, 0x02, 0xa0, 0xe5, 0xab, 0x1c, 0xe0, - 0x04, 0xe5, 0x0f, 0x60, 0xe5, 0x29, 0x60, 0xfc, - 0x87, 0x78, 0xfd, 0x98, 0x78, 0xe5, 0x80, 0xe6, - 0x20, 0xe5, 0x62, 0xe0, 0x1e, 0xc2, 0xe0, 0x04, - 0x82, 0x80, 0x05, 0x06, 0xe5, 0x02, 0x0c, 0xe5, - 0x05, 0x00, 0x85, 0x00, 0x05, 0x00, 0x25, 0x00, - 0x25, 0x00, 0xe5, 0x64, 0xee, 0x09, 0xe0, 0x08, - 0xe5, 0x80, 0xe3, 0x13, 0x12, 0xef, 0x08, 0xe5, - 0x38, 0x20, 0xe5, 0x2e, 0xc0, 0x0f, 0xe0, 0x18, - 0xe5, 0x04, 0x0d, 0x4f, 0xe6, 0x08, 0xd6, 0x12, - 0x13, 0x16, 0xa0, 0xe6, 0x08, 0x16, 0x31, 0x30, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, - 0x36, 0x12, 0x13, 0x76, 0x50, 0x56, 0x00, 0x76, - 0x11, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x56, - 0x0c, 0x11, 0x4c, 0x00, 0x16, 0x0d, 0x36, 0x60, - 0x85, 0x00, 0xe5, 0x7f, 0x20, 0x1b, 0x00, 0x56, - 0x0d, 0x56, 0x12, 0x13, 0x16, 0x0c, 0x16, 0x11, - 0x36, 0xe9, 0x02, 0x36, 0x4c, 0x36, 0xe1, 0x12, - 0x12, 0x16, 0x13, 0x0e, 0x10, 0x0e, 0xe2, 0x12, - 0x12, 0x0c, 0x13, 0x0c, 0x12, 0x13, 0x16, 0x12, - 0x13, 0x36, 0xe5, 0x02, 0x04, 0xe5, 0x25, 0x24, - 0xe5, 0x17, 0x40, 0xa5, 0x20, 0xa5, 0x20, 0xa5, - 0x20, 0x45, 0x40, 0x2d, 0x0c, 0x0e, 0x0f, 0x2d, - 0x00, 0x0f, 0x6c, 0x2f, 0xe0, 0x02, 0x5b, 0x2f, - 0x20, 0xe5, 0x04, 0x00, 0xe5, 0x12, 0x00, 0xe5, - 0x0b, 0x00, 0x25, 0x00, 0xe5, 0x07, 0x20, 0xe5, - 0x06, 0xe0, 0x1a, 0xe5, 0x73, 0x80, 0x56, 0x60, - 0xeb, 0x25, 0x40, 0xef, 0x01, 0xea, 0x2d, 0x6b, - 0xef, 0x09, 0x2b, 0x4f, 0x00, 0xef, 0x05, 0x40, - 0x0f, 0xe0, 0x27, 0xef, 0x25, 0x06, 0xe0, 0x7a, - 0xe5, 0x15, 0x40, 0xe5, 0x29, 0xe0, 0x07, 0x06, - 0xeb, 0x13, 0x60, 0xe5, 0x18, 0x6b, 0xe0, 0x01, - 0xe5, 0x0c, 0x0a, 0xe5, 0x00, 0x0a, 0x80, 0xe5, - 0x1e, 0x86, 0x80, 0xe5, 0x16, 0x00, 0x16, 0xe5, - 0x1c, 0x60, 0xe5, 0x00, 0x16, 0x8a, 0xe0, 0x22, - 0xe1, 0x20, 0xe2, 0x20, 0xe5, 0x46, 0x20, 0xe9, - 0x02, 0xa0, 0xe1, 0x1c, 0x60, 0xe2, 0x1c, 0x60, - 0xe5, 0x20, 0xe0, 0x00, 0xe5, 0x2c, 0xe0, 0x03, - 0x16, 0xe1, 0x03, 0x00, 0xe1, 0x07, 0x00, 0xc1, - 0x00, 0x21, 0x00, 0xe2, 0x03, 0x00, 0xe2, 0x07, - 0x00, 0xc2, 0x00, 0x22, 0xe0, 0x3b, 0xe5, 0x80, - 0xaf, 0xe0, 0x01, 0xe5, 0x0e, 0xe0, 0x02, 0xe5, - 0x00, 0xe0, 0x10, 0xa4, 0x00, 0xe4, 0x22, 0x00, - 0xe4, 0x01, 0xe0, 0x3d, 0xa5, 0x20, 0x05, 0x00, - 0xe5, 0x24, 0x00, 0x25, 0x40, 0x05, 0x20, 0xe5, - 0x0f, 0x00, 0x16, 0xeb, 0x00, 0xe5, 0x0f, 0x2f, - 0xcb, 0xe5, 0x17, 0xe0, 0x00, 0xeb, 0x01, 0xe0, - 0x28, 0xe5, 0x0b, 0x00, 0x25, 0x80, 0x8b, 0xe5, - 0x0e, 0xab, 0x40, 0x16, 0xe5, 0x12, 0x80, 0x16, - 0xe0, 0x38, 0xe5, 0x30, 0x60, 0x2b, 0x25, 0xeb, - 0x08, 0x20, 0xeb, 0x26, 0x05, 0x46, 0x00, 0x26, - 0x80, 0x66, 0x65, 0x00, 0x45, 0x00, 0xe5, 0x15, - 0x20, 0x46, 0x60, 0x06, 0xeb, 0x01, 0xc0, 0xf6, - 0x01, 0xc0, 0xe5, 0x15, 0x2b, 0x16, 0xe5, 0x15, - 0x4b, 0xe0, 0x18, 0xe5, 0x00, 0x0f, 0xe5, 0x14, - 0x26, 0x60, 0x8b, 0xd6, 0xe0, 0x01, 0xe5, 0x2e, - 0x40, 0xd6, 0xe5, 0x0e, 0x20, 0xeb, 0x00, 0xe5, - 0x0b, 0x80, 0xeb, 0x00, 0xe5, 0x0a, 0xc0, 0x76, - 0xe0, 0x04, 0xcb, 0xe0, 0x48, 0xe5, 0x41, 0xe0, - 0x2f, 0xe1, 0x2b, 0xe0, 0x05, 0xe2, 0x2b, 0xc0, - 0xab, 0xe5, 0x1c, 0x66, 0xe0, 0x00, 0xe9, 0x02, - 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, 0x0e, 0xe5, 0x0a, - 0x66, 0x76, 0xe0, 0x1e, 0xe5, 0x0d, 0xcb, 0xe0, - 0x0c, 0xe5, 0x0f, 0xe0, 0x01, 0x07, 0x06, 0x07, - 0xe5, 0x2d, 0xe6, 0x07, 0xd6, 0x60, 0xeb, 0x0c, - 0xe9, 0x02, 0x06, 0x25, 0x26, 0x05, 0xe0, 0x01, - 0x46, 0x07, 0xe5, 0x25, 0x47, 0x66, 0x27, 0x26, - 0x36, 0x1b, 0x76, 0x06, 0xe0, 0x02, 0x1b, 0x20, - 0xe5, 0x11, 0xc0, 0xe9, 0x02, 0xa0, 0x46, 0xe5, - 0x1c, 0x86, 0x07, 0xe6, 0x00, 0x00, 0xe9, 0x02, - 0x76, 0x05, 0x27, 0x05, 0xe0, 0x00, 0xe5, 0x1b, - 0x06, 0x36, 0x05, 0xe0, 0x01, 0x26, 0x07, 0xe5, - 0x28, 0x47, 0xe6, 0x01, 0x27, 0x65, 0x76, 0x66, - 0x16, 0x07, 0x06, 0xe9, 0x02, 0x05, 0x16, 0x05, - 0x56, 0x00, 0xeb, 0x0c, 0xe0, 0x03, 0xe5, 0x0a, - 0x00, 0xe5, 0x11, 0x47, 0x46, 0x27, 0x06, 0x07, - 0x26, 0xb6, 0x06, 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, 0x16, 0xa0, 0xe9, 0x02, 0xe0, 0x2e, 0xe5, - 0x13, 0x20, 0x46, 0x27, 0x66, 0x07, 0x86, 0x60, - 0xe9, 0x02, 0x2b, 0x56, 0x0f, 0xc5, 0xe0, 0x80, - 0x31, 0xe5, 0x24, 0x47, 0xe6, 0x01, 0x07, 0x26, - 0x16, 0xe0, 0x5c, 0xe1, 0x18, 0xe2, 0x18, 0xe9, - 0x02, 0xeb, 0x01, 0xe0, 0x04, 0xe5, 0x00, 0x20, - 0x05, 0x20, 0xe5, 0x00, 0x00, 0x25, 0x00, 0xe5, - 0x10, 0xa7, 0x00, 0x27, 0x20, 0x26, 0x07, 0x06, - 0x05, 0x07, 0x05, 0x07, 0x06, 0x56, 0xe0, 0x01, - 0xe9, 0x02, 0xe0, 0x3e, 0xe5, 0x00, 0x20, 0xe5, - 0x1f, 0x47, 0x66, 0x20, 0x26, 0x67, 0x06, 0x05, - 0x16, 0x05, 0x07, 0xe0, 0x13, 0x05, 0xe6, 0x02, - 0xe5, 0x20, 0xa6, 0x07, 0x05, 0x66, 0xf6, 0x00, - 0x06, 0xe0, 0x00, 0x05, 0xa6, 0x27, 0x46, 0xe5, - 0x26, 0xe6, 0x05, 0x07, 0x26, 0x56, 0x05, 0x96, - 0xe0, 0x05, 0xe5, 0x41, 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, 0x89, - 0xc4, 0xe5, 0x59, 0x36, 0xe0, 0x05, 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, - 0xe5, 0x47, 0x00, 0xe9, 0x02, 0xa0, 0xe5, 0x16, - 0x20, 0x86, 0x16, 0xe0, 0x02, 0xe5, 0x28, 0xc6, - 0x96, 0x6f, 0x64, 0x16, 0x0f, 0xe0, 0x02, 0xe9, - 0x02, 0x00, 0xcb, 0x00, 0xe5, 0x0d, 0x80, 0xe5, - 0x0b, 0xe0, 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, 0x5f, 0x64, 0x00, 0xc4, 0x00, 0x24, 0x00, - 0xe5, 0x80, 0x9b, 0xe0, 0x25, 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, 0x91, 0xd4, 0xe6, 0x26, 0x20, 0xe6, - 0x0f, 0xe0, 0x01, 0xef, 0x6c, 0xe0, 0x34, 0xef, - 0x80, 0x6e, 0xe0, 0x02, 0xef, 0x1f, 0x20, 0xef, - 0x34, 0x27, 0x46, 0x4f, 0xa7, 0xfb, 0x00, 0xe6, - 0x00, 0x2f, 0xc6, 0xef, 0x16, 0x66, 0xef, 0x35, - 0xe0, 0x0d, 0xef, 0x3a, 0x46, 0x0f, 0xe0, 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, 0x83, 0xc8, 0xe2, 0x02, 0x05, 0xe2, 0x0c, - 0xe0, 0x80, 0x59, 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, 0xb8, 0xe5, 0x16, - 0x06, 0xe0, 0x09, 0xe5, 0x24, 0x66, 0xe9, 0x02, - 0x80, 0x0d, 0xe0, 0x84, 0x58, 0xc5, 0x00, 0x65, - 0x00, 0x25, 0x00, 0xe5, 0x07, 0x00, 0xe5, 0x80, - 0x3d, 0x20, 0xeb, 0x01, 0xc6, 0xe0, 0x21, 0xe1, - 0x1a, 0xe2, 0x1a, 0xc6, 0x04, 0x60, 0xe9, 0x02, - 0x60, 0x36, 0xe0, 0x82, 0x89, 0xeb, 0x33, 0x0f, - 0x4b, 0x0d, 0x6b, 0xe0, 0x44, 0xeb, 0x25, 0x0f, - 0xeb, 0x07, 0xe0, 0x80, 0x3a, 0x65, 0x00, 0xe5, - 0x13, 0x00, 0x25, 0x00, 0x05, 0x20, 0x05, 0x00, - 0xe5, 0x02, 0x00, 0x65, 0x00, 0x05, 0x00, 0x05, - 0xa0, 0x05, 0x60, 0x05, 0x00, 0x05, 0x00, 0x05, - 0x00, 0x45, 0x00, 0x25, 0x00, 0x05, 0x20, 0x05, - 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, - 0x00, 0x25, 0x00, 0x05, 0x20, 0x65, 0x00, 0xc5, - 0x00, 0x65, 0x00, 0x65, 0x00, 0x05, 0x00, 0xe5, - 0x02, 0x00, 0xe5, 0x09, 0x80, 0x45, 0x00, 0x85, - 0x00, 0xe5, 0x09, 0xe0, 0x2c, 0x2c, 0xe0, 0x80, - 0x86, 0xef, 0x24, 0x60, 0xef, 0x5c, 0xe0, 0x04, - 0xef, 0x07, 0x20, 0xef, 0x07, 0x00, 0xef, 0x07, - 0x00, 0xef, 0x1d, 0xe0, 0x02, 0xeb, 0x05, 0xef, - 0x80, 0x19, 0xe0, 0x30, 0xef, 0x15, 0xe0, 0x05, - 0xef, 0x24, 0x60, 0xef, 0x01, 0xc0, 0x2f, 0xe0, - 0x06, 0xaf, 0xe0, 0x80, 0x12, 0xef, 0x80, 0x73, - 0x8e, 0xef, 0x82, 0x50, 0x80, 0xef, 0x08, 0x40, - 0xef, 0x05, 0x40, 0xef, 0x6c, 0xe0, 0x04, 0xef, - 0x51, 0xc0, 0xef, 0x04, 0x60, 0x0f, 0xe0, 0x07, - 0xef, 0x04, 0x60, 0xef, 0x30, 0xe0, 0x00, 0xef, - 0x02, 0xa0, 0xef, 0x20, 0xe0, 0x00, 0xef, 0x16, - 0x20, 0x2f, 0xe0, 0x46, 0xef, 0x80, 0xcc, 0xe0, - 0x04, 0xef, 0x06, 0x20, 0x8f, 0x40, 0x8f, 0x40, - 0xcf, 0xe0, 0x01, 0xef, 0x15, 0x40, 0xef, 0x03, - 0x80, 0xaf, 0xe0, 0x02, 0xef, 0x02, 0xa0, 0xef, - 0x00, 0xe0, 0x00, 0xcf, 0xe0, 0x01, 0xef, 0x80, - 0x0b, 0x00, 0xef, 0x2f, 0xe0, 0x1d, 0xe9, 0x02, - 0xe0, 0x83, 0x7e, 0xe5, 0xc0, 0x66, 0x58, 0xe0, - 0x18, 0xe5, 0x8f, 0xb1, 0xc0, 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_Cypro_Minoan, - UNICODE_SCRIPT_Deseret, - UNICODE_SCRIPT_Devanagari, - UNICODE_SCRIPT_Dives_Akuru, - UNICODE_SCRIPT_Dogra, - UNICODE_SCRIPT_Duployan, - UNICODE_SCRIPT_Egyptian_Hieroglyphs, - UNICODE_SCRIPT_Elbasan, - UNICODE_SCRIPT_Elymaic, - UNICODE_SCRIPT_Ethiopic, - UNICODE_SCRIPT_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_Old_Uyghur, - UNICODE_SCRIPT_Oriya, - UNICODE_SCRIPT_Osage, - UNICODE_SCRIPT_Osmanya, - UNICODE_SCRIPT_Pahawh_Hmong, - UNICODE_SCRIPT_Palmyrene, - UNICODE_SCRIPT_Pau_Cin_Hau, - UNICODE_SCRIPT_Phags_Pa, - UNICODE_SCRIPT_Phoenician, - UNICODE_SCRIPT_Psalter_Pahlavi, - UNICODE_SCRIPT_Rejang, - UNICODE_SCRIPT_Runic, - UNICODE_SCRIPT_Samaritan, - UNICODE_SCRIPT_Saurashtra, - UNICODE_SCRIPT_Sharada, - UNICODE_SCRIPT_Shavian, - UNICODE_SCRIPT_Siddham, - UNICODE_SCRIPT_SignWriting, - UNICODE_SCRIPT_Sinhala, - UNICODE_SCRIPT_Sogdian, - UNICODE_SCRIPT_Sora_Sompeng, - UNICODE_SCRIPT_Soyombo, - UNICODE_SCRIPT_Sundanese, - UNICODE_SCRIPT_Syloti_Nagri, - UNICODE_SCRIPT_Syriac, - UNICODE_SCRIPT_Tagalog, - UNICODE_SCRIPT_Tagbanwa, - UNICODE_SCRIPT_Tai_Le, - UNICODE_SCRIPT_Tai_Tham, - UNICODE_SCRIPT_Tai_Viet, - UNICODE_SCRIPT_Takri, - UNICODE_SCRIPT_Tamil, - UNICODE_SCRIPT_Tangut, - UNICODE_SCRIPT_Telugu, - UNICODE_SCRIPT_Thaana, - UNICODE_SCRIPT_Thai, - UNICODE_SCRIPT_Tibetan, - UNICODE_SCRIPT_Tifinagh, - UNICODE_SCRIPT_Tirhuta, - UNICODE_SCRIPT_Tangsa, - UNICODE_SCRIPT_Toto, - UNICODE_SCRIPT_Ugaritic, - UNICODE_SCRIPT_Vai, - UNICODE_SCRIPT_Vithkuqi, - UNICODE_SCRIPT_Wancho, - UNICODE_SCRIPT_Warang_Citi, - UNICODE_SCRIPT_Yezidi, - UNICODE_SCRIPT_Yi, - UNICODE_SCRIPT_Zanabazar_Square, - UNICODE_SCRIPT_COUNT, -} UnicodeScriptEnum; - -static const char unicode_script_name_table[] = - "Adlam,Adlm" "\0" - "Ahom,Ahom" "\0" - "Anatolian_Hieroglyphs,Hluw" "\0" - "Arabic,Arab" "\0" - "Armenian,Armn" "\0" - "Avestan,Avst" "\0" - "Balinese,Bali" "\0" - "Bamum,Bamu" "\0" - "Bassa_Vah,Bass" "\0" - "Batak,Batk" "\0" - "Bengali,Beng" "\0" - "Bhaiksuki,Bhks" "\0" - "Bopomofo,Bopo" "\0" - "Brahmi,Brah" "\0" - "Braille,Brai" "\0" - "Buginese,Bugi" "\0" - "Buhid,Buhd" "\0" - "Canadian_Aboriginal,Cans" "\0" - "Carian,Cari" "\0" - "Caucasian_Albanian,Aghb" "\0" - "Chakma,Cakm" "\0" - "Cham,Cham" "\0" - "Cherokee,Cher" "\0" - "Chorasmian,Chrs" "\0" - "Common,Zyyy" "\0" - "Coptic,Copt,Qaac" "\0" - "Cuneiform,Xsux" "\0" - "Cypriot,Cprt" "\0" - "Cyrillic,Cyrl" "\0" - "Cypro_Minoan,Cpmn" "\0" - "Deseret,Dsrt" "\0" - "Devanagari,Deva" "\0" - "Dives_Akuru,Diak" "\0" - "Dogra,Dogr" "\0" - "Duployan,Dupl" "\0" - "Egyptian_Hieroglyphs,Egyp" "\0" - "Elbasan,Elba" "\0" - "Elymaic,Elym" "\0" - "Ethiopic,Ethi" "\0" - "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" - "Old_Uyghur,Ougr" "\0" - "Oriya,Orya" "\0" - "Osage,Osge" "\0" - "Osmanya,Osma" "\0" - "Pahawh_Hmong,Hmng" "\0" - "Palmyrene,Palm" "\0" - "Pau_Cin_Hau,Pauc" "\0" - "Phags_Pa,Phag" "\0" - "Phoenician,Phnx" "\0" - "Psalter_Pahlavi,Phlp" "\0" - "Rejang,Rjng" "\0" - "Runic,Runr" "\0" - "Samaritan,Samr" "\0" - "Saurashtra,Saur" "\0" - "Sharada,Shrd" "\0" - "Shavian,Shaw" "\0" - "Siddham,Sidd" "\0" - "SignWriting,Sgnw" "\0" - "Sinhala,Sinh" "\0" - "Sogdian,Sogd" "\0" - "Sora_Sompeng,Sora" "\0" - "Soyombo,Soyo" "\0" - "Sundanese,Sund" "\0" - "Syloti_Nagri,Sylo" "\0" - "Syriac,Syrc" "\0" - "Tagalog,Tglg" "\0" - "Tagbanwa,Tagb" "\0" - "Tai_Le,Tale" "\0" - "Tai_Tham,Lana" "\0" - "Tai_Viet,Tavt" "\0" - "Takri,Takr" "\0" - "Tamil,Taml" "\0" - "Tangut,Tang" "\0" - "Telugu,Telu" "\0" - "Thaana,Thaa" "\0" - "Thai,Thai" "\0" - "Tibetan,Tibt" "\0" - "Tifinagh,Tfng" "\0" - "Tirhuta,Tirh" "\0" - "Tangsa,Tnsa" "\0" - "Toto,Toto" "\0" - "Ugaritic,Ugar" "\0" - "Vai,Vaii" "\0" - "Vithkuqi,Vith" "\0" - "Wancho,Wcho" "\0" - "Warang_Citi,Wara" "\0" - "Yezidi,Yezi" "\0" - "Yi,Yiii" "\0" - "Zanabazar_Square,Zanb" "\0" -; - -static const uint8_t unicode_script_table[2690] = { - 0xc0, 0x19, 0x99, 0x46, 0x85, 0x19, 0x99, 0x46, - 0xae, 0x19, 0x80, 0x46, 0x8e, 0x19, 0x80, 0x46, - 0x84, 0x19, 0x96, 0x46, 0x80, 0x19, 0x9e, 0x46, - 0x80, 0x19, 0xe1, 0x60, 0x46, 0xa6, 0x19, 0x84, - 0x46, 0x84, 0x19, 0x81, 0x0d, 0x93, 0x19, 0xe0, - 0x0f, 0x38, 0x83, 0x2c, 0x80, 0x19, 0x82, 0x2c, - 0x01, 0x83, 0x2c, 0x80, 0x19, 0x80, 0x2c, 0x03, - 0x80, 0x2c, 0x80, 0x19, 0x80, 0x2c, 0x80, 0x19, - 0x82, 0x2c, 0x00, 0x80, 0x2c, 0x00, 0x93, 0x2c, - 0x00, 0xbe, 0x2c, 0x8d, 0x1a, 0x8f, 0x2c, 0xe0, - 0x24, 0x1d, 0x81, 0x38, 0xe0, 0x48, 0x1d, 0x00, - 0xa5, 0x05, 0x01, 0xb1, 0x05, 0x01, 0x82, 0x05, - 0x00, 0xb6, 0x35, 0x07, 0x9a, 0x35, 0x03, 0x85, - 0x35, 0x0a, 0x84, 0x04, 0x80, 0x19, 0x85, 0x04, - 0x80, 0x19, 0x8d, 0x04, 0x80, 0x19, 0x82, 0x04, - 0x80, 0x19, 0x9f, 0x04, 0x80, 0x19, 0x89, 0x04, - 0x8a, 0x38, 0x99, 0x04, 0x80, 0x38, 0xe0, 0x0b, - 0x04, 0x80, 0x19, 0xa1, 0x04, 0x8d, 0x89, 0x00, - 0xbb, 0x89, 0x01, 0x82, 0x89, 0xaf, 0x04, 0xb1, - 0x93, 0x0d, 0xba, 0x64, 0x01, 0x82, 0x64, 0xad, - 0x7d, 0x01, 0x8e, 0x7d, 0x00, 0x9b, 0x51, 0x01, - 0x80, 0x51, 0x00, 0x8a, 0x89, 0x04, 0x9e, 0x04, - 0x00, 0x81, 0x04, 0x05, 0xc9, 0x04, 0x80, 0x19, - 0x9c, 0x04, 0xd0, 0x20, 0x83, 0x38, 0x8e, 0x20, - 0x81, 0x19, 0x99, 0x20, 0x83, 0x0b, 0x00, 0x87, - 0x0b, 0x01, 0x81, 0x0b, 0x01, 0x95, 0x0b, 0x00, - 0x86, 0x0b, 0x00, 0x80, 0x0b, 0x02, 0x83, 0x0b, - 0x01, 0x88, 0x0b, 0x01, 0x81, 0x0b, 0x01, 0x83, - 0x0b, 0x07, 0x80, 0x0b, 0x03, 0x81, 0x0b, 0x00, - 0x84, 0x0b, 0x01, 0x98, 0x0b, 0x01, 0x82, 0x2f, - 0x00, 0x85, 0x2f, 0x03, 0x81, 0x2f, 0x01, 0x95, - 0x2f, 0x00, 0x86, 0x2f, 0x00, 0x81, 0x2f, 0x00, - 0x81, 0x2f, 0x00, 0x81, 0x2f, 0x01, 0x80, 0x2f, - 0x00, 0x84, 0x2f, 0x03, 0x81, 0x2f, 0x01, 0x82, - 0x2f, 0x02, 0x80, 0x2f, 0x06, 0x83, 0x2f, 0x00, - 0x80, 0x2f, 0x06, 0x90, 0x2f, 0x09, 0x82, 0x2d, - 0x00, 0x88, 0x2d, 0x00, 0x82, 0x2d, 0x00, 0x95, - 0x2d, 0x00, 0x86, 0x2d, 0x00, 0x81, 0x2d, 0x00, - 0x84, 0x2d, 0x01, 0x89, 0x2d, 0x00, 0x82, 0x2d, - 0x00, 0x82, 0x2d, 0x01, 0x80, 0x2d, 0x0e, 0x83, - 0x2d, 0x01, 0x8b, 0x2d, 0x06, 0x86, 0x2d, 0x00, - 0x82, 0x72, 0x00, 0x87, 0x72, 0x01, 0x81, 0x72, - 0x01, 0x95, 0x72, 0x00, 0x86, 0x72, 0x00, 0x81, - 0x72, 0x00, 0x84, 0x72, 0x01, 0x88, 0x72, 0x01, - 0x81, 0x72, 0x01, 0x82, 0x72, 0x06, 0x82, 0x72, - 0x03, 0x81, 0x72, 0x00, 0x84, 0x72, 0x01, 0x91, - 0x72, 0x09, 0x81, 0x90, 0x00, 0x85, 0x90, 0x02, - 0x82, 0x90, 0x00, 0x83, 0x90, 0x02, 0x81, 0x90, - 0x00, 0x80, 0x90, 0x00, 0x81, 0x90, 0x02, 0x81, - 0x90, 0x02, 0x82, 0x90, 0x02, 0x8b, 0x90, 0x03, - 0x84, 0x90, 0x02, 0x82, 0x90, 0x00, 0x83, 0x90, - 0x01, 0x80, 0x90, 0x05, 0x80, 0x90, 0x0d, 0x94, - 0x90, 0x04, 0x8c, 0x92, 0x00, 0x82, 0x92, 0x00, - 0x96, 0x92, 0x00, 0x8f, 0x92, 0x01, 0x88, 0x92, - 0x00, 0x82, 0x92, 0x00, 0x83, 0x92, 0x06, 0x81, - 0x92, 0x00, 0x82, 0x92, 0x01, 0x80, 0x92, 0x01, - 0x83, 0x92, 0x01, 0x89, 0x92, 0x06, 0x88, 0x92, - 0x8c, 0x3d, 0x00, 0x82, 0x3d, 0x00, 0x96, 0x3d, - 0x00, 0x89, 0x3d, 0x00, 0x84, 0x3d, 0x01, 0x88, - 0x3d, 0x00, 0x82, 0x3d, 0x00, 0x83, 0x3d, 0x06, - 0x81, 0x3d, 0x05, 0x81, 0x3d, 0x00, 0x83, 0x3d, - 0x01, 0x89, 0x3d, 0x00, 0x81, 0x3d, 0x0c, 0x8c, - 0x50, 0x00, 0x82, 0x50, 0x00, 0xb2, 0x50, 0x00, - 0x82, 0x50, 0x00, 0x85, 0x50, 0x03, 0x8f, 0x50, - 0x01, 0x99, 0x50, 0x00, 0x82, 0x83, 0x00, 0x91, - 0x83, 0x02, 0x97, 0x83, 0x00, 0x88, 0x83, 0x00, - 0x80, 0x83, 0x01, 0x86, 0x83, 0x02, 0x80, 0x83, - 0x03, 0x85, 0x83, 0x00, 0x80, 0x83, 0x00, 0x87, - 0x83, 0x05, 0x89, 0x83, 0x01, 0x82, 0x83, 0x0b, - 0xb9, 0x94, 0x03, 0x80, 0x19, 0x9b, 0x94, 0x24, - 0x81, 0x45, 0x00, 0x80, 0x45, 0x00, 0x84, 0x45, - 0x00, 0x97, 0x45, 0x00, 0x80, 0x45, 0x00, 0x96, - 0x45, 0x01, 0x84, 0x45, 0x00, 0x80, 0x45, 0x00, - 0x85, 0x45, 0x01, 0x89, 0x45, 0x01, 0x83, 0x45, - 0x1f, 0xc7, 0x95, 0x00, 0xa3, 0x95, 0x03, 0xa6, - 0x95, 0x00, 0xa3, 0x95, 0x00, 0x8e, 0x95, 0x00, - 0x86, 0x95, 0x83, 0x19, 0x81, 0x95, 0x24, 0xe0, - 0x3f, 0x5f, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04, - 0x80, 0x28, 0x01, 0xaa, 0x28, 0x80, 0x19, 0x83, - 0x28, 0xe0, 0x9f, 0x31, 0xc8, 0x27, 0x00, 0x83, - 0x27, 0x01, 0x86, 0x27, 0x00, 0x80, 0x27, 0x00, - 0x83, 0x27, 0x01, 0xa8, 0x27, 0x00, 0x83, 0x27, - 0x01, 0xa0, 0x27, 0x00, 0x83, 0x27, 0x01, 0x86, - 0x27, 0x00, 0x80, 0x27, 0x00, 0x83, 0x27, 0x01, - 0x8e, 0x27, 0x00, 0xb8, 0x27, 0x00, 0x83, 0x27, - 0x01, 0xc2, 0x27, 0x01, 0x9f, 0x27, 0x02, 0x99, - 0x27, 0x05, 0xd5, 0x17, 0x01, 0x85, 0x17, 0x01, - 0xe2, 0x1f, 0x12, 0x9c, 0x67, 0x02, 0xca, 0x7c, - 0x82, 0x19, 0x8a, 0x7c, 0x06, 0x95, 0x8a, 0x08, - 0x80, 0x8a, 0x94, 0x33, 0x81, 0x19, 0x08, 0x93, - 0x11, 0x0b, 0x8c, 0x8b, 0x00, 0x82, 0x8b, 0x00, - 0x81, 0x8b, 0x0b, 0xdd, 0x41, 0x01, 0x89, 0x41, - 0x05, 0x89, 0x41, 0x05, 0x81, 0x5c, 0x81, 0x19, - 0x80, 0x5c, 0x80, 0x19, 0x93, 0x5c, 0x05, 0xd8, - 0x5c, 0x06, 0xaa, 0x5c, 0x04, 0xc5, 0x12, 0x09, - 0x9e, 0x48, 0x00, 0x8b, 0x48, 0x03, 0x8b, 0x48, - 0x03, 0x80, 0x48, 0x02, 0x8b, 0x48, 0x9d, 0x8c, - 0x01, 0x84, 0x8c, 0x0a, 0xab, 0x62, 0x03, 0x99, - 0x62, 0x05, 0x8a, 0x62, 0x02, 0x81, 0x62, 0x9f, - 0x41, 0x9b, 0x10, 0x01, 0x81, 0x10, 0xbe, 0x8d, - 0x00, 0x9c, 0x8d, 0x01, 0x8a, 0x8d, 0x05, 0x89, - 0x8d, 0x05, 0x8d, 0x8d, 0x01, 0x9e, 0x38, 0x30, - 0xcc, 0x07, 0x02, 0xae, 0x07, 0x00, 0xbf, 0x87, - 0xb3, 0x0a, 0x07, 0x83, 0x0a, 0xb7, 0x47, 0x02, - 0x8e, 0x47, 0x02, 0x82, 0x47, 0xaf, 0x68, 0x88, - 0x1d, 0x06, 0xaa, 0x28, 0x01, 0x82, 0x28, 0x87, - 0x87, 0x07, 0x82, 0x38, 0x80, 0x19, 0x8c, 0x38, - 0x80, 0x19, 0x86, 0x38, 0x83, 0x19, 0x80, 0x38, - 0x85, 0x19, 0x80, 0x38, 0x82, 0x19, 0x81, 0x38, - 0x80, 0x19, 0x04, 0xa5, 0x46, 0x84, 0x2c, 0x80, - 0x1d, 0xb0, 0x46, 0x84, 0x2c, 0x83, 0x46, 0x84, - 0x2c, 0x8c, 0x46, 0x80, 0x1d, 0xc5, 0x46, 0x80, - 0x2c, 0xbf, 0x38, 0xe0, 0x9f, 0x46, 0x95, 0x2c, - 0x01, 0x85, 0x2c, 0x01, 0xa5, 0x2c, 0x01, 0x85, - 0x2c, 0x01, 0x87, 0x2c, 0x00, 0x80, 0x2c, 0x00, - 0x80, 0x2c, 0x00, 0x80, 0x2c, 0x00, 0x9e, 0x2c, - 0x01, 0xb4, 0x2c, 0x00, 0x8e, 0x2c, 0x00, 0x8d, - 0x2c, 0x01, 0x85, 0x2c, 0x00, 0x92, 0x2c, 0x01, - 0x82, 0x2c, 0x00, 0x88, 0x2c, 0x00, 0x8b, 0x19, - 0x81, 0x38, 0xd6, 0x19, 0x00, 0x8a, 0x19, 0x80, - 0x46, 0x01, 0x8a, 0x19, 0x80, 0x46, 0x8e, 0x19, - 0x00, 0x8c, 0x46, 0x02, 0xa0, 0x19, 0x0e, 0xa0, - 0x38, 0x0e, 0xa5, 0x19, 0x80, 0x2c, 0x82, 0x19, - 0x81, 0x46, 0x85, 0x19, 0x80, 0x46, 0x9a, 0x19, - 0x80, 0x46, 0x90, 0x19, 0xa8, 0x46, 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, - 0xdf, 0x29, 0x9f, 0x46, 0xe0, 0x13, 0x1a, 0x04, - 0x86, 0x1a, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04, - 0x80, 0x28, 0x01, 0xb7, 0x96, 0x06, 0x81, 0x96, - 0x0d, 0x80, 0x96, 0x96, 0x27, 0x08, 0x86, 0x27, - 0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86, - 0x27, 0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, - 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x9f, 0x1d, - 0xdd, 0x19, 0x21, 0x99, 0x30, 0x00, 0xd8, 0x30, - 0x0b, 0xe0, 0x75, 0x30, 0x19, 0x8b, 0x19, 0x03, - 0x84, 0x19, 0x80, 0x30, 0x80, 0x19, 0x80, 0x30, - 0x98, 0x19, 0x88, 0x30, 0x83, 0x38, 0x81, 0x31, - 0x87, 0x19, 0x83, 0x30, 0x83, 0x19, 0x00, 0xd5, - 0x36, 0x01, 0x81, 0x38, 0x81, 0x19, 0x82, 0x36, - 0x80, 0x19, 0xd9, 0x3e, 0x81, 0x19, 0x82, 0x3e, - 0x04, 0xaa, 0x0d, 0x00, 0xdd, 0x31, 0x00, 0x8f, - 0x19, 0x9f, 0x0d, 0xa3, 0x19, 0x0b, 0x8f, 0x3e, - 0x9e, 0x31, 0x00, 0xbf, 0x19, 0x9e, 0x31, 0xd0, - 0x19, 0xae, 0x3e, 0x80, 0x19, 0xd7, 0x3e, 0xe0, - 0x47, 0x19, 0xf0, 0x09, 0x5f, 0x30, 0xbf, 0x19, - 0xf0, 0x41, 0x9f, 0x30, 0xe4, 0x2c, 0xa0, 0x02, - 0xb6, 0xa0, 0x08, 0xaf, 0x4b, 0xe0, 0xcb, 0x9b, - 0x13, 0xdf, 0x1d, 0xd7, 0x08, 0x07, 0xa1, 0x19, - 0xe0, 0x05, 0x46, 0x82, 0x19, 0xbf, 0x46, 0x04, - 0x81, 0x46, 0x00, 0x80, 0x46, 0x00, 0x84, 0x46, - 0x17, 0x8d, 0x46, 0xac, 0x88, 0x02, 0x89, 0x19, - 0x05, 0xb7, 0x78, 0x07, 0xc5, 0x7e, 0x07, 0x8b, - 0x7e, 0x05, 0x9f, 0x20, 0xad, 0x3f, 0x80, 0x19, - 0x80, 0x3f, 0xa3, 0x7b, 0x0a, 0x80, 0x7b, 0x9c, - 0x31, 0x02, 0xcd, 0x3b, 0x00, 0x80, 0x19, 0x89, - 0x3b, 0x03, 0x81, 0x3b, 0x9e, 0x5f, 0x00, 0xb6, - 0x16, 0x08, 0x8d, 0x16, 0x01, 0x89, 0x16, 0x01, - 0x83, 0x16, 0x9f, 0x5f, 0xc2, 0x8e, 0x17, 0x84, - 0x8e, 0x96, 0x56, 0x09, 0x85, 0x27, 0x01, 0x85, - 0x27, 0x01, 0x85, 0x27, 0x08, 0x86, 0x27, 0x00, - 0x86, 0x27, 0x00, 0xaa, 0x46, 0x80, 0x19, 0x88, - 0x46, 0x80, 0x2c, 0x83, 0x46, 0x81, 0x19, 0x03, - 0xcf, 0x17, 0xad, 0x56, 0x01, 0x89, 0x56, 0x05, - 0xf0, 0x1b, 0x43, 0x31, 0x0b, 0x96, 0x31, 0x03, - 0xb0, 0x31, 0x70, 0x10, 0xa3, 0xe1, 0x0d, 0x30, - 0x01, 0xe0, 0x09, 0x30, 0x25, 0x86, 0x46, 0x0b, - 0x84, 0x05, 0x04, 0x99, 0x35, 0x00, 0x84, 0x35, - 0x00, 0x80, 0x35, 0x00, 0x81, 0x35, 0x00, 0x81, - 0x35, 0x00, 0x89, 0x35, 0xe0, 0x12, 0x04, 0x0f, - 0xe1, 0x0a, 0x04, 0x81, 0x19, 0xcf, 0x04, 0x01, - 0xb5, 0x04, 0x06, 0x80, 0x04, 0x1f, 0x8f, 0x04, - 0x8f, 0x38, 0x89, 0x19, 0x05, 0x8d, 0x38, 0x81, - 0x1d, 0xa2, 0x19, 0x00, 0x92, 0x19, 0x00, 0x83, - 0x19, 0x03, 0x84, 0x04, 0x00, 0xe0, 0x26, 0x04, - 0x01, 0x80, 0x19, 0x00, 0x9f, 0x19, 0x99, 0x46, - 0x85, 0x19, 0x99, 0x46, 0x8a, 0x19, 0x89, 0x3e, - 0x80, 0x19, 0xac, 0x3e, 0x81, 0x19, 0x9e, 0x31, - 0x02, 0x85, 0x31, 0x01, 0x85, 0x31, 0x01, 0x85, - 0x31, 0x01, 0x82, 0x31, 0x02, 0x86, 0x19, 0x00, - 0x86, 0x19, 0x09, 0x84, 0x19, 0x01, 0x8b, 0x4a, - 0x00, 0x99, 0x4a, 0x00, 0x92, 0x4a, 0x00, 0x81, - 0x4a, 0x00, 0x8e, 0x4a, 0x01, 0x8d, 0x4a, 0x21, - 0xe0, 0x1a, 0x4a, 0x04, 0x82, 0x19, 0x03, 0xac, - 0x19, 0x02, 0x88, 0x19, 0xce, 0x2c, 0x00, 0x8c, - 0x19, 0x02, 0x80, 0x2c, 0x2e, 0xac, 0x19, 0x80, - 0x38, 0x60, 0x21, 0x9c, 0x4c, 0x02, 0xb0, 0x13, - 0x0e, 0x80, 0x38, 0x9a, 0x19, 0x03, 0xa3, 0x6a, - 0x08, 0x82, 0x6a, 0x9a, 0x2a, 0x04, 0xaa, 0x6c, - 0x04, 0x9d, 0x9a, 0x00, 0x80, 0x9a, 0xa3, 0x6d, - 0x03, 0x8d, 0x6d, 0x29, 0xcf, 0x1f, 0xaf, 0x80, - 0x9d, 0x74, 0x01, 0x89, 0x74, 0x05, 0xa3, 0x73, - 0x03, 0xa3, 0x73, 0x03, 0xa7, 0x25, 0x07, 0xb3, - 0x14, 0x0a, 0x80, 0x14, 0x8a, 0x9c, 0x00, 0x8e, - 0x9c, 0x00, 0x86, 0x9c, 0x00, 0x81, 0x9c, 0x00, - 0x8a, 0x9c, 0x00, 0x8e, 0x9c, 0x00, 0x86, 0x9c, - 0x00, 0x81, 0x9c, 0x42, 0xe0, 0xd6, 0x49, 0x08, - 0x95, 0x49, 0x09, 0x87, 0x49, 0x17, 0x85, 0x46, - 0x00, 0xa9, 0x46, 0x00, 0x88, 0x46, 0x44, 0x85, - 0x1c, 0x01, 0x80, 0x1c, 0x00, 0xab, 0x1c, 0x00, - 0x81, 0x1c, 0x02, 0x80, 0x1c, 0x01, 0x80, 0x1c, - 0x95, 0x37, 0x00, 0x88, 0x37, 0x9f, 0x76, 0x9e, - 0x60, 0x07, 0x88, 0x60, 0x2f, 0x92, 0x34, 0x00, - 0x81, 0x34, 0x04, 0x84, 0x34, 0x9b, 0x79, 0x02, - 0x80, 0x79, 0x99, 0x4d, 0x04, 0x80, 0x4d, 0x3f, - 0x9f, 0x59, 0x97, 0x58, 0x03, 0x93, 0x58, 0x01, - 0xad, 0x58, 0x83, 0x40, 0x00, 0x81, 0x40, 0x04, - 0x87, 0x40, 0x00, 0x82, 0x40, 0x00, 0x9c, 0x40, - 0x01, 0x82, 0x40, 0x03, 0x89, 0x40, 0x06, 0x88, - 0x40, 0x06, 0x9f, 0x6f, 0x9f, 0x6b, 0x1f, 0xa6, - 0x52, 0x03, 0x8b, 0x52, 0x08, 0xb5, 0x06, 0x02, - 0x86, 0x06, 0x95, 0x3a, 0x01, 0x87, 0x3a, 0x92, - 0x39, 0x04, 0x87, 0x39, 0x91, 0x7a, 0x06, 0x83, - 0x7a, 0x0b, 0x86, 0x7a, 0x4f, 0xc8, 0x70, 0x36, - 0xb2, 0x69, 0x0c, 0xb2, 0x69, 0x06, 0x85, 0x69, - 0xa7, 0x32, 0x07, 0x89, 0x32, 0x60, 0xc5, 0x9e, - 0x04, 0x00, 0xa9, 0x9f, 0x00, 0x82, 0x9f, 0x01, - 0x81, 0x9f, 0x4d, 0xa7, 0x6e, 0x07, 0xa9, 0x84, - 0x15, 0x99, 0x71, 0x25, 0x9b, 0x18, 0x13, 0x96, - 0x26, 0x08, 0xcd, 0x0e, 0x03, 0xa3, 0x0e, 0x08, - 0x80, 0x0e, 0xc2, 0x3c, 0x09, 0x80, 0x3c, 0x01, - 0x98, 0x85, 0x06, 0x89, 0x85, 0x05, 0xb4, 0x15, - 0x00, 0x91, 0x15, 0x07, 0xa6, 0x4f, 0x08, 0xdf, - 0x7f, 0x00, 0x93, 0x83, 0x0a, 0x91, 0x42, 0x00, - 0xab, 0x42, 0x40, 0x86, 0x5e, 0x00, 0x80, 0x5e, - 0x00, 0x83, 0x5e, 0x00, 0x8e, 0x5e, 0x00, 0x8a, - 0x5e, 0x05, 0xba, 0x44, 0x04, 0x89, 0x44, 0x05, - 0x83, 0x2b, 0x00, 0x87, 0x2b, 0x01, 0x81, 0x2b, - 0x01, 0x95, 0x2b, 0x00, 0x86, 0x2b, 0x00, 0x81, - 0x2b, 0x00, 0x84, 0x2b, 0x00, 0x80, 0x38, 0x88, - 0x2b, 0x01, 0x81, 0x2b, 0x01, 0x82, 0x2b, 0x01, - 0x80, 0x2b, 0x05, 0x80, 0x2b, 0x04, 0x86, 0x2b, - 0x01, 0x86, 0x2b, 0x02, 0x84, 0x2b, 0x60, 0x2a, - 0xdb, 0x63, 0x00, 0x84, 0x63, 0x1d, 0xc7, 0x97, - 0x07, 0x89, 0x97, 0x60, 0x45, 0xb5, 0x81, 0x01, - 0xa5, 0x81, 0x21, 0xc4, 0x5b, 0x0a, 0x89, 0x5b, - 0x05, 0x8c, 0x5c, 0x12, 0xb9, 0x8f, 0x05, 0x89, - 0x8f, 0x35, 0x9a, 0x02, 0x01, 0x8e, 0x02, 0x03, - 0x96, 0x02, 0x60, 0x58, 0xbb, 0x22, 0x60, 0x03, - 0xd2, 0x9e, 0x0b, 0x80, 0x9e, 0x86, 0x21, 0x01, - 0x80, 0x21, 0x01, 0x87, 0x21, 0x00, 0x81, 0x21, - 0x00, 0x9d, 0x21, 0x00, 0x81, 0x21, 0x01, 0x8b, - 0x21, 0x08, 0x89, 0x21, 0x45, 0x87, 0x61, 0x01, - 0xad, 0x61, 0x01, 0x8a, 0x61, 0x1a, 0xc7, 0xa1, - 0x07, 0xd2, 0x86, 0x0c, 0x8f, 0x12, 0xb8, 0x77, - 0x60, 0xa6, 0x88, 0x0c, 0x00, 0xac, 0x0c, 0x00, - 0x8d, 0x0c, 0x09, 0x9c, 0x0c, 0x02, 0x9f, 0x53, - 0x01, 0x95, 0x53, 0x00, 0x8d, 0x53, 0x48, 0x86, - 0x54, 0x00, 0x81, 0x54, 0x00, 0xab, 0x54, 0x02, - 0x80, 0x54, 0x00, 0x81, 0x54, 0x00, 0x88, 0x54, - 0x07, 0x89, 0x54, 0x05, 0x85, 0x2e, 0x00, 0x81, - 0x2e, 0x00, 0xa4, 0x2e, 0x00, 0x81, 0x2e, 0x00, - 0x85, 0x2e, 0x06, 0x89, 0x2e, 0x60, 0xd5, 0x98, - 0x4e, 0x60, 0x56, 0x80, 0x4b, 0x0e, 0xb1, 0x90, - 0x0c, 0x80, 0x90, 0xe3, 0x39, 0x1b, 0x60, 0x05, - 0xe0, 0x0e, 0x1b, 0x00, 0x84, 0x1b, 0x0a, 0xe0, - 0x63, 0x1b, 0x69, 0xeb, 0xe0, 0x02, 0x1e, 0x0c, - 0xe3, 0xce, 0x24, 0x00, 0x88, 0x24, 0x6f, 0x66, - 0xe1, 0xe6, 0x03, 0x70, 0x11, 0x58, 0xe1, 0xd8, - 0x08, 0x06, 0x9e, 0x5d, 0x00, 0x89, 0x5d, 0x03, - 0x81, 0x5d, 0xce, 0x98, 0x00, 0x89, 0x98, 0x05, - 0x9d, 0x09, 0x01, 0x85, 0x09, 0x09, 0xc5, 0x75, - 0x09, 0x89, 0x75, 0x00, 0x86, 0x75, 0x00, 0x94, - 0x75, 0x04, 0x92, 0x75, 0x62, 0x4f, 0xda, 0x55, - 0x60, 0x04, 0xca, 0x5a, 0x03, 0xb8, 0x5a, 0x06, - 0x90, 0x5a, 0x3f, 0x80, 0x91, 0x80, 0x65, 0x81, - 0x30, 0x80, 0x43, 0x0a, 0x81, 0x30, 0x0d, 0xf0, - 0x07, 0x97, 0x91, 0x07, 0xe2, 0x9f, 0x91, 0xe1, - 0x75, 0x43, 0x29, 0x88, 0x91, 0x70, 0x12, 0x86, - 0x83, 0x3e, 0x00, 0x86, 0x3e, 0x00, 0x81, 0x3e, - 0x00, 0x80, 0x3e, 0xe0, 0xbe, 0x36, 0x82, 0x3e, - 0x2c, 0x82, 0x36, 0x10, 0x83, 0x3e, 0x07, 0xe1, - 0x2b, 0x65, 0x68, 0xa3, 0xe0, 0x0a, 0x23, 0x04, - 0x8c, 0x23, 0x02, 0x88, 0x23, 0x06, 0x89, 0x23, - 0x01, 0x83, 0x23, 0x83, 0x19, 0x70, 0x01, 0xfb, - 0xad, 0x38, 0x01, 0x96, 0x38, 0x08, 0xe0, 0x13, - 0x19, 0x3b, 0xe0, 0x95, 0x19, 0x09, 0xa6, 0x19, - 0x01, 0xbd, 0x19, 0x82, 0x38, 0x90, 0x19, 0x87, - 0x38, 0x81, 0x19, 0x86, 0x38, 0x9d, 0x19, 0x83, - 0x38, 0xbc, 0x19, 0x14, 0xc5, 0x2c, 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, 0x82, 0x0e, 0x84, 0x82, - 0x00, 0x8e, 0x82, 0x63, 0xef, 0x9e, 0x46, 0x60, - 0x80, 0x86, 0x29, 0x00, 0x90, 0x29, 0x01, 0x86, - 0x29, 0x00, 0x81, 0x29, 0x00, 0x84, 0x29, 0x60, - 0x74, 0xac, 0x66, 0x02, 0x8d, 0x66, 0x01, 0x89, - 0x66, 0x03, 0x81, 0x66, 0x60, 0xdf, 0x9e, 0x99, - 0x10, 0xb9, 0x9d, 0x04, 0x80, 0x9d, 0x64, 0x7f, - 0x86, 0x27, 0x00, 0x83, 0x27, 0x00, 0x81, 0x27, - 0x00, 0x8e, 0x27, 0x00, 0xe0, 0x64, 0x57, 0x01, - 0x8f, 0x57, 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, 0x36, 0x81, 0x19, - 0x0c, 0xab, 0x19, 0x03, 0x88, 0x19, 0x06, 0x81, - 0x19, 0x0d, 0x85, 0x19, 0x60, 0x39, 0xe3, 0x77, - 0x19, 0x04, 0x8f, 0x19, 0x02, 0x8c, 0x19, 0x02, - 0xe0, 0x13, 0x19, 0x0b, 0xd8, 0x19, 0x06, 0x8b, - 0x19, 0x03, 0x80, 0x19, 0x0e, 0x8b, 0x19, 0x03, - 0xb7, 0x19, 0x07, 0x89, 0x19, 0x05, 0xa7, 0x19, - 0x07, 0x9d, 0x19, 0x01, 0x81, 0x19, 0x4d, 0xe0, - 0xf3, 0x19, 0x0b, 0x8d, 0x19, 0x01, 0x84, 0x19, - 0x02, 0x84, 0x19, 0x02, 0x86, 0x19, 0x08, 0x9c, - 0x19, 0x02, 0x8a, 0x19, 0x04, 0x85, 0x19, 0x09, - 0x89, 0x19, 0x05, 0x87, 0x19, 0x07, 0x86, 0x19, - 0x08, 0xe0, 0x32, 0x19, 0x00, 0xb6, 0x19, 0x24, - 0x89, 0x19, 0x63, 0xa5, 0xf0, 0x96, 0x7f, 0x30, - 0x1f, 0xef, 0xd8, 0x30, 0x06, 0xe0, 0x7d, 0x30, - 0x01, 0xf0, 0x06, 0x21, 0x30, 0x0d, 0xf0, 0x0c, - 0xd0, 0x30, 0x6b, 0xbe, 0xe1, 0xbd, 0x30, 0x65, - 0x81, 0xf0, 0x02, 0xea, 0x30, 0x7a, 0xdc, 0x55, - 0x80, 0x19, 0x1d, 0xdf, 0x19, 0x60, 0x1f, 0xe0, - 0x8f, 0x38, -}; - -static const uint8_t unicode_script_ext_table[828] = { - 0x82, 0xc1, 0x00, 0x00, 0x01, 0x2c, 0x01, 0x00, - 0x00, 0x01, 0x2c, 0x1c, 0x00, 0x0c, 0x01, 0x46, - 0x80, 0x92, 0x00, 0x00, 0x02, 0x1d, 0x6c, 0x00, - 0x02, 0x1d, 0x29, 0x01, 0x02, 0x1d, 0x46, 0x00, - 0x02, 0x1d, 0x29, 0x81, 0x03, 0x00, 0x00, 0x06, - 0x04, 0x64, 0x32, 0x89, 0x93, 0x9f, 0x0d, 0x00, - 0x00, 0x06, 0x04, 0x64, 0x32, 0x89, 0x93, 0x9f, - 0x00, 0x03, 0x04, 0x89, 0x93, 0x01, 0x00, 0x00, - 0x07, 0x01, 0x04, 0x64, 0x32, 0x89, 0x93, 0x9f, - 0x1f, 0x00, 0x00, 0x09, 0x01, 0x04, 0x51, 0x52, - 0x71, 0x7a, 0x32, 0x84, 0x89, 0x09, 0x00, 0x0a, - 0x02, 0x04, 0x89, 0x09, 0x00, 0x09, 0x03, 0x04, - 0x93, 0x9f, 0x05, 0x00, 0x00, 0x02, 0x04, 0x89, - 0x62, 0x00, 0x00, 0x02, 0x04, 0x32, 0x81, 0xfb, - 0x00, 0x00, 0x0d, 0x0b, 0x20, 0x2b, 0x2d, 0x2f, - 0x3d, 0x46, 0x50, 0x72, 0x7f, 0x90, 0x92, 0x97, - 0x00, 0x0c, 0x0b, 0x20, 0x2b, 0x2d, 0x2f, 0x3d, - 0x46, 0x50, 0x72, 0x90, 0x92, 0x97, 0x10, 0x00, - 0x00, 0x14, 0x0b, 0x20, 0x22, 0x2e, 0x54, 0x2b, - 0x2d, 0x2f, 0x3d, 0x4f, 0x50, 0x61, 0x72, 0x44, - 0x83, 0x88, 0x8f, 0x90, 0x92, 0x97, 0x00, 0x15, - 0x0b, 0x20, 0x22, 0x2e, 0x54, 0x2b, 0x2d, 0x2f, - 0x3d, 0x48, 0x4f, 0x50, 0x61, 0x72, 0x44, 0x83, - 0x88, 0x8f, 0x90, 0x92, 0x97, 0x09, 0x04, 0x20, - 0x22, 0x3c, 0x4f, 0x75, 0x00, 0x09, 0x03, 0x0b, - 0x15, 0x88, 0x75, 0x00, 0x09, 0x02, 0x2f, 0x5e, - 0x75, 0x00, 0x09, 0x02, 0x2d, 0x42, 0x80, 0x75, - 0x00, 0x0d, 0x02, 0x2b, 0x90, 0x80, 0x71, 0x00, - 0x09, 0x02, 0x3d, 0x61, 0x82, 0xcf, 0x00, 0x09, - 0x03, 0x15, 0x5f, 0x8c, 0x80, 0x30, 0x00, 0x00, - 0x02, 0x28, 0x46, 0x85, 0xb8, 0x00, 0x01, 0x04, - 0x11, 0x33, 0x8b, 0x8a, 0x80, 0x4a, 0x00, 0x01, - 0x02, 0x5c, 0x78, 0x00, 0x00, 0x00, 0x02, 0x5c, - 0x78, 0x84, 0x49, 0x00, 0x00, 0x04, 0x0b, 0x20, - 0x2b, 0x3d, 0x00, 0x01, 0x20, 0x00, 0x04, 0x0b, - 0x20, 0x2b, 0x3d, 0x00, 0x02, 0x20, 0x2b, 0x00, - 0x01, 0x20, 0x01, 0x02, 0x0b, 0x20, 0x00, 0x02, - 0x20, 0x7f, 0x00, 0x02, 0x0b, 0x20, 0x00, 0x02, - 0x20, 0x7f, 0x00, 0x06, 0x20, 0x3d, 0x50, 0x72, - 0x90, 0x92, 0x00, 0x01, 0x20, 0x01, 0x02, 0x20, - 0x7f, 0x01, 0x01, 0x20, 0x00, 0x02, 0x20, 0x7f, - 0x00, 0x02, 0x0b, 0x20, 0x06, 0x01, 0x20, 0x00, - 0x02, 0x20, 0x61, 0x00, 0x02, 0x0b, 0x20, 0x01, - 0x01, 0x20, 0x00, 0x02, 0x0b, 0x20, 0x03, 0x01, - 0x20, 0x00, 0x08, 0x0b, 0x20, 0x2b, 0x3d, 0x61, - 0x72, 0x92, 0x97, 0x00, 0x02, 0x20, 0x2b, 0x00, - 0x03, 0x20, 0x2b, 0x3d, 0x01, 0x02, 0x0b, 0x20, - 0x00, 0x01, 0x0b, 0x01, 0x02, 0x20, 0x2b, 0x00, - 0x01, 0x61, 0x80, 0x44, 0x00, 0x01, 0x01, 0x2c, - 0x35, 0x00, 0x00, 0x02, 0x1d, 0x89, 0x00, 0x00, - 0x00, 0x01, 0x89, 0x81, 0xb3, 0x00, 0x00, 0x02, - 0x46, 0x5c, 0x80, 0x3f, 0x00, 0x00, 0x03, 0x20, - 0x2b, 0x46, 0x8c, 0xd1, 0x00, 0x00, 0x02, 0x1d, - 0x29, 0x81, 0x3c, 0x00, 0x01, 0x06, 0x0d, 0x31, - 0x30, 0x36, 0x3e, 0xa0, 0x00, 0x05, 0x0d, 0x31, - 0x30, 0x36, 0x3e, 0x01, 0x00, 0x00, 0x01, 0x30, - 0x00, 0x00, 0x09, 0x06, 0x0d, 0x31, 0x30, 0x36, - 0x3e, 0xa0, 0x00, 0x00, 0x00, 0x05, 0x0d, 0x31, - 0x30, 0x36, 0x3e, 0x07, 0x06, 0x0d, 0x31, 0x30, - 0x36, 0x3e, 0xa0, 0x03, 0x05, 0x0d, 0x31, 0x30, - 0x36, 0x3e, 0x09, 0x00, 0x03, 0x02, 0x0d, 0x30, - 0x01, 0x00, 0x00, 0x05, 0x0d, 0x31, 0x30, 0x36, - 0x3e, 0x04, 0x02, 0x36, 0x3e, 0x00, 0x00, 0x00, - 0x05, 0x0d, 0x31, 0x30, 0x36, 0x3e, 0x03, 0x00, - 0x01, 0x03, 0x30, 0x36, 0x3e, 0x01, 0x01, 0x30, - 0x58, 0x00, 0x03, 0x02, 0x36, 0x3e, 0x02, 0x00, - 0x00, 0x02, 0x36, 0x3e, 0x59, 0x00, 0x00, 0x06, - 0x0d, 0x31, 0x30, 0x36, 0x3e, 0xa0, 0x00, 0x02, - 0x36, 0x3e, 0x80, 0x12, 0x00, 0x0f, 0x01, 0x30, - 0x1f, 0x00, 0x23, 0x01, 0x30, 0x3b, 0x00, 0x27, - 0x01, 0x30, 0x37, 0x00, 0x30, 0x01, 0x30, 0x0e, - 0x00, 0x0b, 0x01, 0x30, 0x32, 0x00, 0x00, 0x01, - 0x30, 0x57, 0x00, 0x18, 0x01, 0x30, 0x09, 0x00, - 0x04, 0x01, 0x30, 0x5f, 0x00, 0x1e, 0x01, 0x30, - 0xc0, 0x31, 0xef, 0x00, 0x00, 0x02, 0x1d, 0x29, - 0x80, 0x0f, 0x00, 0x07, 0x02, 0x30, 0x46, 0x80, - 0xa7, 0x00, 0x02, 0x0e, 0x20, 0x22, 0x2d, 0x2f, - 0x42, 0x3d, 0x3c, 0x4f, 0x50, 0x5b, 0x61, 0x44, - 0x8f, 0x97, 0x02, 0x0d, 0x20, 0x22, 0x2d, 0x2f, - 0x42, 0x3d, 0x3c, 0x4f, 0x5b, 0x61, 0x44, 0x8f, - 0x97, 0x03, 0x0b, 0x20, 0x22, 0x2d, 0x2f, 0x42, - 0x3c, 0x4f, 0x5b, 0x44, 0x8f, 0x97, 0x80, 0x36, - 0x00, 0x00, 0x02, 0x0b, 0x20, 0x00, 0x00, 0x00, - 0x02, 0x20, 0x90, 0x39, 0x00, 0x00, 0x03, 0x3f, - 0x46, 0x5f, 0x80, 0x1f, 0x00, 0x00, 0x02, 0x10, - 0x3b, 0xc0, 0x12, 0xed, 0x00, 0x01, 0x02, 0x04, - 0x64, 0x80, 0x31, 0x00, 0x00, 0x02, 0x04, 0x93, - 0x09, 0x00, 0x00, 0x02, 0x04, 0x93, 0x46, 0x00, - 0x01, 0x05, 0x0d, 0x31, 0x30, 0x36, 0x3e, 0x80, - 0x99, 0x00, 0x04, 0x06, 0x0d, 0x31, 0x30, 0x36, - 0x3e, 0xa0, 0x09, 0x00, 0x00, 0x02, 0x36, 0x3e, - 0x2c, 0x00, 0x01, 0x02, 0x36, 0x3e, 0x80, 0xdf, - 0x00, 0x01, 0x03, 0x1e, 0x1c, 0x4a, 0x00, 0x02, - 0x1c, 0x4a, 0x03, 0x00, 0x2c, 0x03, 0x1c, 0x49, - 0x4a, 0x02, 0x00, 0x08, 0x02, 0x1c, 0x4a, 0x81, - 0x1f, 0x00, 0x1b, 0x02, 0x04, 0x1a, 0x87, 0x75, - 0x00, 0x00, 0x02, 0x52, 0x71, 0x87, 0x8d, 0x00, - 0x00, 0x02, 0x2b, 0x90, 0x00, 0x00, 0x00, 0x02, - 0x2b, 0x90, 0x36, 0x00, 0x01, 0x02, 0x2b, 0x90, - 0x8c, 0x12, 0x00, 0x01, 0x02, 0x2b, 0x90, 0x00, - 0x00, 0x00, 0x02, 0x2b, 0x90, 0xc0, 0x5c, 0x4b, - 0x00, 0x03, 0x01, 0x23, 0x96, 0x3b, 0x00, 0x11, - 0x01, 0x30, 0x9e, 0x5d, 0x00, 0x01, 0x01, 0x30, - 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[417] = { - 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, 0x8a, - 0x82, 0xb0, 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, 0xac, 0x81, 0x8c, - 0x80, 0xac, 0x88, 0x88, 0x80, 0xbc, 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[59] = { - 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, 0x60, 0x5c, 0x1f, 0x01, 0x10, - 0xa9, 0x80, 0x88, -}; - -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[19] = { - 0x45, 0xff, 0x85, 0x40, 0xd6, 0x80, 0xb0, 0x80, - 0x41, 0x7f, 0x81, 0xcf, 0x80, 0x61, 0x07, 0xd9, - 0x80, 0x8e, 0x80, -}; - -static const uint8_t unicode_prop_XID_Start1_table[31] = { - 0x43, 0x79, 0x80, 0x4a, 0xb7, 0x80, 0xfe, 0x80, - 0x60, 0x21, 0xe6, 0x81, 0x60, 0xcb, 0xc0, 0x85, - 0x41, 0x95, 0x81, 0xf3, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x80, 0x41, 0x1e, 0x81, -}; - -static const uint8_t unicode_prop_XID_Continue1_table[23] = { - 0x43, 0x79, 0x80, 0x60, 0x2d, 0x1f, 0x81, 0x60, - 0xcb, 0xc0, 0x85, 0x41, 0x95, 0x81, 0xf3, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -}; - -static const uint8_t unicode_prop_Changes_When_Titlecased1_table[22] = { - 0x41, 0xc3, 0x08, 0x08, 0x81, 0xa4, 0x81, 0x4e, - 0xdc, 0xaa, 0x0a, 0x4e, 0x87, 0x3f, 0x3f, 0x87, - 0x8b, 0x80, 0x8e, 0x80, 0xae, 0x80, -}; - -static const uint8_t unicode_prop_Changes_When_Casefolded1_table[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[448] = { - 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, 0x84, 0x45, 0x1b, 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, - 0x80, 0x12, 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, 0x47, 0x87, 0x20, 0xa9, 0x80, 0x88, 0x60, - 0xb4, 0xe4, 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[55] = { - 0xac, 0x80, 0x45, 0x5b, 0x80, 0xb2, 0x80, 0x4e, - 0x40, 0x80, 0x44, 0x04, 0x80, 0x48, 0x08, 0x85, - 0xbc, 0x80, 0xa6, 0x80, 0x8e, 0x80, 0x41, 0x85, - 0x80, 0x4c, 0x03, 0x01, 0x80, 0x9e, 0x0b, 0x80, - 0x9b, 0x80, 0x41, 0xbd, 0x80, 0x92, 0x80, 0xee, - 0x80, 0x60, 0xcd, 0x8f, 0x81, 0xa4, 0x80, 0x89, - 0x80, 0x40, 0xa8, 0x80, 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[391] = { - 0xdd, 0x00, 0x80, 0xc6, 0x05, 0x03, 0x01, 0x81, - 0x41, 0xf6, 0x40, 0x9e, 0x07, 0x25, 0x90, 0x0b, - 0x80, 0x88, 0x81, 0x40, 0xfc, 0x84, 0x40, 0xd0, - 0x80, 0xb6, 0x90, 0x80, 0x9a, 0x00, 0x01, 0x00, - 0x40, 0x85, 0x3b, 0x81, 0x40, 0x85, 0x0b, 0x0a, - 0x82, 0xc2, 0x9a, 0xda, 0x8a, 0xb9, 0x8a, 0xa1, - 0x81, 0xfd, 0x87, 0xa8, 0x89, 0x8f, 0x9b, 0xbc, - 0x80, 0x8f, 0x02, 0x83, 0x9b, 0x80, 0xc9, 0x80, - 0x8f, 0x80, 0xed, 0x80, 0x8f, 0x80, 0xed, 0x80, - 0x8f, 0x80, 0xae, 0x82, 0xbb, 0x80, 0x8f, 0x06, - 0x80, 0xf6, 0x80, 0xed, 0x80, 0x8f, 0x80, 0xed, - 0x80, 0x8f, 0x80, 0xec, 0x81, 0x8f, 0x80, 0xfb, - 0x80, 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, 0x43, 0xb3, 0x81, 0x40, 0xb2, 0x8a, - 0x88, 0x80, 0x41, 0x5a, 0x82, 0x41, 0x38, 0x39, - 0x80, 0xaf, 0x8e, 0x81, 0x8a, 0xe7, 0x80, 0x8e, - 0x80, 0xa5, 0x88, 0xb5, 0x81, 0x40, 0x89, 0x81, - 0xbf, 0x85, 0xd1, 0x98, 0x18, 0x28, 0x0a, 0xb1, - 0xbe, 0xd8, 0x8b, 0xa4, 0x8a, 0x41, 0xbc, 0x00, - 0x82, 0x8a, 0x82, 0x8c, 0x82, 0x8c, 0x82, 0x8c, - 0x81, 0x4c, 0xef, 0x82, 0x41, 0x3c, 0x80, 0x41, - 0xf9, 0x85, 0xe8, 0x83, 0xde, 0x80, 0x60, 0x75, - 0x71, 0x80, 0x8b, 0x08, 0x80, 0x9b, 0x81, 0xd1, - 0x81, 0x8d, 0xa1, 0xe5, 0x82, 0xec, 0x81, 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, 0x44, - 0x9e, 0x28, 0xa9, 0x80, 0x88, 0x43, 0x29, 0x81, - 0x42, 0x3a, 0x85, 0x42, 0x1d, 0x8a, 0xb0, 0x83, - 0x40, 0xbf, 0x80, 0xa8, 0x80, 0xc7, 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, 0x3f, - 0xfd, 0x18, 0x30, 0x81, 0x5f, 0x00, 0xad, 0x81, - 0x96, 0x42, 0x1f, 0x12, 0x2f, 0x39, 0x86, 0x9d, - 0x83, 0x4f, 0x81, 0x86, 0x41, 0x76, 0x80, 0xbc, - 0x83, 0x45, 0xdf, 0x86, 0xec, 0x10, 0x82, -}; - -static const uint8_t unicode_prop_Extender_table[92] = { - 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, 0x48, 0x0f, 0x81, 0x4b, 0xd9, 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, 0xff, - 0x60, 0x58, 0xff, 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, 0xdf, 0x9f, 0x50, - 0x38, 0x86, 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[194] = { - 0xa0, 0x80, 0x8b, 0x80, 0x8f, 0x80, 0x45, 0x48, - 0x80, 0x40, 0x92, 0x82, 0x40, 0xb3, 0x80, 0xaa, - 0x82, 0x40, 0xf5, 0x80, 0xbc, 0x00, 0x02, 0x81, - 0x41, 0x24, 0x81, 0x46, 0xe3, 0x81, 0x43, 0x15, - 0x03, 0x81, 0x43, 0x04, 0x80, 0x40, 0xc5, 0x81, - 0x40, 0xcb, 0x04, 0x80, 0x41, 0x39, 0x81, 0x41, - 0x61, 0x83, 0x40, 0xad, 0x09, 0x81, 0x9c, 0x81, - 0x40, 0xbb, 0x81, 0xc0, 0x81, 0x43, 0xbb, 0x81, - 0x88, 0x82, 0x4d, 0xe3, 0x80, 0x8c, 0x80, 0x95, - 0x81, 0x41, 0xac, 0x80, 0x60, 0x74, 0xfb, 0x80, - 0x41, 0x0d, 0x81, 0x40, 0xe2, 0x02, 0x80, 0x41, - 0x7d, 0x81, 0xd5, 0x81, 0xde, 0x80, 0x40, 0x97, - 0x81, 0x40, 0x92, 0x82, 0x40, 0x8f, 0x81, 0x40, - 0xf8, 0x80, 0x60, 0x52, 0x65, 0x02, 0x81, 0x40, - 0xa8, 0x80, 0x8b, 0x80, 0x8f, 0x80, 0xc0, 0x80, - 0x4a, 0xf3, 0x81, 0x44, 0xfc, 0x84, 0xab, 0x83, - 0x40, 0xbc, 0x81, 0xf4, 0x83, 0xfe, 0x82, 0x40, - 0x80, 0x0d, 0x80, 0x8f, 0x81, 0xd7, 0x08, 0x81, - 0xeb, 0x80, 0x41, 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[74] = { - 0xe8, 0x81, 0x40, 0xc3, 0x80, 0x41, 0x18, 0x80, - 0x9d, 0x80, 0xb3, 0x80, 0x93, 0x80, 0x41, 0x3f, - 0x80, 0xe1, 0x00, 0x80, 0x59, 0x08, 0x80, 0xb2, - 0x80, 0x8c, 0x02, 0x80, 0x40, 0x83, 0x80, 0x40, - 0x9c, 0x80, 0x41, 0xa4, 0x80, 0x40, 0xd5, 0x81, - 0x4b, 0x31, 0x80, 0x61, 0xa7, 0xa4, 0x81, 0xb1, - 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, - 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, - 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0x48, - 0x85, 0x80, -}; - -static const uint8_t unicode_prop_Terminal_Punctuation_table[246] = { - 0xa0, 0x80, 0x89, 0x00, 0x80, 0x8a, 0x0a, 0x80, - 0x43, 0x3d, 0x07, 0x80, 0x42, 0x00, 0x80, 0xb8, - 0x80, 0xc7, 0x80, 0x8d, 0x00, 0x82, 0x40, 0xb3, - 0x80, 0xaa, 0x8a, 0x00, 0x40, 0xea, 0x81, 0xb5, - 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, 0x9c, 0x81, 0x40, 0xbb, 0x84, - 0xbd, 0x81, 0x43, 0xbb, 0x81, 0x88, 0x82, 0x4d, - 0xe3, 0x80, 0x8c, 0x03, 0x80, 0x89, 0x00, 0x0a, - 0x81, 0x41, 0xab, 0x81, 0x60, 0x74, 0xfa, 0x81, - 0x41, 0x0c, 0x82, 0x40, 0xe2, 0x84, 0x41, 0x7d, - 0x81, 0xd5, 0x81, 0xde, 0x80, 0x40, 0x96, 0x82, - 0x40, 0x92, 0x82, 0xfe, 0x80, 0x8f, 0x81, 0x40, - 0xf8, 0x80, 0x60, 0x52, 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, 0xab, 0x83, 0x40, 0xbc, 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, - 0xff, 0x60, 0x5a, 0x0d, 0x08, 0x00, 0x81, 0x89, - 0x00, 0x00, 0x09, 0x82, 0x61, 0x05, 0xd5, 0x60, - 0xa6, 0xdf, 0x9f, 0x50, 0x38, 0x86, 0x40, 0xdd, - 0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x54, 0x1e, - 0x53, 0x4a, -}; - -static const uint8_t unicode_prop_Variation_Selector_table[13] = { - 0x58, 0x0a, 0x10, 0x80, 0x60, 0xe5, 0xef, 0x8f, - 0x6d, 0x02, 0xef, 0x40, 0xef, -}; - -static const uint8_t unicode_prop_White_Space_table[22] = { - 0x88, 0x84, 0x91, 0x80, 0xe3, 0x80, 0x99, 0x80, - 0x55, 0xde, 0x80, 0x49, 0x7e, 0x8a, 0x9c, 0x0c, - 0x80, 0xae, 0x80, 0x4f, 0x9f, 0x80, -}; - -static const uint8_t unicode_prop_Bidi_Mirrored_table[173] = { - 0xa7, 0x81, 0x91, 0x00, 0x80, 0x9b, 0x00, 0x80, - 0x9c, 0x00, 0x80, 0xac, 0x80, 0x8e, 0x80, 0x4e, - 0x7d, 0x83, 0x47, 0x5c, 0x81, 0x49, 0x9b, 0x81, - 0x89, 0x81, 0xb5, 0x81, 0x8d, 0x81, 0x40, 0xb0, - 0x80, 0x40, 0xbf, 0x1a, 0x2a, 0x02, 0x0a, 0x18, - 0x18, 0x00, 0x03, 0x88, 0x20, 0x80, 0x91, 0x23, - 0x88, 0x08, 0x00, 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, - 0xaa, 0x87, 0x41, 0xaa, 0x89, 0x0f, 0x60, 0xce, - 0x3c, 0x2c, 0x81, 0x40, 0xa1, 0x81, 0x91, 0x00, - 0x80, 0x9b, 0x00, 0x80, 0x9c, 0x00, 0x00, 0x08, - 0x81, 0x60, 0xd7, 0x76, 0x80, 0xb8, 0x80, 0xb8, - 0x80, 0xb8, 0x80, 0xb8, 0x80, -}; - -static const uint8_t unicode_prop_Emoji_table[239] = { - 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, 0x84, - 0x88, 0x10, 0x01, 0x10, 0x81, 0x89, 0x40, 0xe2, - 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, 0x89, 0x80, - 0x40, 0xb8, 0xef, 0x22, 0x22, 0x86, 0x88, 0x9c, - 0x82, 0x8a, 0x25, 0x89, 0x89, 0x2f, 0x3e, -}; - -static const uint8_t unicode_prop_Emoji_Component_table[28] = { - 0xa2, 0x05, 0x04, 0x89, 0x5f, 0xd2, 0x80, 0x40, - 0xd4, 0x80, 0x60, 0xdd, 0x2a, 0x80, 0x60, 0xf3, - 0xd5, 0x99, 0x41, 0xfa, 0x84, 0x45, 0xaf, 0x83, - 0x6c, 0x06, 0x6b, 0xdf, -}; - -static const uint8_t unicode_prop_Emoji_Modifier_table[4] = { - 0x61, 0xf3, 0xfa, 0x84, -}; - -static const uint8_t unicode_prop_Emoji_Modifier_Base_table[71] = { - 0x60, 0x26, 0x1c, 0x80, 0x40, 0xda, 0x80, 0x8f, - 0x83, 0x61, 0xcc, 0x76, 0x80, 0xbb, 0x11, 0x01, - 0x82, 0xf4, 0x09, 0x8a, 0x94, 0x92, 0x10, 0x1a, - 0x02, 0x30, 0x00, 0x97, 0x80, 0x40, 0xc8, 0x0b, - 0x80, 0x94, 0x03, 0x81, 0x40, 0xad, 0x12, 0x84, - 0xd2, 0x80, 0x8f, 0x82, 0x88, 0x80, 0x8a, 0x80, - 0x42, 0x3e, 0x01, 0x07, 0x3d, 0x80, 0x88, 0x89, - 0x0a, 0xb7, 0x80, 0xbc, 0x08, 0x08, 0x80, 0x90, - 0x10, 0x8c, 0x40, 0xe4, 0x82, 0xa9, 0x86, -}; - -static const uint8_t unicode_prop_Emoji_Presentation_table[145] = { - 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, 0x22, 0x8a, 0x0e, 0x88, - 0x40, 0xe2, 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, - 0x89, 0x80, 0x40, 0xb8, 0xef, 0x22, 0x22, 0x86, - 0x88, 0x9c, 0x82, 0x8a, 0x25, 0x89, 0x89, 0x2f, - 0x3e, -}; - -static const uint8_t unicode_prop_Extended_Pictographic_table[156] = { - 0x40, 0xa8, 0x03, 0x80, 0x5f, 0x8c, 0x80, 0x8b, - 0x80, 0x40, 0xd7, 0x80, 0x95, 0x80, 0xd9, 0x85, - 0x8e, 0x81, 0x41, 0x6e, 0x81, 0x8b, 0x80, 0xde, - 0x80, 0xc5, 0x80, 0x98, 0x8a, 0x1a, 0x40, 0xc6, - 0x80, 0x40, 0xe6, 0x81, 0x89, 0x80, 0x88, 0x80, - 0xb9, 0x18, 0x28, 0x8b, 0x80, 0xf1, 0x89, 0xf5, - 0x81, 0x8a, 0x00, 0x00, 0x28, 0x10, 0x28, 0x89, - 0x81, 0x8e, 0x01, 0x03, 0x00, 0x03, 0x10, 0x80, - 0x8a, 0x84, 0xac, 0x82, 0x88, 0x80, 0x8d, 0x80, - 0x8d, 0x80, 0x41, 0x73, 0x81, 0x41, 0xce, 0x82, - 0x92, 0x81, 0xb2, 0x03, 0x80, 0x44, 0xd9, 0x80, - 0x8b, 0x80, 0x42, 0x58, 0x00, 0x80, 0x61, 0xbd, - 0x65, 0x40, 0xff, 0x8c, 0x82, 0x9e, 0x80, 0xbb, - 0x85, 0x8b, 0x81, 0x8d, 0x01, 0x89, 0x91, 0xb8, - 0x9a, 0x8e, 0x89, 0x80, 0x93, 0x01, 0x88, 0x03, - 0x88, 0x41, 0xb1, 0x84, 0x41, 0x3d, 0x87, 0x41, - 0x09, 0xaf, 0xff, 0xf3, 0x8b, 0xd4, 0xaa, 0x8b, - 0x83, 0xb7, 0x87, 0x89, 0x85, 0xa7, 0x87, 0x9d, - 0xd1, 0x8b, 0xae, 0x80, 0x89, 0x80, 0x41, 0xb8, - 0x40, 0xff, 0x43, 0xfd, -}; - -static const uint8_t unicode_prop_Default_Ignorable_Code_Point_table[51] = { - 0x40, 0xac, 0x80, 0x42, 0xa0, 0x80, 0x42, 0xcb, - 0x80, 0x4b, 0x41, 0x81, 0x46, 0x52, 0x81, 0xd4, - 0x84, 0x47, 0xfa, 0x84, 0x99, 0x84, 0xb0, 0x8f, - 0x50, 0xf3, 0x80, 0x60, 0xcc, 0x9a, 0x8f, 0x40, - 0xee, 0x80, 0x40, 0x9f, 0x80, 0xce, 0x88, 0x60, - 0xbc, 0xa6, 0x83, 0x54, 0xce, 0x87, 0x6c, 0x2e, - 0x84, 0x4f, 0xff, -}; - -typedef enum { - UNICODE_PROP_Hyphen, - UNICODE_PROP_Other_Math, - UNICODE_PROP_Other_Alphabetic, - UNICODE_PROP_Other_Lowercase, - UNICODE_PROP_Other_Uppercase, - UNICODE_PROP_Other_Grapheme_Extend, - UNICODE_PROP_Other_Default_Ignorable_Code_Point, - UNICODE_PROP_Other_ID_Start, - UNICODE_PROP_Other_ID_Continue, - UNICODE_PROP_Prepended_Concatenation_Mark, - UNICODE_PROP_ID_Continue1, - UNICODE_PROP_XID_Start1, - UNICODE_PROP_XID_Continue1, - UNICODE_PROP_Changes_When_Titlecased1, - UNICODE_PROP_Changes_When_Casefolded1, - UNICODE_PROP_Changes_When_NFKC_Casefolded1, - UNICODE_PROP_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/third_party/quickjs/libunicode.c b/third_party/quickjs/libunicode.c deleted file mode 100644 index 554ad151c..000000000 --- a/third_party/quickjs/libunicode.c +++ /dev/null @@ -1,1564 +0,0 @@ -/* - * Unicode utilities - * - * Copyright (c) 2017-2018 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/assert.h" -#include "libc/limits.h" -#include "libc/mem/mem.h" -#include "libc/runtime/runtime.h" -#include "libc/stdio/stdio.h" -#include "libc/str/str.h" -#include "third_party/quickjs/cutils.h" -#include "third_party/quickjs/libunicode.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - - -#include "third_party/quickjs/libunicode-table.inc" - -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: - case DECOMP_TYPE_L2: - case DECOMP_TYPE_L3: - case DECOMP_TYPE_L4: - case DECOMP_TYPE_L5: - case DECOMP_TYPE_L6: - case DECOMP_TYPE_L7: - l = type - DECOMP_TYPE_L1 + 1; - d += (c - code) * l * 2; - for(i = 0; i < l; i++) { - if ((res[i] = unicode_get16(d + 2 * i)) == 0) - return 0; - } - return l; - case DECOMP_TYPE_LL1: - case DECOMP_TYPE_LL2: - { - uint32_t k, p; - l = type - DECOMP_TYPE_LL1 + 1; - k = (c - code) * l; - p = len * l * 2; - for(i = 0; i < l; i++) { - c1 = unicode_get16(d + 2 * k) | - (((d[p + (k / 4)] >> ((k % 4) * 2)) & 3) << 16); - if (!c1) - return 0; - res[i] = c1; - k++; - } - } - return l; - case DECOMP_TYPE_S1: - case DECOMP_TYPE_S2: - case DECOMP_TYPE_S3: - case DECOMP_TYPE_S4: - case DECOMP_TYPE_S5: - l = type - DECOMP_TYPE_S1 + 1; - d += (c - code) * l; - for(i = 0; i < l; i++) { - if ((res[i] = unicode_get_short_code(d[i])) == 0) - return 0; - } - return l; - case DECOMP_TYPE_I1: - l = 1; - p = 0; - goto decomp_type_i; - case DECOMP_TYPE_I2_0: - case DECOMP_TYPE_I2_1: - case DECOMP_TYPE_I3_1: - case DECOMP_TYPE_I3_2: - case DECOMP_TYPE_I4_1: - case DECOMP_TYPE_I4_2: - l = 2 + ((type - DECOMP_TYPE_I2_0) >> 1); - p = ((type - DECOMP_TYPE_I2_0) & 1) + (l > 2); - decomp_type_i: - for(i = 0; i < l; i++) { - c1 = unicode_get16(d + 2 * i); - if (i == p) - c1 += c - code; - res[i] = c1; - } - return l; - case DECOMP_TYPE_B18: - l = 18; - goto decomp_type_b; - case DECOMP_TYPE_B1: - case DECOMP_TYPE_B2: - case DECOMP_TYPE_B3: - case DECOMP_TYPE_B4: - case DECOMP_TYPE_B5: - case DECOMP_TYPE_B6: - case DECOMP_TYPE_B7: - case DECOMP_TYPE_B8: - l = type - DECOMP_TYPE_B1 + 1; - decomp_type_b: - { - uint32_t c_min; - c_min = unicode_get16(d); - d += 2 + (c - code) * l; - for(i = 0; i < l; i++) { - c1 = d[i]; - if (c1 == 0xff) - c1 = 0x20; - else - c1 += c_min; - res[i] = c1; - } - } - return l; - case DECOMP_TYPE_LS2: - d += (c - code) * 3; - if (!(res[0] = unicode_get16(d))) - return 0; - res[1] = unicode_get_short_code(d[2]); - return 2; - case DECOMP_TYPE_PAT3: - res[0] = unicode_get16(d); - res[2] = unicode_get16(d + 2); - d += 4 + (c - code) * 2; - res[1] = unicode_get16(d); - return 3; - case DECOMP_TYPE_S2_UL: - case DECOMP_TYPE_LS2_UL: - c1 = c - code; - if (type == DECOMP_TYPE_S2_UL) { - d += c1 & ~1; - c = unicode_get_short_code(*d); - d++; - } else { - d += (c1 >> 1) * 3; - c = unicode_get16(d); - d += 2; - } - if (c1 & 1) - c = unicode_get_lower_simple(c); - res[0] = c; - res[1] = unicode_get_short_code(*d); - return 2; - } - } - return 0; -} - - -/* return the length of the decomposition (length <= - UNICODE_DECOMP_LEN_MAX) or 0 if no decomposition */ -static int unicode_decomp_char(uint32_t *res, uint32_t c, BOOL is_compat1) -{ - uint32_t v, type, is_compat, code, len; - int idx_min, idx_max, idx; - - idx_min = 0; - idx_max = countof(unicode_decomp_table1) - 1; - while (idx_min <= idx_max) { - idx = (idx_max + idx_min) / 2; - v = unicode_decomp_table1[idx]; - code = v >> (32 - 18); - len = (v >> (32 - 18 - 7)) & 0x7f; - // printf("idx=%d code=%05x len=%d\n", idx, code, len); - if (c < code) { - idx_max = idx - 1; - } else if (c >= code + len) { - idx_min = idx + 1; - } else { - is_compat = v & 1; - if (is_compat1 < is_compat) - break; - type = (v >> (32 - 18 - 7 - 6)) & 0x3f; - return unicode_decomp_entry(res, c, idx, code, len, type); - } - } - return 0; -} - -/* return 0 if no pair found */ -static int unicode_compose_pair(uint32_t c0, uint32_t c1) -{ - uint32_t code, len, type, v, idx1, d_idx, d_offset, ch; - int idx_min, idx_max, idx, d; - uint32_t pair[2]; - - idx_min = 0; - idx_max = countof(unicode_comp_table) - 1; - while (idx_min <= idx_max) { - idx = (idx_max + idx_min) / 2; - idx1 = unicode_comp_table[idx]; - - /* idx1 represent an entry of the decomposition table */ - d_idx = idx1 >> 6; - d_offset = idx1 & 0x3f; - v = unicode_decomp_table1[d_idx]; - code = v >> (32 - 18); - len = (v >> (32 - 18 - 7)) & 0x7f; - type = (v >> (32 - 18 - 7 - 6)) & 0x3f; - ch = code + d_offset; - unicode_decomp_entry(pair, ch, d_idx, code, len, type); - d = c0 - pair[0]; - if (d == 0) - d = c1 - pair[1]; - if (d < 0) { - idx_max = idx - 1; - } else if (d > 0) { - idx_min = idx + 1; - } else { - return ch; - } - } - return 0; -} - -/* return the combining class of character c (between 0 and 255) */ -static int unicode_get_cc(uint32_t c) -{ - uint32_t code, n, type, cc, c1, b; - int pos; - const uint8_t *p; - - pos = get_index_pos(&code, c, - unicode_cc_index, sizeof(unicode_cc_index) / 3); - if (pos < 0) - return 0; - p = unicode_cc_table + pos; - 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/third_party/quickjs/libunicode.h b/third_party/quickjs/libunicode.h deleted file mode 100644 index d32f2b480..000000000 --- a/third_party/quickjs/libunicode.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBUNICODE_H_ -#define COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBUNICODE_H_ -#include "third_party/quickjs/libunicode.h" -COSMOPOLITAN_C_START_ - -#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 - -/* clang-format on */ -COSMOPOLITAN_C_END_ -#endif /* COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBUNICODE_H_ */ diff --git a/third_party/quickjs/list.h b/third_party/quickjs/list.h deleted file mode 100644 index d1b8644fe..000000000 --- a/third_party/quickjs/list.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIST_H_ -#define COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIST_H_ -COSMOPOLITAN_C_START_ - -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) - -/* clang-format on */ -COSMOPOLITAN_C_END_ -#endif /* COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIST_H_ */ diff --git a/third_party/quickjs/map.c b/third_party/quickjs/map.c deleted file mode 100644 index df444e6da..000000000 --- a/third_party/quickjs/map.c +++ /dev/null @@ -1,748 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/assert.h" -#include "third_party/quickjs/internal.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv, int magic) -{ - JSMapState *s; - JSValue obj, adder = JS_UNDEFINED, iter = JS_UNDEFINED, next_method = JS_UNDEFINED; - JSValueConst arr; - BOOL is_set, is_weak; - is_set = magic & MAGIC_SET; - is_weak = ((magic & MAGIC_WEAK) != 0); - obj = js_create_from_ctor(ctx, new_target, JS_CLASS_MAP + magic); - if (JS_IsException(obj)) - return JS_EXCEPTION; - s = js_mallocz(ctx, sizeof(*s)); - if (!s) - goto fail; - init_list_head(&s->records); - s->is_weak = is_weak; - JS_SetOpaque(obj, s); - s->hash_size = 1; - s->hash_table = js_malloc(ctx, sizeof(s->hash_table[0]) * s->hash_size); - if (!s->hash_table) - goto fail; - init_list_head(&s->hash_table[0]); - s->record_count_threshold = 4; - arr = JS_UNDEFINED; - if (argc > 0) - arr = argv[0]; - if (!JS_IsUndefined(arr) && !JS_IsNull(arr)) { - JSValue item, ret; - BOOL done; - adder = JS_GetProperty(ctx, obj, is_set ? JS_ATOM_add : JS_ATOM_set); - if (JS_IsException(adder)) - goto fail; - if (!JS_IsFunction(ctx, adder)) { - JS_ThrowTypeError(ctx, "set/add is not a function"); - goto fail; - } - iter = JS_GetIterator(ctx, arr, FALSE); - if (JS_IsException(iter)) - goto fail; - next_method = JS_GetProperty(ctx, iter, JS_ATOM_next); - if (JS_IsException(next_method)) - goto fail; - for(;;) { - item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done); - if (JS_IsException(item)) - goto fail; - if (done) { - JS_FreeValue(ctx, item); - break; - } - if (is_set) { - ret = JS_Call(ctx, adder, obj, 1, (JSValueConst *)&item); - if (JS_IsException(ret)) { - JS_FreeValue(ctx, item); - goto fail; - } - } else { - JSValue key, value; - JSValueConst args[2]; - key = JS_UNDEFINED; - value = JS_UNDEFINED; - if (!JS_IsObject(item)) { - JS_ThrowTypeErrorNotAnObject(ctx); - goto fail1; - } - key = JS_GetPropertyUint32(ctx, item, 0); - if (JS_IsException(key)) - goto fail1; - value = JS_GetPropertyUint32(ctx, item, 1); - if (JS_IsException(value)) - goto fail1; - args[0] = key; - args[1] = value; - ret = JS_Call(ctx, adder, obj, 2, args); - if (JS_IsException(ret)) { - fail1: - JS_FreeValue(ctx, item); - JS_FreeValue(ctx, key); - JS_FreeValue(ctx, value); - goto fail; - } - JS_FreeValue(ctx, key); - JS_FreeValue(ctx, value); - } - JS_FreeValue(ctx, ret); - JS_FreeValue(ctx, item); - } - JS_FreeValue(ctx, next_method); - JS_FreeValue(ctx, iter); - JS_FreeValue(ctx, adder); - } - return obj; - fail: - if (JS_IsObject(iter)) { - /* close the iterator object, preserving pending exception */ - JS_IteratorClose(ctx, iter, TRUE); - } - JS_FreeValue(ctx, next_method); - JS_FreeValue(ctx, iter); - JS_FreeValue(ctx, adder); - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -/* XXX: could normalize strings to speed up comparison */ -static JSValueConst map_normalize_key(JSContext *ctx, JSValueConst key) -{ - uint32_t tag = JS_VALUE_GET_TAG(key); - /* convert -0.0 to +0.0 */ - if (JS_TAG_IS_FLOAT64(tag) && JS_VALUE_GET_FLOAT64(key) == 0.0) { - key = JS_NewInt32(ctx, 0); - } - return key; -} - -/* XXX: better hash ? */ -static uint32_t map_hash_key(JSContext *ctx, JSValueConst key) -{ - uint32_t tag = JS_VALUE_GET_NORM_TAG(key); - uint32_t h; - double d; - JSFloat64Union u; - switch(tag) { - case JS_TAG_BOOL: - h = JS_VALUE_GET_INT(key); - break; - case JS_TAG_STRING: - h = hash_string(JS_VALUE_GET_STRING(key), 0); - break; - case JS_TAG_OBJECT: - case JS_TAG_SYMBOL: - h = (uintptr_t)JS_VALUE_GET_PTR(key) * 3163; - break; - case JS_TAG_INT: - d = JS_VALUE_GET_INT(key) * 3163; - goto hash_float64; - case JS_TAG_FLOAT64: - d = JS_VALUE_GET_FLOAT64(key); - /* normalize the NaN */ - if (isnan(d)) - d = JS_FLOAT64_NAN; - hash_float64: - u.d = d; - h = (u.u32[0] ^ u.u32[1]) * 3163; - break; - default: - h = 0; /* XXX: bignum support */ - break; - } - h ^= tag; - return h; -} - -static JSMapRecord *map_find_record(JSContext *ctx, JSMapState *s, - JSValueConst key) -{ - struct list_head *el; - JSMapRecord *mr; - uint32_t h; - h = map_hash_key(ctx, key) & (s->hash_size - 1); - list_for_each(el, &s->hash_table[h]) { - mr = list_entry(el, JSMapRecord, hash_link); - if (js_same_value_zero(ctx, mr->key, key)) - return mr; - } - return NULL; -} - -static void map_hash_resize(JSContext *ctx, JSMapState *s) -{ - uint32_t new_hash_size, i, h; - size_t slack; - struct list_head *new_hash_table, *el; - JSMapRecord *mr; - /* XXX: no reporting of memory allocation failure */ - if (s->hash_size == 1) - new_hash_size = 4; - else - new_hash_size = s->hash_size * 2; - new_hash_table = js_realloc2(ctx, s->hash_table, - sizeof(new_hash_table[0]) * new_hash_size, &slack); - if (!new_hash_table) - return; - new_hash_size += slack / sizeof(*new_hash_table); - for(i = 0; i < new_hash_size; i++) - init_list_head(&new_hash_table[i]); - list_for_each(el, &s->records) { - mr = list_entry(el, JSMapRecord, link); - if (!mr->empty) { - h = map_hash_key(ctx, mr->key) & (new_hash_size - 1); - list_add_tail(&mr->hash_link, &new_hash_table[h]); - } - } - s->hash_table = new_hash_table; - s->hash_size = new_hash_size; - s->record_count_threshold = new_hash_size * 2; -} - -static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s, - JSValueConst key) -{ - uint32_t h; - JSMapRecord *mr; - mr = js_malloc(ctx, sizeof(*mr)); - if (!mr) - return NULL; - mr->ref_count = 1; - mr->map = s; - mr->empty = FALSE; - if (s->is_weak) { - JSObject *p = JS_VALUE_GET_OBJ(key); - /* Add the weak reference */ - mr->next_weak_ref = p->first_weak_ref; - p->first_weak_ref = mr; - } else { - JS_DupValue(ctx, key); - } - mr->key = (JSValue)key; - h = map_hash_key(ctx, key) & (s->hash_size - 1); - list_add_tail(&mr->hash_link, &s->hash_table[h]); - list_add_tail(&mr->link, &s->records); - s->record_count++; - if (s->record_count >= s->record_count_threshold) { - map_hash_resize(ctx, s); - } - return mr; -} - -/* Remove the weak reference from the object weak - reference list. we don't use a doubly linked list to - save space, assuming a given object has few weak - references to it */ -static void delete_weak_ref(JSRuntime *rt, JSMapRecord *mr) -{ - JSMapRecord **pmr, *mr1; - JSObject *p; - p = JS_VALUE_GET_OBJ(mr->key); - pmr = &p->first_weak_ref; - for(;;) { - mr1 = *pmr; - assert(mr1 != NULL); - if (mr1 == mr) - break; - pmr = &mr1->next_weak_ref; - } - *pmr = mr1->next_weak_ref; -} - -static void map_delete_record(JSRuntime *rt, JSMapState *s, JSMapRecord *mr) -{ - if (mr->empty) - return; - list_del(&mr->hash_link); - if (s->is_weak) { - delete_weak_ref(rt, mr); - } else { - JS_FreeValueRT(rt, mr->key); - } - JS_FreeValueRT(rt, mr->value); - if (--mr->ref_count == 0) { - list_del(&mr->link); - js_free_rt(rt, mr); - } else { - /* keep a zombie record for iterators */ - mr->empty = TRUE; - mr->key = JS_UNDEFINED; - mr->value = JS_UNDEFINED; - } - s->record_count--; -} - -static void map_decref_record(JSRuntime *rt, JSMapRecord *mr) -{ - if (--mr->ref_count == 0) { - /* the record can be safely removed */ - assert(mr->empty); - list_del(&mr->link); - js_free_rt(rt, mr); - } -} - -void reset_weak_ref(JSRuntime *rt, JSObject *p) -{ - JSMapRecord *mr, *mr_next; - JSMapState *s; - (void)s; - /* first pass to remove the records from the WeakMap/WeakSet - lists */ - for(mr = p->first_weak_ref; mr != NULL; mr = mr->next_weak_ref) { - s = mr->map; - assert(s->is_weak); - assert(!mr->empty); /* no iterator on WeakMap/WeakSet */ - list_del(&mr->hash_link); - list_del(&mr->link); - } - /* second pass to free the values to avoid modifying the weak - reference list while traversing it. */ - for(mr = p->first_weak_ref; mr != NULL; mr = mr_next) { - mr_next = mr->next_weak_ref; - JS_FreeValueRT(rt, mr->value); - js_free_rt(rt, mr); - } - p->first_weak_ref = NULL; /* fail safe */ -} - -static JSValue js_map_set(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic); - JSMapRecord *mr; - JSValueConst key, value; - if (!s) - return JS_EXCEPTION; - key = map_normalize_key(ctx, argv[0]); - if (s->is_weak && !JS_IsObject(key)) - return JS_ThrowTypeErrorNotAnObject(ctx); - if (magic & MAGIC_SET) - value = JS_UNDEFINED; - else - value = argv[1]; - mr = map_find_record(ctx, s, key); - if (mr) { - JS_FreeValue(ctx, mr->value); - } else { - mr = map_add_record(ctx, s, key); - if (!mr) - return JS_EXCEPTION; - } - mr->value = JS_DupValue(ctx, value); - return JS_DupValue(ctx, this_val); -} - -static JSValue js_map_get(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic); - JSMapRecord *mr; - JSValueConst key; - if (!s) - return JS_EXCEPTION; - key = map_normalize_key(ctx, argv[0]); - mr = map_find_record(ctx, s, key); - if (!mr) - return JS_UNDEFINED; - else - return JS_DupValue(ctx, mr->value); -} - -static JSValue js_map_has(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic); - JSMapRecord *mr; - JSValueConst key; - if (!s) - return JS_EXCEPTION; - key = map_normalize_key(ctx, argv[0]); - mr = map_find_record(ctx, s, key); - return JS_NewBool(ctx, (mr != NULL)); -} - -static JSValue js_map_delete(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic); - JSMapRecord *mr; - JSValueConst key; - if (!s) - return JS_EXCEPTION; - key = map_normalize_key(ctx, argv[0]); - mr = map_find_record(ctx, s, key); - if (!mr) - return JS_FALSE; - map_delete_record(ctx->rt, s, mr); - return JS_TRUE; -} - -static JSValue js_map_clear(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic); - struct list_head *el, *el1; - JSMapRecord *mr; - if (!s) - return JS_EXCEPTION; - list_for_each_safe(el, el1, &s->records) { - mr = list_entry(el, JSMapRecord, link); - map_delete_record(ctx->rt, s, mr); - } - return JS_UNDEFINED; -} - -static JSValue js_map_get_size(JSContext *ctx, JSValueConst this_val, int magic) -{ - JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic); - if (!s) - return JS_EXCEPTION; - return JS_NewUint32(ctx, s->record_count); -} - -static JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic); - JSValueConst func, this_arg; - JSValue ret, args[3]; - struct list_head *el; - JSMapRecord *mr; - if (!s) - return JS_EXCEPTION; - func = argv[0]; - if (argc > 1) - this_arg = argv[1]; - else - this_arg = JS_UNDEFINED; - if (check_function(ctx, func)) - return JS_EXCEPTION; - /* Note: the list can be modified while traversing it, but the - current element is locked */ - el = s->records.next; - while (el != &s->records) { - mr = list_entry(el, JSMapRecord, link); - if (!mr->empty) { - mr->ref_count++; - /* must duplicate in case the record is deleted */ - args[1] = JS_DupValue(ctx, mr->key); - if (magic) - args[0] = args[1]; - else - args[0] = JS_DupValue(ctx, mr->value); - args[2] = (JSValue)this_val; - ret = JS_Call(ctx, func, this_arg, 3, (JSValueConst *)args); - JS_FreeValue(ctx, args[0]); - if (!magic) - JS_FreeValue(ctx, args[1]); - el = el->next; - map_decref_record(ctx->rt, mr); - if (JS_IsException(ret)) - return ret; - JS_FreeValue(ctx, ret); - } else { - el = el->next; - } - } - return JS_UNDEFINED; -} - -void js_map_finalizer(JSRuntime *rt, JSValue val) -{ - JSObject *p; - JSMapState *s; - struct list_head *el, *el1; - JSMapRecord *mr; - p = JS_VALUE_GET_OBJ(val); - s = p->u.map_state; - if (s) { - /* if the object is deleted we are sure that no iterator is - using it */ - list_for_each_safe(el, el1, &s->records) { - mr = list_entry(el, JSMapRecord, link); - if (!mr->empty) { - if (s->is_weak) - delete_weak_ref(rt, mr); - else - JS_FreeValueRT(rt, mr->key); - JS_FreeValueRT(rt, mr->value); - } - js_free_rt(rt, mr); - } - js_free_rt(rt, s->hash_table); - js_free_rt(rt, s); - } -} - -void js_map_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JSMapState *s; - struct list_head *el; - JSMapRecord *mr; - s = p->u.map_state; - if (s) { - list_for_each(el, &s->records) { - mr = list_entry(el, JSMapRecord, link); - if (!s->is_weak) - JS_MarkValue(rt, mr->key, mark_func); - JS_MarkValue(rt, mr->value, mark_func); - } - } -} - -void js_map_iterator_finalizer(JSRuntime *rt, JSValue val) -{ - JSObject *p; - JSMapIteratorData *it; - p = JS_VALUE_GET_OBJ(val); - it = p->u.map_iterator_data; - if (it) { - /* During the GC sweep phase the Map finalizer may be - called before the Map iterator finalizer */ - if (JS_IsLiveObject(rt, it->obj) && it->cur_record) { - map_decref_record(rt, it->cur_record); - } - JS_FreeValueRT(rt, it->obj); - js_free_rt(rt, it); - } -} - -void js_map_iterator_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JSMapIteratorData *it; - it = p->u.map_iterator_data; - if (it) { - /* the record is already marked by the object */ - JS_MarkValue(rt, it->obj, mark_func); - } -} - -static JSValue js_create_map_iterator(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSIteratorKindEnum kind; - JSMapState *s; - JSMapIteratorData *it; - JSValue enum_obj; - kind = magic >> 2; - magic &= 3; - s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic); - if (!s) - return JS_EXCEPTION; - enum_obj = JS_NewObjectClass(ctx, JS_CLASS_MAP_ITERATOR + magic); - if (JS_IsException(enum_obj)) - goto fail; - it = js_malloc(ctx, sizeof(*it)); - if (!it) { - JS_FreeValue(ctx, enum_obj); - goto fail; - } - it->obj = JS_DupValue(ctx, this_val); - it->kind = kind; - it->cur_record = NULL; - JS_SetOpaque(enum_obj, it); - return enum_obj; - fail: - return JS_EXCEPTION; -} - -static JSValue js_map_iterator_next(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - BOOL *pdone, int magic) -{ - JSMapIteratorData *it; - JSMapState *s; - JSMapRecord *mr; - struct list_head *el; - it = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP_ITERATOR + magic); - if (!it) { - *pdone = FALSE; - return JS_EXCEPTION; - } - if (JS_IsUndefined(it->obj)) - goto done; - s = JS_GetOpaque(it->obj, JS_CLASS_MAP + magic); - assert(s != NULL); - if (!it->cur_record) { - el = s->records.next; - } else { - mr = it->cur_record; - el = mr->link.next; - map_decref_record(ctx->rt, mr); /* the record can be freed here */ - } - for(;;) { - if (el == &s->records) { - /* no more record */ - it->cur_record = NULL; - JS_FreeValue(ctx, it->obj); - it->obj = JS_UNDEFINED; - done: - /* end of enumeration */ - *pdone = TRUE; - return JS_UNDEFINED; - } - mr = list_entry(el, JSMapRecord, link); - if (!mr->empty) - break; - /* get the next record */ - el = mr->link.next; - } - /* lock the record so that it won't be freed */ - mr->ref_count++; - it->cur_record = mr; - *pdone = FALSE; - if (it->kind == JS_ITERATOR_KIND_KEY) { - return JS_DupValue(ctx, mr->key); - } else { - JSValueConst args[2]; - args[0] = mr->key; - if (magic) - args[1] = mr->key; - else - args[1] = mr->value; - if (it->kind == JS_ITERATOR_KIND_VALUE) { - return JS_DupValue(ctx, args[1]); - } else { - return js_create_array(ctx, 2, args); - } - } -} - -static const JSCFunctionListEntry js_map_funcs[] = { - JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ), -}; - -static const JSCFunctionListEntry js_map_proto_funcs[] = { - JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, 0 ), - JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, 0 ), - JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, 0 ), - JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, 0 ), - JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, 0 ), - JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, 0), - JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, 0 ), - JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_VALUE << 2) | 0 ), - JS_CFUNC_MAGIC_DEF("keys", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | 0 ), - JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | 0 ), - JS_ALIAS_DEF("[Symbol.iterator]", "entries" ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map", JS_PROP_CONFIGURABLE ), -}; - -static const JSCFunctionListEntry js_map_iterator_proto_funcs[] = { - JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, 0 ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map Iterator", JS_PROP_CONFIGURABLE ), -}; - -static const JSCFunctionListEntry js_set_proto_funcs[] = { - JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET ), - JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET ), - JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET ), - JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, MAGIC_SET ), - JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, MAGIC_SET ), - JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, MAGIC_SET ), - JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | MAGIC_SET ), - JS_ALIAS_DEF("keys", "values" ), - JS_ALIAS_DEF("[Symbol.iterator]", "values" ), - JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | MAGIC_SET ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set", JS_PROP_CONFIGURABLE ), -}; - -static const JSCFunctionListEntry js_set_iterator_proto_funcs[] = { - JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, MAGIC_SET ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set Iterator", JS_PROP_CONFIGURABLE ), -}; - -static const JSCFunctionListEntry js_weak_map_proto_funcs[] = { - JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, MAGIC_WEAK ), - JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, MAGIC_WEAK ), - JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_WEAK ), - JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_WEAK ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakMap", JS_PROP_CONFIGURABLE ), -}; - -static const JSCFunctionListEntry js_weak_set_proto_funcs[] = { - JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET | MAGIC_WEAK ), - JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET | MAGIC_WEAK ), - JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET | MAGIC_WEAK ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakSet", JS_PROP_CONFIGURABLE ), -}; - -static const JSCFunctionListEntry * const js_map_proto_funcs_ptr[6] = { - js_map_proto_funcs, - js_set_proto_funcs, - js_weak_map_proto_funcs, - js_weak_set_proto_funcs, - js_map_iterator_proto_funcs, - js_set_iterator_proto_funcs, -}; - -static const uint8_t js_map_proto_funcs_count[6] = { - countof(js_map_proto_funcs), - countof(js_set_proto_funcs), - countof(js_weak_map_proto_funcs), - countof(js_weak_set_proto_funcs), - countof(js_map_iterator_proto_funcs), - countof(js_set_iterator_proto_funcs), -}; - -void JS_AddIntrinsicMapSet(JSContext *ctx) -{ - int i; - JSValue obj1; - char buf[ATOM_GET_STR_BUF_SIZE]; - for(i = 0; i < 4; i++) { - const char *name = JS_AtomGetStr(ctx, buf, sizeof(buf), - JS_ATOM_Map + i); - ctx->class_proto[JS_CLASS_MAP + i] = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP + i], - js_map_proto_funcs_ptr[i], - js_map_proto_funcs_count[i]); - obj1 = JS_NewCFunctionMagic(ctx, js_map_constructor, name, 0, - JS_CFUNC_constructor_magic, i); - if (i < 2) { - JS_SetPropertyFunctionList(ctx, obj1, js_map_funcs, - countof(js_map_funcs)); - } - JS_NewGlobalCConstructor2(ctx, obj1, name, ctx->class_proto[JS_CLASS_MAP + i]); - } - for(i = 0; i < 2; i++) { - ctx->class_proto[JS_CLASS_MAP_ITERATOR + i] = - JS_NewObjectProto(ctx, ctx->iterator_proto); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP_ITERATOR + i], - js_map_proto_funcs_ptr[i + 4], - js_map_proto_funcs_count[i + 4]); - } -} diff --git a/third_party/quickjs/math.c b/third_party/quickjs/math.c deleted file mode 100644 index c967088d1..000000000 --- a/third_party/quickjs/math.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/calls/struct/timeval.h" -#include "libc/time/time.h" -#include "third_party/quickjs/internal.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -/* precondition: a and b are not NaN */ -static double js_fmin(double a, double b) -{ - if (a == 0 && b == 0) { - JSFloat64Union a1, b1; - a1.d = a; - b1.d = b; - a1.u64 |= b1.u64; - return a1.d; - } else { - return fmin(a, b); - } -} - -/* precondition: a and b are not NaN */ -static double js_fmax(double a, double b) -{ - if (a == 0 && b == 0) { - JSFloat64Union a1, b1; - a1.d = a; - b1.d = b; - a1.u64 &= b1.u64; - return a1.d; - } else { - return fmax(a, b); - } -} - -static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - BOOL is_max = magic; - double r, a; - int i; - uint32_t tag; - if (UNLIKELY(argc == 0)) { - return __JS_NewFloat64(ctx, is_max ? -1.0 / 0.0 : 1.0 / 0.0); - } - tag = JS_VALUE_GET_TAG(argv[0]); - if (tag == JS_TAG_INT) { - int a1, r1 = JS_VALUE_GET_INT(argv[0]); - for(i = 1; i < argc; i++) { - tag = JS_VALUE_GET_TAG(argv[i]); - if (tag != JS_TAG_INT) { - r = r1; - goto generic_case; - } - a1 = JS_VALUE_GET_INT(argv[i]); - if (is_max) - r1 = max_int(r1, a1); - else - r1 = min_int(r1, a1); - } - return JS_NewInt32(ctx, r1); - } else { - if (JS_ToFloat64(ctx, &r, argv[0])) - return JS_EXCEPTION; - i = 1; - generic_case: - while (i < argc) { - if (JS_ToFloat64(ctx, &a, argv[i])) - return JS_EXCEPTION; - if (!isnan(r)) { - if (isnan(a)) { - r = a; - } else { - if (is_max) - r = js_fmax(r, a); - else - r = js_fmin(r, a); - } - } - i++; - } - return JS_NewFloat64(ctx, r); - } -} - -static double js_math_sign(double a) -{ - if (isnan(a) || a == 0.0) - return a; - if (a < 0) - return -1; - else - return 1; -} - -static double js_math_round(double a) -{ - JSFloat64Union u; - uint64_t frac_mask, one; - unsigned int e, s; - u.d = a; - e = (u.u64 >> 52) & 0x7ff; - if (e < 1023) { - /* abs(a) < 1 */ - if (e == (1023 - 1) && u.u64 != 0xbfe0000000000000) { - /* abs(a) > 0.5 or a = 0.5: return +/-1.0 */ - u.u64 = (u.u64 & ((uint64_t)1 << 63)) | ((uint64_t)1023 << 52); - } else { - /* return +/-0.0 */ - u.u64 &= (uint64_t)1 << 63; - } - } else if (e < (1023 + 52)) { - s = u.u64 >> 63; - one = (uint64_t)1 << (52 - (e - 1023)); - frac_mask = one - 1; - u.u64 += (one >> 1) - s; - u.u64 &= ~frac_mask; /* truncate to an integer */ - } - /* otherwise: abs(a) >= 2^52, or NaN, +/-Infinity: no change */ - return u.d; -} - -static JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - double r, a; - int i; - r = 0; - if (argc > 0) { - if (JS_ToFloat64(ctx, &r, argv[0])) - return JS_EXCEPTION; - if (argc == 1) { - r = fabs(r); - } else { - /* use the built-in function to minimize precision loss */ - for (i = 1; i < argc; i++) { - if (JS_ToFloat64(ctx, &a, argv[i])) - return JS_EXCEPTION; - r = hypot(r, a); - } - } - } - return JS_NewFloat64(ctx, r); -} - -static double js_math_fround(double a) -{ - return (float)a; -} - -static JSValue js_math_imul(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int a, b; - if (JS_ToInt32(ctx, &a, argv[0])) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &b, argv[1])) - return JS_EXCEPTION; - /* purposely ignoring overflow */ - return JS_NewInt32(ctx, a * b); -} - -static JSValue js_math_clz32(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - uint32_t a, r; - if (JS_ToUint32(ctx, &a, argv[0])) - return JS_EXCEPTION; - if (a == 0) - r = 32; - else - r = clz32(a); - return JS_NewInt32(ctx, r); -} - -/* xorshift* random number generator by Marsaglia */ -static uint64_t xorshift64star(uint64_t *pstate) -{ - uint64_t x; - x = *pstate; - x ^= x >> 12; - x ^= x << 25; - x ^= x >> 27; - *pstate = x; - return x * 0x2545F4914F6CDD1D; -} - -static void js_random_init(JSContext *ctx) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - ctx->random_state = ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec; - /* the state must be non zero */ - if (ctx->random_state == 0) - ctx->random_state = 1; -} - -static JSValue js_math_random(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSFloat64Union u; - uint64_t v; - - v = xorshift64star(&ctx->random_state); - /* 1.0 <= u.d < 2 */ - u.u64 = ((uint64_t)0x3ff << 52) | (v >> 12); - return __JS_NewFloat64(ctx, u.d - 1.0); -} - -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); - } -} - -static const JSCFunctionListEntry js_math_funcs[] = { - JS_CFUNC_MAGIC_DEF("min", 2, js_math_min_max, 0 ), - JS_CFUNC_MAGIC_DEF("max", 2, js_math_min_max, 1 ), - JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, fabs ), - JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, floor ), - JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, ceil ), - JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_math_round ), - JS_CFUNC_SPECIAL_DEF("sqrt", 1, f_f, sqrt ), - JS_CFUNC_SPECIAL_DEF("acos", 1, f_f, acos ), - JS_CFUNC_SPECIAL_DEF("asin", 1, f_f, asin ), - JS_CFUNC_SPECIAL_DEF("atan", 1, f_f, atan ), - JS_CFUNC_SPECIAL_DEF("atan2", 2, f_f_f, atan2 ), - JS_CFUNC_SPECIAL_DEF("cos", 1, f_f, cos ), - JS_CFUNC_SPECIAL_DEF("exp", 1, f_f, exp ), - JS_CFUNC_SPECIAL_DEF("log", 1, f_f, log ), - JS_CFUNC_SPECIAL_DEF("pow", 2, f_f_f, js_pow ), - JS_CFUNC_SPECIAL_DEF("sin", 1, f_f, sin ), - JS_CFUNC_SPECIAL_DEF("tan", 1, f_f, tan ), - /* ES6 */ - JS_CFUNC_SPECIAL_DEF("trunc", 1, f_f, trunc ), - JS_CFUNC_SPECIAL_DEF("sign", 1, f_f, js_math_sign ), - JS_CFUNC_SPECIAL_DEF("cosh", 1, f_f, cosh ), - JS_CFUNC_SPECIAL_DEF("sinh", 1, f_f, sinh ), - JS_CFUNC_SPECIAL_DEF("tanh", 1, f_f, tanh ), - JS_CFUNC_SPECIAL_DEF("acosh", 1, f_f, acosh ), - JS_CFUNC_SPECIAL_DEF("asinh", 1, f_f, asinh ), - JS_CFUNC_SPECIAL_DEF("atanh", 1, f_f, atanh ), - JS_CFUNC_SPECIAL_DEF("expm1", 1, f_f, expm1 ), - JS_CFUNC_SPECIAL_DEF("log1p", 1, f_f, log1p ), - JS_CFUNC_SPECIAL_DEF("log2", 1, f_f, log2 ), - JS_CFUNC_SPECIAL_DEF("log10", 1, f_f, log10 ), - JS_CFUNC_SPECIAL_DEF("cbrt", 1, f_f, cbrt ), - JS_CFUNC_DEF("hypot", 2, js_math_hypot ), - JS_CFUNC_DEF("random", 0, js_math_random ), - JS_CFUNC_SPECIAL_DEF("fround", 1, f_f, js_math_fround ), - JS_CFUNC_DEF("imul", 2, js_math_imul ), - JS_CFUNC_DEF("clz32", 1, js_math_clz32 ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Math", JS_PROP_CONFIGURABLE ), - JS_PROP_DOUBLE_DEF("E", 2.718281828459045, 0 ), - JS_PROP_DOUBLE_DEF("LN10", 2.302585092994046, 0 ), - JS_PROP_DOUBLE_DEF("LN2", 0.6931471805599453, 0 ), - JS_PROP_DOUBLE_DEF("LOG2E", 1.4426950408889634, 0 ), - JS_PROP_DOUBLE_DEF("LOG10E", 0.4342944819032518, 0 ), - JS_PROP_DOUBLE_DEF("PI", 3.141592653589793, 0 ), - JS_PROP_DOUBLE_DEF("SQRT1_2", 0.7071067811865476, 0 ), - JS_PROP_DOUBLE_DEF("SQRT2", 1.4142135623730951, 0 ), -}; - -static const JSCFunctionListEntry js_math_obj[] = { - JS_OBJECT_DEF("Math", js_math_funcs, countof(js_math_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ), -}; - -void JS_AddIntrinsicMath(JSContext *ctx) { - /* Math: create as autoinit object */ - js_random_init(ctx); - JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_math_obj, countof(js_math_obj)); -} diff --git a/third_party/quickjs/mem.c b/third_party/quickjs/mem.c deleted file mode 100644 index cc2eba087..000000000 --- a/third_party/quickjs/mem.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "third_party/quickjs/internal.h" -#include "third_party/quickjs/libregexp.h" -#include "third_party/quickjs/quickjs.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx) -{ - return JS_ThrowTypeError(ctx, "revoked proxy"); -} - -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); -} - -/* warning: the refcount of the context is not incremented. Return - NULL in case of exception (case of revoked proxy only) */ -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; -} - -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; -} - -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 - case JS_TAG_OBJECT: - { - JSObject *p = JS_VALUE_GET_OBJ(val); - BOOL ret; - ret = !p->is_HTMLDDA; - JS_FreeValue(ctx, val); - return ret; - } - break; - default: - if (JS_TAG_IS_FLOAT64(tag)) { - double d = JS_VALUE_GET_FLOAT64(val); - return !isnan(d) && d != 0; - } else { - JS_FreeValue(ctx, val); - return TRUE; - } - } -} - -int JS_ToBool(JSContext *ctx, JSValueConst val) -{ - return JS_ToBoolFree(ctx, JS_DupValue(ctx, val)); -} - -JSValue js_get_this(JSContext *ctx, JSValueConst this_val) -{ - return JS_DupValue(ctx, this_val); -} diff --git a/third_party/quickjs/object.c b/third_party/quickjs/object.c deleted file mode 100644 index 82a8dd832..000000000 --- a/third_party/quickjs/object.c +++ /dev/null @@ -1,1247 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "third_party/quickjs/internal.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -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; -} - -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 JSValue js_object_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) -{ - JSValue ret; - if (!JS_IsUndefined(new_target) && - JS_VALUE_GET_OBJ(new_target) != - JS_VALUE_GET_OBJ(JS_GetActiveFunction(ctx))) { - ret = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT); - } else { - int tag = JS_VALUE_GET_NORM_TAG(argv[0]); - switch(tag) { - case JS_TAG_NULL: - case JS_TAG_UNDEFINED: - ret = JS_NewObject(ctx); - break; - default: - ret = JS_ToObject(ctx, argv[0]); - break; - } - } - return ret; -} - -static __exception int JS_DefinePropertyDesc(JSContext *ctx, JSValueConst obj, - JSAtom prop, JSValueConst desc, - int flags) -{ - JSPropertyDescriptor d; - int ret; - if (js_obj_to_desc(ctx, &d, desc) < 0) - return -1; - ret = JS_DefineProperty(ctx, obj, prop, - d.value, d.getter, d.setter, d.flags | flags); - js_free_desc(ctx, &d); - return ret; -} - -static __exception int JS_ObjectDefineProperties(JSContext *ctx, - JSValueConst obj, - JSValueConst properties) -{ - JSValue props, desc; - JSObject *p; - JSPropertyEnum *atoms; - uint32_t len, i; - int ret = -1; - if (!JS_IsObject(obj)) { - JS_ThrowTypeErrorNotAnObject(ctx); - return -1; - } - desc = JS_UNDEFINED; - props = JS_ToObject(ctx, properties); - if (JS_IsException(props)) - return -1; - p = JS_VALUE_GET_OBJ(props); - if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK) < 0) - goto exception; - for(i = 0; i < len; i++) { - JS_FreeValue(ctx, desc); - desc = JS_GetProperty(ctx, props, atoms[i].atom); - if (JS_IsException(desc)) - goto exception; - if (JS_DefinePropertyDesc(ctx, obj, atoms[i].atom, desc, JS_PROP_THROW) < 0) - goto exception; - } - ret = 0; -exception: - js_free_prop_enum(ctx, atoms, len); - JS_FreeValue(ctx, props); - JS_FreeValue(ctx, desc); - return ret; -} - -static JSValue js_object_create(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst proto, props; - JSValue obj; - proto = argv[0]; - if (!JS_IsObject(proto) && !JS_IsNull(proto)) - return JS_ThrowTypeError(ctx, "not a prototype"); - obj = JS_NewObjectProto(ctx, proto); - if (JS_IsException(obj)) - return JS_EXCEPTION; - props = argv[1]; - if (!JS_IsUndefined(props)) { - if (JS_ObjectDefineProperties(ctx, obj, props)) { - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - } - return obj; -} - -JSValue js_object_getPrototypeOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSValueConst val; - val = argv[0]; - if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) { - /* ES6 feature non compatible with ES5.1: primitive types are - accepted */ - if (magic || JS_VALUE_GET_TAG(val) == JS_TAG_NULL || - JS_VALUE_GET_TAG(val) == JS_TAG_UNDEFINED) - return JS_ThrowTypeErrorNotAnObject(ctx); - } - return JS_GetPrototype(ctx, val); -} - -static JSValue js_object_setPrototypeOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst obj; - obj = argv[0]; - if (JS_SetPrototypeInternal(ctx, obj, argv[1], TRUE) < 0) - return JS_EXCEPTION; - return JS_DupValue(ctx, obj); -} - -/* magic = 1 if called as Reflect.defineProperty */ -JSValue js_object_defineProperty(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSValueConst obj, prop, desc; - int ret, flags; - JSAtom atom; - obj = argv[0]; - prop = argv[1]; - desc = argv[2]; - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - return JS_ThrowTypeErrorNotAnObject(ctx); - atom = JS_ValueToAtom(ctx, prop); - if (UNLIKELY(atom == JS_ATOM_NULL)) - return JS_EXCEPTION; - flags = 0; - if (!magic) - flags |= JS_PROP_THROW; - ret = JS_DefinePropertyDesc(ctx, obj, atom, desc, flags); - JS_FreeAtom(ctx, atom); - if (ret < 0) { - return JS_EXCEPTION; - } else if (magic) { - return JS_NewBool(ctx, ret); - } else { - return JS_DupValue(ctx, obj); - } -} - -static JSValue js_object_defineProperties(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // defineProperties(obj, properties) - JSValueConst obj = argv[0]; - if (JS_ObjectDefineProperties(ctx, obj, argv[1])) - return JS_EXCEPTION; - else - return JS_DupValue(ctx, obj); -} - -/* magic = 1 if called as __defineSetter__ */ -static JSValue js_object___defineGetter__(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSValue obj; - JSValueConst prop, value, get, set; - int ret, flags; - JSAtom atom; - prop = argv[0]; - value = argv[1]; - obj = JS_ToObject(ctx, this_val); - if (JS_IsException(obj)) - return JS_EXCEPTION; - if (check_function(ctx, value)) { - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - atom = JS_ValueToAtom(ctx, prop); - if (UNLIKELY(atom == JS_ATOM_NULL)) { - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - flags = JS_PROP_THROW | - JS_PROP_HAS_ENUMERABLE | JS_PROP_ENUMERABLE | - JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE; - if (magic) { - get = JS_UNDEFINED; - set = value; - flags |= JS_PROP_HAS_SET; - } else { - get = value; - set = JS_UNDEFINED; - flags |= JS_PROP_HAS_GET; - } - ret = JS_DefineProperty(ctx, obj, atom, JS_UNDEFINED, get, set, flags); - JS_FreeValue(ctx, obj); - JS_FreeAtom(ctx, atom); - if (ret < 0) { - return JS_EXCEPTION; - } else { - return JS_UNDEFINED; - } -} - -JSValue js_object_getOwnPropertyDescriptor(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSValueConst prop; - JSAtom atom; - JSValue ret, obj; - JSPropertyDescriptor desc; - int res, flags; - if (magic) { - /* Reflect.getOwnPropertyDescriptor case */ - if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT) - return JS_ThrowTypeErrorNotAnObject(ctx); - obj = JS_DupValue(ctx, argv[0]); - } else { - obj = JS_ToObject(ctx, argv[0]); - if (JS_IsException(obj)) - return obj; - } - prop = argv[1]; - atom = JS_ValueToAtom(ctx, prop); - if (UNLIKELY(atom == JS_ATOM_NULL)) - goto exception; - ret = JS_UNDEFINED; - if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { - res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), atom); - if (res < 0) - goto exception; - if (res) { - ret = JS_NewObject(ctx); - if (JS_IsException(ret)) - goto exception1; - flags = JS_PROP_C_W_E | JS_PROP_THROW; - if (desc.flags & JS_PROP_GETSET) { - if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, desc.getter), flags) < 0 - || JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, desc.setter), flags) < 0) - goto exception1; - } else { - if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, desc.value), flags) < 0 - || JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable, - JS_NewBool(ctx, (desc.flags & JS_PROP_WRITABLE) != 0), flags) < 0) - goto exception1; - } - if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable, - JS_NewBool(ctx, (desc.flags & JS_PROP_ENUMERABLE) != 0), flags) < 0 - || JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable, - JS_NewBool(ctx, (desc.flags & JS_PROP_CONFIGURABLE) != 0), flags) < 0) - goto exception1; - js_free_desc(ctx, &desc); - } - } - JS_FreeAtom(ctx, atom); - JS_FreeValue(ctx, obj); - return ret; -exception1: - js_free_desc(ctx, &desc); - JS_FreeValue(ctx, ret); -exception: - JS_FreeAtom(ctx, atom); - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue js_object_getOwnPropertyDescriptors(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - //getOwnPropertyDescriptors(obj) - JSValue obj, r; - JSObject *p; - JSPropertyEnum *props; - uint32_t len, i; - r = JS_UNDEFINED; - obj = JS_ToObject(ctx, argv[0]); - if (JS_IsException(obj)) - return JS_EXCEPTION; - p = JS_VALUE_GET_OBJ(obj); - if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, - JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK)) - goto exception; - r = JS_NewObject(ctx); - if (JS_IsException(r)) - goto exception; - for(i = 0; i < len; i++) { - JSValue atomValue, desc; - JSValueConst args[2]; - atomValue = JS_AtomToValue(ctx, props[i].atom); - if (JS_IsException(atomValue)) - goto exception; - args[0] = obj; - args[1] = atomValue; - desc = js_object_getOwnPropertyDescriptor(ctx, JS_UNDEFINED, 2, args, 0); - JS_FreeValue(ctx, atomValue); - if (JS_IsException(desc)) - goto exception; - if (!JS_IsUndefined(desc)) { - if (JS_DefinePropertyValue(ctx, r, props[i].atom, desc, - JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - } - } - js_free_prop_enum(ctx, props, len); - JS_FreeValue(ctx, obj); - return r; -exception: - js_free_prop_enum(ctx, props, len); - JS_FreeValue(ctx, obj); - JS_FreeValue(ctx, r); - return JS_EXCEPTION; -} - -JSValue JS_ToObject(JSContext *ctx, JSValueConst val) -{ - int tag = JS_VALUE_GET_NORM_TAG(val); - JSValue obj; - switch(tag) { - default: - case JS_TAG_NULL: - case JS_TAG_UNDEFINED: - return JS_ThrowTypeError(ctx, "cannot convert to object"); - case JS_TAG_OBJECT: - case JS_TAG_EXCEPTION: - return JS_DupValue(ctx, val); -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_INT: - obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT); - goto set_value; - case JS_TAG_BIG_FLOAT: - obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_FLOAT); - goto set_value; - case JS_TAG_BIG_DECIMAL: - obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_DECIMAL); - goto set_value; -#endif - case JS_TAG_INT: - case JS_TAG_FLOAT64: - obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER); - goto set_value; - case JS_TAG_STRING: - /* XXX: should call the string constructor */ - { - JSString *p1 = JS_VALUE_GET_STRING(val); - obj = JS_NewObjectClass(ctx, JS_CLASS_STRING); - JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0); - } - goto set_value; - case JS_TAG_BOOL: - obj = JS_NewObjectClass(ctx, JS_CLASS_BOOLEAN); - goto set_value; - case JS_TAG_SYMBOL: - obj = JS_NewObjectClass(ctx, JS_CLASS_SYMBOL); - set_value: - if (!JS_IsException(obj)) - JS_SetObjectData(ctx, obj, JS_DupValue(ctx, val)); - return obj; - } -} - -JSValue JS_ToObjectFree(JSContext *ctx, JSValue val) -{ - JSValue obj = JS_ToObject(ctx, val); - JS_FreeValue(ctx, val); - return obj; -} - -int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d, JSValueConst desc) -{ - JSValue val, getter, setter; - int flags; - if (!JS_IsObject(desc)) { - JS_ThrowTypeErrorNotAnObject(ctx); - return -1; - } - flags = 0; - val = JS_UNDEFINED; - getter = JS_UNDEFINED; - setter = JS_UNDEFINED; - if (JS_HasProperty(ctx, desc, JS_ATOM_configurable)) { - JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_configurable); - if (JS_IsException(prop)) - goto fail; - flags |= JS_PROP_HAS_CONFIGURABLE; - if (JS_ToBoolFree(ctx, prop)) - flags |= JS_PROP_CONFIGURABLE; - } - if (JS_HasProperty(ctx, desc, JS_ATOM_writable)) { - JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_writable); - if (JS_IsException(prop)) - goto fail; - flags |= JS_PROP_HAS_WRITABLE; - if (JS_ToBoolFree(ctx, prop)) - flags |= JS_PROP_WRITABLE; - } - if (JS_HasProperty(ctx, desc, JS_ATOM_enumerable)) { - JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_enumerable); - if (JS_IsException(prop)) - goto fail; - flags |= JS_PROP_HAS_ENUMERABLE; - if (JS_ToBoolFree(ctx, prop)) - flags |= JS_PROP_ENUMERABLE; - } - if (JS_HasProperty(ctx, desc, JS_ATOM_value)) { - flags |= JS_PROP_HAS_VALUE; - val = JS_GetProperty(ctx, desc, JS_ATOM_value); - if (JS_IsException(val)) - goto fail; - } - if (JS_HasProperty(ctx, desc, JS_ATOM_get)) { - flags |= JS_PROP_HAS_GET; - getter = JS_GetProperty(ctx, desc, JS_ATOM_get); - if (JS_IsException(getter) || - !(JS_IsUndefined(getter) || JS_IsFunction(ctx, getter))) { - JS_ThrowTypeError(ctx, "invalid getter"); - goto fail; - } - } - if (JS_HasProperty(ctx, desc, JS_ATOM_set)) { - flags |= JS_PROP_HAS_SET; - setter = JS_GetProperty(ctx, desc, JS_ATOM_set); - if (JS_IsException(setter) || - !(JS_IsUndefined(setter) || JS_IsFunction(ctx, setter))) { - JS_ThrowTypeError(ctx, "invalid setter"); - goto fail; - } - } - if ((flags & (JS_PROP_HAS_SET | JS_PROP_HAS_GET)) && - (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE))) { - JS_ThrowTypeError(ctx, "cannot have setter/getter and value or writable"); - goto fail; - } - d->flags = flags; - d->value = val; - d->getter = getter; - d->setter = setter; - return 0; - fail: - JS_FreeValue(ctx, val); - JS_FreeValue(ctx, getter); - JS_FreeValue(ctx, setter); - return -1; -} - -JSValue JS_GetOwnPropertyNames2(JSContext *ctx, JSValueConst obj1, int flags, int kind) -{ - JSValue obj, r, val, key, value; - JSObject *p; - JSPropertyEnum *atoms; - uint32_t len, i, j; - r = JS_UNDEFINED; - val = JS_UNDEFINED; - obj = JS_ToObject(ctx, obj1); - if (JS_IsException(obj)) - return JS_EXCEPTION; - p = JS_VALUE_GET_OBJ(obj); - if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, flags & ~JS_GPN_ENUM_ONLY)) - goto exception; - r = JS_NewArray(ctx); - if (JS_IsException(r)) - goto exception; - for(j = i = 0; i < len; i++) { - JSAtom atom = atoms[i].atom; - if (flags & JS_GPN_ENUM_ONLY) { - JSPropertyDescriptor desc; - int res; - - /* Check if property is still enumerable */ - res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom); - if (res < 0) - goto exception; - if (!res) - continue; - js_free_desc(ctx, &desc); - if (!(desc.flags & JS_PROP_ENUMERABLE)) - continue; - } - switch(kind) { - default: - case JS_ITERATOR_KIND_KEY: - val = JS_AtomToValue(ctx, atom); - if (JS_IsException(val)) - goto exception; - break; - case JS_ITERATOR_KIND_VALUE: - val = JS_GetProperty(ctx, obj, atom); - if (JS_IsException(val)) - goto exception; - break; - case JS_ITERATOR_KIND_KEY_AND_VALUE: - val = JS_NewArray(ctx); - if (JS_IsException(val)) - goto exception; - key = JS_AtomToValue(ctx, atom); - if (JS_IsException(key)) - goto exception1; - if (JS_CreateDataPropertyUint32(ctx, val, 0, key, JS_PROP_THROW) < 0) - goto exception1; - value = JS_GetProperty(ctx, obj, atom); - if (JS_IsException(value)) - goto exception1; - if (JS_CreateDataPropertyUint32(ctx, val, 1, value, JS_PROP_THROW) < 0) - goto exception1; - break; - } - if (JS_CreateDataPropertyUint32(ctx, r, j++, val, 0) < 0) - goto exception; - } - goto done; - -exception1: - JS_FreeValue(ctx, val); -exception: - JS_FreeValue(ctx, r); - r = JS_EXCEPTION; -done: - js_free_prop_enum(ctx, atoms, len); - JS_FreeValue(ctx, obj); - return r; -} - -static JSValue js_object_getOwnPropertyNames(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_GetOwnPropertyNames2(ctx, argv[0], - JS_GPN_STRING_MASK, JS_ITERATOR_KIND_KEY); -} - -static JSValue js_object_getOwnPropertySymbols(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_GetOwnPropertyNames2(ctx, argv[0], - JS_GPN_SYMBOL_MASK, JS_ITERATOR_KIND_KEY); -} - -JSValue js_object_keys(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int kind) -{ - return JS_GetOwnPropertyNames2(ctx, argv[0], - JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK, kind); -} - -JSValue js_object_isExtensible(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int reflect) -{ - JSValueConst obj; - int ret; - obj = argv[0]; - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) { - if (reflect) - return JS_ThrowTypeErrorNotAnObject(ctx); - else - return JS_FALSE; - } - ret = JS_IsExtensible(ctx, obj); - if (ret < 0) - return JS_EXCEPTION; - else - return JS_NewBool(ctx, ret); -} - -JSValue js_object_preventExtensions(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int reflect) -{ - JSValueConst obj; - int ret; - obj = argv[0]; - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) { - if (reflect) - return JS_ThrowTypeErrorNotAnObject(ctx); - else - return JS_DupValue(ctx, obj); - } - ret = JS_PreventExtensions(ctx, obj); - if (ret < 0) - return JS_EXCEPTION; - if (reflect) { - return JS_NewBool(ctx, ret); - } else { - if (!ret) - return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false"); - return JS_DupValue(ctx, obj); - } -} - -static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj; - JSAtom atom; - JSObject *p; - BOOL ret; - atom = JS_ValueToAtom(ctx, argv[0]); /* must be done first */ - if (UNLIKELY(atom == JS_ATOM_NULL)) - return JS_EXCEPTION; - obj = JS_ToObject(ctx, this_val); - if (JS_IsException(obj)) { - JS_FreeAtom(ctx, atom); - return obj; - } - p = JS_VALUE_GET_OBJ(obj); - ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom); - JS_FreeAtom(ctx, atom); - JS_FreeValue(ctx, obj); - if (ret < 0) - return JS_EXCEPTION; - else - return JS_NewBool(ctx, ret); -} - -static JSValue js_object_hasOwn(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj; - JSAtom atom; - JSObject *p; - BOOL ret; - obj = JS_ToObject(ctx, argv[0]); - if (JS_IsException(obj)) - return obj; - atom = JS_ValueToAtom(ctx, argv[1]); - if (UNLIKELY(atom == JS_ATOM_NULL)) { - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - p = JS_VALUE_GET_OBJ(obj); - ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom); - JS_FreeAtom(ctx, atom); - JS_FreeValue(ctx, obj); - if (ret < 0) - return JS_EXCEPTION; - else - return JS_NewBool(ctx, ret); -} - -static JSValue js_object_valueOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_ToObject(ctx, this_val); -} - -JSValue js_object_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj, tag; - int is_array; - JSAtom atom; - JSObject *p; - if (JS_IsNull(this_val)) { - tag = JS_NewString(ctx, "Null"); - } else if (JS_IsUndefined(this_val)) { - tag = JS_NewString(ctx, "Undefined"); - } else { - obj = JS_ToObject(ctx, this_val); - if (JS_IsException(obj)) - return obj; - is_array = JS_IsArray(ctx, obj); - if (is_array < 0) { - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - if (is_array) { - atom = JS_ATOM_Array; - } else if (JS_IsFunction(ctx, obj)) { - atom = JS_ATOM_Function; - } else { - p = JS_VALUE_GET_OBJ(obj); - switch(p->class_id) { - case JS_CLASS_STRING: - case JS_CLASS_ARGUMENTS: - case JS_CLASS_MAPPED_ARGUMENTS: - case JS_CLASS_ERROR: - case JS_CLASS_BOOLEAN: - case JS_CLASS_NUMBER: - case JS_CLASS_DATE: - case JS_CLASS_REGEXP: - atom = ctx->rt->class_array[p->class_id].class_name; - break; - default: - atom = JS_ATOM_Object; - break; - } - } - tag = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_toStringTag); - JS_FreeValue(ctx, obj); - if (JS_IsException(tag)) - return JS_EXCEPTION; - if (!JS_IsString(tag)) { - JS_FreeValue(ctx, tag); - tag = JS_AtomToString(ctx, atom); - } - } - return JS_ConcatString3(ctx, "[object ", tag, "]"); -} - -static JSValue js_object_toLocaleString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_Invoke(ctx, this_val, JS_ATOM_toString, 0, NULL); -} - -static JSValue js_object_assign(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // Object.assign(obj, source1) - JSValue obj, s; - int i; - s = JS_UNDEFINED; - obj = JS_ToObject(ctx, argv[0]); - if (JS_IsException(obj)) - goto exception; - for (i = 1; i < argc; i++) { - if (!JS_IsNull(argv[i]) && !JS_IsUndefined(argv[i])) { - s = JS_ToObject(ctx, argv[i]); - if (JS_IsException(s)) - goto exception; - if (JS_CopyDataProperties(ctx, obj, s, JS_UNDEFINED, TRUE)) - goto exception; - JS_FreeValue(ctx, s); - } - } - return obj; -exception: - JS_FreeValue(ctx, obj); - JS_FreeValue(ctx, s); - return JS_EXCEPTION; -} - -JSValue js_object_seal(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int freeze_flag) -{ - JSValueConst obj = argv[0]; - JSObject *p; - JSPropertyEnum *props; - uint32_t len, i; - int flags, desc_flags, res; - if (!JS_IsObject(obj)) - return JS_DupValue(ctx, obj); - res = JS_PreventExtensions(ctx, obj); - if (res < 0) - return JS_EXCEPTION; - if (!res) { - return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false"); - } - p = JS_VALUE_GET_OBJ(obj); - flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK; - if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags)) - return JS_EXCEPTION; - for(i = 0; i < len; i++) { - JSPropertyDescriptor desc; - JSAtom prop = props[i].atom; - desc_flags = JS_PROP_THROW | JS_PROP_HAS_CONFIGURABLE; - if (freeze_flag) { - res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop); - if (res < 0) - goto exception; - if (res) { - if (desc.flags & JS_PROP_WRITABLE) - desc_flags |= JS_PROP_HAS_WRITABLE; - js_free_desc(ctx, &desc); - } - } - if (JS_DefineProperty(ctx, obj, prop, JS_UNDEFINED, - JS_UNDEFINED, JS_UNDEFINED, desc_flags) < 0) - goto exception; - } - js_free_prop_enum(ctx, props, len); - return JS_DupValue(ctx, obj); - exception: - js_free_prop_enum(ctx, props, len); - return JS_EXCEPTION; -} - -static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int is_frozen) -{ - JSValueConst obj = argv[0]; - JSObject *p; - JSPropertyEnum *props; - uint32_t len, i; - int flags, res; - if (!JS_IsObject(obj)) - return JS_TRUE; - p = JS_VALUE_GET_OBJ(obj); - flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK; - if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags)) - return JS_EXCEPTION; - for(i = 0; i < len; i++) { - JSPropertyDescriptor desc; - JSAtom prop = props[i].atom; - res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop); - if (res < 0) - goto exception; - if (res) { - js_free_desc(ctx, &desc); - if ((desc.flags & JS_PROP_CONFIGURABLE) - || (is_frozen && (desc.flags & JS_PROP_WRITABLE))) { - res = FALSE; - goto done; - } - } - } - res = JS_IsExtensible(ctx, obj); - if (res < 0) - return JS_EXCEPTION; - res ^= 1; -done: - js_free_prop_enum(ctx, props, len); - return JS_NewBool(ctx, res); -exception: - js_free_prop_enum(ctx, props, len); - return JS_EXCEPTION; -} - -static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj, iter, next_method = JS_UNDEFINED; - JSValueConst iterable; - BOOL done; - /* RequireObjectCoercible() not necessary because it is tested in - JS_GetIterator() by JS_GetProperty() */ - iterable = argv[0]; - obj = JS_NewObject(ctx); - if (JS_IsException(obj)) - return obj; - iter = JS_GetIterator(ctx, iterable, FALSE); - if (JS_IsException(iter)) - goto fail; - next_method = JS_GetProperty(ctx, iter, JS_ATOM_next); - if (JS_IsException(next_method)) - goto fail; - for(;;) { - JSValue key, value, item; - item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done); - if (JS_IsException(item)) - goto fail; - if (done) { - JS_FreeValue(ctx, item); - break; - } - key = JS_UNDEFINED; - value = JS_UNDEFINED; - if (!JS_IsObject(item)) { - JS_ThrowTypeErrorNotAnObject(ctx); - goto fail1; - } - key = JS_GetPropertyUint32(ctx, item, 0); - if (JS_IsException(key)) - goto fail1; - value = JS_GetPropertyUint32(ctx, item, 1); - if (JS_IsException(value)) { - JS_FreeValue(ctx, key); - goto fail1; - } - if (JS_DefinePropertyValueValue(ctx, obj, key, value, - JS_PROP_C_W_E | JS_PROP_THROW) < 0) { - fail1: - JS_FreeValue(ctx, item); - goto fail; - } - JS_FreeValue(ctx, item); - } - JS_FreeValue(ctx, next_method); - JS_FreeValue(ctx, iter); - return obj; - fail: - if (JS_IsObject(iter)) { - /* close the iterator object, preserving pending exception */ - JS_IteratorClose(ctx, iter, TRUE); - } - JS_FreeValue(ctx, next_method); - JS_FreeValue(ctx, iter); - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -#if 0 -/* Note: corresponds to ECMA spec: CreateDataPropertyOrThrow() */ -static JSValue js_object___setOwnProperty(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int ret; - ret = JS_DefinePropertyValueValue(ctx, argv[0], JS_DupValue(ctx, argv[1]), - JS_DupValue(ctx, argv[2]), - JS_PROP_C_W_E | JS_PROP_THROW); - if (ret < 0) - return JS_EXCEPTION; - else - return JS_NewBool(ctx, ret); -} - -static JSValue js_object___toObject(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_ToObject(ctx, argv[0]); -} - -static JSValue js_object___toPrimitive(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int hint = HINT_NONE; - - if (JS_VALUE_GET_TAG(argv[1]) == JS_TAG_INT) - hint = JS_VALUE_GET_INT(argv[1]); - - return JS_ToPrimitive(ctx, argv[0], hint); -} -#endif - -/* return an empty string if not an object */ -static JSValue js_object___getClass(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSAtom atom; - JSObject *p; - uint32_t tag; - int class_id; - - tag = JS_VALUE_GET_NORM_TAG(argv[0]); - if (tag == JS_TAG_OBJECT) { - p = JS_VALUE_GET_OBJ(argv[0]); - class_id = p->class_id; - if (class_id == JS_CLASS_PROXY && JS_IsFunction(ctx, argv[0])) - class_id = JS_CLASS_BYTECODE_FUNCTION; - atom = ctx->rt->class_array[class_id].class_name; - } else { - atom = JS_ATOM_empty_string; - } - return JS_AtomToString(ctx, atom); -} - -static JSValue js_object_is(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_NewBool(ctx, js_same_value(ctx, argv[0], argv[1])); -} - -#if 0 -static JSValue js_object___getObjectData(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_GetObjectData(ctx, argv[0]); -} - -static JSValue js_object___setObjectData(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - if (JS_SetObjectData(ctx, argv[0], JS_DupValue(ctx, argv[1]))) - return JS_EXCEPTION; - return JS_DupValue(ctx, argv[1]); -} - -static JSValue js_object___toPropertyKey(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_ToPropertyKey(ctx, argv[0]); -} - -static JSValue js_object___isObject(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_NewBool(ctx, JS_IsObject(argv[0])); -} - -static JSValue js_object___isSameValueZero(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_NewBool(ctx, js_same_value_zero(ctx, argv[0], argv[1])); -} - -static JSValue js_object___isConstructor(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_NewBool(ctx, JS_IsConstructor(ctx, argv[0])); -} -#endif - -JSValue JS_SpeciesConstructor(JSContext *ctx, JSValueConst obj, JSValueConst defaultConstructor) -{ - JSValue ctor, species; - if (!JS_IsObject(obj)) - return JS_ThrowTypeErrorNotAnObject(ctx); - ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor); - if (JS_IsException(ctor)) - return ctor; - if (JS_IsUndefined(ctor)) - return JS_DupValue(ctx, defaultConstructor); - if (!JS_IsObject(ctor)) { - JS_FreeValue(ctx, ctor); - return JS_ThrowTypeErrorNotAnObject(ctx); - } - species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species); - JS_FreeValue(ctx, ctor); - if (JS_IsException(species)) - return species; - if (JS_IsUndefined(species) || JS_IsNull(species)) - return JS_DupValue(ctx, defaultConstructor); - if (!JS_IsConstructor(ctx, species)) { - JS_FreeValue(ctx, species); - return JS_ThrowTypeError(ctx, "not a constructor"); - } - return species; -} - -#if 0 -static JSValue js_object___speciesConstructor(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_SpeciesConstructor(ctx, argv[0], argv[1]); -} -#endif - -static JSValue js_object_get___proto__(JSContext *ctx, JSValueConst this_val) -{ - JSValue val, ret; - val = JS_ToObject(ctx, this_val); - if (JS_IsException(val)) - return val; - ret = JS_GetPrototype(ctx, val); - JS_FreeValue(ctx, val); - return ret; -} - -static JSValue js_object_set___proto__(JSContext *ctx, JSValueConst this_val, - JSValueConst proto) -{ - if (JS_IsUndefined(this_val) || JS_IsNull(this_val)) - return JS_ThrowTypeErrorNotAnObject(ctx); - if (!JS_IsObject(proto) && !JS_IsNull(proto)) - return JS_UNDEFINED; - if (JS_SetPrototypeInternal(ctx, this_val, proto, TRUE) < 0) - return JS_EXCEPTION; - else - return JS_UNDEFINED; -} - -static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj, v1; - JSValueConst v; - int res; - v = argv[0]; - if (!JS_IsObject(v)) - return JS_FALSE; - obj = JS_ToObject(ctx, this_val); - if (JS_IsException(obj)) - return JS_EXCEPTION; - v1 = JS_DupValue(ctx, v); - for(;;) { - v1 = JS_GetPrototypeFree(ctx, v1); - if (JS_IsException(v1)) - goto exception; - if (JS_IsNull(v1)) { - res = FALSE; - break; - } - if (JS_VALUE_GET_OBJ(obj) == JS_VALUE_GET_OBJ(v1)) { - res = TRUE; - break; - } - /* avoid infinite loop (possible with proxies) */ - if (js_poll_interrupts(ctx)) - goto exception; - } - JS_FreeValue(ctx, v1); - JS_FreeValue(ctx, obj); - return JS_NewBool(ctx, res); -exception: - JS_FreeValue(ctx, v1); - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue js_object_propertyIsEnumerable(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj, res = JS_EXCEPTION; - JSAtom prop = JS_ATOM_NULL; - JSPropertyDescriptor desc; - int has_prop; - obj = JS_ToObject(ctx, this_val); - if (JS_IsException(obj)) - goto exception; - prop = JS_ValueToAtom(ctx, argv[0]); - if (UNLIKELY(prop == JS_ATOM_NULL)) - goto exception; - has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop); - if (has_prop < 0) - goto exception; - if (has_prop) { - res = JS_NewBool(ctx, (desc.flags & JS_PROP_ENUMERABLE) != 0); - js_free_desc(ctx, &desc); - } else { - res = JS_FALSE; - } -exception: - JS_FreeAtom(ctx, prop); - JS_FreeValue(ctx, obj); - return res; -} - -static JSValue js_object___lookupGetter__(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int setter) -{ - JSValue obj, res = JS_EXCEPTION; - JSAtom prop = JS_ATOM_NULL; - JSPropertyDescriptor desc; - int has_prop; - obj = JS_ToObject(ctx, this_val); - if (JS_IsException(obj)) - goto exception; - prop = JS_ValueToAtom(ctx, argv[0]); - if (UNLIKELY(prop == JS_ATOM_NULL)) - goto exception; - for (;;) { - has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop); - if (has_prop < 0) - goto exception; - if (has_prop) { - if (desc.flags & JS_PROP_GETSET) - res = JS_DupValue(ctx, setter ? desc.setter : desc.getter); - else - res = JS_UNDEFINED; - js_free_desc(ctx, &desc); - break; - } - obj = JS_GetPrototypeFree(ctx, obj); - if (JS_IsException(obj)) - goto exception; - if (JS_IsNull(obj)) { - res = JS_UNDEFINED; - break; - } - /* avoid infinite loop (possible with proxies) */ - if (js_poll_interrupts(ctx)) - goto exception; - } -exception: - JS_FreeAtom(ctx, prop); - JS_FreeValue(ctx, obj); - return res; -} - -static const JSCFunctionListEntry js_object_funcs[] = { - JS_CFUNC_DEF("create", 2, js_object_create ), - JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 0 ), - JS_CFUNC_DEF("setPrototypeOf", 2, js_object_setPrototypeOf ), - JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 0 ), - JS_CFUNC_DEF("defineProperties", 2, js_object_defineProperties ), - JS_CFUNC_DEF("getOwnPropertyNames", 1, js_object_getOwnPropertyNames ), - JS_CFUNC_DEF("getOwnPropertySymbols", 1, js_object_getOwnPropertySymbols ), - JS_CFUNC_MAGIC_DEF("keys", 1, js_object_keys, JS_ITERATOR_KIND_KEY ), - JS_CFUNC_MAGIC_DEF("values", 1, js_object_keys, JS_ITERATOR_KIND_VALUE ), - JS_CFUNC_MAGIC_DEF("entries", 1, js_object_keys, JS_ITERATOR_KIND_KEY_AND_VALUE ), - JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 0 ), - JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 0 ), - JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 0 ), - JS_CFUNC_DEF("getOwnPropertyDescriptors", 1, js_object_getOwnPropertyDescriptors ), - JS_CFUNC_DEF("is", 2, js_object_is ), - JS_CFUNC_DEF("assign", 2, js_object_assign ), - JS_CFUNC_MAGIC_DEF("seal", 1, js_object_seal, 0 ), - JS_CFUNC_MAGIC_DEF("freeze", 1, js_object_seal, 1 ), - JS_CFUNC_MAGIC_DEF("isSealed", 1, js_object_isSealed, 0 ), - JS_CFUNC_MAGIC_DEF("isFrozen", 1, js_object_isSealed, 1 ), - JS_CFUNC_DEF("__getClass", 1, js_object___getClass ), - //JS_CFUNC_DEF("__isObject", 1, js_object___isObject ), - //JS_CFUNC_DEF("__isConstructor", 1, js_object___isConstructor ), - //JS_CFUNC_DEF("__toObject", 1, js_object___toObject ), - //JS_CFUNC_DEF("__setOwnProperty", 3, js_object___setOwnProperty ), - //JS_CFUNC_DEF("__toPrimitive", 2, js_object___toPrimitive ), - //JS_CFUNC_DEF("__toPropertyKey", 1, js_object___toPropertyKey ), - //JS_CFUNC_DEF("__speciesConstructor", 2, js_object___speciesConstructor ), - //JS_CFUNC_DEF("__isSameValueZero", 2, js_object___isSameValueZero ), - //JS_CFUNC_DEF("__getObjectData", 1, js_object___getObjectData ), - //JS_CFUNC_DEF("__setObjectData", 2, js_object___setObjectData ), - JS_CFUNC_DEF("fromEntries", 1, js_object_fromEntries ), - JS_CFUNC_DEF("hasOwn", 2, js_object_hasOwn ), -}; - -static const JSCFunctionListEntry js_object_proto_funcs[] = { - JS_CFUNC_DEF("toString", 0, js_object_toString ), - JS_CFUNC_DEF("toLocaleString", 0, js_object_toLocaleString ), - JS_CFUNC_DEF("valueOf", 0, js_object_valueOf ), - JS_CFUNC_DEF("hasOwnProperty", 1, js_object_hasOwnProperty ), - JS_CFUNC_DEF("isPrototypeOf", 1, js_object_isPrototypeOf ), - JS_CFUNC_DEF("propertyIsEnumerable", 1, js_object_propertyIsEnumerable ), - JS_CGETSET_DEF("__proto__", js_object_get___proto__, js_object_set___proto__ ), - JS_CFUNC_MAGIC_DEF("__defineGetter__", 2, js_object___defineGetter__, 0 ), - JS_CFUNC_MAGIC_DEF("__defineSetter__", 2, js_object___defineGetter__, 1 ), - JS_CFUNC_MAGIC_DEF("__lookupGetter__", 1, js_object___lookupGetter__, 0 ), - JS_CFUNC_MAGIC_DEF("__lookupSetter__", 1, js_object___lookupGetter__, 1 ), -}; - -void JS_AddIntrinsicObject(JSContext *ctx) { - JSValueConst obj; - obj = JS_NewGlobalCConstructor(ctx, "Object", js_object_constructor, 1, - ctx->class_proto[JS_CLASS_OBJECT]); - JS_SetPropertyFunctionList(ctx, obj, js_object_funcs, countof(js_object_funcs)); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_OBJECT], - js_object_proto_funcs, countof(js_object_proto_funcs)); -} diff --git a/third_party/quickjs/parse.c b/third_party/quickjs/parse.c deleted file mode 100644 index 105d8633c..000000000 --- a/third_party/quickjs/parse.c +++ /dev/null @@ -1,6148 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/assert.h" -#include "libc/runtime/runtime.h" -#include "libc/str/str.h" -#include "third_party/quickjs/internal.h" -#include "third_party/quickjs/libregexp.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -static __exception int js_parse_assign_expr(JSParseState *); -static __exception int js_parse_assign_expr2(JSParseState *, int); -static __exception int js_parse_expr(JSParseState *); -static __exception int js_parse_function_decl(JSParseState *, JSParseFunctionEnum, JSFunctionKindEnum, JSAtom, const uint8_t *, int); -static __exception int js_parse_function_decl2(JSParseState *, JSParseFunctionEnum, JSFunctionKindEnum, JSAtom, const uint8_t *, int, JSParseExportEnum, JSFunctionDef **); -static __exception int js_parse_postfix_expr(JSParseState *, int); -static __exception int js_parse_unary(JSParseState *, int); - -void js_parse_init(JSContext *ctx, JSParseState *s, - const char *input, size_t input_len, - const char *filename) -{ - bzero(s, sizeof(*s)); - s->ctx = ctx; - s->filename = filename; - s->line_num = 1; - s->buf_ptr = (const uint8_t *)input; - s->buf_end = s->buf_ptr + input_len; - s->token.val = ' '; - s->token.line_num = 1; -} - -/* Note: all the fields are already sealed except length */ -static int seal_template_obj(JSContext *ctx, JSValueConst obj) -{ - JSObject *p; - JSShapeProperty *prs; - p = JS_VALUE_GET_OBJ(obj); - prs = find_own_property1(p, JS_ATOM_length); - if (prs) { - if (js_update_property_flags(ctx, p, &prs, - prs->flags & ~(JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE))) - return -1; - } - p->extensible = FALSE; - return 0; -} - -static __exception int emit_push_const(JSParseState *s, JSValueConst val, - BOOL as_atom) -{ - int idx; - if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING && as_atom) { - JSAtom atom; - /* warning: JS_NewAtomStr frees the string value */ - JS_DupValue(s->ctx, val); - atom = JS_NewAtomStr(s->ctx, JS_VALUE_GET_STRING(val)); - if (atom != JS_ATOM_NULL && !__JS_AtomIsTaggedInt(atom)) { - emit_op(s, OP_push_atom_value); - emit_u32(s, atom); - return 0; - } - } - idx = cpool_add(s, JS_DupValue(s->ctx, val)); - if (idx < 0) - return -1; - emit_op(s, OP_push_const); - emit_u32(s, idx); - return 0; -} - -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; -} - -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; - /* XXX: need a specific JSON case to avoid - accepting invalid escapes */ - switch(c) { - case '\0': - if (p >= s->buf_end) - goto invalid_char; - p++; - break; - case '\'': - case '\"': - case '\\': - p++; - break; - case '\r': /* accept DOS and MAC newline sequences */ - if (p[1] == '\n') { - p++; - } - /* fall thru */ - case '\n': - /* ignore escaped newline sequence */ - p++; - if (sep != '`') - s->line_num++; - continue; - default: - if (c >= '0' && c <= '9') { - if (!s->cur_func) - goto invalid_escape; /* 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 { - if (c >= '8' || sep == '`') { - /* Note: according to ES2021, \8 and \9 are not - accepted in strict mode or in templates. */ - goto invalid_escape; - } else { - if (do_throw) - js_parse_error(s, "octal escape sequences are not allowed in strict mode"); - } - goto fail; - } - } else if (c >= 0x80) { - const uint8_t *p_next; - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next); - if (c > 0x10FFFF) { - goto invalid_utf8; - } - p = p_next; - /* LS or PS are skipped */ - if (c == CP_LS || c == CP_PS) - continue; - } else { - parse_escape: - ret = lre_parse_escape(&p, TRUE); - if (ret == -1) { - invalid_escape: - if (do_throw) - js_parse_error(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; -} - -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 __exception int js_parse_statement_or_decl(JSParseState *s, - int decl_mask); - -static __exception int js_parse_statement(JSParseState *s) -{ - return js_parse_statement_or_decl(s, 0); -} - -static int get_first_lexical_var(JSFunctionDef *fd, int scope) -{ - while (scope >= 0) { - int scope_idx = fd->scopes[scope].first; - if (scope_idx >= 0) - return scope_idx; - scope = fd->scopes[scope].parent; - } - return -1; -} - -static void pop_scope(JSParseState *s) { - if (s->cur_func) { - /* disable scoped variables */ - JSFunctionDef *fd = s->cur_func; - int scope = fd->scope_level; - emit_op(s, OP_leave_scope); - emit_u16(s, scope); - fd->scope_level = fd->scopes[scope].parent; - fd->scope_first = get_first_lexical_var(fd, fd->scope_level); - } -} - -static __exception int js_parse_block(JSParseState *s) -{ - if (js_parse_expect(s, '{')) - return -1; - if (s->token.val != '}') { - push_scope(s); - for(;;) { - if (js_parse_statement_or_decl(s, DECL_MASK_ALL)) - return -1; - if (s->token.val == '}') - break; - } - pop_scope(s); - } - if (next_token(s)) - return -1; - return 0; -} - -static __exception int js_parse_template(JSParseState *s, int call, int *argc) -{ - JSContext *ctx = s->ctx; - JSValue raw_array, template_object; - JSToken cooked; - int depth, ret; - raw_array = JS_UNDEFINED; /* avoid warning */ - template_object = JS_UNDEFINED; /* avoid warning */ - if (call) { - /* Create a template object: an array of cooked strings */ - /* Create an array of raw strings and store it to the raw property */ - template_object = JS_NewArray(ctx); - if (JS_IsException(template_object)) - return -1; - // pool_idx = s->cur_func->cpool_count; - ret = emit_push_const(s, template_object, 0); - JS_FreeValue(ctx, template_object); - if (ret) - return -1; - raw_array = JS_NewArray(ctx); - if (JS_IsException(raw_array)) - return -1; - if (JS_DefinePropertyValue(ctx, template_object, JS_ATOM_raw, - raw_array, JS_PROP_THROW) < 0) { - return -1; - } - } - depth = 0; - while (s->token.val == TOK_TEMPLATE) { - const uint8_t *p = s->token.ptr + 1; - cooked = s->token; - if (call) { - if (JS_DefinePropertyValueUint32(ctx, raw_array, depth, - JS_DupValue(ctx, s->token.u.str.str), - JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) { - return -1; - } - /* re-parse the string with escape sequences but do not throw a - syntax error if it contains invalid sequences - */ - if (js_parse_string(s, '`', FALSE, p, &cooked, &p)) { - cooked.u.str.str = JS_UNDEFINED; - } - if (JS_DefinePropertyValueUint32(ctx, template_object, depth, - cooked.u.str.str, - JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) { - return -1; - } - } else { - JSString *str; - /* re-parse the string with escape sequences and throw a - syntax error if it contains invalid sequences - */ - JS_FreeValue(ctx, s->token.u.str.str); - s->token.u.str.str = JS_UNDEFINED; - if (js_parse_string(s, '`', TRUE, p, &cooked, &p)) - return -1; - str = JS_VALUE_GET_STRING(cooked.u.str.str); - if (str->len != 0 || depth == 0) { - ret = emit_push_const(s, cooked.u.str.str, 1); - JS_FreeValue(s->ctx, cooked.u.str.str); - if (ret) - return -1; - if (depth == 0) { - if (s->token.u.str.sep == '`') - goto done1; - emit_op(s, OP_get_field2); - emit_atom(s, JS_ATOM_concat); - } - depth++; - } else { - JS_FreeValue(s->ctx, cooked.u.str.str); - } - } - if (s->token.u.str.sep == '`') - goto done; - if (next_token(s)) - return -1; - if (js_parse_expr(s)) - return -1; - depth++; - if (s->token.val != '}') { - return js_parse_error(s, "expected '}' after template expression"); - } - /* XXX: should convert to string at this stage? */ - free_token(s, &s->token); - /* Resume TOK_TEMPLATE parsing (s->token.line_num and - * s->token.ptr are OK) */ - s->got_lf = FALSE; - s->last_line_num = s->token.line_num; - if (js_parse_template_part(s, s->buf_ptr)) - return -1; - } - return js_parse_expect(s, TOK_TEMPLATE); - done: - if (call) { - /* Seal the objects */ - seal_template_obj(ctx, raw_array); - seal_template_obj(ctx, template_object); - *argc = depth + 1; - } else { - emit_op(s, OP_call_method); - emit_u16(s, depth - 1); - } - done1: - return next_token(s); -} - -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 int js_parse_get_pos(JSParseState *s, JSParsePos *sp) -{ - sp->last_line_num = s->last_line_num; - sp->line_num = s->token.line_num; - sp->ptr = s->token.ptr; - sp->got_lf = s->got_lf; - return 0; -} - -static __exception int js_parse_seek_token(JSParseState *s, const JSParsePos *sp) -{ - s->token.line_num = sp->last_line_num; - s->line_num = sp->line_num; - s->buf_ptr = sp->ptr; - s->got_lf = sp->got_lf; - return next_token(s); -} - -/* test if the current token is a let keyword. Use simplistic look-ahead scanner */ -static int is_let(JSParseState *s, int decl_mask) -{ - int res = FALSE; - if (token_is_pseudo_keyword(s, JS_ATOM_let)) { -#if 1 - JSParsePos pos; - js_parse_get_pos(s, &pos); - for (;;) { - if (next_token(s)) { - res = -1; - break; - } - if (s->token.val == '[') { - /* let [ is a syntax restriction: - it never introduces an ExpressionStatement */ - res = TRUE; - break; - } - if (s->token.val == '{' || - (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved) || - s->token.val == TOK_LET || - s->token.val == TOK_YIELD || - s->token.val == TOK_AWAIT) { - /* Check for possible ASI if not scanning for Declaration */ - /* XXX: should also check that `{` introduces a BindingPattern, - but Firefox does not and rejects eval("let=1;let\n{if(1)2;}") */ - if (s->last_line_num == s->token.line_num || (decl_mask & DECL_MASK_OTHER)) { - res = TRUE; - break; - } - break; - } - break; - } - if (js_parse_seek_token(s, &pos)) { - res = -1; - } -#else - int tok = peek_token(s, TRUE); - if (tok == '{' || tok == TOK_IDENT || peek_token(s, FALSE) == '[') { - res = TRUE; - } -#endif - } - return res; -} - -static int peek_token(JSParseState *s, BOOL no_line_terminator) -{ - const uint8_t *p = s->buf_ptr; - return simple_next_token(&p, no_line_terminator); -} - -/* test if the current token is a label. Use simplistic look-ahead scanner */ -static BOOL is_label(JSParseState *s) -{ - return (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved && - peek_token(s, FALSE) == ':'); -} - -static BOOL token_is_ident(int tok) -{ - /* Accept keywords and reserved words as property names */ - return (tok == TOK_IDENT || - (tok >= TOK_FIRST_KEYWORD && - tok <= TOK_LAST_KEYWORD)); -} - -/* if the property is an expression, name = JS_ATOM_NULL */ -static int __exception js_parse_property_name(JSParseState *s, - JSAtom *pname, - BOOL allow_method, BOOL allow_var, - BOOL allow_private) -{ - int is_private = 0; - BOOL is_non_reserved_ident; - JSAtom name; - int prop_type; - prop_type = PROP_TYPE_IDENT; - if (allow_method) { - if (token_is_pseudo_keyword(s, JS_ATOM_get) - || token_is_pseudo_keyword(s, JS_ATOM_set)) { - /* get x(), set x() */ - name = JS_DupAtom(s->ctx, s->token.u.ident.atom); - if (next_token(s)) - goto fail1; - if (s->token.val == ':' || s->token.val == ',' || - s->token.val == '}' || s->token.val == '(') { - is_non_reserved_ident = TRUE; - goto ident_found; - } - prop_type = PROP_TYPE_GET + (name == JS_ATOM_set); - JS_FreeAtom(s->ctx, name); - } else if (s->token.val == '*') { - if (next_token(s)) - goto fail; - prop_type = PROP_TYPE_STAR; - } else if (token_is_pseudo_keyword(s, JS_ATOM_async) && - peek_token(s, TRUE) != '\n') { - name = JS_DupAtom(s->ctx, s->token.u.ident.atom); - if (next_token(s)) - goto fail1; - if (s->token.val == ':' || s->token.val == ',' || - s->token.val == '}' || s->token.val == '(') { - is_non_reserved_ident = TRUE; - goto ident_found; - } - JS_FreeAtom(s->ctx, name); - if (s->token.val == '*') { - if (next_token(s)) - goto fail; - prop_type = PROP_TYPE_ASYNC_STAR; - } else { - prop_type = PROP_TYPE_ASYNC; - } - } - } - if (token_is_ident(s->token.val)) { - /* variable can only be a non-reserved identifier */ - is_non_reserved_ident = - (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved); - /* keywords and reserved words have a valid atom */ - name = JS_DupAtom(s->ctx, s->token.u.ident.atom); - if (next_token(s)) - goto fail1; - ident_found: - if (is_non_reserved_ident && - prop_type == PROP_TYPE_IDENT && allow_var) { - if (!(s->token.val == ':' || - (s->token.val == '(' && allow_method))) { - prop_type = PROP_TYPE_VAR; - } - } - } else if (s->token.val == TOK_STRING) { - name = JS_ValueToAtom(s->ctx, s->token.u.str.str); - if (name == JS_ATOM_NULL) - goto fail; - if (next_token(s)) - goto fail1; - } else if (s->token.val == TOK_NUMBER) { - JSValue val; - val = s->token.u.num.val; -#ifdef CONFIG_BIGNUM - if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - val = s->ctx->rt->bigfloat_ops. - mul_pow10_to_float64(s->ctx, &p->num, - s->token.u.num.exponent); - if (JS_IsException(val)) - goto fail; - name = JS_ValueToAtom(s->ctx, val); - JS_FreeValue(s->ctx, val); - } else -#endif - { - name = JS_ValueToAtom(s->ctx, val); - } - if (name == JS_ATOM_NULL) - goto fail; - if (next_token(s)) - goto fail1; - } else if (s->token.val == '[') { - if (next_token(s)) - goto fail; - if (js_parse_expr(s)) - goto fail; - if (js_parse_expect(s, ']')) - goto fail; - name = JS_ATOM_NULL; - } else if (s->token.val == TOK_PRIVATE_NAME && allow_private) { - name = JS_DupAtom(s->ctx, s->token.u.ident.atom); - if (next_token(s)) - goto fail1; - is_private = PROP_TYPE_PRIVATE; - } else { - goto invalid_prop; - } - if (prop_type != PROP_TYPE_IDENT && prop_type != PROP_TYPE_VAR && - s->token.val != '(') { - JS_FreeAtom(s->ctx, name); - invalid_prop: - js_parse_error(s, "invalid property name"); - goto fail; - } - *pname = name; - return prop_type | is_private; - fail1: - JS_FreeAtom(s->ctx, name); - fail: - *pname = JS_ATOM_NULL; - return -1; -} - -static void set_object_name_computed(JSParseState *s) -{ - JSFunctionDef *fd = s->cur_func; - int opcode; - opcode = get_prev_opcode(fd); - if (opcode == OP_set_name) { - /* XXX: should free atom after OP_set_name? */ - fd->byte_code.size = fd->last_opcode_pos; - fd->last_opcode_pos = -1; - emit_op(s, OP_set_name_computed); - } else if (opcode == OP_set_class_name) { - int define_class_pos; - define_class_pos = fd->last_opcode_pos + 1 - - get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1); - assert(fd->byte_code.buf[define_class_pos] == OP_define_class); - fd->byte_code.buf[define_class_pos] = OP_define_class_computed; - fd->last_opcode_pos = -1; - } -} - -static void set_object_name(JSParseState *s, JSAtom name) -{ - JSFunctionDef *fd = s->cur_func; - int opcode; - opcode = get_prev_opcode(fd); - if (opcode == OP_set_name) { - /* XXX: should free atom after OP_set_name? */ - fd->byte_code.size = fd->last_opcode_pos; - fd->last_opcode_pos = -1; - emit_op(s, OP_set_name); - emit_atom(s, name); - } else if (opcode == OP_set_class_name) { - int define_class_pos; - JSAtom atom; - define_class_pos = fd->last_opcode_pos + 1 - - get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1); - assert(fd->byte_code.buf[define_class_pos] == OP_define_class); - /* for consistency we free the previous atom which is - JS_ATOM_empty_string */ - atom = get_u32(fd->byte_code.buf + define_class_pos + 1); - JS_FreeAtom(s->ctx, atom); - put_u32(fd->byte_code.buf + define_class_pos + 1, - JS_DupAtom(s->ctx, name)); - fd->last_opcode_pos = -1; - } -} - -static __exception int js_parse_object_literal(JSParseState *s) -{ - JSAtom name = JS_ATOM_NULL; - const uint8_t *start_ptr; - int start_line, prop_type; - BOOL has_proto; - if (next_token(s)) - goto fail; - /* XXX: add an initial length that will be patched back */ - emit_op(s, OP_object); - has_proto = FALSE; - while (s->token.val != '}') { - /* specific case for getter/setter */ - start_ptr = s->token.ptr; - start_line = s->token.line_num; - if (s->token.val == TOK_ELLIPSIS) { - if (next_token(s)) - return -1; - if (js_parse_assign_expr(s)) - return -1; - emit_op(s, OP_null); /* dummy excludeList */ - emit_op(s, OP_copy_data_properties); - emit_u8(s, 2 | (1 << 2) | (0 << 5)); - emit_op(s, OP_drop); /* pop excludeList */ - emit_op(s, OP_drop); /* pop src object */ - goto next; - } - prop_type = js_parse_property_name(s, &name, TRUE, TRUE, FALSE); - if (prop_type < 0) - goto fail; - if (prop_type == PROP_TYPE_VAR) { - /* shortcut for x: x */ - emit_op(s, OP_scope_get_var); - emit_atom(s, name); - emit_u16(s, s->cur_func->scope_level); - emit_op(s, OP_define_field); - emit_atom(s, name); - } else if (s->token.val == '(') { - BOOL is_getset = (prop_type == PROP_TYPE_GET || - prop_type == PROP_TYPE_SET); - JSParseFunctionEnum func_type; - JSFunctionKindEnum func_kind; - int op_flags; - func_kind = JS_FUNC_NORMAL; - if (is_getset) { - func_type = JS_PARSE_FUNC_GETTER + prop_type - PROP_TYPE_GET; - } else { - func_type = JS_PARSE_FUNC_METHOD; - if (prop_type == PROP_TYPE_STAR) - func_kind = JS_FUNC_GENERATOR; - else if (prop_type == PROP_TYPE_ASYNC) - func_kind = JS_FUNC_ASYNC; - else if (prop_type == PROP_TYPE_ASYNC_STAR) - func_kind = JS_FUNC_ASYNC_GENERATOR; - } - if (js_parse_function_decl(s, func_type, func_kind, JS_ATOM_NULL, - start_ptr, start_line)) - goto fail; - if (name == JS_ATOM_NULL) { - emit_op(s, OP_define_method_computed); - } else { - emit_op(s, OP_define_method); - emit_atom(s, name); - } - if (is_getset) { - op_flags = OP_DEFINE_METHOD_GETTER + - prop_type - PROP_TYPE_GET; - } else { - op_flags = OP_DEFINE_METHOD_METHOD; - } - emit_u8(s, op_flags | OP_DEFINE_METHOD_ENUMERABLE); - } else { - if (js_parse_expect(s, ':')) - goto fail; - if (js_parse_assign_expr(s)) - goto fail; - if (name == JS_ATOM_NULL) { - set_object_name_computed(s); - emit_op(s, OP_define_array_el); - emit_op(s, OP_drop); - } else if (name == JS_ATOM___proto__) { - if (has_proto) { - js_parse_error(s, "duplicate __proto__ property name"); - goto fail; - } - emit_op(s, OP_set_proto); - has_proto = TRUE; - } else { - set_object_name(s, name); - emit_op(s, OP_define_field); - emit_atom(s, name); - } - } - JS_FreeAtom(s->ctx, name); - next: - name = JS_ATOM_NULL; - if (s->token.val != ',') - break; - if (next_token(s)) - goto fail; - } - if (js_parse_expect(s, '}')) - goto fail; - return 0; - fail: - JS_FreeAtom(s->ctx, name); - return -1; -} - -/* return TRUE if a regexp literal is allowed after this token */ -static BOOL is_regexp_allowed(int tok) -{ - switch (tok) { - case TOK_NUMBER: - case TOK_STRING: - case TOK_REGEXP: - case TOK_DEC: - case TOK_INC: - case TOK_NULL: - case TOK_FALSE: - case TOK_TRUE: - case TOK_THIS: - case ')': - case ']': - case '}': /* XXX: regexp may occur after */ - case TOK_IDENT: - return FALSE; - default: - return TRUE; - } -} - -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; -} - -/* XXX: improve speed with early bailout */ -/* XXX: no longer works if regexps are present. Could use previous - regexp parsing heuristics to handle most cases */ -static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_terminator) -{ - char state[256]; - size_t level = 0; - JSParsePos pos; - int last_tok, tok = TOK_EOF; - int c, tok_len, bits = 0; - /* protect from underflow */ - state[level++] = 0; - js_parse_get_pos(s, &pos); - last_tok = 0; - for (;;) { - switch(s->token.val) { - case '(': - case '[': - case '{': - if (level >= sizeof(state)) - goto done; - state[level++] = s->token.val; - break; - case ')': - if (state[--level] != '(') - goto done; - break; - case ']': - if (state[--level] != '[') - goto done; - break; - case '}': - c = state[--level]; - if (c == '`') { - /* continue the parsing of the template */ - free_token(s, &s->token); - /* Resume TOK_TEMPLATE parsing (s->token.line_num and - * s->token.ptr are OK) */ - s->got_lf = FALSE; - s->last_line_num = s->token.line_num; - if (js_parse_template_part(s, s->buf_ptr)) - goto done; - goto handle_template; - } else if (c != '{') { - goto done; - } - break; - case TOK_TEMPLATE: - handle_template: - if (s->token.u.str.sep != '`') { - /* '${' inside the template : closing '}' and continue - parsing the template */ - if (level >= sizeof(state)) - goto done; - state[level++] = '`'; - } - break; - case TOK_EOF: - goto done; - case ';': - if (level == 2) { - bits |= SKIP_HAS_SEMI; - } - break; - case TOK_ELLIPSIS: - if (level == 2) { - bits |= SKIP_HAS_ELLIPSIS; - } - break; - case '=': - bits |= SKIP_HAS_ASSIGNMENT; - break; - case TOK_DIV_ASSIGN: - tok_len = 2; - goto parse_regexp; - case '/': - tok_len = 1; - parse_regexp: - if (is_regexp_allowed(last_tok)) { - s->buf_ptr -= tok_len; - if (js_parse_regexp(s)) { - /* XXX: should clear the exception */ - goto done; - } - } - break; - } - /* last_tok is only used to recognize regexps */ - if (s->token.val == TOK_IDENT && - (token_is_pseudo_keyword(s, JS_ATOM_of) || - token_is_pseudo_keyword(s, JS_ATOM_yield))) { - last_tok = TOK_OF; - } else { - last_tok = s->token.val; - } - if (next_token(s)) { - /* XXX: should clear the exception generated by next_token() */ - break; - } - if (level <= 1) { - tok = s->token.val; - if (token_is_pseudo_keyword(s, JS_ATOM_of)) - tok = TOK_OF; - if (no_line_terminator && s->last_line_num != s->token.line_num) - tok = '\n'; - break; - } - } - done: - if (pbits) { - *pbits = bits; - } - if (js_parse_seek_token(s, &pos)) - return -1; - return tok; -} - - -static int js_parse_check_duplicate_parameter(JSParseState *s, JSAtom name) -{ - /* Check for duplicate parameter names */ - JSFunctionDef *fd = s->cur_func; - int i; - for (i = 0; i < fd->arg_count; i++) { - if (fd->args[i].var_name == name) - goto duplicate; - } - for (i = 0; i < fd->var_count; i++) { - if (fd->vars[i].var_name == name) - goto duplicate; - } - return 0; -duplicate: - return js_parse_error(s, "duplicate parameter names not allowed in this context"); -} - -static JSAtom js_parse_destructuring_var(JSParseState *s, int tok, int is_arg) -{ - JSAtom name; - if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved) - || ((s->cur_func->js_mode & JS_MODE_STRICT) && - (s->token.u.ident.atom == JS_ATOM_eval || s->token.u.ident.atom == JS_ATOM_arguments))) { - js_parse_error(s, "invalid destructuring target"); - return JS_ATOM_NULL; - } - name = JS_DupAtom(s->ctx, s->token.u.ident.atom); - if (is_arg && js_parse_check_duplicate_parameter(s, name)) - goto fail; - if (next_token(s)) - goto fail; - return name; -fail: - JS_FreeAtom(s->ctx, name); - return JS_ATOM_NULL; -} - -static __exception int js_parse_expr_paren(JSParseState *s) -{ - if (js_parse_expect(s, '(')) - return -1; - if (js_parse_expr(s)) - return -1; - if (js_parse_expect(s, ')')) - return -1; - return 0; -} - -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_left_hand_side_expr(JSParseState *s) -{ - return js_parse_postfix_expr(s, PF_POSTFIX_CALL); -} - -/* add a private field variable in the current scope */ -static int add_private_class_field(JSParseState *s, JSFunctionDef *fd, - JSAtom name, JSVarKindEnum var_kind) -{ - JSContext *ctx = s->ctx; - JSVarDef *vd; - int idx; - idx = add_scope_var(ctx, fd, name, var_kind); - if (idx < 0) - return idx; - vd = &fd->vars[idx]; - vd->is_lexical = 1; - vd->is_const = 1; - return idx; -} - -static BOOL js_is_live_code(JSParseState *s) { - switch (get_prev_opcode(s->cur_func)) { - case OP_tail_call: - case OP_tail_call_method: - case OP_return: - case OP_return_undef: - case OP_return_async: - case OP_throw: - case OP_throw_error: - case OP_goto: -#if SHORT_OPCODES - case OP_goto8: - case OP_goto16: -#endif - case OP_ret: - return FALSE; - default: - return TRUE; - } -} - -/* return label or -1 if dead code */ -static int emit_goto(JSParseState *s, int opcode, int label) -{ - if (js_is_live_code(s)) { - if (label < 0) - label = new_label(s); - emit_op(s, opcode); - emit_u32(s, label); - s->cur_func->label_slots[label].ref_count++; - return label; - } - return -1; -} - -/* create a function to initialize class fields */ -static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s) -{ - JSFunctionDef *fd; - fd = js_new_function_def(s->ctx, s->cur_func, FALSE, FALSE, - s->filename, 0); - if (!fd) - return NULL; - fd->func_name = JS_ATOM_NULL; - fd->has_prototype = FALSE; - fd->has_home_object = TRUE; - fd->has_arguments_binding = FALSE; - fd->has_this_binding = TRUE; - fd->is_derived_class_constructor = FALSE; - fd->new_target_allowed = TRUE; - fd->super_call_allowed = FALSE; - fd->super_allowed = fd->has_home_object; - fd->arguments_allowed = FALSE; - fd->func_kind = JS_FUNC_NORMAL; - fd->func_type = JS_PARSE_FUNC_METHOD; - return fd; -} - -static __exception int emit_class_init_start(JSParseState *s, - ClassFieldsDef *cf) -{ - int label_add_brand; - cf->fields_init_fd = js_parse_function_class_fields_init(s); - if (!cf->fields_init_fd) - return -1; - s->cur_func = cf->fields_init_fd; - /* XXX: would be better to add the code only if needed, maybe in a - later pass */ - emit_op(s, OP_push_false); /* will be patched later */ - cf->brand_push_pos = cf->fields_init_fd->last_opcode_pos; - label_add_brand = emit_goto(s, OP_if_false, -1); - emit_op(s, OP_scope_get_var); - emit_atom(s, JS_ATOM_this); - emit_u16(s, 0); - emit_op(s, OP_scope_get_var); - emit_atom(s, JS_ATOM_home_object); - emit_u16(s, 0); - emit_op(s, OP_add_brand); - emit_label(s, label_add_brand); - s->cur_func = s->cur_func->parent; - return 0; -} - -static __exception int add_brand(JSParseState *s, ClassFieldsDef *cf) -{ - if (!cf->has_brand) { - /* define the brand field in 'this' of the initializer */ - if (!cf->fields_init_fd) { - if (emit_class_init_start(s, cf)) - return -1; - } - /* patch the start of the function to enable the OP_add_brand code */ - cf->fields_init_fd->byte_code.buf[cf->brand_push_pos] = OP_push_true; - cf->has_brand = TRUE; - } - return 0; -} - -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); -} - -/* XXX: could generate specific bytecode */ -static __exception int js_parse_class_default_ctor(JSParseState *s, - BOOL has_super, - JSFunctionDef **pfd) -{ - JSParsePos pos; - const char *str; - int ret, line_num; - JSParseFunctionEnum func_type; - const uint8_t *saved_buf_end; - js_parse_get_pos(s, &pos); - if (has_super) { - /* spec change: no argument evaluation */ - str = "(){super(...arguments);}"; - func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR; - } else { - str = "(){}"; - func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR; - } - line_num = s->token.line_num; - saved_buf_end = s->buf_end; - s->buf_ptr = (uint8_t *)str; - s->buf_end = (uint8_t *)(str + strlen(str)); - ret = next_token(s); - if (!ret) { - ret = js_parse_function_decl2(s, func_type, JS_FUNC_NORMAL, - JS_ATOM_NULL, (uint8_t *)str, - line_num, JS_PARSE_EXPORT_NONE, pfd); - } - s->buf_end = saved_buf_end; - ret |= js_parse_seek_token(s, &pos); - return ret; -} - -static void emit_class_init_end(JSParseState *s, ClassFieldsDef *cf) -{ - int cpool_idx; - s->cur_func = cf->fields_init_fd; - emit_op(s, OP_return_undef); - s->cur_func = s->cur_func->parent; - cpool_idx = cpool_add(s, JS_NULL); - cf->fields_init_fd->parent_cpool_idx = cpool_idx; - emit_op(s, OP_fclosure); - emit_u32(s, cpool_idx); - emit_op(s, OP_set_home_object); -} - -static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, - JSParseExportEnum export_flag) -{ - JSContext *ctx = s->ctx; - JSFunctionDef *fd = s->cur_func; - JSAtom name = JS_ATOM_NULL, class_name = JS_ATOM_NULL, class_name1; - JSAtom class_var_name = JS_ATOM_NULL; - JSFunctionDef *method_fd, *ctor_fd; - int saved_js_mode, class_name_var_idx, prop_type, ctor_cpool_offset; - int class_flags = 0, i, define_class_offset; - BOOL is_static, is_private; - const uint8_t *class_start_ptr = s->token.ptr; - const uint8_t *start_ptr; - ClassFieldsDef class_fields[2]; - /* classes are parsed and executed in strict mode */ - saved_js_mode = fd->js_mode; - fd->js_mode |= JS_MODE_STRICT; - if (next_token(s)) - goto fail; - if (s->token.val == TOK_IDENT) { - if (s->token.u.ident.is_reserved) { - js_parse_error_reserved_identifier(s); - goto fail; - } - class_name = JS_DupAtom(ctx, s->token.u.ident.atom); - if (next_token(s)) - goto fail; - } else if (!is_class_expr && export_flag != JS_PARSE_EXPORT_DEFAULT) { - js_parse_error(s, "class statement requires a name"); - goto fail; - } - if (!is_class_expr) { - if (class_name == JS_ATOM_NULL) - class_var_name = JS_ATOM__default_; /* export default */ - else - class_var_name = class_name; - class_var_name = JS_DupAtom(ctx, class_var_name); - } - push_scope(s); - if (s->token.val == TOK_EXTENDS) { - class_flags = JS_DEFINE_CLASS_HAS_HERITAGE; - if (next_token(s)) - goto fail; - if (js_parse_left_hand_side_expr(s)) - goto fail; - } else { - emit_op(s, OP_undefined); - } - /* add a 'const' definition for the class name */ - if (class_name != JS_ATOM_NULL) { - class_name_var_idx = define_var(s, fd, class_name, JS_VAR_DEF_CONST); - if (class_name_var_idx < 0) - goto fail; - } - if (js_parse_expect(s, '{')) - goto fail; - /* this scope contains the private fields */ - push_scope(s); - emit_op(s, OP_push_const); - ctor_cpool_offset = fd->byte_code.size; - emit_u32(s, 0); /* will be patched at the end of the class parsing */ - if (class_name == JS_ATOM_NULL) { - if (class_var_name != JS_ATOM_NULL) - class_name1 = JS_ATOM_default; - else - class_name1 = JS_ATOM_empty_string; - } else { - class_name1 = class_name; - } - emit_op(s, OP_define_class); - emit_atom(s, class_name1); - emit_u8(s, class_flags); - define_class_offset = fd->last_opcode_pos; - for(i = 0; i < 2; i++) { - ClassFieldsDef *cf = &class_fields[i]; - cf->fields_init_fd = NULL; - cf->computed_fields_count = 0; - cf->has_brand = FALSE; - } - ctor_fd = NULL; - while (s->token.val != '}') { - if (s->token.val == ';') { - if (next_token(s)) - goto fail; - continue; - } - is_static = (s->token.val == TOK_STATIC); - prop_type = -1; - if (is_static) { - if (next_token(s)) - goto fail; - /* allow "static" field name */ - if (s->token.val == ';' || s->token.val == '=') { - is_static = FALSE; - name = JS_DupAtom(ctx, JS_ATOM_static); - prop_type = PROP_TYPE_IDENT; - } - } - if (is_static) - emit_op(s, OP_swap); - start_ptr = s->token.ptr; - if (prop_type < 0) { - prop_type = js_parse_property_name(s, &name, TRUE, FALSE, TRUE); - if (prop_type < 0) - goto fail; - } - is_private = prop_type & PROP_TYPE_PRIVATE; - prop_type &= ~PROP_TYPE_PRIVATE; - if ((name == JS_ATOM_constructor && !is_static && - prop_type != PROP_TYPE_IDENT) || - (name == JS_ATOM_prototype && is_static) || - name == JS_ATOM_hash_constructor) { - js_parse_error(s, "invalid method name"); - goto fail; - } - if (prop_type == PROP_TYPE_GET || prop_type == PROP_TYPE_SET) { - BOOL is_set = prop_type - PROP_TYPE_GET; - JSFunctionDef *method_fd; - if (is_private) { - int idx, var_kind; - idx = find_private_class_field(ctx, fd, name, fd->scope_level); - if (idx >= 0) { - var_kind = fd->vars[idx].var_kind; - if (var_kind == JS_VAR_PRIVATE_FIELD || - var_kind == JS_VAR_PRIVATE_METHOD || - var_kind == JS_VAR_PRIVATE_GETTER_SETTER || - var_kind == (JS_VAR_PRIVATE_GETTER + is_set)) { - goto private_field_already_defined; - } - fd->vars[idx].var_kind = JS_VAR_PRIVATE_GETTER_SETTER; - } else { - if (add_private_class_field(s, fd, name, - JS_VAR_PRIVATE_GETTER + is_set) < 0) - goto fail; - } - if (add_brand(s, &class_fields[is_static]) < 0) - goto fail; - } - if (js_parse_function_decl2(s, JS_PARSE_FUNC_GETTER + is_set, - JS_FUNC_NORMAL, JS_ATOM_NULL, - start_ptr, s->token.line_num, - JS_PARSE_EXPORT_NONE, &method_fd)) - goto fail; - if (is_private) { - method_fd->need_home_object = TRUE; /* needed for brand check */ - emit_op(s, OP_set_home_object); - /* XXX: missing function name */ - emit_op(s, OP_scope_put_var_init); - if (is_set) { - JSAtom setter_name; - int ret; - setter_name = get_private_setter_name(ctx, name); - if (setter_name == JS_ATOM_NULL) - goto fail; - emit_atom(s, setter_name); - ret = add_private_class_field(s, fd, setter_name, - JS_VAR_PRIVATE_SETTER); - JS_FreeAtom(ctx, setter_name); - if (ret < 0) - goto fail; - } else { - emit_atom(s, name); - } - emit_u16(s, s->cur_func->scope_level); - } else { - if (name == JS_ATOM_NULL) { - emit_op(s, OP_define_method_computed); - } else { - emit_op(s, OP_define_method); - emit_atom(s, name); - } - emit_u8(s, OP_DEFINE_METHOD_GETTER + is_set); - } - } else if (prop_type == PROP_TYPE_IDENT && s->token.val != '(') { - ClassFieldsDef *cf = &class_fields[is_static]; - JSAtom field_var_name = JS_ATOM_NULL; - /* class field */ - /* XXX: spec: not consistent with method name checks */ - if (name == JS_ATOM_constructor || name == JS_ATOM_prototype) { - js_parse_error(s, "invalid field name"); - goto fail; - } - if (is_private) { - if (find_private_class_field(ctx, fd, name, - fd->scope_level) >= 0) { - goto private_field_already_defined; - } - if (add_private_class_field(s, fd, name, - JS_VAR_PRIVATE_FIELD) < 0) - goto fail; - emit_op(s, OP_private_symbol); - emit_atom(s, name); - emit_op(s, OP_scope_put_var_init); - emit_atom(s, name); - emit_u16(s, s->cur_func->scope_level); - } - if (!cf->fields_init_fd) { - if (emit_class_init_start(s, cf)) - goto fail; - } - if (name == JS_ATOM_NULL ) { - /* save the computed field name into a variable */ - field_var_name = js_atom_concat_num(ctx, JS_ATOM_computed_field + is_static, cf->computed_fields_count); - if (field_var_name == JS_ATOM_NULL) - goto fail; - if (define_var(s, fd, field_var_name, JS_VAR_DEF_CONST) < 0) { - JS_FreeAtom(ctx, field_var_name); - goto fail; - } - emit_op(s, OP_to_propkey); - emit_op(s, OP_scope_put_var_init); - emit_atom(s, field_var_name); - emit_u16(s, s->cur_func->scope_level); - } - s->cur_func = cf->fields_init_fd; - emit_op(s, OP_scope_get_var); - emit_atom(s, JS_ATOM_this); - emit_u16(s, 0); - if (name == JS_ATOM_NULL) { - emit_op(s, OP_scope_get_var); - emit_atom(s, field_var_name); - emit_u16(s, s->cur_func->scope_level); - cf->computed_fields_count++; - JS_FreeAtom(ctx, field_var_name); - } else if (is_private) { - emit_op(s, OP_scope_get_var); - emit_atom(s, name); - emit_u16(s, s->cur_func->scope_level); - } - if (s->token.val == '=') { - if (next_token(s)) - goto fail; - if (js_parse_assign_expr(s)) - goto fail; - } else { - emit_op(s, OP_undefined); - } - if (is_private) { - set_object_name_computed(s); - emit_op(s, OP_define_private_field); - } else if (name == JS_ATOM_NULL) { - set_object_name_computed(s); - emit_op(s, OP_define_array_el); - emit_op(s, OP_drop); - } else { - set_object_name(s, name); - emit_op(s, OP_define_field); - emit_atom(s, name); - } - s->cur_func = s->cur_func->parent; - if (js_parse_expect_semi(s)) - goto fail; - } else { - JSParseFunctionEnum func_type; - JSFunctionKindEnum func_kind; - func_type = JS_PARSE_FUNC_METHOD; - func_kind = JS_FUNC_NORMAL; - if (prop_type == PROP_TYPE_STAR) { - func_kind = JS_FUNC_GENERATOR; - } else if (prop_type == PROP_TYPE_ASYNC) { - func_kind = JS_FUNC_ASYNC; - } else if (prop_type == PROP_TYPE_ASYNC_STAR) { - func_kind = JS_FUNC_ASYNC_GENERATOR; - } else if (name == JS_ATOM_constructor && !is_static) { - if (ctor_fd) { - js_parse_error(s, "property constructor appears more than once"); - goto fail; - } - if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE) - func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR; - else - func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR; - } - if (is_private) { - if (add_brand(s, &class_fields[is_static]) < 0) - goto fail; - } - if (js_parse_function_decl2(s, func_type, func_kind, JS_ATOM_NULL, start_ptr, s->token.line_num, JS_PARSE_EXPORT_NONE, &method_fd)) - goto fail; - if (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR || - func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) { - ctor_fd = method_fd; - } else if (is_private) { - method_fd->need_home_object = TRUE; /* needed for brand check */ - if (find_private_class_field(ctx, fd, name, - fd->scope_level) >= 0) { - private_field_already_defined: - js_parse_error(s, "private class field is already defined"); - goto fail; - } - if (add_private_class_field(s, fd, name, - JS_VAR_PRIVATE_METHOD) < 0) - goto fail; - emit_op(s, OP_set_home_object); - emit_op(s, OP_set_name); - emit_atom(s, name); - emit_op(s, OP_scope_put_var_init); - emit_atom(s, name); - emit_u16(s, s->cur_func->scope_level); - } else { - if (name == JS_ATOM_NULL) { - emit_op(s, OP_define_method_computed); - } else { - emit_op(s, OP_define_method); - emit_atom(s, name); - } - emit_u8(s, OP_DEFINE_METHOD_METHOD); - } - } - if (is_static) - emit_op(s, OP_swap); - JS_FreeAtom(ctx, name); - name = JS_ATOM_NULL; - } - if (s->token.val != '}') { - js_parse_error(s, "expecting '%c'", '}'); - goto fail; - } - if (!ctor_fd) { - if (js_parse_class_default_ctor(s, class_flags & JS_DEFINE_CLASS_HAS_HERITAGE, &ctor_fd)) - goto fail; - } - /* patch the constant pool index for the constructor */ - put_u32(fd->byte_code.buf + ctor_cpool_offset, ctor_fd->parent_cpool_idx); - /* store the class source code in the constructor. */ - if (!(fd->js_mode & JS_MODE_STRIP)) { - js_free(ctx, ctor_fd->source); - ctor_fd->source_len = s->buf_ptr - class_start_ptr; - ctor_fd->source = js_strndup(ctx, (const char *)class_start_ptr, - ctor_fd->source_len); - if (!ctor_fd->source) - goto fail; - } - /* consume the '}' */ - if (next_token(s)) - goto fail; - /* store the function to initialize the fields to that it can be - referenced by the constructor */ - { - ClassFieldsDef *cf = &class_fields[0]; - int var_idx; - var_idx = define_var(s, fd, JS_ATOM_class_fields_init, - JS_VAR_DEF_CONST); - if (var_idx < 0) - goto fail; - if (cf->fields_init_fd) { - emit_class_init_end(s, cf); - } else { - emit_op(s, OP_undefined); - } - emit_op(s, OP_scope_put_var_init); - emit_atom(s, JS_ATOM_class_fields_init); - emit_u16(s, s->cur_func->scope_level); - } - /* drop the prototype */ - emit_op(s, OP_drop); - /* initialize the static fields */ - if (class_fields[1].fields_init_fd != NULL) { - ClassFieldsDef *cf = &class_fields[1]; - emit_op(s, OP_dup); - emit_class_init_end(s, cf); - emit_op(s, OP_call_method); - emit_u16(s, 0); - emit_op(s, OP_drop); - } - if (class_name != JS_ATOM_NULL) { - /* store the class name in the scoped class name variable (it - is independent from the class statement variable - definition) */ - emit_op(s, OP_dup); - emit_op(s, OP_scope_put_var_init); - emit_atom(s, class_name); - emit_u16(s, fd->scope_level); - } - pop_scope(s); - pop_scope(s); - /* the class statements have a block level scope */ - if (class_var_name != JS_ATOM_NULL) { - if (define_var(s, fd, class_var_name, JS_VAR_DEF_LET) < 0) - goto fail; - emit_op(s, OP_scope_put_var_init); - emit_atom(s, class_var_name); - emit_u16(s, fd->scope_level); - } else { - if (class_name == JS_ATOM_NULL) { - /* cannot use OP_set_name because the name of the class - must be defined before the static initializers are - executed */ - emit_op(s, OP_set_class_name); - emit_u32(s, fd->last_opcode_pos + 1 - define_class_offset); - } - } - if (export_flag != JS_PARSE_EXPORT_NONE) { - if (!add_export_entry(s, fd->module, - class_var_name, - export_flag == JS_PARSE_EXPORT_NAMED ? class_var_name : JS_ATOM_default, - JS_EXPORT_TYPE_LOCAL)) - goto fail; - } - JS_FreeAtom(ctx, class_name); - JS_FreeAtom(ctx, class_var_name); - fd->js_mode = saved_js_mode; - return 0; - fail: - JS_FreeAtom(ctx, name); - JS_FreeAtom(ctx, class_name); - JS_FreeAtom(ctx, class_var_name); - fd->js_mode = saved_js_mode; - return -1; -} - -static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope, - JSAtom *pname, int *plabel, int *pdepth, BOOL keep, - int tok) -{ - JSFunctionDef *fd; - int opcode, scope, label, depth; - JSAtom name; - /* we check the last opcode to get the lvalue type */ - fd = s->cur_func; - scope = 0; - name = JS_ATOM_NULL; - label = -1; - depth = 0; - switch(opcode = get_prev_opcode(fd)) { - case OP_scope_get_var: - name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1); - scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5); - if ((name == JS_ATOM_arguments || name == JS_ATOM_eval) && - (fd->js_mode & JS_MODE_STRICT)) { - return js_parse_error(s, "invalid lvalue in strict mode"); - } - if (name == JS_ATOM_this || name == JS_ATOM_new_target) - goto invalid_lvalue; - depth = 2; /* will generate OP_get_ref_value */ - break; - case OP_get_field: - name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1); - depth = 1; - break; - case OP_scope_get_private_field: - name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1); - scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5); - depth = 1; - break; - case OP_get_array_el: - depth = 2; - break; - case OP_get_super_value: - depth = 3; - break; - default: - invalid_lvalue: - if (tok == TOK_FOR) { - return js_parse_error(s, "invalid for in/of left hand-side"); - } else if (tok == TOK_INC || tok == TOK_DEC) { - return js_parse_error(s, "invalid increment/decrement operand"); - } else if (tok == '[' || tok == '{') { - return js_parse_error(s, "invalid destructuring target"); - } else { - return js_parse_error(s, "invalid assignment left-hand side"); - } - } - /* remove the last opcode */ - fd->byte_code.size = fd->last_opcode_pos; - fd->last_opcode_pos = -1; - if (keep) { - /* get the value but keep the object/fields on the stack */ - switch(opcode) { - case OP_scope_get_var: - label = new_label(s); - emit_op(s, OP_scope_make_ref); - emit_atom(s, name); - emit_u32(s, label); - emit_u16(s, scope); - update_label(fd, label, 1); - emit_op(s, OP_get_ref_value); - opcode = OP_get_ref_value; - break; - case OP_get_field: - emit_op(s, OP_get_field2); - emit_atom(s, name); - break; - case OP_scope_get_private_field: - emit_op(s, OP_scope_get_private_field2); - emit_atom(s, name); - emit_u16(s, scope); - break; - case OP_get_array_el: - /* XXX: replace by a single opcode ? */ - emit_op(s, OP_to_propkey2); - emit_op(s, OP_dup2); - emit_op(s, OP_get_array_el); - break; - case OP_get_super_value: - emit_op(s, OP_to_propkey); - emit_op(s, OP_dup3); - emit_op(s, OP_get_super_value); - break; - default: - abort(); - } - } else { - switch(opcode) { - case OP_scope_get_var: - label = new_label(s); - emit_op(s, OP_scope_make_ref); - emit_atom(s, name); - emit_u32(s, label); - emit_u16(s, scope); - update_label(fd, label, 1); - opcode = OP_get_ref_value; - break; - case OP_get_array_el: - emit_op(s, OP_to_propkey2); - break; - case OP_get_super_value: - emit_op(s, OP_to_propkey); - break; - } - } - *popcode = opcode; - *pscope = scope; - /* name has refcount for OP_get_field and OP_get_ref_value, - and JS_ATOM_NULL for other opcodes */ - *pname = name; - *plabel = label; - if (pdepth) - *pdepth = depth; - return 0; -} - -static __exception int js_define_var(JSParseState *s, JSAtom name, int tok) -{ - JSFunctionDef *fd = s->cur_func; - JSVarDefEnum var_def_type; - if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) { - return js_parse_error(s, "yield is a reserved identifier"); - } - if ((name == JS_ATOM_arguments || name == JS_ATOM_eval) - && (fd->js_mode & JS_MODE_STRICT)) { - return js_parse_error(s, "invalid variable name in strict mode"); - } - if ((name == JS_ATOM_let || name == JS_ATOM_undefined) - && (tok == TOK_LET || tok == TOK_CONST)) { - return js_parse_error(s, "invalid lexical variable name"); - } - switch(tok) { - case TOK_LET: - var_def_type = JS_VAR_DEF_LET; - break; - case TOK_CONST: - var_def_type = JS_VAR_DEF_CONST; - break; - case TOK_VAR: - var_def_type = JS_VAR_DEF_VAR; - break; - case TOK_CATCH: - var_def_type = JS_VAR_DEF_CATCH; - break; - default: - abort(); - } - if (define_var(s, fd, name, var_def_type) < 0) - return -1; - return 0; -} - -/* name has a live reference. 'is_let' is only used with opcode = - OP_scope_get_var which is never generated by get_lvalue(). */ -static void put_lvalue(JSParseState *s, int opcode, int scope, - JSAtom name, int label, PutLValueEnum special, - BOOL is_let) -{ - switch(opcode) { - case OP_get_field: - case OP_scope_get_private_field: - /* depth = 1 */ - switch(special) { - case PUT_LVALUE_NOKEEP: - case PUT_LVALUE_NOKEEP_DEPTH: - break; - case PUT_LVALUE_KEEP_TOP: - emit_op(s, OP_insert2); /* obj v -> v obj v */ - break; - case PUT_LVALUE_KEEP_SECOND: - emit_op(s, OP_perm3); /* obj v0 v -> v0 obj v */ - break; - case PUT_LVALUE_NOKEEP_BOTTOM: - emit_op(s, OP_swap); - break; - default: - abort(); - } - break; - case OP_get_array_el: - case OP_get_ref_value: - /* depth = 2 */ - if (opcode == OP_get_ref_value) { - JS_FreeAtom(s->ctx, name); - emit_label(s, label); - } - switch(special) { - case PUT_LVALUE_NOKEEP: - emit_op(s, OP_nop); /* will trigger optimization */ - break; - case PUT_LVALUE_NOKEEP_DEPTH: - break; - case PUT_LVALUE_KEEP_TOP: - emit_op(s, OP_insert3); /* obj prop v -> v obj prop v */ - break; - case PUT_LVALUE_KEEP_SECOND: - emit_op(s, OP_perm4); /* obj prop v0 v -> v0 obj prop v */ - break; - case PUT_LVALUE_NOKEEP_BOTTOM: - emit_op(s, OP_rot3l); - break; - default: - abort(); - } - break; - case OP_get_super_value: - /* depth = 3 */ - switch(special) { - case PUT_LVALUE_NOKEEP: - case PUT_LVALUE_NOKEEP_DEPTH: - break; - case PUT_LVALUE_KEEP_TOP: - emit_op(s, OP_insert4); /* this obj prop v -> v this obj prop v */ - break; - case PUT_LVALUE_KEEP_SECOND: - emit_op(s, OP_perm5); /* this obj prop v0 v -> v0 this obj prop v */ - break; - case PUT_LVALUE_NOKEEP_BOTTOM: - emit_op(s, OP_rot4l); - break; - default: - abort(); - } - break; - default: - break; - } - switch(opcode) { - case OP_scope_get_var: /* val -- */ - assert(special == PUT_LVALUE_NOKEEP || - special == PUT_LVALUE_NOKEEP_DEPTH); - emit_op(s, is_let ? OP_scope_put_var_init : OP_scope_put_var); - emit_u32(s, name); /* has refcount */ - emit_u16(s, scope); - break; - case OP_get_field: - emit_op(s, OP_put_field); - emit_u32(s, name); /* name has refcount */ - break; - case OP_scope_get_private_field: - emit_op(s, OP_scope_put_private_field); - emit_u32(s, name); /* name has refcount */ - emit_u16(s, scope); - break; - case OP_get_array_el: - emit_op(s, OP_put_array_el); - break; - case OP_get_ref_value: - emit_op(s, OP_put_ref_value); - break; - case OP_get_super_value: - emit_op(s, OP_put_super_value); - break; - default: - abort(); - } -} - -static void js_emit_spread_code(JSParseState *s, int depth) -{ - int label_rest_next, label_rest_done; - /* XXX: could check if enum object is an actual array and optimize - slice extraction. enumeration record and target array are in a - different order from OP_append case. */ - /* enum_rec xxx -- enum_rec xxx array 0 */ - emit_op(s, OP_array_from); - emit_u16(s, 0); - emit_op(s, OP_push_i32); - emit_u32(s, 0); - emit_label(s, label_rest_next = new_label(s)); - emit_op(s, OP_for_of_next); - emit_u8(s, 2 + depth); - label_rest_done = emit_goto(s, OP_if_true, -1); - /* array idx val -- array idx */ - emit_op(s, OP_define_array_el); - emit_op(s, OP_inc); - emit_goto(s, OP_goto, label_rest_next); - emit_label(s, label_rest_done); - /* enum_rec xxx array idx undef -- enum_rec xxx array */ - emit_op(s, OP_drop); - emit_op(s, OP_drop); -} - -static void push_break_entry(JSFunctionDef *fd, BlockEnv *be, - JSAtom label_name, - int label_break, int label_cont, - int drop_count) -{ - be->prev = fd->top_break; - fd->top_break = be; - be->label_name = label_name; - be->label_break = label_break; - be->label_cont = label_cont; - be->drop_count = drop_count; - be->label_finally = -1; - be->scope_level = fd->scope_level; - be->has_iterator = FALSE; -} - -static void pop_break_entry(JSFunctionDef *fd) -{ - BlockEnv *be; - be = fd->top_break; - fd->top_break = be->prev; -} - -/* Return -1 if error, 0 if no initializer, 1 if an initializer is - present at the top level. */ -static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, - int hasval, int has_ellipsis, - BOOL allow_initializer) -{ - int label_parse, label_assign, label_done, label_lvalue, depth_lvalue; - int start_addr, assign_addr; - JSAtom prop_name, var_name; - int opcode, scope, tok1, skip_bits; - BOOL has_initializer; - if (has_ellipsis < 0) { - /* pre-parse destructuration target for spread detection */ - js_parse_skip_parens_token(s, &skip_bits, FALSE); - has_ellipsis = skip_bits & SKIP_HAS_ELLIPSIS; - } - label_parse = new_label(s); - label_assign = new_label(s); - start_addr = s->cur_func->byte_code.size; - if (hasval) { - /* consume value from the stack */ - emit_op(s, OP_dup); - emit_op(s, OP_undefined); - emit_op(s, OP_strict_eq); - emit_goto(s, OP_if_true, label_parse); - emit_label(s, label_assign); - } else { - emit_goto(s, OP_goto, label_parse); - emit_label(s, label_assign); - /* leave value on the stack */ - emit_op(s, OP_dup); - } - assign_addr = s->cur_func->byte_code.size; - if (s->token.val == '{') { - if (next_token(s)) - return -1; - /* throw an exception if the value cannot be converted to an object */ - emit_op(s, OP_to_object); - if (has_ellipsis) { - /* add excludeList on stack just below src object */ - emit_op(s, OP_object); - emit_op(s, OP_swap); - } - while (s->token.val != '}') { - int prop_type; - if (s->token.val == TOK_ELLIPSIS) { - if (!has_ellipsis) { - JS_ThrowInternalError(s->ctx, "unexpected ellipsis token"); - return -1; - } - if (next_token(s)) - return -1; - if (tok) { - var_name = js_parse_destructuring_var(s, tok, is_arg); - if (var_name == JS_ATOM_NULL) - return -1; - opcode = OP_scope_get_var; - scope = s->cur_func->scope_level; - label_lvalue = -1; - depth_lvalue = 0; - } else { - if (js_parse_left_hand_side_expr(s)) - return -1; - if (get_lvalue(s, &opcode, &scope, &var_name, - &label_lvalue, &depth_lvalue, FALSE, '{')) - return -1; - } - if (s->token.val != '}') { - js_parse_error(s, "assignment rest property must be last"); - goto var_error; - } - emit_op(s, OP_object); /* target */ - emit_op(s, OP_copy_data_properties); - emit_u8(s, 0 | ((depth_lvalue + 1) << 2) | ((depth_lvalue + 2) << 5)); - goto set_val; - } - prop_type = js_parse_property_name(s, &prop_name, FALSE, TRUE, FALSE); - if (prop_type < 0) - return -1; - var_name = JS_ATOM_NULL; - opcode = OP_scope_get_var; - scope = s->cur_func->scope_level; - label_lvalue = -1; - depth_lvalue = 0; - if (prop_type == PROP_TYPE_IDENT) { - if (next_token(s)) - goto prop_error; - if ((s->token.val == '[' || s->token.val == '{') - && ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' || - tok1 == '=' || tok1 == '}')) { - if (prop_name == JS_ATOM_NULL) { - /* computed property name on stack */ - if (has_ellipsis) { - /* define the property in excludeList */ - emit_op(s, OP_to_propkey); /* avoid calling ToString twice */ - emit_op(s, OP_perm3); /* TOS: src excludeList prop */ - emit_op(s, OP_null); /* TOS: src excludeList prop null */ - emit_op(s, OP_define_array_el); /* TOS: src excludeList prop */ - emit_op(s, OP_perm3); /* TOS: excludeList src prop */ - } - /* get the computed property from the source object */ - emit_op(s, OP_get_array_el2); - } else { - /* named property */ - if (has_ellipsis) { - /* define the property in excludeList */ - emit_op(s, OP_swap); /* TOS: src excludeList */ - emit_op(s, OP_null); /* TOS: src excludeList null */ - emit_op(s, OP_define_field); /* TOS: src excludeList */ - emit_atom(s, prop_name); - emit_op(s, OP_swap); /* TOS: excludeList src */ - } - /* get the named property from the source object */ - emit_op(s, OP_get_field2); - emit_u32(s, prop_name); - } - if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE) < 0) - return -1; - if (s->token.val == '}') - break; - /* accept a trailing comma before the '}' */ - if (js_parse_expect(s, ',')) - return -1; - continue; - } - if (prop_name == JS_ATOM_NULL) { - emit_op(s, OP_to_propkey2); - if (has_ellipsis) { - /* define the property in excludeList */ - emit_op(s, OP_perm3); - emit_op(s, OP_null); - emit_op(s, OP_define_array_el); - emit_op(s, OP_perm3); - } - /* source prop -- source source prop */ - emit_op(s, OP_dup1); - } else { - if (has_ellipsis) { - /* define the property in excludeList */ - emit_op(s, OP_swap); - emit_op(s, OP_null); - emit_op(s, OP_define_field); - emit_atom(s, prop_name); - emit_op(s, OP_swap); - } - /* source -- source source */ - emit_op(s, OP_dup); - } - if (tok) { - var_name = js_parse_destructuring_var(s, tok, is_arg); - if (var_name == JS_ATOM_NULL) - goto prop_error; - } else { - if (js_parse_left_hand_side_expr(s)) - goto prop_error; - lvalue: - if (get_lvalue(s, &opcode, &scope, &var_name, - &label_lvalue, &depth_lvalue, FALSE, '{')) - goto prop_error; - /* swap ref and lvalue object if any */ - if (prop_name == JS_ATOM_NULL) { - switch(depth_lvalue) { - case 1: - /* source prop x -> x source prop */ - emit_op(s, OP_rot3r); - break; - case 2: - /* source prop x y -> x y source prop */ - emit_op(s, OP_swap2); /* t p2 s p1 */ - break; - case 3: - /* source prop x y z -> x y z source prop */ - emit_op(s, OP_rot5l); - emit_op(s, OP_rot5l); - break; - } - } else { - switch(depth_lvalue) { - case 1: - /* source x -> x source */ - emit_op(s, OP_swap); - break; - case 2: - /* source x y -> x y source */ - emit_op(s, OP_rot3l); - break; - case 3: - /* source x y z -> x y z source */ - emit_op(s, OP_rot4l); - break; - } - } - } - if (prop_name == JS_ATOM_NULL) { - /* computed property name on stack */ - /* XXX: should have OP_get_array_el2x with depth */ - /* source prop -- val */ - emit_op(s, OP_get_array_el); - } else { - /* named property */ - /* XXX: should have OP_get_field2x with depth */ - /* source -- val */ - emit_op(s, OP_get_field); - emit_u32(s, prop_name); - } - } else { - /* prop_type = PROP_TYPE_VAR, cannot be a computed property */ - if (is_arg && js_parse_check_duplicate_parameter(s, prop_name)) - goto prop_error; - if ((s->cur_func->js_mode & JS_MODE_STRICT) && - (prop_name == JS_ATOM_eval || prop_name == JS_ATOM_arguments)) { - js_parse_error(s, "invalid destructuring target"); - goto prop_error; - } - if (has_ellipsis) { - /* define the property in excludeList */ - emit_op(s, OP_swap); - emit_op(s, OP_null); - emit_op(s, OP_define_field); - emit_atom(s, prop_name); - emit_op(s, OP_swap); - } - if (!tok || tok == TOK_VAR) { - /* generate reference */ - /* source -- source source */ - emit_op(s, OP_dup); - emit_op(s, OP_scope_get_var); - emit_atom(s, prop_name); - emit_u16(s, s->cur_func->scope_level); - goto lvalue; - } - var_name = JS_DupAtom(s->ctx, prop_name); - /* source -- source val */ - emit_op(s, OP_get_field2); - emit_u32(s, prop_name); - } - set_val: - if (tok) { - if (js_define_var(s, var_name, tok)) - goto var_error; - scope = s->cur_func->scope_level; - } - if (s->token.val == '=') { /* handle optional default value */ - int label_hasval; - emit_op(s, OP_dup); - emit_op(s, OP_undefined); - emit_op(s, OP_strict_eq); - label_hasval = emit_goto(s, OP_if_false, -1); - if (next_token(s)) - goto var_error; - emit_op(s, OP_drop); - if (js_parse_assign_expr(s)) - goto var_error; - if (opcode == OP_scope_get_var || opcode == OP_get_ref_value) - set_object_name(s, var_name); - emit_label(s, label_hasval); - } - /* store value into lvalue object */ - put_lvalue(s, opcode, scope, var_name, label_lvalue, - PUT_LVALUE_NOKEEP_DEPTH, - (tok == TOK_CONST || tok == TOK_LET)); - if (s->token.val == '}') - break; - /* accept a trailing comma before the '}' */ - if (js_parse_expect(s, ',')) - return -1; - } - /* drop the source object */ - emit_op(s, OP_drop); - if (has_ellipsis) { - emit_op(s, OP_drop); /* pop excludeList */ - } - if (next_token(s)) - return -1; - } else if (s->token.val == '[') { - BOOL has_spread; - int enum_depth; - BlockEnv block_env; - if (next_token(s)) - return -1; - /* the block environment is only needed in generators in case - 'yield' triggers a 'return' */ - push_break_entry(s->cur_func, &block_env, - JS_ATOM_NULL, -1, -1, 2); - block_env.has_iterator = TRUE; - emit_op(s, OP_for_of_start); - has_spread = FALSE; - while (s->token.val != ']') { - /* get the next value */ - if (s->token.val == TOK_ELLIPSIS) { - if (next_token(s)) - return -1; - if (s->token.val == ',' || s->token.val == ']') - return js_parse_error(s, "missing binding pattern..."); - has_spread = TRUE; - } - if (s->token.val == ',') { - /* do nothing, skip the value, has_spread is false */ - emit_op(s, OP_for_of_next); - emit_u8(s, 0); - emit_op(s, OP_drop); - emit_op(s, OP_drop); - } else if ((s->token.val == '[' || s->token.val == '{') - && ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' || - tok1 == '=' || tok1 == ']')) { - if (has_spread) { - if (tok1 == '=') - return js_parse_error(s, "rest element cannot have a default value"); - js_emit_spread_code(s, 0); - } else { - emit_op(s, OP_for_of_next); - emit_u8(s, 0); - emit_op(s, OP_drop); - } - if (js_parse_destructuring_element(s, tok, is_arg, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0) - return -1; - } else { - var_name = JS_ATOM_NULL; - enum_depth = 0; - if (tok) { - var_name = js_parse_destructuring_var(s, tok, is_arg); - if (var_name == JS_ATOM_NULL) - goto var_error; - if (js_define_var(s, var_name, tok)) - goto var_error; - opcode = OP_scope_get_var; - scope = s->cur_func->scope_level; - } else { - if (js_parse_left_hand_side_expr(s)) - return -1; - if (get_lvalue(s, &opcode, &scope, &var_name, - &label_lvalue, &enum_depth, FALSE, '[')) { - return -1; - } - } - if (has_spread) { - js_emit_spread_code(s, enum_depth); - } else { - emit_op(s, OP_for_of_next); - emit_u8(s, enum_depth); - emit_op(s, OP_drop); - } - if (s->token.val == '=' && !has_spread) { - /* handle optional default value */ - int label_hasval; - emit_op(s, OP_dup); - emit_op(s, OP_undefined); - emit_op(s, OP_strict_eq); - label_hasval = emit_goto(s, OP_if_false, -1); - if (next_token(s)) - goto var_error; - emit_op(s, OP_drop); - if (js_parse_assign_expr(s)) - goto var_error; - if (opcode == OP_scope_get_var || opcode == OP_get_ref_value) - set_object_name(s, var_name); - emit_label(s, label_hasval); - } - /* store value into lvalue object */ - put_lvalue(s, opcode, scope, var_name, - label_lvalue, PUT_LVALUE_NOKEEP_DEPTH, - (tok == TOK_CONST || tok == TOK_LET)); - } - if (s->token.val == ']') - break; - if (has_spread) - return js_parse_error(s, "rest element must be the last one"); - /* accept a trailing comma before the ']' */ - if (js_parse_expect(s, ',')) - return -1; - } - /* close iterator object: - if completed, enum_obj has been replaced by undefined */ - emit_op(s, OP_iterator_close); - pop_break_entry(s->cur_func); - if (next_token(s)) - return -1; - } else { - return js_parse_error(s, "invalid assignment syntax"); - } - if (s->token.val == '=' && allow_initializer) { - label_done = emit_goto(s, OP_goto, -1); - if (next_token(s)) - return -1; - emit_label(s, label_parse); - if (hasval) - emit_op(s, OP_drop); - if (js_parse_assign_expr(s)) - return -1; - emit_goto(s, OP_goto, label_assign); - emit_label(s, label_done); - has_initializer = TRUE; - } else { - /* normally hasval is true except if - js_parse_skip_parens_token() was wrong in the parsing */ - // assert(hasval); - if (!hasval) { - js_parse_error(s, "too complicated destructuring expression"); - return -1; - } - /* remove test and decrement label ref count */ - memset(s->cur_func->byte_code.buf + start_addr, OP_nop, - assign_addr - start_addr); - s->cur_func->label_slots[label_parse].ref_count--; - has_initializer = FALSE; - } - return has_initializer; - prop_error: - JS_FreeAtom(s->ctx, prop_name); - var_error: - JS_FreeAtom(s->ctx, var_name); - return -1; -} - -static __exception int js_parse_array_literal(JSParseState *s) -{ - uint32_t idx; - BOOL need_length; - if (next_token(s)) - return -1; - /* small regular arrays are created on the stack */ - idx = 0; - while (s->token.val != ']' && idx < 32) { - if (s->token.val == ',' || s->token.val == TOK_ELLIPSIS) - break; - if (js_parse_assign_expr(s)) - return -1; - idx++; - /* accept trailing comma */ - if (s->token.val == ',') { - if (next_token(s)) - return -1; - } else - if (s->token.val != ']') - goto done; - } - emit_op(s, OP_array_from); - emit_u16(s, idx); - /* larger arrays and holes are handled with explicit indices */ - need_length = FALSE; - while (s->token.val != ']' && idx < 0x7fffffff) { - if (s->token.val == TOK_ELLIPSIS) - break; - need_length = TRUE; - if (s->token.val != ',') { - if (js_parse_assign_expr(s)) - return -1; - emit_op(s, OP_define_field); - emit_u32(s, __JS_AtomFromUInt32(idx)); - need_length = FALSE; - } - idx++; - /* accept trailing comma */ - if (s->token.val == ',') { - if (next_token(s)) - return -1; - } - } - if (s->token.val == ']') { - if (need_length) { - /* Set the length: Cannot use OP_define_field because - length is not configurable */ - emit_op(s, OP_dup); - emit_op(s, OP_push_i32); - emit_u32(s, idx); - emit_op(s, OP_put_field); - emit_atom(s, JS_ATOM_length); - } - goto done; - } - /* huge arrays and spread elements require a dynamic index on the stack */ - emit_op(s, OP_push_i32); - emit_u32(s, idx); - /* stack has array, index */ - while (s->token.val != ']') { - if (s->token.val == TOK_ELLIPSIS) { - if (next_token(s)) - return -1; - if (js_parse_assign_expr(s)) - return -1; -#if 1 - emit_op(s, OP_append); -#else - int label_next, label_done; - label_next = new_label(s); - label_done = new_label(s); - /* enumerate object */ - emit_op(s, OP_for_of_start); - emit_op(s, OP_rot5l); - emit_op(s, OP_rot5l); - emit_label(s, label_next); - /* on stack: enum_rec array idx */ - emit_op(s, OP_for_of_next); - emit_u8(s, 2); - emit_goto(s, OP_if_true, label_done); - /* append element */ - /* enum_rec array idx val -> enum_rec array new_idx */ - emit_op(s, OP_define_array_el); - emit_op(s, OP_inc); - emit_goto(s, OP_goto, label_next); - emit_label(s, label_done); - /* close enumeration */ - emit_op(s, OP_drop); /* drop undef val */ - emit_op(s, OP_nip1); /* drop enum_rec */ - emit_op(s, OP_nip1); - emit_op(s, OP_nip1); -#endif - } else { - need_length = TRUE; - if (s->token.val != ',') { - if (js_parse_assign_expr(s)) - return -1; - /* a idx val */ - emit_op(s, OP_define_array_el); - need_length = FALSE; - } - emit_op(s, OP_inc); - } - if (s->token.val != ',') - break; - if (next_token(s)) - return -1; - } - if (need_length) { - /* Set the length: cannot use OP_define_field because - length is not configurable */ - emit_op(s, OP_dup1); /* array length - array array length */ - emit_op(s, OP_put_field); - emit_atom(s, JS_ATOM_length); - } else { - emit_op(s, OP_drop); /* array length - array */ - } -done: - return js_parse_expect(s, ']'); -} - -/* XXX: remove */ -static BOOL has_with_scope(JSFunctionDef *s, int scope_level) -{ - /* check if scope chain contains a with statement */ - while (s) { - int scope_idx = s->scopes[scope_level].first; - while (scope_idx >= 0) { - JSVarDef *vd = &s->vars[scope_idx]; - if (vd->var_name == JS_ATOM__with_) - return TRUE; - scope_idx = vd->scope_next; - } - /* check parent scopes */ - scope_level = s->parent_scope_level; - s = s->parent; - } - return FALSE; -} - -static void optional_chain_test(JSParseState *s, int *poptional_chaining_label, - int drop_count) -{ - int label_next, i; - if (*poptional_chaining_label < 0) - *poptional_chaining_label = new_label(s); - /* XXX: could be more efficient with a specific opcode */ - emit_op(s, OP_dup); - emit_op(s, OP_is_undefined_or_null); - label_next = emit_goto(s, OP_if_false, -1); - for(i = 0; i < drop_count; i++) - emit_op(s, OP_drop); - emit_op(s, OP_undefined); - emit_goto(s, OP_goto, *poptional_chaining_label); - emit_label(s, label_next); -} - -/* initialize the class fields, called by the constructor. Note: - super() can be called in an arrow function, so and - can be variable references */ -static void emit_class_field_init(JSParseState *s) -{ - int label_next; - emit_op(s, OP_scope_get_var); - emit_atom(s, JS_ATOM_class_fields_init); - emit_u16(s, s->cur_func->scope_level); - /* no need to call the class field initializer if not defined */ - emit_op(s, OP_dup); - label_next = emit_goto(s, OP_if_false, -1); - emit_op(s, OP_scope_get_var); - emit_atom(s, JS_ATOM_this); - emit_u16(s, 0); - emit_op(s, OP_swap); - emit_op(s, OP_call_method); - emit_u16(s, 0); - emit_label(s, label_next); - emit_op(s, OP_drop); -} - -/* allowed parse_flags: PF_POSTFIX_CALL, PF_ARROW_FUNC */ -static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) -{ - FuncCallType call_type; - int optional_chaining_label; - BOOL accept_lparen = (parse_flags & PF_POSTFIX_CALL) != 0; - call_type = FUNC_CALL_NORMAL; - switch(s->token.val) { - case TOK_NUMBER: - { - JSValue val; - val = s->token.u.num.val; - if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) { - emit_op(s, OP_push_i32); - emit_u32(s, JS_VALUE_GET_INT(val)); - } else -#ifdef CONFIG_BIGNUM - if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) { - slimb_t e; - int ret; - /* need a runtime conversion */ - /* XXX: could add a cache and/or do it once at - the start of the function */ - if (emit_push_const(s, val, 0) < 0) - return -1; - e = s->token.u.num.exponent; - if (e == (int32_t)e) { - emit_op(s, OP_push_i32); - emit_u32(s, e); - } else { - val = JS_NewBigInt64_1(s->ctx, e); - if (JS_IsException(val)) - return -1; - ret = emit_push_const(s, val, 0); - JS_FreeValue(s->ctx, val); - if (ret < 0) - return -1; - } - emit_op(s, OP_mul_pow10); - } else -#endif - { - if (emit_push_const(s, val, 0) < 0) - return -1; - } - } - if (next_token(s)) - return -1; - break; - case TOK_TEMPLATE: - if (js_parse_template(s, 0, NULL)) - return -1; - break; - case TOK_STRING: - if (emit_push_const(s, s->token.u.str.str, 1)) - return -1; - if (next_token(s)) - return -1; - break; - case TOK_DIV_ASSIGN: - s->buf_ptr -= 2; - goto parse_regexp; - case '/': - s->buf_ptr--; - parse_regexp: - { - JSValue str; - int ret, backtrace_flags; - if (!s->ctx->compile_regexp) - return js_parse_error(s, "RegExp are not supported"); - /* the previous token is '/' or '/=', so no need to free */ - if (js_parse_regexp(s)) - return -1; - ret = emit_push_const(s, s->token.u.regexp.body, 0); - str = s->ctx->compile_regexp(s->ctx, s->token.u.regexp.body, - s->token.u.regexp.flags); - if (JS_IsException(str)) { - /* add the line number info */ - backtrace_flags = 0; - if (s->cur_func && s->cur_func->backtrace_barrier) - backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL; - build_backtrace(s->ctx, s->ctx->rt->current_exception, - s->filename, s->token.line_num, - backtrace_flags); - return -1; - } - ret = emit_push_const(s, str, 0); - JS_FreeValue(s->ctx, str); - if (ret) - return -1; - /* we use a specific opcode to be sure the correct - function is called (otherwise the bytecode would have - to be verified by the RegExp constructor) */ - emit_op(s, OP_regexp); - if (next_token(s)) - return -1; - } - break; - case '(': - if ((parse_flags & PF_ARROW_FUNC) && - js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) { - if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW, - JS_FUNC_NORMAL, JS_ATOM_NULL, - s->token.ptr, s->token.line_num)) - return -1; - } else { - if (js_parse_expr_paren(s)) - return -1; - } - break; - case TOK_FUNCTION: - if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR, - JS_FUNC_NORMAL, JS_ATOM_NULL, - s->token.ptr, s->token.line_num)) - return -1; - break; - case TOK_CLASS: - if (js_parse_class(s, TRUE, JS_PARSE_EXPORT_NONE)) - return -1; - break; - case TOK_NULL: - if (next_token(s)) - return -1; - emit_op(s, OP_null); - break; - case TOK_THIS: - if (next_token(s)) - return -1; - emit_op(s, OP_scope_get_var); - emit_atom(s, JS_ATOM_this); - emit_u16(s, 0); - break; - case TOK_FALSE: - if (next_token(s)) - return -1; - emit_op(s, OP_push_false); - break; - case TOK_TRUE: - if (next_token(s)) - return -1; - emit_op(s, OP_push_true); - break; - case TOK_IDENT: - { - JSAtom name; - if (s->token.u.ident.is_reserved) { - return js_parse_error_reserved_identifier(s); - } - if ((parse_flags & PF_ARROW_FUNC) && - peek_token(s, TRUE) == TOK_ARROW) { - if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW, - JS_FUNC_NORMAL, JS_ATOM_NULL, - s->token.ptr, s->token.line_num)) - return -1; - } else if (token_is_pseudo_keyword(s, JS_ATOM_async) && - peek_token(s, TRUE) != '\n') { - const uint8_t *source_ptr; - int source_line_num; - source_ptr = s->token.ptr; - source_line_num = s->token.line_num; - if (next_token(s)) - return -1; - if (s->token.val == TOK_FUNCTION) { - if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR, - JS_FUNC_ASYNC, JS_ATOM_NULL, - source_ptr, source_line_num)) - return -1; - } else if ((parse_flags & PF_ARROW_FUNC) && - ((s->token.val == '(' && - js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) || - (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved && - peek_token(s, TRUE) == TOK_ARROW))) { - if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW, - JS_FUNC_ASYNC, JS_ATOM_NULL, - source_ptr, source_line_num)) - return -1; - } else { - name = JS_DupAtom(s->ctx, JS_ATOM_async); - goto do_get_var; - } - } else { - if (s->token.u.ident.atom == JS_ATOM_arguments && - !s->cur_func->arguments_allowed) { - js_parse_error(s, "'arguments' identifier is not allowed in class field initializer"); - return -1; - } - name = JS_DupAtom(s->ctx, s->token.u.ident.atom); - if (next_token(s)) /* update line number before emitting code */ - return -1; - do_get_var: - emit_op(s, OP_scope_get_var); - emit_u32(s, name); - emit_u16(s, s->cur_func->scope_level); - } - } - break; - case '{': - case '[': - { - int skip_bits; - if (js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') { - if (js_parse_destructuring_element(s, 0, 0, FALSE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0) - return -1; - } else { - if (s->token.val == '{') { - if (js_parse_object_literal(s)) - return -1; - } else { - if (js_parse_array_literal(s)) - return -1; - } - } - } - break; - case TOK_NEW: - if (next_token(s)) - return -1; - if (s->token.val == '.') { - if (next_token(s)) - return -1; - if (!token_is_pseudo_keyword(s, JS_ATOM_target)) - return js_parse_error(s, "expecting target"); - if (!s->cur_func->new_target_allowed) - return js_parse_error(s, "new.target only allowed within functions"); - if (next_token(s)) - return -1; - emit_op(s, OP_scope_get_var); - emit_atom(s, JS_ATOM_new_target); - emit_u16(s, 0); - } else { - if (js_parse_postfix_expr(s, 0)) - return -1; - accept_lparen = TRUE; - if (s->token.val != '(') { - /* new operator on an object */ - emit_op(s, OP_dup); - emit_op(s, OP_call_constructor); - emit_u16(s, 0); - } else { - call_type = FUNC_CALL_NEW; - } - } - break; - case TOK_SUPER: - if (next_token(s)) - return -1; - if (s->token.val == '(') { - if (!s->cur_func->super_call_allowed) - return js_parse_error(s, "super() is only valid in a derived class constructor"); - call_type = FUNC_CALL_SUPER_CTOR; - } else if (s->token.val == '.' || s->token.val == '[') { - if (!s->cur_func->super_allowed) - return js_parse_error(s, "'super' is only valid in a method"); - emit_op(s, OP_scope_get_var); - emit_atom(s, JS_ATOM_this); - emit_u16(s, 0); - emit_op(s, OP_scope_get_var); - emit_atom(s, JS_ATOM_home_object); - emit_u16(s, 0); - emit_op(s, OP_get_super); - } else { - return js_parse_error(s, "invalid use of 'super'"); - } - break; - case TOK_IMPORT: - if (next_token(s)) - return -1; - if (s->token.val == '.') { - if (next_token(s)) - return -1; - if (!token_is_pseudo_keyword(s, JS_ATOM_meta)) - return js_parse_error(s, "meta expected"); - if (!s->is_module) - return js_parse_error(s, "import.meta only valid in module code"); - if (next_token(s)) - return -1; - emit_op(s, OP_special_object); - emit_u8(s, OP_SPECIAL_OBJECT_IMPORT_META); - } else { - if (js_parse_expect(s, '(')) - return -1; - if (!accept_lparen) - return js_parse_error(s, "invalid use of 'import()'"); - if (js_parse_assign_expr(s)) - return -1; - if (js_parse_expect(s, ')')) - return -1; - emit_op(s, OP_import); - } - break; - default: - return js_parse_error(s, "unexpected token in expression: '%.*s'", - (int)(s->buf_ptr - s->token.ptr), s->token.ptr); - } - optional_chaining_label = -1; - for(;;) { - JSFunctionDef *fd = s->cur_func; - BOOL has_optional_chain = FALSE; - if (s->token.val == TOK_QUESTION_MARK_DOT) { - /* optional chaining */ - if (next_token(s)) - return -1; - has_optional_chain = TRUE; - if (s->token.val == '(' && accept_lparen) { - goto parse_func_call; - } else if (s->token.val == '[') { - goto parse_array_access; - } else { - goto parse_property; - } - } else if (s->token.val == TOK_TEMPLATE && - call_type == FUNC_CALL_NORMAL) { - if (optional_chaining_label >= 0) { - return js_parse_error(s, "template literal cannot appear in an optional chain"); - } - call_type = FUNC_CALL_TEMPLATE; - goto parse_func_call2; - } else if (s->token.val == '(' && accept_lparen) { - int opcode, arg_count, drop_count; - /* function call */ - parse_func_call: - if (next_token(s)) - return -1; - if (call_type == FUNC_CALL_NORMAL) { - parse_func_call2: - switch(opcode = get_prev_opcode(fd)) { - case OP_get_field: - /* keep the object on the stack */ - fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2; - drop_count = 2; - break; - case OP_scope_get_private_field: - /* keep the object on the stack */ - fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_private_field2; - drop_count = 2; - break; - case OP_get_array_el: - /* keep the object on the stack */ - fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2; - drop_count = 2; - break; - case OP_scope_get_var: - { - JSAtom name; - int scope; - name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1); - scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5); - if (name == JS_ATOM_eval && call_type == FUNC_CALL_NORMAL && !has_optional_chain) { - /* direct 'eval' */ - opcode = OP_eval; - } else { - /* verify if function name resolves to a simple - get_loc/get_arg: a function call inside a `with` - statement can resolve to a method call of the - `with` context object - */ - /* XXX: always generate the OP_scope_get_ref - and remove it in variable resolution - pass ? */ - if (has_with_scope(fd, scope)) { - opcode = OP_scope_get_ref; - fd->byte_code.buf[fd->last_opcode_pos] = opcode; - } - } - drop_count = 1; - } - break; - case OP_get_super_value: - fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el; - /* on stack: this func_obj */ - opcode = OP_get_array_el; - drop_count = 2; - break; - default: - opcode = OP_invalid; - drop_count = 1; - break; - } - if (has_optional_chain) { - optional_chain_test(s, &optional_chaining_label, - drop_count); - } - } else { - opcode = OP_invalid; - } - if (call_type == FUNC_CALL_TEMPLATE) { - if (js_parse_template(s, 1, &arg_count)) - return -1; - goto emit_func_call; - } else if (call_type == FUNC_CALL_SUPER_CTOR) { - emit_op(s, OP_scope_get_var); - emit_atom(s, JS_ATOM_this_active_func); - emit_u16(s, 0); - emit_op(s, OP_get_super); - emit_op(s, OP_scope_get_var); - emit_atom(s, JS_ATOM_new_target); - emit_u16(s, 0); - } else if (call_type == FUNC_CALL_NEW) { - emit_op(s, OP_dup); /* new.target = function */ - } - /* parse arguments */ - arg_count = 0; - while (s->token.val != ')') { - if (arg_count >= 65535) { - return js_parse_error(s, "Too many call arguments"); - } - if (s->token.val == TOK_ELLIPSIS) - break; - if (js_parse_assign_expr(s)) - return -1; - arg_count++; - if (s->token.val == ')') - break; - /* accept a trailing comma before the ')' */ - if (js_parse_expect(s, ',')) - return -1; - } - if (s->token.val == TOK_ELLIPSIS) { - emit_op(s, OP_array_from); - emit_u16(s, arg_count); - emit_op(s, OP_push_i32); - emit_u32(s, arg_count); - /* on stack: array idx */ - while (s->token.val != ')') { - if (s->token.val == TOK_ELLIPSIS) { - if (next_token(s)) - return -1; - if (js_parse_assign_expr(s)) - return -1; -#if 1 - /* XXX: could pass is_last indicator? */ - emit_op(s, OP_append); -#else - int label_next, label_done; - label_next = new_label(s); - label_done = new_label(s); - /* push enumerate object below array/idx pair */ - emit_op(s, OP_for_of_start); - emit_op(s, OP_rot5l); - emit_op(s, OP_rot5l); - emit_label(s, label_next); - /* on stack: enum_rec array idx */ - emit_op(s, OP_for_of_next); - emit_u8(s, 2); - emit_goto(s, OP_if_true, label_done); - /* append element */ - /* enum_rec array idx val -> enum_rec array new_idx */ - emit_op(s, OP_define_array_el); - emit_op(s, OP_inc); - emit_goto(s, OP_goto, label_next); - emit_label(s, label_done); - /* close enumeration, drop enum_rec and idx */ - emit_op(s, OP_drop); /* drop undef */ - emit_op(s, OP_nip1); /* drop enum_rec */ - emit_op(s, OP_nip1); - emit_op(s, OP_nip1); -#endif - } else { - if (js_parse_assign_expr(s)) - return -1; - /* array idx val */ - emit_op(s, OP_define_array_el); - emit_op(s, OP_inc); - } - if (s->token.val == ')') - break; - /* accept a trailing comma before the ')' */ - if (js_parse_expect(s, ',')) - return -1; - } - if (next_token(s)) - return -1; - /* drop the index */ - emit_op(s, OP_drop); - /* apply function call */ - switch(opcode) { - case OP_get_field: - case OP_scope_get_private_field: - case OP_get_array_el: - case OP_scope_get_ref: - /* obj func array -> func obj array */ - emit_op(s, OP_perm3); - emit_op(s, OP_apply); - emit_u16(s, call_type == FUNC_CALL_NEW); - break; - case OP_eval: - emit_op(s, OP_apply_eval); - emit_u16(s, fd->scope_level); - fd->has_eval_call = TRUE; - break; - default: - if (call_type == FUNC_CALL_SUPER_CTOR) { - emit_op(s, OP_apply); - emit_u16(s, 1); - /* set the 'this' value */ - emit_op(s, OP_dup); - emit_op(s, OP_scope_put_var_init); - emit_atom(s, JS_ATOM_this); - emit_u16(s, 0); - emit_class_field_init(s); - } else if (call_type == FUNC_CALL_NEW) { - /* obj func array -> func obj array */ - emit_op(s, OP_perm3); - emit_op(s, OP_apply); - emit_u16(s, 1); - } else { - /* func array -> func undef array */ - emit_op(s, OP_undefined); - emit_op(s, OP_swap); - emit_op(s, OP_apply); - emit_u16(s, 0); - } - break; - } - } else { - if (next_token(s)) - return -1; - emit_func_call: - switch(opcode) { - case OP_get_field: - case OP_scope_get_private_field: - case OP_get_array_el: - case OP_scope_get_ref: - emit_op(s, OP_call_method); - emit_u16(s, arg_count); - break; - case OP_eval: - emit_op(s, OP_eval); - emit_u16(s, arg_count); - emit_u16(s, fd->scope_level); - fd->has_eval_call = TRUE; - break; - default: - if (call_type == FUNC_CALL_SUPER_CTOR) { - emit_op(s, OP_call_constructor); - emit_u16(s, arg_count); - /* set the 'this' value */ - emit_op(s, OP_dup); - emit_op(s, OP_scope_put_var_init); - emit_atom(s, JS_ATOM_this); - emit_u16(s, 0); - emit_class_field_init(s); - } else if (call_type == FUNC_CALL_NEW) { - emit_op(s, OP_call_constructor); - emit_u16(s, arg_count); - } else { - emit_op(s, OP_call); - emit_u16(s, arg_count); - } - break; - } - } - call_type = FUNC_CALL_NORMAL; - } else if (s->token.val == '.') { - if (next_token(s)) - return -1; - parse_property: - if (s->token.val == TOK_PRIVATE_NAME) { - /* private class field */ - if (get_prev_opcode(fd) == OP_get_super) { - return js_parse_error(s, "private class field forbidden after super"); - } - if (has_optional_chain) { - optional_chain_test(s, &optional_chaining_label, 1); - } - emit_op(s, OP_scope_get_private_field); - emit_atom(s, s->token.u.ident.atom); - emit_u16(s, s->cur_func->scope_level); - } else { - if (!token_is_ident(s->token.val)) { - return js_parse_error(s, "expecting field name"); - } - if (get_prev_opcode(fd) == OP_get_super) { - JSValue val; - int ret; - val = JS_AtomToValue(s->ctx, s->token.u.ident.atom); - ret = emit_push_const(s, val, 1); - JS_FreeValue(s->ctx, val); - if (ret) - return -1; - emit_op(s, OP_get_super_value); - } else { - if (has_optional_chain) { - optional_chain_test(s, &optional_chaining_label, 1); - } - emit_op(s, OP_get_field); - emit_atom(s, s->token.u.ident.atom); - } - } - if (next_token(s)) - return -1; - } else if (s->token.val == '[') { - int prev_op; - parse_array_access: - prev_op = get_prev_opcode(fd); - if (has_optional_chain) { - optional_chain_test(s, &optional_chaining_label, 1); - } - if (next_token(s)) - return -1; - if (js_parse_expr(s)) - return -1; - if (js_parse_expect(s, ']')) - return -1; - if (prev_op == OP_get_super) { - emit_op(s, OP_get_super_value); - } else { - emit_op(s, OP_get_array_el); - } - } else { - break; - } - } - if (optional_chaining_label >= 0) - emit_label(s, optional_chaining_label); - return 0; -} - -static int js_unsupported_keyword(JSParseState *s, JSAtom atom) -{ - char buf[ATOM_GET_STR_BUF_SIZE]; - return js_parse_error(s, "unsupported keyword: %s", - JS_AtomGetStr(s->ctx, buf, sizeof(buf), atom)); -} - -/* XXX: handle IteratorClose when exiting the loop before the - enumeration is done */ -static __exception int js_parse_for_in_of(JSParseState *s, int label_name, - BOOL is_async) -{ - JSContext *ctx = s->ctx; - JSFunctionDef *fd = s->cur_func; - JSAtom var_name; - BOOL has_initializer, is_for_of, has_destructuring; - int tok, tok1, opcode, scope, block_scope_level; - int label_next, label_expr, label_cont, label_body, label_break; - int pos_next, pos_expr; - BlockEnv break_entry; - has_initializer = FALSE; - has_destructuring = FALSE; - is_for_of = FALSE; - block_scope_level = fd->scope_level; - label_cont = new_label(s); - label_body = new_label(s); - label_break = new_label(s); - label_next = new_label(s); - /* create scope for the lexical variables declared in the enumeration - expressions. XXX: Not completely correct because of weird capturing - semantics in `for (i of o) a.push(function(){return i})` */ - push_scope(s); - /* local for_in scope starts here so individual elements - can be closed in statement. */ - push_break_entry(s->cur_func, &break_entry, - label_name, label_break, label_cont, 1); - break_entry.scope_level = block_scope_level; - label_expr = emit_goto(s, OP_goto, -1); - pos_next = s->cur_func->byte_code.size; - emit_label(s, label_next); - tok = s->token.val; - switch (is_let(s, DECL_MASK_OTHER)) { - case TRUE: - tok = TOK_LET; - break; - case FALSE: - break; - default: - return -1; - } - if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) { - if (next_token(s)) - return -1; - if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) { - if (s->token.val == '[' || s->token.val == '{') { - if (js_parse_destructuring_element(s, tok, 0, TRUE, -1, FALSE) < 0) - return -1; - has_destructuring = TRUE; - } else { - return js_parse_error(s, "variable name expected"); - } - var_name = JS_ATOM_NULL; - } else { - var_name = JS_DupAtom(ctx, s->token.u.ident.atom); - if (next_token(s)) { - JS_FreeAtom(s->ctx, var_name); - return -1; - } - if (js_define_var(s, var_name, tok)) { - JS_FreeAtom(s->ctx, var_name); - return -1; - } - emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ? - OP_scope_put_var_init : OP_scope_put_var); - emit_atom(s, var_name); - emit_u16(s, fd->scope_level); - } - } else { - int skip_bits; - if ((s->token.val == '[' || s->token.val == '{') - && ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == TOK_IN || tok1 == TOK_OF)) { - if (js_parse_destructuring_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0) - return -1; - } else { - int lvalue_label; - if (js_parse_left_hand_side_expr(s)) - return -1; - if (get_lvalue(s, &opcode, &scope, &var_name, &lvalue_label, - NULL, FALSE, TOK_FOR)) - return -1; - put_lvalue(s, opcode, scope, var_name, lvalue_label, - PUT_LVALUE_NOKEEP_BOTTOM, FALSE); - } - var_name = JS_ATOM_NULL; - } - emit_goto(s, OP_goto, label_body); - pos_expr = s->cur_func->byte_code.size; - emit_label(s, label_expr); - if (s->token.val == '=') { - /* XXX: potential scoping issue if inside `with` statement */ - has_initializer = TRUE; - /* parse and evaluate initializer prior to evaluating the - object (only used with "for in" with a non lexical variable - in non strict mode */ - if (next_token(s) || js_parse_assign_expr2(s, 0)) { - JS_FreeAtom(ctx, var_name); - return -1; - } - if (var_name != JS_ATOM_NULL) { - emit_op(s, OP_scope_put_var); - emit_atom(s, var_name); - emit_u16(s, fd->scope_level); - } - } - JS_FreeAtom(ctx, var_name); - if (token_is_pseudo_keyword(s, JS_ATOM_of)) { - break_entry.has_iterator = is_for_of = TRUE; - break_entry.drop_count += 2; - if (has_initializer) - goto initializer_error; - } else if (s->token.val == TOK_IN) { - if (is_async) - return js_parse_error(s, "'for await' loop should be used with 'of'"); - if (has_initializer && - (tok != TOK_VAR || (fd->js_mode & JS_MODE_STRICT) || - has_destructuring)) { - initializer_error: - return js_parse_error(s, "a declaration in the head of a for-%s loop can't have an initializer", - is_for_of ? "of" : "in"); - } - } else { - return js_parse_error(s, "expected 'of' or 'in' in for control expression"); - } - if (next_token(s)) - return -1; - if (is_for_of) { - if (js_parse_assign_expr(s)) - return -1; - } else { - if (js_parse_expr(s)) - return -1; - } - /* close the scope after having evaluated the expression so that - the TDZ values are in the closures */ - close_scopes(s, s->cur_func->scope_level, block_scope_level); - if (is_for_of) { - if (is_async) - emit_op(s, OP_for_await_of_start); - else - emit_op(s, OP_for_of_start); - /* on stack: enum_rec */ - } else { - emit_op(s, OP_for_in_start); - /* on stack: enum_obj */ - } - emit_goto(s, OP_goto, label_cont); - if (js_parse_expect(s, ')')) - return -1; - if (OPTIMIZE) { - /* move the `next` code here */ - DynBuf *bc = &s->cur_func->byte_code; - int chunk_size = pos_expr - pos_next; - int offset = bc->size - pos_next; - int i; - dbuf_realloc(bc, bc->size + chunk_size); - dbuf_put(bc, bc->buf + pos_next, chunk_size); - memset(bc->buf + pos_next, OP_nop, chunk_size); - /* `next` part ends with a goto */ - s->cur_func->last_opcode_pos = bc->size - 5; - /* relocate labels */ - for (i = label_cont; i < s->cur_func->label_count; i++) { - LabelSlot *ls = &s->cur_func->label_slots[i]; - if (ls->pos >= pos_next && ls->pos < pos_expr) - ls->pos += offset; - } - } - emit_label(s, label_body); - if (js_parse_statement(s)) - return -1; - close_scopes(s, s->cur_func->scope_level, block_scope_level); - emit_label(s, label_cont); - if (is_for_of) { - if (is_async) { - /* call the next method */ - /* stack: iter_obj next catch_offset */ - emit_op(s, OP_dup3); - emit_op(s, OP_drop); - emit_op(s, OP_call_method); - emit_u16(s, 0); - /* get the result of the promise */ - emit_op(s, OP_await); - /* unwrap the value and done values */ - emit_op(s, OP_iterator_get_value_done); - } else { - emit_op(s, OP_for_of_next); - emit_u8(s, 0); - } - } else { - emit_op(s, OP_for_in_next); - } - /* on stack: enum_rec / enum_obj value bool */ - emit_goto(s, OP_if_false, label_next); - /* drop the undefined value from for_xx_next */ - emit_op(s, OP_drop); - emit_label(s, label_break); - if (is_for_of) { - /* close and drop enum_rec */ - emit_op(s, OP_iterator_close); - } else { - emit_op(s, OP_drop); - } - pop_break_entry(s->cur_func); - pop_scope(s); - return 0; -} - -/* allowed parse_flags: PF_IN_ACCEPTED */ -static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok, - BOOL export_flag) -{ - JSContext *ctx = s->ctx; - JSFunctionDef *fd = s->cur_func; - JSAtom name = JS_ATOM_NULL; - for (;;) { - if (s->token.val == TOK_IDENT) { - if (s->token.u.ident.is_reserved) { - return js_parse_error_reserved_identifier(s); - } - name = JS_DupAtom(ctx, s->token.u.ident.atom); - if (name == JS_ATOM_let && (tok == TOK_LET || tok == TOK_CONST)) { - js_parse_error(s, "'let' is not a valid lexical identifier"); - goto var_error; - } - if (next_token(s)) - goto var_error; - if (js_define_var(s, name, tok)) - goto var_error; - if (export_flag) { - if (!add_export_entry(s, s->cur_func->module, name, name, - JS_EXPORT_TYPE_LOCAL)) - goto var_error; - } - if (s->token.val == '=') { - if (next_token(s)) - goto var_error; - if (tok == TOK_VAR) { - /* Must make a reference for proper `with` semantics */ - int opcode, scope, label; - JSAtom name1; - emit_op(s, OP_scope_get_var); - emit_atom(s, name); - emit_u16(s, fd->scope_level); - if (get_lvalue(s, &opcode, &scope, &name1, &label, NULL, FALSE, '=') < 0) - goto var_error; - if (js_parse_assign_expr2(s, parse_flags)) { - JS_FreeAtom(ctx, name1); - goto var_error; - } - set_object_name(s, name); - put_lvalue(s, opcode, scope, name1, label, - PUT_LVALUE_NOKEEP, FALSE); - } else { - if (js_parse_assign_expr2(s, parse_flags)) - goto var_error; - set_object_name(s, name); - emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ? - OP_scope_put_var_init : OP_scope_put_var); - emit_atom(s, name); - emit_u16(s, fd->scope_level); - } - } else { - if (tok == TOK_CONST) { - js_parse_error(s, "missing initializer for const variable"); - goto var_error; - } - if (tok == TOK_LET) { - /* initialize lexical variable upon entering its scope */ - emit_op(s, OP_undefined); - emit_op(s, OP_scope_put_var_init); - emit_atom(s, name); - emit_u16(s, fd->scope_level); - } - } - JS_FreeAtom(ctx, name); - } else { - int skip_bits; - if ((s->token.val == '[' || s->token.val == '{') - && js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') { - emit_op(s, OP_undefined); - if (js_parse_destructuring_element(s, tok, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0) - return -1; - } else { - return js_parse_error(s, "variable name expected"); - } - } - if (s->token.val != ',') - break; - if (next_token(s)) - return -1; - } - return 0; - var_error: - JS_FreeAtom(ctx, name); - return -1; -} - -/* execute the finally blocks before return */ -static void emit_return(JSParseState *s, BOOL hasval) -{ - BlockEnv *top; - int drop_count; - drop_count = 0; - top = s->cur_func->top_break; - while (top != NULL) { - /* XXX: emit the appropriate OP_leave_scope opcodes? Probably not - required as all local variables will be closed upon returning - from JS_CallInternal, but not in the same order. */ - if (top->has_iterator) { - /* with 'yield', the exact number of OP_drop to emit is - unknown, so we use a specific operation to look for - the catch offset */ - if (!hasval) { - emit_op(s, OP_undefined); - hasval = TRUE; - } - emit_op(s, OP_iterator_close_return); - if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) { - int label_next, label_next2; - emit_op(s, OP_drop); /* catch offset */ - emit_op(s, OP_drop); /* next */ - emit_op(s, OP_get_field2); - emit_atom(s, JS_ATOM_return); - /* stack: iter_obj return_func */ - emit_op(s, OP_dup); - emit_op(s, OP_is_undefined_or_null); - label_next = emit_goto(s, OP_if_true, -1); - emit_op(s, OP_call_method); - emit_u16(s, 0); - emit_op(s, OP_iterator_check_object); - emit_op(s, OP_await); - label_next2 = emit_goto(s, OP_goto, -1); - emit_label(s, label_next); - emit_op(s, OP_drop); - emit_label(s, label_next2); - emit_op(s, OP_drop); - } else { - emit_op(s, OP_iterator_close); - } - drop_count = -3; - } - drop_count += top->drop_count; - if (top->label_finally != -1) { - while(drop_count) { - /* must keep the stack top if hasval */ - emit_op(s, hasval ? OP_nip : OP_drop); - drop_count--; - } - if (!hasval) { - /* must push return value to keep same stack size */ - emit_op(s, OP_undefined); - hasval = TRUE; - } - emit_goto(s, OP_gosub, top->label_finally); - } - top = top->prev; - } - if (s->cur_func->is_derived_class_constructor) { - int label_return; - /* 'this' can be uninitialized, so it may be accessed only if - the derived class constructor does not return an object */ - if (hasval) { - emit_op(s, OP_check_ctor_return); - label_return = emit_goto(s, OP_if_false, -1); - emit_op(s, OP_drop); - } else { - label_return = -1; - } - /* XXX: if this is not initialized, should throw the - ReferenceError in the caller realm */ - emit_op(s, OP_scope_get_var); - emit_atom(s, JS_ATOM_this); - emit_u16(s, 0); - emit_label(s, label_return); - emit_op(s, OP_return); - } else if (s->cur_func->func_kind != JS_FUNC_NORMAL) { - if (!hasval) { - emit_op(s, OP_undefined); - } else if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) { - emit_op(s, OP_await); - } - emit_op(s, OP_return_async); - } else { - emit_op(s, hasval ? OP_return : OP_return_undef); - } -} - -static void set_eval_ret_undefined(JSParseState *s) -{ - if (s->cur_func->eval_ret_idx >= 0) { - emit_op(s, OP_undefined); - emit_op(s, OP_put_loc); - emit_u16(s, s->cur_func->eval_ret_idx); - } -} - -/* allowed parse_flags: PF_IN_ACCEPTED */ -static __exception int js_parse_expr2(JSParseState *s, int parse_flags) -{ - BOOL comma = FALSE; - for(;;) { - if (js_parse_assign_expr2(s, parse_flags)) - return -1; - if (comma) { - /* prevent get_lvalue from using the last expression - as an lvalue. This also prevents the conversion of - of get_var to get_ref for method lookup in function - call inside `with` statement. - */ - s->cur_func->last_opcode_pos = -1; - } - if (s->token.val != ',') - break; - comma = TRUE; - if (next_token(s)) - return -1; - emit_op(s, OP_drop); - } - return 0; -} - -static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont) -{ - BlockEnv *top; - int i, scope_level; - scope_level = s->cur_func->scope_level; - top = s->cur_func->top_break; - while (top != NULL) { - close_scopes(s, scope_level, top->scope_level); - scope_level = top->scope_level; - if (is_cont && - top->label_cont != -1 && - (name == JS_ATOM_NULL || top->label_name == name)) { - /* continue stays inside the same block */ - emit_goto(s, OP_goto, top->label_cont); - return 0; - } - if (!is_cont && - top->label_break != -1 && - (name == JS_ATOM_NULL || top->label_name == name)) { - emit_goto(s, OP_goto, top->label_break); - return 0; - } - i = 0; - if (top->has_iterator) { - emit_op(s, OP_iterator_close); - i += 3; - } - for(; i < top->drop_count; i++) - emit_op(s, OP_drop); - if (top->label_finally != -1) { - /* must push dummy value to keep same stack depth */ - emit_op(s, OP_undefined); - emit_goto(s, OP_gosub, top->label_finally); - emit_op(s, OP_drop); - } - top = top->prev; - } - if (name == JS_ATOM_NULL) { - if (is_cont) - return js_parse_error(s, "continue must be inside loop"); - else - return js_parse_error(s, "break must be inside loop or switch"); - } else { - return js_parse_error(s, "break/continue label not found"); - } -} - -static int js_parse_statement_or_decl(JSParseState *s, int decl_mask) -{ - JSContext *ctx = s->ctx; - JSAtom label_name; - int tok; - /* specific label handling */ - /* XXX: support multiple labels on loop statements */ - label_name = JS_ATOM_NULL; - if (is_label(s)) { - BlockEnv *be; - label_name = JS_DupAtom(ctx, s->token.u.ident.atom); - for (be = s->cur_func->top_break; be; be = be->prev) { - if (be->label_name == label_name) { - js_parse_error(s, "duplicate label name"); - goto fail; - } - } - if (next_token(s)) - goto fail; - if (js_parse_expect(s, ':')) - goto fail; - if (s->token.val != TOK_FOR - && s->token.val != TOK_DO - && s->token.val != TOK_WHILE) { - /* labelled regular statement */ - int label_break, mask; - BlockEnv break_entry; - label_break = new_label(s); - push_break_entry(s->cur_func, &break_entry, - label_name, label_break, -1, 0); - if (!(s->cur_func->js_mode & JS_MODE_STRICT) && - (decl_mask & DECL_MASK_FUNC_WITH_LABEL)) { - mask = DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL; - } else { - mask = 0; - } - if (js_parse_statement_or_decl(s, mask)) - goto fail; - emit_label(s, label_break); - pop_break_entry(s->cur_func); - goto done; - } - } - switch(tok = s->token.val) { - case '{': - if (js_parse_block(s)) - goto fail; - break; - case TOK_RETURN: - if (s->cur_func->is_eval) { - js_parse_error(s, "return not in a function"); - goto fail; - } - if (next_token(s)) - goto fail; - if (s->token.val != ';' && s->token.val != '}' && !s->got_lf) { - if (js_parse_expr(s)) - goto fail; - emit_return(s, TRUE); - } else { - emit_return(s, FALSE); - } - if (js_parse_expect_semi(s)) - goto fail; - break; - case TOK_THROW: - if (next_token(s)) - goto fail; - if (s->got_lf) { - js_parse_error(s, "line terminator not allowed after throw"); - goto fail; - } - if (js_parse_expr(s)) - goto fail; - emit_op(s, OP_throw); - if (js_parse_expect_semi(s)) - goto fail; - break; - case TOK_LET: - case TOK_CONST: - haslet: - if (!(decl_mask & DECL_MASK_OTHER)) { - js_parse_error(s, "lexical declarations can't appear in single-statement context"); - goto fail; - } - /* fall thru */ - case TOK_VAR: - if (next_token(s)) - goto fail; - if (js_parse_var(s, TRUE, tok, FALSE)) - goto fail; - if (js_parse_expect_semi(s)) - goto fail; - break; - case TOK_IF: - { - int label1, label2, mask; - if (next_token(s)) - goto fail; - /* create a new scope for `let f;if(1) function f(){}` */ - push_scope(s); - set_eval_ret_undefined(s); - if (js_parse_expr_paren(s)) - goto fail; - label1 = emit_goto(s, OP_if_false, -1); - if (s->cur_func->js_mode & JS_MODE_STRICT) - mask = 0; - else - mask = DECL_MASK_FUNC; /* Annex B.3.4 */ - if (js_parse_statement_or_decl(s, mask)) - goto fail; - if (s->token.val == TOK_ELSE) { - label2 = emit_goto(s, OP_goto, -1); - if (next_token(s)) - goto fail; - emit_label(s, label1); - if (js_parse_statement_or_decl(s, mask)) - goto fail; - label1 = label2; - } - emit_label(s, label1); - pop_scope(s); - } - break; - case TOK_WHILE: - { - int label_cont, label_break; - BlockEnv break_entry; - label_cont = new_label(s); - label_break = new_label(s); - push_break_entry(s->cur_func, &break_entry, - label_name, label_break, label_cont, 0); - if (next_token(s)) - goto fail; - set_eval_ret_undefined(s); - emit_label(s, label_cont); - if (js_parse_expr_paren(s)) - goto fail; - emit_goto(s, OP_if_false, label_break); - if (js_parse_statement(s)) - goto fail; - emit_goto(s, OP_goto, label_cont); - emit_label(s, label_break); - pop_break_entry(s->cur_func); - } - break; - case TOK_DO: - { - int label_cont, label_break, label1; - BlockEnv break_entry; - label_cont = new_label(s); - label_break = new_label(s); - label1 = new_label(s); - push_break_entry(s->cur_func, &break_entry, - label_name, label_break, label_cont, 0); - if (next_token(s)) - goto fail; - emit_label(s, label1); - set_eval_ret_undefined(s); - if (js_parse_statement(s)) - goto fail; - emit_label(s, label_cont); - if (js_parse_expect(s, TOK_WHILE)) - goto fail; - if (js_parse_expr_paren(s)) - goto fail; - /* Insert semicolon if missing */ - if (s->token.val == ';') { - if (next_token(s)) - goto fail; - } - emit_goto(s, OP_if_true, label1); - emit_label(s, label_break); - pop_break_entry(s->cur_func); - } - break; - case TOK_FOR: - { - int label_cont, label_break, label_body, label_test; - int pos_cont, pos_body, block_scope_level; - BlockEnv break_entry; - int tok, bits; - BOOL is_async; - if (next_token(s)) - goto fail; - set_eval_ret_undefined(s); - bits = 0; - is_async = FALSE; - if (s->token.val == '(') { - js_parse_skip_parens_token(s, &bits, FALSE); - } else if (s->token.val == TOK_AWAIT) { - if (!(s->cur_func->func_kind & JS_FUNC_ASYNC)) { - js_parse_error(s, "for await is only valid in asynchronous functions"); - goto fail; - } - is_async = TRUE; - if (next_token(s)) - goto fail; - } - if (js_parse_expect(s, '(')) - goto fail; - if (!(bits & SKIP_HAS_SEMI)) { - /* parse for/in or for/of */ - if (js_parse_for_in_of(s, label_name, is_async)) - goto fail; - break; - } - block_scope_level = s->cur_func->scope_level; - /* create scope for the lexical variables declared in the initial, - test and increment expressions */ - push_scope(s); - /* initial expression */ - tok = s->token.val; - if (tok != ';') { - switch (is_let(s, DECL_MASK_OTHER)) { - case TRUE: - tok = TOK_LET; - break; - case FALSE: - break; - default: - goto fail; - } - if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) { - if (next_token(s)) - goto fail; - if (js_parse_var(s, FALSE, tok, FALSE)) - goto fail; - } else { - if (js_parse_expr2(s, FALSE)) - goto fail; - emit_op(s, OP_drop); - } - /* close the closures before the first iteration */ - close_scopes(s, s->cur_func->scope_level, block_scope_level); - } - if (js_parse_expect(s, ';')) - goto fail; - label_test = new_label(s); - label_cont = new_label(s); - label_body = new_label(s); - label_break = new_label(s); - push_break_entry(s->cur_func, &break_entry, - label_name, label_break, label_cont, 0); - /* test expression */ - if (s->token.val == ';') { - /* no test expression */ - label_test = label_body; - } else { - emit_label(s, label_test); - if (js_parse_expr(s)) - goto fail; - emit_goto(s, OP_if_false, label_break); - } - if (js_parse_expect(s, ';')) - goto fail; - if (s->token.val == ')') { - /* no end expression */ - break_entry.label_cont = label_cont = label_test; - pos_cont = 0; /* avoid warning */ - } else { - /* skip the end expression */ - emit_goto(s, OP_goto, label_body); - pos_cont = s->cur_func->byte_code.size; - emit_label(s, label_cont); - if (js_parse_expr(s)) - goto fail; - emit_op(s, OP_drop); - if (label_test != label_body) - emit_goto(s, OP_goto, label_test); - } - if (js_parse_expect(s, ')')) - goto fail; - pos_body = s->cur_func->byte_code.size; - emit_label(s, label_body); - if (js_parse_statement(s)) - goto fail; - /* close the closures before the next iteration */ - /* XXX: check continue case */ - close_scopes(s, s->cur_func->scope_level, block_scope_level); - if (OPTIMIZE && label_test != label_body && label_cont != label_test) { - /* move the increment code here */ - DynBuf *bc = &s->cur_func->byte_code; - int chunk_size = pos_body - pos_cont; - int offset = bc->size - pos_cont; - int i; - dbuf_realloc(bc, bc->size + chunk_size); - dbuf_put(bc, bc->buf + pos_cont, chunk_size); - memset(bc->buf + pos_cont, OP_nop, chunk_size); - /* increment part ends with a goto */ - s->cur_func->last_opcode_pos = bc->size - 5; - /* relocate labels */ - for (i = label_cont; i < s->cur_func->label_count; i++) { - LabelSlot *ls = &s->cur_func->label_slots[i]; - if (ls->pos >= pos_cont && ls->pos < pos_body) - ls->pos += offset; - } - } else { - emit_goto(s, OP_goto, label_cont); - } - emit_label(s, label_break); - pop_break_entry(s->cur_func); - pop_scope(s); - } - break; - case TOK_BREAK: - case TOK_CONTINUE: - { - int is_cont = s->token.val - TOK_BREAK; - int label; - if (next_token(s)) - goto fail; - if (!s->got_lf && s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved) - label = s->token.u.ident.atom; - else - label = JS_ATOM_NULL; - if (emit_break(s, label, is_cont)) - goto fail; - if (label != JS_ATOM_NULL) { - if (next_token(s)) - goto fail; - } - if (js_parse_expect_semi(s)) - goto fail; - } - break; - case TOK_SWITCH: - { - int label_case, label_break, label1; - int default_label_pos; - BlockEnv break_entry; - if (next_token(s)) - goto fail; - set_eval_ret_undefined(s); - if (js_parse_expr_paren(s)) - goto fail; - push_scope(s); - label_break = new_label(s); - push_break_entry(s->cur_func, &break_entry, - label_name, label_break, -1, 1); - if (js_parse_expect(s, '{')) - goto fail; - default_label_pos = -1; - label_case = -1; - while (s->token.val != '}') { - if (s->token.val == TOK_CASE) { - label1 = -1; - if (label_case >= 0) { - /* skip the case if needed */ - label1 = emit_goto(s, OP_goto, -1); - } - emit_label(s, label_case); - label_case = -1; - for (;;) { - /* parse a sequence of case clauses */ - if (next_token(s)) - goto fail; - emit_op(s, OP_dup); - if (js_parse_expr(s)) - goto fail; - if (js_parse_expect(s, ':')) - goto fail; - emit_op(s, OP_strict_eq); - if (s->token.val == TOK_CASE) { - label1 = emit_goto(s, OP_if_true, label1); - } else { - label_case = emit_goto(s, OP_if_false, -1); - emit_label(s, label1); - break; - } - } - } else if (s->token.val == TOK_DEFAULT) { - if (next_token(s)) - goto fail; - if (js_parse_expect(s, ':')) - goto fail; - if (default_label_pos >= 0) { - js_parse_error(s, "duplicate default"); - goto fail; - } - if (label_case < 0) { - /* falling thru direct from switch expression */ - label_case = emit_goto(s, OP_goto, -1); - } - /* Emit a dummy label opcode. Label will be patched after - the end of the switch body. Do not use emit_label(s, 0) - because it would clobber label 0 address, preventing - proper optimizer operation. - */ - emit_op(s, OP_label); - emit_u32(s, 0); - default_label_pos = s->cur_func->byte_code.size - 4; - } else { - if (label_case < 0) { - /* falling thru direct from switch expression */ - js_parse_error(s, "invalid switch statement"); - goto fail; - } - if (js_parse_statement_or_decl(s, DECL_MASK_ALL)) - goto fail; - } - } - if (js_parse_expect(s, '}')) - goto fail; - if (default_label_pos >= 0) { - /* Ugly patch for the the `default` label, shameful and risky */ - put_u32(s->cur_func->byte_code.buf + default_label_pos, - label_case); - s->cur_func->label_slots[label_case].pos = default_label_pos + 4; - } else { - emit_label(s, label_case); - } - emit_label(s, label_break); - emit_op(s, OP_drop); /* drop the switch expression */ - pop_break_entry(s->cur_func); - pop_scope(s); - } - break; - case TOK_TRY: - { - int label_catch, label_catch2, label_finally, label_end; - JSAtom name; - BlockEnv block_env; - set_eval_ret_undefined(s); - if (next_token(s)) - goto fail; - label_catch = new_label(s); - label_catch2 = new_label(s); - label_finally = new_label(s); - label_end = new_label(s); - emit_goto(s, OP_catch, label_catch); - push_break_entry(s->cur_func, &block_env, - JS_ATOM_NULL, -1, -1, 1); - block_env.label_finally = label_finally; - if (js_parse_block(s)) - goto fail; - pop_break_entry(s->cur_func); - if (js_is_live_code(s)) { - /* drop the catch offset */ - emit_op(s, OP_drop); - /* must push dummy value to keep same stack size */ - emit_op(s, OP_undefined); - emit_goto(s, OP_gosub, label_finally); - emit_op(s, OP_drop); - emit_goto(s, OP_goto, label_end); - } - if (s->token.val == TOK_CATCH) { - if (next_token(s)) - goto fail; - push_scope(s); /* catch variable */ - emit_label(s, label_catch); - if (s->token.val == '{') { - /* support optional-catch-binding feature */ - emit_op(s, OP_drop); /* pop the exception object */ - } else { - if (js_parse_expect(s, '(')) - goto fail; - if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) { - if (s->token.val == '[' || s->token.val == '{') { - /* XXX: TOK_LET is not completely correct */ - if (js_parse_destructuring_element(s, TOK_LET, 0, TRUE, -1, TRUE) < 0) - goto fail; - } else { - js_parse_error(s, "identifier expected"); - goto fail; - } - } else { - name = JS_DupAtom(ctx, s->token.u.ident.atom); - if (next_token(s) - || js_define_var(s, name, TOK_CATCH) < 0) { - JS_FreeAtom(ctx, name); - goto fail; - } - /* store the exception value in the catch variable */ - emit_op(s, OP_scope_put_var); - emit_u32(s, name); - emit_u16(s, s->cur_func->scope_level); - } - if (js_parse_expect(s, ')')) - goto fail; - } - /* XXX: should keep the address to nop it out if there is no finally block */ - emit_goto(s, OP_catch, label_catch2); - push_scope(s); /* catch block */ - push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL, - -1, -1, 1); - block_env.label_finally = label_finally; - if (js_parse_block(s)) - goto fail; - pop_break_entry(s->cur_func); - pop_scope(s); /* catch block */ - pop_scope(s); /* catch variable */ - if (js_is_live_code(s)) { - /* drop the catch2 offset */ - emit_op(s, OP_drop); - /* XXX: should keep the address to nop it out if there is no finally block */ - /* must push dummy value to keep same stack size */ - emit_op(s, OP_undefined); - emit_goto(s, OP_gosub, label_finally); - emit_op(s, OP_drop); - emit_goto(s, OP_goto, label_end); - } - /* catch exceptions thrown in the catch block to execute the - * finally clause and rethrow the exception */ - emit_label(s, label_catch2); - /* catch value is at TOS, no need to push undefined */ - emit_goto(s, OP_gosub, label_finally); - emit_op(s, OP_throw); - } else if (s->token.val == TOK_FINALLY) { - /* finally without catch : execute the finally clause - * and rethrow the exception */ - emit_label(s, label_catch); - /* catch value is at TOS, no need to push undefined */ - emit_goto(s, OP_gosub, label_finally); - emit_op(s, OP_throw); - } else { - js_parse_error(s, "expecting catch or finally"); - goto fail; - } - emit_label(s, label_finally); - if (s->token.val == TOK_FINALLY) { - int saved_eval_ret_idx = 0; /* avoid warning */ - if (next_token(s)) - goto fail; - /* on the stack: ret_value gosub_ret_value */ - push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL, - -1, -1, 2); - if (s->cur_func->eval_ret_idx >= 0) { - /* 'finally' updates eval_ret only if not a normal - termination */ - saved_eval_ret_idx = - add_var(s->ctx, s->cur_func, JS_ATOM__ret_); - if (saved_eval_ret_idx < 0) - goto fail; - emit_op(s, OP_get_loc); - emit_u16(s, s->cur_func->eval_ret_idx); - emit_op(s, OP_put_loc); - emit_u16(s, saved_eval_ret_idx); - set_eval_ret_undefined(s); - } - if (js_parse_block(s)) - goto fail; - if (s->cur_func->eval_ret_idx >= 0) { - emit_op(s, OP_get_loc); - emit_u16(s, saved_eval_ret_idx); - emit_op(s, OP_put_loc); - emit_u16(s, s->cur_func->eval_ret_idx); - } - pop_break_entry(s->cur_func); - } - emit_op(s, OP_ret); - emit_label(s, label_end); - } - break; - case ';': - /* empty statement */ - if (next_token(s)) - goto fail; - break; - case TOK_WITH: - if (s->cur_func->js_mode & JS_MODE_STRICT) { - js_parse_error(s, "invalid keyword: with"); - goto fail; - } else { - int with_idx; - if (next_token(s)) - goto fail; - if (js_parse_expr_paren(s)) - goto fail; - push_scope(s); - with_idx = define_var(s, s->cur_func, JS_ATOM__with_, - JS_VAR_DEF_WITH); - if (with_idx < 0) - goto fail; - emit_op(s, OP_to_object); - emit_op(s, OP_put_loc); - emit_u16(s, with_idx); - set_eval_ret_undefined(s); - if (js_parse_statement(s)) - goto fail; - /* Popping scope drops lexical context for the with object variable */ - pop_scope(s); - } - break; - case TOK_FUNCTION: - /* ES6 Annex B.3.2 and B.3.3 semantics */ - if (!(decl_mask & DECL_MASK_FUNC)) - goto func_decl_error; - if (!(decl_mask & DECL_MASK_OTHER) && peek_token(s, FALSE) == '*') - goto func_decl_error; - goto parse_func_var; - case TOK_IDENT: - if (s->token.u.ident.is_reserved) { - js_parse_error_reserved_identifier(s); - goto fail; - } - /* Determine if `let` introduces a Declaration or an ExpressionStatement */ - switch (is_let(s, decl_mask)) { - case TRUE: - tok = TOK_LET; - goto haslet; - case FALSE: - break; - default: - goto fail; - } - if (token_is_pseudo_keyword(s, JS_ATOM_async) && - peek_token(s, TRUE) == TOK_FUNCTION) { - if (!(decl_mask & DECL_MASK_OTHER)) { - func_decl_error: - js_parse_error(s, "function declarations can't appear in single-statement context"); - goto fail; - } - parse_func_var: - if (js_parse_function_decl(s, JS_PARSE_FUNC_VAR, - JS_FUNC_NORMAL, JS_ATOM_NULL, - s->token.ptr, s->token.line_num)) - goto fail; - break; - } - goto hasexpr; - case TOK_CLASS: - if (!(decl_mask & DECL_MASK_OTHER)) { - js_parse_error(s, "class declarations can't appear in single-statement context"); - goto fail; - } - if (js_parse_class(s, FALSE, JS_PARSE_EXPORT_NONE)) - return -1; - break; - case TOK_DEBUGGER: - /* currently no debugger, so just skip the keyword */ - if (next_token(s)) - goto fail; - if (js_parse_expect_semi(s)) - goto fail; - break; - case TOK_ENUM: - case TOK_EXPORT: - case TOK_EXTENDS: - js_unsupported_keyword(s, s->token.u.ident.atom); - goto fail; - default: - hasexpr: - if (js_parse_expr(s)) - goto fail; - if (s->cur_func->eval_ret_idx >= 0) { - /* store the expression value so that it can be returned - by eval() */ - emit_op(s, OP_put_loc); - emit_u16(s, s->cur_func->eval_ret_idx); - } else { - emit_op(s, OP_drop); /* drop the result */ - } - if (js_parse_expect_semi(s)) - goto fail; - break; - } -done: - JS_FreeAtom(ctx, label_name); - return 0; -fail: - JS_FreeAtom(ctx, label_name); - return -1; -} - -static __exception int js_parse_delete(JSParseState *s) -{ - JSFunctionDef *fd = s->cur_func; - JSAtom name; - int opcode; - if (next_token(s)) - return -1; - if (js_parse_unary(s, PF_POW_FORBIDDEN)) - return -1; - switch(opcode = get_prev_opcode(fd)) { - case OP_get_field: - { - JSValue val; - int ret; - name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1); - fd->byte_code.size = fd->last_opcode_pos; - fd->last_opcode_pos = -1; - val = JS_AtomToValue(s->ctx, name); - ret = emit_push_const(s, val, 1); - JS_FreeValue(s->ctx, val); - JS_FreeAtom(s->ctx, name); - if (ret) - return ret; - } - goto do_delete; - case OP_get_array_el: - fd->byte_code.size = fd->last_opcode_pos; - fd->last_opcode_pos = -1; - do_delete: - emit_op(s, OP_delete); - break; - case OP_scope_get_var: - /* 'delete this': this is not a reference */ - name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1); - if (name == JS_ATOM_this || name == JS_ATOM_new_target) - goto ret_true; - if (fd->js_mode & JS_MODE_STRICT) { - return js_parse_error(s, "cannot delete a direct reference in strict mode"); - } else { - fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_delete_var; - } - break; - case OP_scope_get_private_field: - return js_parse_error(s, "cannot delete a private class field"); - case OP_get_super_value: - emit_op(s, OP_throw_error); - emit_atom(s, JS_ATOM_NULL); - emit_u8(s, JS_THROW_ERROR_DELETE_SUPER); - break; - default: - ret_true: - emit_op(s, OP_drop); - emit_op(s, OP_push_true); - break; - } - return 0; -} - -/* allowed parse_flags: PF_ARROW_FUNC, PF_POW_ALLOWED, PF_POW_FORBIDDEN */ -static __exception int js_parse_unary(JSParseState *s, int parse_flags) -{ - int op; - switch(s->token.val) { - case '+': - case '-': - case '!': - case '~': - case TOK_VOID: - op = s->token.val; - if (next_token(s)) - return -1; - if (js_parse_unary(s, PF_POW_FORBIDDEN)) - return -1; - switch(op) { - case '-': - emit_op(s, OP_neg); - break; - case '+': - emit_op(s, OP_plus); - break; - case '!': - emit_op(s, OP_lnot); - break; - case '~': - emit_op(s, OP_not); - break; - case TOK_VOID: - emit_op(s, OP_drop); - emit_op(s, OP_undefined); - break; - default: - abort(); - } - parse_flags = 0; - break; - case TOK_DEC: - case TOK_INC: - { - int opcode, op, scope, label; - JSAtom name; - op = s->token.val; - if (next_token(s)) - return -1; - if (js_parse_unary(s, 0)) - return -1; - if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op)) - return -1; - emit_op(s, OP_dec + op - TOK_DEC); - put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP, - FALSE); - } - break; - case TOK_TYPEOF: - { - JSFunctionDef *fd; - if (next_token(s)) - return -1; - if (js_parse_unary(s, PF_POW_FORBIDDEN)) - return -1; - /* reference access should not return an exception, so we - patch the get_var */ - fd = s->cur_func; - if (get_prev_opcode(fd) == OP_scope_get_var) { - fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_var_undef; - } - emit_op(s, OP_typeof); - parse_flags = 0; - } - break; - case TOK_DELETE: - if (js_parse_delete(s)) - return -1; - parse_flags = 0; - break; - case TOK_AWAIT: - if (!(s->cur_func->func_kind & JS_FUNC_ASYNC)) - return js_parse_error(s, "unexpected 'await' keyword"); - if (!s->cur_func->in_function_body) - return js_parse_error(s, "await in default expression"); - if (next_token(s)) - return -1; - if (js_parse_unary(s, PF_POW_FORBIDDEN)) - return -1; - emit_op(s, OP_await); - parse_flags = 0; - break; - default: - if (js_parse_postfix_expr(s, (parse_flags & PF_ARROW_FUNC) | - PF_POSTFIX_CALL)) - return -1; - if (!s->got_lf && - (s->token.val == TOK_DEC || s->token.val == TOK_INC)) { - int opcode, op, scope, label; - JSAtom name; - op = s->token.val; - if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op)) - return -1; - emit_op(s, OP_post_dec + op - TOK_DEC); - put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_SECOND, - FALSE); - if (next_token(s)) - return -1; - } - break; - } - if (parse_flags & (PF_POW_ALLOWED | PF_POW_FORBIDDEN)) { -#ifdef CONFIG_BIGNUM - if (s->token.val == TOK_POW || s->token.val == TOK_MATH_POW) { - /* Extended exponentiation syntax rules: we extend the ES7 - grammar in order to have more intuitive semantics: - -2**2 evaluates to -4. */ - if (!(s->cur_func->js_mode & JS_MODE_MATH)) { - if (parse_flags & PF_POW_FORBIDDEN) { - JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'"); - return -1; - } - } - if (next_token(s)) - return -1; - if (js_parse_unary(s, PF_POW_ALLOWED)) - return -1; - emit_op(s, OP_pow); - } -#else - if (s->token.val == TOK_POW) { - /* Strict ES7 exponentiation syntax rules: To solve - conficting semantics between different implementations - regarding the precedence of prefix operators and the - postifx exponential, ES7 specifies that -2**2 is a - syntax error. */ - if (parse_flags & PF_POW_FORBIDDEN) { - JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'"); - return -1; - } - if (next_token(s)) - return -1; - if (js_parse_unary(s, PF_POW_ALLOWED)) - return -1; - emit_op(s, OP_pow); - } -#endif - } - return 0; -} - -/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */ -static __exception int js_parse_expr_binary(JSParseState *s, int level, - int parse_flags) -{ - int op, opcode; - if (level == 0) { - return js_parse_unary(s, (parse_flags & PF_ARROW_FUNC) | - PF_POW_ALLOWED); - } - if (js_parse_expr_binary(s, level - 1, parse_flags)) - return -1; - for(;;) { - op = s->token.val; - switch(level) { - case 1: - switch(op) { - case '*': - opcode = OP_mul; - break; - case '/': - opcode = OP_div; - break; - case '%': -#ifdef CONFIG_BIGNUM - if (s->cur_func->js_mode & JS_MODE_MATH) - opcode = OP_math_mod; - else -#endif - opcode = OP_mod; - break; - default: - return 0; - } - break; - case 2: - switch(op) { - case '+': - opcode = OP_add; - break; - case '-': - opcode = OP_sub; - break; - default: - return 0; - } - break; - case 3: - switch(op) { - case TOK_SHL: - opcode = OP_shl; - break; - case TOK_SAR: - opcode = OP_sar; - break; - case TOK_SHR: - opcode = OP_shr; - break; - default: - return 0; - } - break; - case 4: - switch(op) { - case '<': - opcode = OP_lt; - break; - case '>': - opcode = OP_gt; - break; - case TOK_LTE: - opcode = OP_lte; - break; - case TOK_GTE: - opcode = OP_gte; - break; - case TOK_INSTANCEOF: - opcode = OP_instanceof; - break; - case TOK_IN: - if (parse_flags & PF_IN_ACCEPTED) { - opcode = OP_in; - } else { - return 0; - } - break; - default: - return 0; - } - break; - case 5: - switch(op) { - case TOK_EQ: - opcode = OP_eq; - break; - case TOK_NEQ: - opcode = OP_neq; - break; - case TOK_STRICT_EQ: - opcode = OP_strict_eq; - break; - case TOK_STRICT_NEQ: - opcode = OP_strict_neq; - break; - default: - return 0; - } - break; - case 6: - switch(op) { - case '&': - opcode = OP_and; - break; - default: - return 0; - } - break; - case 7: - switch(op) { - case '^': - opcode = OP_xor; - break; - default: - return 0; - } - break; - case 8: - switch(op) { - case '|': - opcode = OP_or; - break; - default: - return 0; - } - break; - default: - abort(); - } - if (next_token(s)) - return -1; - if (js_parse_expr_binary(s, level - 1, parse_flags & ~PF_ARROW_FUNC)) - return -1; - emit_op(s, opcode); - } - return 0; -} - -/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */ -static __exception int js_parse_logical_and_or(JSParseState *s, int op, - int parse_flags) -{ - int label1; - if (op == TOK_LAND) { - if (js_parse_expr_binary(s, 8, parse_flags)) - return -1; - } else { - if (js_parse_logical_and_or(s, TOK_LAND, parse_flags)) - return -1; - } - if (s->token.val == op) { - label1 = new_label(s); - for(;;) { - if (next_token(s)) - return -1; - emit_op(s, OP_dup); - emit_goto(s, op == TOK_LAND ? OP_if_false : OP_if_true, label1); - emit_op(s, OP_drop); - if (op == TOK_LAND) { - if (js_parse_expr_binary(s, 8, parse_flags & ~PF_ARROW_FUNC)) - return -1; - } else { - if (js_parse_logical_and_or(s, TOK_LAND, - parse_flags & ~PF_ARROW_FUNC)) - return -1; - } - if (s->token.val != op) { - if (s->token.val == TOK_DOUBLE_QUESTION_MARK) - return js_parse_error(s, "cannot mix ?? with && or ||"); - break; - } - } - emit_label(s, label1); - } - return 0; -} - -static __exception int js_parse_coalesce_expr(JSParseState *s, int parse_flags) -{ - int label1; - if (js_parse_logical_and_or(s, TOK_LOR, parse_flags)) - return -1; - if (s->token.val == TOK_DOUBLE_QUESTION_MARK) { - label1 = new_label(s); - for(;;) { - if (next_token(s)) - return -1; - emit_op(s, OP_dup); - emit_op(s, OP_is_undefined_or_null); - emit_goto(s, OP_if_false, label1); - emit_op(s, OP_drop); - if (js_parse_expr_binary(s, 8, parse_flags & ~PF_ARROW_FUNC)) - return -1; - if (s->token.val != TOK_DOUBLE_QUESTION_MARK) - break; - } - emit_label(s, label1); - } - return 0; -} - -/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */ -static __exception int js_parse_cond_expr(JSParseState *s, int parse_flags) -{ - int label1, label2; - if (js_parse_coalesce_expr(s, parse_flags)) - return -1; - if (s->token.val == '?') { - if (next_token(s)) - return -1; - label1 = emit_goto(s, OP_if_false, -1); - if (js_parse_assign_expr(s)) - return -1; - if (js_parse_expect(s, ':')) - return -1; - label2 = emit_goto(s, OP_goto, -1); - emit_label(s, label1); - if (js_parse_assign_expr2(s, parse_flags & PF_IN_ACCEPTED)) - return -1; - emit_label(s, label2); - } - return 0; -} - -/* allowed parse_flags: PF_IN_ACCEPTED */ -static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags) -{ - int opcode, op, scope; - JSAtom name0 = JS_ATOM_NULL; - JSAtom name; - if (s->token.val == TOK_YIELD) { - BOOL is_star = FALSE, is_async; - if (!(s->cur_func->func_kind & JS_FUNC_GENERATOR)) - return js_parse_error(s, "unexpected 'yield' keyword"); - if (!s->cur_func->in_function_body) - return js_parse_error(s, "yield in default expression"); - if (next_token(s)) - return -1; - /* XXX: is there a better method to detect 'yield' without - parameters ? */ - if (s->token.val != ';' && s->token.val != ')' && - s->token.val != ']' && s->token.val != '}' && - s->token.val != ',' && s->token.val != ':' && !s->got_lf) { - if (s->token.val == '*') { - is_star = TRUE; - if (next_token(s)) - return -1; - } - if (js_parse_assign_expr2(s, parse_flags)) - return -1; - } else { - emit_op(s, OP_undefined); - } - is_async = (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR); - if (is_star) { - int label_loop, label_return, label_next; - int label_return1, label_yield, label_throw, label_throw1; - int label_throw2; - label_loop = new_label(s); - label_yield = new_label(s); - emit_op(s, is_async ? OP_for_await_of_start : OP_for_of_start); - /* remove the catch offset (XXX: could avoid pushing back - undefined) */ - emit_op(s, OP_drop); - emit_op(s, OP_undefined); - emit_op(s, OP_undefined); /* initial value */ - emit_label(s, label_loop); - emit_op(s, OP_iterator_next); - if (is_async) - emit_op(s, OP_await); - emit_op(s, OP_iterator_check_object); - emit_op(s, OP_get_field2); - emit_atom(s, JS_ATOM_done); - label_next = emit_goto(s, OP_if_true, -1); /* end of loop */ - emit_label(s, label_yield); - if (is_async) { - /* OP_async_yield_star takes the value as parameter */ - emit_op(s, OP_get_field); - emit_atom(s, JS_ATOM_value); - emit_op(s, OP_await); - emit_op(s, OP_async_yield_star); - } else { - /* OP_yield_star takes (value, done) as parameter */ - emit_op(s, OP_yield_star); - } - emit_op(s, OP_dup); - label_return = emit_goto(s, OP_if_true, -1); - emit_op(s, OP_drop); - emit_goto(s, OP_goto, label_loop); - emit_label(s, label_return); - emit_op(s, OP_push_i32); - emit_u32(s, 2); - emit_op(s, OP_strict_eq); - label_throw = emit_goto(s, OP_if_true, -1); - /* return handling */ - if (is_async) - emit_op(s, OP_await); - emit_op(s, OP_iterator_call); - emit_u8(s, 0); - label_return1 = emit_goto(s, OP_if_true, -1); - if (is_async) - emit_op(s, OP_await); - emit_op(s, OP_iterator_check_object); - emit_op(s, OP_get_field2); - emit_atom(s, JS_ATOM_done); - emit_goto(s, OP_if_false, label_yield); - emit_op(s, OP_get_field); - emit_atom(s, JS_ATOM_value); - emit_label(s, label_return1); - emit_op(s, OP_nip); - emit_op(s, OP_nip); - emit_op(s, OP_nip); - emit_return(s, TRUE); - /* throw handling */ - emit_label(s, label_throw); - emit_op(s, OP_iterator_call); - emit_u8(s, 1); - label_throw1 = emit_goto(s, OP_if_true, -1); - if (is_async) - emit_op(s, OP_await); - emit_op(s, OP_iterator_check_object); - emit_op(s, OP_get_field2); - emit_atom(s, JS_ATOM_done); - emit_goto(s, OP_if_false, label_yield); - emit_goto(s, OP_goto, label_next); - /* close the iterator and throw a type error exception */ - emit_label(s, label_throw1); - emit_op(s, OP_iterator_call); - emit_u8(s, 2); - label_throw2 = emit_goto(s, OP_if_true, -1); - if (is_async) - emit_op(s, OP_await); - emit_label(s, label_throw2); - emit_op(s, OP_throw_error); - emit_atom(s, JS_ATOM_NULL); - emit_u8(s, JS_THROW_ERROR_ITERATOR_THROW); - emit_label(s, label_next); - emit_op(s, OP_get_field); - emit_atom(s, JS_ATOM_value); - emit_op(s, OP_nip); /* keep the value associated with - done = true */ - emit_op(s, OP_nip); - emit_op(s, OP_nip); - } else { - int label_next; - if (is_async) - emit_op(s, OP_await); - emit_op(s, OP_yield); - label_next = emit_goto(s, OP_if_false, -1); - emit_return(s, TRUE); - emit_label(s, label_next); - } - return 0; - } - if (s->token.val == TOK_IDENT) { - /* name0 is used to check for OP_set_name pattern, not duplicated */ - name0 = s->token.u.ident.atom; - } - if (js_parse_cond_expr(s, parse_flags | PF_ARROW_FUNC)) - return -1; - op = s->token.val; - if (op == '=' || (op >= TOK_MUL_ASSIGN && op <= TOK_POW_ASSIGN)) { - int label; - if (next_token(s)) - return -1; - if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, (op != '='), op) < 0) - return -1; - if (js_parse_assign_expr2(s, parse_flags)) { - JS_FreeAtom(s->ctx, name); - return -1; - } - if (op == '=') { - if (opcode == OP_get_ref_value && name == name0) { - set_object_name(s, name); - } - } else { - static const uint8_t assign_opcodes[] = { - OP_mul, OP_div, OP_mod, OP_add, OP_sub, - OP_shl, OP_sar, OP_shr, OP_and, OP_xor, OP_or, -#ifdef CONFIG_BIGNUM - OP_pow, -#endif - OP_pow, - }; - op = assign_opcodes[op - TOK_MUL_ASSIGN]; -#ifdef CONFIG_BIGNUM - if (s->cur_func->js_mode & JS_MODE_MATH) { - if (op == OP_mod) - op = OP_math_mod; - } -#endif - emit_op(s, op); - } - put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP, FALSE); - } else if (op >= TOK_LAND_ASSIGN && op <= TOK_DOUBLE_QUESTION_MARK_ASSIGN) { - int label, label1, depth_lvalue, label2; - if (next_token(s)) - return -1; - if (get_lvalue(s, &opcode, &scope, &name, &label, - &depth_lvalue, TRUE, op) < 0) - return -1; - emit_op(s, OP_dup); - if (op == TOK_DOUBLE_QUESTION_MARK_ASSIGN) - emit_op(s, OP_is_undefined_or_null); - label1 = emit_goto(s, op == TOK_LOR_ASSIGN ? OP_if_true : OP_if_false, - -1); - emit_op(s, OP_drop); - if (js_parse_assign_expr2(s, parse_flags)) { - JS_FreeAtom(s->ctx, name); - return -1; - } - if (opcode == OP_get_ref_value && name == name0) { - set_object_name(s, name); - } - switch(depth_lvalue) { - case 1: - emit_op(s, OP_insert2); - break; - case 2: - emit_op(s, OP_insert3); - break; - case 3: - emit_op(s, OP_insert4); - break; - default: - abort(); - } - /* XXX: we disable the OP_put_ref_value optimization by not - using put_lvalue() otherwise depth_lvalue is not correct */ - put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_NOKEEP_DEPTH, - FALSE); - label2 = emit_goto(s, OP_goto, -1); - emit_label(s, label1); - /* remove the lvalue stack entries */ - while (depth_lvalue != 0) { - emit_op(s, OP_nip); - depth_lvalue--; - } - emit_label(s, label2); - } - return 0; -} - -static __exception int js_parse_assign_expr(JSParseState *s) -{ - return js_parse_assign_expr2(s, PF_IN_ACCEPTED); -} - -static __exception int js_parse_expr(JSParseState *s) -{ - return js_parse_expr2(s, PF_IN_ACCEPTED); -} - -static __exception JSAtom js_parse_from_clause(JSParseState *s) -{ - JSAtom module_name; - if (!token_is_pseudo_keyword(s, JS_ATOM_from)) { - js_parse_error(s, "from clause expected"); - return JS_ATOM_NULL; - } - if (next_token(s)) - return JS_ATOM_NULL; - if (s->token.val != TOK_STRING) { - js_parse_error(s, "string expected"); - return JS_ATOM_NULL; - } - module_name = JS_ValueToAtom(s->ctx, s->token.u.str.str); - if (module_name == JS_ATOM_NULL) - return JS_ATOM_NULL; - if (next_token(s)) { - JS_FreeAtom(s->ctx, module_name); - return JS_ATOM_NULL; - } - return module_name; -} - -static int add_import(JSParseState *s, JSModuleDef *m, - JSAtom local_name, JSAtom import_name) -{ - JSContext *ctx = s->ctx; - int i, var_idx; - JSImportEntry *mi; - BOOL is_local; - if (local_name == JS_ATOM_arguments || local_name == JS_ATOM_eval) - return js_parse_error(s, "invalid import binding"); - if (local_name != JS_ATOM_default) { - for (i = 0; i < s->cur_func->closure_var_count; i++) { - if (s->cur_func->closure_var[i].var_name == local_name) - return js_parse_error(s, "duplicate import binding"); - } - } - is_local = (import_name == JS_ATOM__star_); - var_idx = add_closure_var(ctx, s->cur_func, is_local, FALSE, - m->import_entries_count, - local_name, TRUE, TRUE, FALSE); - if (var_idx < 0) - return -1; - if (js_resize_array(ctx, (void **)&m->import_entries, - sizeof(JSImportEntry), - &m->import_entries_size, - m->import_entries_count + 1)) - return -1; - mi = &m->import_entries[m->import_entries_count++]; - mi->import_name = JS_DupAtom(ctx, import_name); - mi->var_idx = var_idx; - return 0; -} - -static int add_req_module_entry(JSContext *ctx, JSModuleDef *m, - JSAtom module_name) -{ - JSReqModuleEntry *rme; - int i; - /* no need to add the module request if it is already present */ - for(i = 0; i < m->req_module_entries_count; i++) { - rme = &m->req_module_entries[i]; - if (rme->module_name == module_name) - return i; - } - if (js_resize_array(ctx, (void **)&m->req_module_entries, - sizeof(JSReqModuleEntry), - &m->req_module_entries_size, - m->req_module_entries_count + 1)) - return -1; - rme = &m->req_module_entries[m->req_module_entries_count++]; - rme->module_name = JS_DupAtom(ctx, module_name); - rme->module = NULL; - return i; -} - -static __exception int js_parse_import(JSParseState *s) -{ - JSContext *ctx = s->ctx; - JSModuleDef *m = s->cur_func->module; - JSAtom local_name, import_name, module_name; - int first_import, i, idx; - if (next_token(s)) - return -1; - first_import = m->import_entries_count; - if (s->token.val == TOK_STRING) { - module_name = JS_ValueToAtom(ctx, s->token.u.str.str); - if (module_name == JS_ATOM_NULL) - return -1; - if (next_token(s)) { - JS_FreeAtom(ctx, module_name); - return -1; - } - } else { - if (s->token.val == TOK_IDENT) { - if (s->token.u.ident.is_reserved) { - return js_parse_error_reserved_identifier(s); - } - /* "default" import */ - local_name = JS_DupAtom(ctx, s->token.u.ident.atom); - import_name = JS_ATOM_default; - if (next_token(s)) - goto fail; - if (add_import(s, m, local_name, import_name)) - goto fail; - JS_FreeAtom(ctx, local_name); - if (s->token.val != ',') - goto end_import_clause; - if (next_token(s)) - return -1; - } - if (s->token.val == '*') { - /* name space import */ - if (next_token(s)) - return -1; - if (!token_is_pseudo_keyword(s, JS_ATOM_as)) - return js_parse_error(s, "expecting 'as'"); - if (next_token(s)) - return -1; - if (!token_is_ident(s->token.val)) { - js_parse_error(s, "identifier expected"); - return -1; - } - local_name = JS_DupAtom(ctx, s->token.u.ident.atom); - import_name = JS_ATOM__star_; - if (next_token(s)) - goto fail; - if (add_import(s, m, local_name, import_name)) - goto fail; - JS_FreeAtom(ctx, local_name); - } else if (s->token.val == '{') { - if (next_token(s)) - return -1; - while (s->token.val != '}') { - if (!token_is_ident(s->token.val)) { - js_parse_error(s, "identifier expected"); - return -1; - } - import_name = JS_DupAtom(ctx, s->token.u.ident.atom); - local_name = JS_ATOM_NULL; - if (next_token(s)) - goto fail; - if (token_is_pseudo_keyword(s, JS_ATOM_as)) { - if (next_token(s)) - goto fail; - if (!token_is_ident(s->token.val)) { - js_parse_error(s, "identifier expected"); - goto fail; - } - local_name = JS_DupAtom(ctx, s->token.u.ident.atom); - if (next_token(s)) { - fail: - JS_FreeAtom(ctx, local_name); - JS_FreeAtom(ctx, import_name); - return -1; - } - } else { - local_name = JS_DupAtom(ctx, import_name); - } - if (add_import(s, m, local_name, import_name)) - goto fail; - JS_FreeAtom(ctx, local_name); - JS_FreeAtom(ctx, import_name); - if (s->token.val != ',') - break; - if (next_token(s)) - return -1; - } - if (js_parse_expect(s, '}')) - return -1; - } - end_import_clause: - module_name = js_parse_from_clause(s); - if (module_name == JS_ATOM_NULL) - return -1; - } - idx = add_req_module_entry(ctx, m, module_name); - JS_FreeAtom(ctx, module_name); - if (idx < 0) - return -1; - for(i = first_import; i < m->import_entries_count; i++) - m->import_entries[i].req_module_idx = idx; - return js_parse_expect_semi(s); -} - -static int add_star_export_entry(JSContext *ctx, JSModuleDef *m, - int req_module_idx) -{ - JSStarExportEntry *se; - if (js_resize_array(ctx, (void **)&m->star_export_entries, - sizeof(JSStarExportEntry), - &m->star_export_entries_size, - m->star_export_entries_count + 1)) - return -1; - se = &m->star_export_entries[m->star_export_entries_count++]; - se->req_module_idx = req_module_idx; - return 0; -} - -int js_parse_export(JSParseState *s) -{ - JSContext *ctx = s->ctx; - JSModuleDef *m = s->cur_func->module; - JSAtom local_name, export_name; - int first_export, idx, i, tok; - JSAtom module_name; - JSExportEntry *me; - if (next_token(s)) - return -1; - tok = s->token.val; - if (tok == TOK_CLASS) { - return js_parse_class(s, FALSE, JS_PARSE_EXPORT_NAMED); - } else if (tok == TOK_FUNCTION || - (token_is_pseudo_keyword(s, JS_ATOM_async) && - peek_token(s, TRUE) == TOK_FUNCTION)) { - return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT, - JS_FUNC_NORMAL, JS_ATOM_NULL, - s->token.ptr, s->token.line_num, - JS_PARSE_EXPORT_NAMED, NULL); - } - if (next_token(s)) - return -1; - switch(tok) { - case '{': - first_export = m->export_entries_count; - while (s->token.val != '}') { - if (!token_is_ident(s->token.val)) { - js_parse_error(s, "identifier expected"); - return -1; - } - local_name = JS_DupAtom(ctx, s->token.u.ident.atom); - export_name = JS_ATOM_NULL; - if (next_token(s)) - goto fail; - if (token_is_pseudo_keyword(s, JS_ATOM_as)) { - if (next_token(s)) - goto fail; - if (!token_is_ident(s->token.val)) { - js_parse_error(s, "identifier expected"); - goto fail; - } - export_name = JS_DupAtom(ctx, s->token.u.ident.atom); - if (next_token(s)) { - fail: - JS_FreeAtom(ctx, local_name); - fail1: - JS_FreeAtom(ctx, export_name); - return -1; - } - } else { - export_name = JS_DupAtom(ctx, local_name); - } - me = add_export_entry(s, m, local_name, export_name, - JS_EXPORT_TYPE_LOCAL); - JS_FreeAtom(ctx, local_name); - JS_FreeAtom(ctx, export_name); - if (!me) - return -1; - if (s->token.val != ',') - break; - if (next_token(s)) - return -1; - } - if (js_parse_expect(s, '}')) - return -1; - if (token_is_pseudo_keyword(s, JS_ATOM_from)) { - module_name = js_parse_from_clause(s); - if (module_name == JS_ATOM_NULL) - return -1; - idx = add_req_module_entry(ctx, m, module_name); - JS_FreeAtom(ctx, module_name); - if (idx < 0) - return -1; - for(i = first_export; i < m->export_entries_count; i++) { - me = &m->export_entries[i]; - me->export_type = JS_EXPORT_TYPE_INDIRECT; - me->u.req_module_idx = idx; - } - } - break; - case '*': - if (token_is_pseudo_keyword(s, JS_ATOM_as)) { - /* export ns from */ - if (next_token(s)) - return -1; - if (!token_is_ident(s->token.val)) { - js_parse_error(s, "identifier expected"); - return -1; - } - export_name = JS_DupAtom(ctx, s->token.u.ident.atom); - if (next_token(s)) - goto fail1; - module_name = js_parse_from_clause(s); - if (module_name == JS_ATOM_NULL) - goto fail1; - idx = add_req_module_entry(ctx, m, module_name); - JS_FreeAtom(ctx, module_name); - if (idx < 0) - goto fail1; - me = add_export_entry(s, m, JS_ATOM__star_, export_name, - JS_EXPORT_TYPE_INDIRECT); - JS_FreeAtom(ctx, export_name); - if (!me) - return -1; - me->u.req_module_idx = idx; - } else { - module_name = js_parse_from_clause(s); - if (module_name == JS_ATOM_NULL) - return -1; - idx = add_req_module_entry(ctx, m, module_name); - JS_FreeAtom(ctx, module_name); - if (idx < 0) - return -1; - if (add_star_export_entry(ctx, m, idx) < 0) - return -1; - } - break; - case TOK_DEFAULT: - if (s->token.val == TOK_CLASS) { - return js_parse_class(s, FALSE, JS_PARSE_EXPORT_DEFAULT); - } else if (s->token.val == TOK_FUNCTION || - (token_is_pseudo_keyword(s, JS_ATOM_async) && - peek_token(s, TRUE) == TOK_FUNCTION)) { - return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT, - JS_FUNC_NORMAL, JS_ATOM_NULL, - s->token.ptr, s->token.line_num, - JS_PARSE_EXPORT_DEFAULT, NULL); - } else { - if (js_parse_assign_expr(s)) - return -1; - } - /* set the name of anonymous functions */ - set_object_name(s, JS_ATOM_default); - /* store the value in the _default_ global variable and export - it */ - local_name = JS_ATOM__default_; - if (define_var(s, s->cur_func, local_name, JS_VAR_DEF_LET) < 0) - return -1; - emit_op(s, OP_scope_put_var_init); - emit_atom(s, local_name); - emit_u16(s, 0); - if (!add_export_entry(s, m, local_name, JS_ATOM_default, - JS_EXPORT_TYPE_LOCAL)) - return -1; - break; - case TOK_VAR: - case TOK_LET: - case TOK_CONST: - return js_parse_var(s, TRUE, tok, TRUE); - default: - return js_parse_error(s, "invalid export syntax"); - } - return js_parse_expect_semi(s); -} - -static __exception int js_parse_source_element(JSParseState *s) -{ - JSFunctionDef *fd = s->cur_func; - int tok; - if (s->token.val == TOK_FUNCTION || - (token_is_pseudo_keyword(s, JS_ATOM_async) && - peek_token(s, TRUE) == TOK_FUNCTION)) { - if (js_parse_function_decl(s, JS_PARSE_FUNC_STATEMENT, - JS_FUNC_NORMAL, JS_ATOM_NULL, - s->token.ptr, s->token.line_num)) - return -1; - } else if (s->token.val == TOK_EXPORT && fd->module) { - if (js_parse_export(s)) - return -1; - } else if (s->token.val == TOK_IMPORT && fd->module && - ((tok = peek_token(s, FALSE)) != '(' && tok != '.')) { - /* the peek_token is needed to avoid confusion with ImportCall - (dynamic import) or import.meta */ - if (js_parse_import(s)) - return -1; - } else { - if (js_parse_statement_or_decl(s, DECL_MASK_ALL)) - return -1; - } - return 0; -} - -static __exception int js_parse_directives(JSParseState *s) -{ - char str[20]; - JSParsePos pos; - BOOL has_semi; - if (s->token.val != TOK_STRING) - return 0; - js_parse_get_pos(s, &pos); - while(s->token.val == TOK_STRING) { - /* Copy actual source string representation */ - snprintf(str, sizeof str, "%.*s", - (int)(s->buf_ptr - s->token.ptr - 2), s->token.ptr + 1); - if (next_token(s)) - return -1; - has_semi = FALSE; - switch (s->token.val) { - case ';': - if (next_token(s)) - return -1; - has_semi = TRUE; - break; - case '}': - case TOK_EOF: - has_semi = TRUE; - break; - case TOK_NUMBER: - case TOK_STRING: - case TOK_TEMPLATE: - case TOK_IDENT: - case TOK_REGEXP: - case TOK_DEC: - case TOK_INC: - case TOK_NULL: - case TOK_FALSE: - case TOK_TRUE: - case TOK_IF: - case TOK_RETURN: - case TOK_VAR: - case TOK_THIS: - case TOK_DELETE: - case TOK_TYPEOF: - case TOK_NEW: - case TOK_DO: - case TOK_WHILE: - case TOK_FOR: - case TOK_SWITCH: - case TOK_THROW: - case TOK_TRY: - case TOK_FUNCTION: - case TOK_DEBUGGER: - case TOK_WITH: - case TOK_CLASS: - case TOK_CONST: - case TOK_ENUM: - case TOK_EXPORT: - case TOK_IMPORT: - case TOK_SUPER: - case TOK_INTERFACE: - case TOK_LET: - case TOK_PACKAGE: - case TOK_PRIVATE: - case TOK_PROTECTED: - case TOK_PUBLIC: - case TOK_STATIC: - /* automatic insertion of ';' */ - if (s->got_lf) - has_semi = TRUE; - break; - default: - break; - } - if (!has_semi) - break; - if (!strcmp(str, "use strict")) { - s->cur_func->has_use_strict = TRUE; - s->cur_func->js_mode |= JS_MODE_STRICT; - } -#if !defined(DUMP_BYTECODE) || !(DUMP_BYTECODE & 8) - else if (!strcmp(str, "use strip")) { - s->cur_func->js_mode |= JS_MODE_STRIP; - } -#endif -#ifdef CONFIG_BIGNUM - else if (s->ctx->bignum_ext && !strcmp(str, "use math")) { - s->cur_func->js_mode |= JS_MODE_MATH; - } -#endif - } - return js_parse_seek_token(s, &pos); -} - -static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd, - JSAtom func_name) -{ - JSAtom name; - int i, idx; - if (fd->js_mode & JS_MODE_STRICT) { - if (!fd->has_simple_parameter_list && fd->has_use_strict) { - return js_parse_error(s, "\"use strict\" not allowed in function with default or destructuring parameter"); - } - if (func_name == JS_ATOM_eval || func_name == JS_ATOM_arguments) { - return js_parse_error(s, "invalid function name in strict code"); - } - for (idx = 0; idx < fd->arg_count; idx++) { - name = fd->args[idx].var_name; - if (name == JS_ATOM_eval || name == JS_ATOM_arguments) { - return js_parse_error(s, "invalid argument name in strict code"); - } - } - } - /* check async_generator case */ - if ((fd->js_mode & JS_MODE_STRICT) - || !fd->has_simple_parameter_list - || (fd->func_type == JS_PARSE_FUNC_METHOD && fd->func_kind == JS_FUNC_ASYNC) - || fd->func_type == JS_PARSE_FUNC_ARROW - || fd->func_type == JS_PARSE_FUNC_METHOD) { - for (idx = 0; idx < fd->arg_count; idx++) { - name = fd->args[idx].var_name; - if (name != JS_ATOM_NULL) { - for (i = 0; i < idx; i++) { - if (fd->args[i].var_name == name) - goto duplicate; - } - /* Check if argument name duplicates a destructuring parameter */ - /* XXX: should have a flag for such variables */ - for (i = 0; i < fd->var_count; i++) { - if (fd->vars[i].var_name == name && - fd->vars[i].scope_level == 0) - goto duplicate; - } - } - } - } - return 0; -duplicate: - return js_parse_error(s, "duplicate argument names not allowed in this context"); -} - -static int add_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name) -{ - JSVarDef *vd; - /* the local variable indexes are currently stored on 16 bits */ - if (fd->arg_count >= JS_MAX_LOCAL_VARS) { - JS_ThrowInternalError(ctx, "too many arguments"); - return -1; - } - if (js_resize_array(ctx, (void **)&fd->args, sizeof(fd->args[0]), - &fd->arg_size, fd->arg_count + 1)) - return -1; - vd = &fd->args[fd->arg_count++]; - bzero(vd, sizeof(*vd)); - vd->var_name = JS_DupAtom(ctx, name); - vd->func_pool_idx = -1; - return fd->arg_count - 1; -} - -/* func_name must be JS_ATOM_NULL for JS_PARSE_FUNC_STATEMENT and - JS_PARSE_FUNC_EXPR, JS_PARSE_FUNC_ARROW and JS_PARSE_FUNC_VAR */ -static __exception int js_parse_function_decl2(JSParseState *s, - JSParseFunctionEnum func_type, - JSFunctionKindEnum func_kind, - JSAtom func_name, - const uint8_t *ptr, - int function_line_num, - JSParseExportEnum export_flag, - JSFunctionDef **pfd) -{ - JSContext *ctx = s->ctx; - JSFunctionDef *fd = s->cur_func; - BOOL is_expr; - int func_idx, lexical_func_idx = -1; - BOOL has_opt_arg; - BOOL create_func_var = FALSE; - is_expr = (func_type != JS_PARSE_FUNC_STATEMENT && - func_type != JS_PARSE_FUNC_VAR); - if (func_type == JS_PARSE_FUNC_STATEMENT || - func_type == JS_PARSE_FUNC_VAR || - func_type == JS_PARSE_FUNC_EXPR) { - if (func_kind == JS_FUNC_NORMAL && - token_is_pseudo_keyword(s, JS_ATOM_async) && - peek_token(s, TRUE) != '\n') { - if (next_token(s)) - return -1; - func_kind = JS_FUNC_ASYNC; - } - if (next_token(s)) - return -1; - if (s->token.val == '*') { - if (next_token(s)) - return -1; - func_kind |= JS_FUNC_GENERATOR; - } - if (s->token.val == TOK_IDENT) { - if (s->token.u.ident.is_reserved || - (s->token.u.ident.atom == JS_ATOM_yield && - func_type == JS_PARSE_FUNC_EXPR && - (func_kind & JS_FUNC_GENERATOR)) || - (s->token.u.ident.atom == JS_ATOM_await && - func_type == JS_PARSE_FUNC_EXPR && - (func_kind & JS_FUNC_ASYNC))) { - return js_parse_error_reserved_identifier(s); - } - } - if (s->token.val == TOK_IDENT || - (((s->token.val == TOK_YIELD && !(fd->js_mode & JS_MODE_STRICT)) || - (s->token.val == TOK_AWAIT && !s->is_module)) && - func_type == JS_PARSE_FUNC_EXPR)) { - func_name = JS_DupAtom(ctx, s->token.u.ident.atom); - if (next_token(s)) { - JS_FreeAtom(ctx, func_name); - return -1; - } - } else { - if (func_type != JS_PARSE_FUNC_EXPR && - export_flag != JS_PARSE_EXPORT_DEFAULT) { - return js_parse_error(s, "function name expected"); - } - } - } else if (func_type != JS_PARSE_FUNC_ARROW) { - func_name = JS_DupAtom(ctx, func_name); - } - if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_MODULE && - (func_type == JS_PARSE_FUNC_STATEMENT || func_type == JS_PARSE_FUNC_VAR)) { - JSGlobalVar *hf; - hf = find_global_var(fd, func_name); - /* XXX: should check scope chain */ - if (hf && hf->scope_level == fd->scope_level) { - js_parse_error(s, "invalid redefinition of global identifier in module code"); - JS_FreeAtom(ctx, func_name); - return -1; - } - } - if (func_type == JS_PARSE_FUNC_VAR) { - if (!(fd->js_mode & JS_MODE_STRICT) - && func_kind == JS_FUNC_NORMAL - && find_lexical_decl(ctx, fd, func_name, fd->scope_first, FALSE) < 0 - && !((func_idx = find_var(ctx, fd, func_name)) >= 0 && (func_idx & ARGUMENT_VAR_OFFSET)) - && !(func_name == JS_ATOM_arguments && fd->has_arguments_binding)) { - create_func_var = TRUE; - } - /* Create the lexical name here so that the function closure - contains it */ - if (fd->is_eval && - (fd->eval_type == JS_EVAL_TYPE_GLOBAL || - fd->eval_type == JS_EVAL_TYPE_MODULE) && - fd->scope_level == fd->body_scope) { - /* avoid creating a lexical variable in the global - scope. XXX: check annex B */ - JSGlobalVar *hf; - hf = find_global_var(fd, func_name); - /* XXX: should check scope chain */ - if (hf && hf->scope_level == fd->scope_level) { - js_parse_error(s, "invalid redefinition of global identifier"); - JS_FreeAtom(ctx, func_name); - return -1; - } - } else { - /* Always create a lexical name, fail if at the same scope as - existing name */ - /* Lexical variable will be initialized upon entering scope */ - lexical_func_idx = define_var(s, fd, func_name, - func_kind != JS_FUNC_NORMAL ? - JS_VAR_DEF_NEW_FUNCTION_DECL : - JS_VAR_DEF_FUNCTION_DECL); - if (lexical_func_idx < 0) { - JS_FreeAtom(ctx, func_name); - return -1; - } - } - } - fd = js_new_function_def(ctx, fd, FALSE, is_expr, - s->filename, function_line_num); - if (!fd) { - JS_FreeAtom(ctx, func_name); - return -1; - } - if (pfd) - *pfd = fd; - s->cur_func = fd; - fd->func_name = func_name; - /* XXX: test !fd->is_generator is always false */ - fd->has_prototype = (func_type == JS_PARSE_FUNC_STATEMENT || - func_type == JS_PARSE_FUNC_VAR || - func_type == JS_PARSE_FUNC_EXPR) && - func_kind == JS_FUNC_NORMAL; - fd->has_home_object = (func_type == JS_PARSE_FUNC_METHOD || - func_type == JS_PARSE_FUNC_GETTER || - func_type == JS_PARSE_FUNC_SETTER || - func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR || - func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR); - fd->has_arguments_binding = (func_type != JS_PARSE_FUNC_ARROW); - fd->has_this_binding = fd->has_arguments_binding; - fd->is_derived_class_constructor = (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR); - if (func_type == JS_PARSE_FUNC_ARROW) { - fd->new_target_allowed = fd->parent->new_target_allowed; - fd->super_call_allowed = fd->parent->super_call_allowed; - fd->super_allowed = fd->parent->super_allowed; - fd->arguments_allowed = fd->parent->arguments_allowed; - } else { - fd->new_target_allowed = TRUE; - fd->super_call_allowed = fd->is_derived_class_constructor; - fd->super_allowed = fd->has_home_object; - fd->arguments_allowed = TRUE; - } - /* fd->in_function_body == FALSE prevents yield/await during the parsing - of the arguments in generator/async functions. They are parsed as - regular identifiers for other function kinds. */ - fd->func_kind = func_kind; - fd->func_type = func_type; - if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR || - func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) { - /* error if not invoked as a constructor */ - emit_op(s, OP_check_ctor); - } - if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) { - emit_class_field_init(s); - } - /* parse arguments */ - fd->has_simple_parameter_list = TRUE; - fd->has_parameter_expressions = FALSE; - has_opt_arg = FALSE; - if (func_type == JS_PARSE_FUNC_ARROW && s->token.val == TOK_IDENT) { - JSAtom name; - if (s->token.u.ident.is_reserved) { - js_parse_error_reserved_identifier(s); - goto fail; - } - name = s->token.u.ident.atom; - if (add_arg(ctx, fd, name) < 0) - goto fail; - fd->defined_arg_count = 1; - } else { - if (s->token.val == '(') { - int skip_bits; - /* if there is an '=' inside the parameter list, we - consider there is a parameter expression inside */ - js_parse_skip_parens_token(s, &skip_bits, FALSE); - if (skip_bits & SKIP_HAS_ASSIGNMENT) - fd->has_parameter_expressions = TRUE; - if (next_token(s)) - goto fail; - } else { - if (js_parse_expect(s, '(')) - goto fail; - } - if (fd->has_parameter_expressions) { - fd->scope_level = -1; /* force no parent scope */ - if (push_scope(s) < 0) - return -1; - } - while (s->token.val != ')') { - JSAtom name; - BOOL rest = FALSE; - int idx, has_initializer; - if (s->token.val == TOK_ELLIPSIS) { - fd->has_simple_parameter_list = FALSE; - rest = TRUE; - if (next_token(s)) - goto fail; - } - if (s->token.val == '[' || s->token.val == '{') { - fd->has_simple_parameter_list = FALSE; - if (rest) { - emit_op(s, OP_rest); - emit_u16(s, fd->arg_count); - } else { - /* unnamed arg for destructuring */ - idx = add_arg(ctx, fd, JS_ATOM_NULL); - emit_op(s, OP_get_arg); - emit_u16(s, idx); - } - has_initializer = js_parse_destructuring_element(s, fd->has_parameter_expressions ? TOK_LET : TOK_VAR, 1, TRUE, -1, TRUE); - if (has_initializer < 0) - goto fail; - if (has_initializer) - has_opt_arg = TRUE; - if (!has_opt_arg) - fd->defined_arg_count++; - } else if (s->token.val == TOK_IDENT) { - if (s->token.u.ident.is_reserved) { - js_parse_error_reserved_identifier(s); - goto fail; - } - name = s->token.u.ident.atom; - if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) { - js_parse_error_reserved_identifier(s); - goto fail; - } - if (fd->has_parameter_expressions) { - if (define_var(s, fd, name, JS_VAR_DEF_LET) < 0) - goto fail; - } - /* XXX: could avoid allocating an argument if rest is true */ - idx = add_arg(ctx, fd, name); - if (idx < 0) - goto fail; - if (next_token(s)) - goto fail; - if (rest) { - emit_op(s, OP_rest); - emit_u16(s, idx); - if (fd->has_parameter_expressions) { - emit_op(s, OP_dup); - emit_op(s, OP_scope_put_var_init); - emit_atom(s, name); - emit_u16(s, fd->scope_level); - } - emit_op(s, OP_put_arg); - emit_u16(s, idx); - fd->has_simple_parameter_list = FALSE; - has_opt_arg = TRUE; - } else if (s->token.val == '=') { - int label; - fd->has_simple_parameter_list = FALSE; - has_opt_arg = TRUE; - if (next_token(s)) - goto fail; - label = new_label(s); - emit_op(s, OP_get_arg); - emit_u16(s, idx); - emit_op(s, OP_dup); - emit_op(s, OP_undefined); - emit_op(s, OP_strict_eq); - emit_goto(s, OP_if_false, label); - emit_op(s, OP_drop); - if (js_parse_assign_expr(s)) - goto fail; - set_object_name(s, name); - emit_op(s, OP_dup); - emit_op(s, OP_put_arg); - emit_u16(s, idx); - emit_label(s, label); - emit_op(s, OP_scope_put_var_init); - emit_atom(s, name); - emit_u16(s, fd->scope_level); - } else { - if (!has_opt_arg) { - fd->defined_arg_count++; - } - if (fd->has_parameter_expressions) { - /* copy the argument to the argument scope */ - emit_op(s, OP_get_arg); - emit_u16(s, idx); - emit_op(s, OP_scope_put_var_init); - emit_atom(s, name); - emit_u16(s, fd->scope_level); - } - } - } else { - js_parse_error(s, "missing formal parameter"); - goto fail; - } - if (rest && s->token.val != ')') { - js_parse_expect(s, ')'); - goto fail; - } - if (s->token.val == ')') - break; - if (js_parse_expect(s, ',')) - goto fail; - } - if ((func_type == JS_PARSE_FUNC_GETTER && fd->arg_count != 0) || - (func_type == JS_PARSE_FUNC_SETTER && fd->arg_count != 1)) { - js_parse_error(s, "invalid number of arguments for getter or setter"); - goto fail; - } - } - if (fd->has_parameter_expressions) { - int idx; - /* Copy the variables in the argument scope to the variable - scope (see FunctionDeclarationInstantiation() in spec). The - normal arguments are already present, so no need to copy - them. */ - idx = fd->scopes[fd->scope_level].first; - while (idx >= 0) { - JSVarDef *vd = &fd->vars[idx]; - if (vd->scope_level != fd->scope_level) - break; - if (find_var(ctx, fd, vd->var_name) < 0) { - if (add_var(ctx, fd, vd->var_name) < 0) - goto fail; - vd = &fd->vars[idx]; /* fd->vars may have been reallocated */ - emit_op(s, OP_scope_get_var); - emit_atom(s, vd->var_name); - emit_u16(s, fd->scope_level); - emit_op(s, OP_scope_put_var); - emit_atom(s, vd->var_name); - emit_u16(s, 0); - } - idx = vd->scope_next; - } - /* the argument scope has no parent, hence we don't use pop_scope(s) */ - emit_op(s, OP_leave_scope); - emit_u16(s, fd->scope_level); - /* set the variable scope as the current scope */ - fd->scope_level = 0; - fd->scope_first = fd->scopes[fd->scope_level].first; - } - if (next_token(s)) - goto fail; - /* generator function: yield after the parameters are evaluated */ - if (func_kind == JS_FUNC_GENERATOR || - func_kind == JS_FUNC_ASYNC_GENERATOR) - emit_op(s, OP_initial_yield); - /* in generators, yield expression is forbidden during the parsing - of the arguments */ - fd->in_function_body = TRUE; - push_scope(s); /* enter body scope */ - fd->body_scope = fd->scope_level; - if (s->token.val == TOK_ARROW) { - if (next_token(s)) - goto fail; - if (s->token.val != '{') { - if (js_parse_function_check_names(s, fd, func_name)) - goto fail; - if (js_parse_assign_expr(s)) - goto fail; - if (func_kind != JS_FUNC_NORMAL) - emit_op(s, OP_return_async); - else - emit_op(s, OP_return); - if (!(fd->js_mode & JS_MODE_STRIP)) { - /* save the function source code */ - /* the end of the function source code is after the last - token of the function source stored into s->last_ptr */ - fd->source_len = s->last_ptr - ptr; - fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len); - if (!fd->source) - goto fail; - } - goto done; - } - } - if (js_parse_expect(s, '{')) - goto fail; - if (js_parse_directives(s)) - goto fail; - /* in strict_mode, check function and argument names */ - if (js_parse_function_check_names(s, fd, func_name)) - goto fail; - while (s->token.val != '}') { - if (js_parse_source_element(s)) - goto fail; - } - if (!(fd->js_mode & JS_MODE_STRIP)) { - /* save the function source code */ - fd->source_len = s->buf_ptr - ptr; - fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len); - if (!fd->source) - goto fail; - } - if (next_token(s)) { - /* consume the '}' */ - goto fail; - } - /* in case there is no return, add one */ - if (js_is_live_code(s)) { - emit_return(s, FALSE); - } -done: - s->cur_func = fd->parent; - /* create the function object */ - { - int idx; - JSAtom func_name = fd->func_name; - /* the real object will be set at the end of the compilation */ - idx = cpool_add(s, JS_NULL); - fd->parent_cpool_idx = idx; - if (is_expr) { - /* for constructors, no code needs to be generated here */ - if (func_type != JS_PARSE_FUNC_CLASS_CONSTRUCTOR && - func_type != JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) { - /* OP_fclosure creates the function object from the bytecode - and adds the scope information */ - emit_op(s, OP_fclosure); - emit_u32(s, idx); - if (func_name == JS_ATOM_NULL) { - emit_op(s, OP_set_name); - emit_u32(s, JS_ATOM_NULL); - } - } - } else if (func_type == JS_PARSE_FUNC_VAR) { - emit_op(s, OP_fclosure); - emit_u32(s, idx); - if (create_func_var) { - if (s->cur_func->is_global_var) { - JSGlobalVar *hf; - /* the global variable must be defined at the start of the - function */ - hf = add_global_var(ctx, s->cur_func, func_name); - if (!hf) - goto fail; - /* it is considered as defined at the top level - (needed for annex B.3.3.4 and B.3.3.5 - checks) */ - hf->scope_level = 0; - hf->force_init = ((s->cur_func->js_mode & JS_MODE_STRICT) != 0); - /* store directly into global var, bypass lexical scope */ - emit_op(s, OP_dup); - emit_op(s, OP_scope_put_var); - emit_atom(s, func_name); - emit_u16(s, 0); - } else { - /* do not call define_var to bypass lexical scope check */ - func_idx = find_var(ctx, s->cur_func, func_name); - if (func_idx < 0) { - func_idx = add_var(ctx, s->cur_func, func_name); - if (func_idx < 0) - goto fail; - } - /* store directly into local var, bypass lexical catch scope */ - emit_op(s, OP_dup); - emit_op(s, OP_scope_put_var); - emit_atom(s, func_name); - emit_u16(s, 0); - } - } - if (lexical_func_idx >= 0) { - /* lexical variable will be initialized upon entering scope */ - s->cur_func->vars[lexical_func_idx].func_pool_idx = idx; - emit_op(s, OP_drop); - } else { - /* store function object into its lexical name */ - /* XXX: could use OP_put_loc directly */ - emit_op(s, OP_scope_put_var_init); - emit_atom(s, func_name); - emit_u16(s, s->cur_func->scope_level); - } - } else { - if (!s->cur_func->is_global_var) { - int var_idx = define_var(s, s->cur_func, func_name, JS_VAR_DEF_VAR); - if (var_idx < 0) - goto fail; - /* the variable will be assigned at the top of the function */ - if (var_idx & ARGUMENT_VAR_OFFSET) { - s->cur_func->args[var_idx - ARGUMENT_VAR_OFFSET].func_pool_idx = idx; - } else { - s->cur_func->vars[var_idx].func_pool_idx = idx; - } - } else { - JSAtom func_var_name; - JSGlobalVar *hf; - if (func_name == JS_ATOM_NULL) - func_var_name = JS_ATOM__default_; /* export default */ - else - func_var_name = func_name; - /* the variable will be assigned at the top of the function */ - hf = add_global_var(ctx, s->cur_func, func_var_name); - if (!hf) - goto fail; - hf->cpool_idx = idx; - if (export_flag != JS_PARSE_EXPORT_NONE) { - if (!add_export_entry(s, s->cur_func->module, func_var_name, - export_flag == JS_PARSE_EXPORT_NAMED ? func_var_name : JS_ATOM_default, JS_EXPORT_TYPE_LOCAL)) - goto fail; - } - } - } - } - return 0; - fail: - s->cur_func = fd->parent; - js_free_function_def(ctx, fd); - if (pfd) - *pfd = NULL; - return -1; -} - -static __exception int js_parse_function_decl(JSParseState *s, - JSParseFunctionEnum func_type, - JSFunctionKindEnum func_kind, - JSAtom func_name, - const uint8_t *ptr, - int function_line_num) -{ - return js_parse_function_decl2(s, func_type, func_kind, func_name, ptr, - function_line_num, JS_PARSE_EXPORT_NONE, - NULL); -} - -int js_parse_program(JSParseState *s) -{ - JSFunctionDef *fd = s->cur_func; - int idx; - if (next_token(s)) - return -1; - if (js_parse_directives(s)) - return -1; - fd->is_global_var = (fd->eval_type == JS_EVAL_TYPE_GLOBAL) || - (fd->eval_type == JS_EVAL_TYPE_MODULE) || - !(fd->js_mode & JS_MODE_STRICT); - if (!s->is_module) { - /* hidden variable for the return value */ - fd->eval_ret_idx = idx = add_var(s->ctx, fd, JS_ATOM__ret_); - if (idx < 0) - return -1; - } - while (s->token.val != TOK_EOF) { - if (js_parse_source_element(s)) - return -1; - } - if (!s->is_module) { - /* return the value of the hidden variable eval_ret_idx */ - emit_op(s, OP_get_loc); - emit_u16(s, fd->eval_ret_idx); - emit_op(s, OP_return); - } else { - emit_op(s, OP_return_undef); - } - return 0; -} diff --git a/third_party/quickjs/prim.c b/third_party/quickjs/prim.c deleted file mode 100644 index c22c711ef..000000000 --- a/third_party/quickjs/prim.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "third_party/quickjs/internal.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -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; -} - -JSValue JS_ToPrimitive(JSContext *ctx, JSValueConst val, int hint) -{ - return JS_ToPrimitiveFree(ctx, JS_DupValue(ctx, val), hint); -} diff --git a/third_party/quickjs/promise.c b/third_party/quickjs/promise.c deleted file mode 100644 index 62d62edd6..000000000 --- a/third_party/quickjs/promise.c +++ /dev/null @@ -1,1568 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/assert.h" -#include "third_party/quickjs/internal.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -typedef enum JSPromiseStateEnum { - JS_PROMISE_PENDING, - JS_PROMISE_FULFILLED, - JS_PROMISE_REJECTED, -} JSPromiseStateEnum; - -typedef struct JSPromiseData { - JSPromiseStateEnum promise_state; - /* 0=fulfill, 1=reject, list of JSPromiseReactionData.link */ - struct list_head promise_reactions[2]; - BOOL is_handled; /* Note: only useful to debug */ - JSValue promise_result; -} JSPromiseData; - -typedef struct JSPromiseFunctionDataResolved { - int ref_count; - BOOL already_resolved; -} JSPromiseFunctionDataResolved; - -typedef struct JSPromiseFunctionData { - JSValue promise; - JSPromiseFunctionDataResolved *presolved; -} JSPromiseFunctionData; - -typedef struct JSPromiseReactionData { - struct list_head link; /* not used in promise_reaction_job */ - JSValue resolving_funcs[2]; - JSValue handler; -} JSPromiseReactionData; - -static int js_create_resolving_functions(JSContext *ctx, JSValue *args, - JSValueConst promise); - -static void promise_reaction_data_free(JSRuntime *rt, - JSPromiseReactionData *rd) -{ - JS_FreeValueRT(rt, rd->resolving_funcs[0]); - JS_FreeValueRT(rt, rd->resolving_funcs[1]); - JS_FreeValueRT(rt, rd->handler); - js_free_rt(rt, rd); -} - -static JSValue promise_reaction_job(JSContext *ctx, int argc, - JSValueConst *argv) -{ - JSValueConst handler, arg, func; - JSValue res, res2; - BOOL is_reject; - - assert(argc == 5); - handler = argv[2]; - is_reject = JS_ToBool(ctx, argv[3]); - arg = argv[4]; -#ifdef DUMP_PROMISE - printf("promise_reaction_job: is_reject=%d\n", is_reject); -#endif - - if (JS_IsUndefined(handler)) { - if (is_reject) { - res = JS_Throw(ctx, JS_DupValue(ctx, arg)); - } else { - res = JS_DupValue(ctx, arg); - } - } else { - res = JS_Call(ctx, handler, JS_UNDEFINED, 1, &arg); - } - is_reject = JS_IsException(res); - if (is_reject) - res = JS_GetException(ctx); - func = argv[is_reject]; - /* as an extension, we support undefined as value to avoid - creating a dummy promise in the 'await' implementation of async - functions */ - if (!JS_IsUndefined(func)) { - res2 = JS_Call(ctx, func, JS_UNDEFINED, - 1, (JSValueConst *)&res); - } else { - res2 = JS_UNDEFINED; - } - JS_FreeValue(ctx, res); - - return res2; -} - -void JS_SetHostPromiseRejectionTracker(JSRuntime *rt, - JSHostPromiseRejectionTracker *cb, - void *opaque) -{ - rt->host_promise_rejection_tracker = cb; - rt->host_promise_rejection_tracker_opaque = opaque; -} - -static void fulfill_or_reject_promise(JSContext *ctx, JSValueConst promise, - JSValueConst value, BOOL is_reject) -{ - JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE); - struct list_head *el, *el1; - JSPromiseReactionData *rd; - JSValueConst args[5]; - - if (!s || s->promise_state != JS_PROMISE_PENDING) - return; /* should never happen */ - set_value(ctx, &s->promise_result, JS_DupValue(ctx, value)); - s->promise_state = JS_PROMISE_FULFILLED + is_reject; -#ifdef DUMP_PROMISE - printf("fulfill_or_reject_promise: is_reject=%d\n", is_reject); -#endif - if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) { - JSRuntime *rt = ctx->rt; - if (rt->host_promise_rejection_tracker) { - rt->host_promise_rejection_tracker(ctx, promise, value, FALSE, - rt->host_promise_rejection_tracker_opaque); - } - } - - list_for_each_safe(el, el1, &s->promise_reactions[is_reject]) { - rd = list_entry(el, JSPromiseReactionData, link); - args[0] = rd->resolving_funcs[0]; - args[1] = rd->resolving_funcs[1]; - args[2] = rd->handler; - args[3] = JS_NewBool(ctx, is_reject); - args[4] = value; - JS_EnqueueJob(ctx, promise_reaction_job, 5, args); - list_del(&rd->link); - promise_reaction_data_free(ctx->rt, rd); - } - - list_for_each_safe(el, el1, &s->promise_reactions[1 - is_reject]) { - rd = list_entry(el, JSPromiseReactionData, link); - list_del(&rd->link); - promise_reaction_data_free(ctx->rt, rd); - } -} - -static void reject_promise(JSContext *ctx, JSValueConst promise, - JSValueConst value) -{ - fulfill_or_reject_promise(ctx, promise, value, TRUE); -} - -static JSValue js_promise_resolve_thenable_job(JSContext *ctx, - int argc, JSValueConst *argv) -{ - JSValueConst promise, thenable, then; - JSValue args[2], res; - -#ifdef DUMP_PROMISE - printf("js_promise_resolve_thenable_job\n"); -#endif - assert(argc == 3); - promise = argv[0]; - thenable = argv[1]; - then = argv[2]; - if (js_create_resolving_functions(ctx, args, promise) < 0) - return JS_EXCEPTION; - res = JS_Call(ctx, then, thenable, 2, (JSValueConst *)args); - if (JS_IsException(res)) { - JSValue error = JS_GetException(ctx); - res = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error); - JS_FreeValue(ctx, error); - } - JS_FreeValue(ctx, args[0]); - JS_FreeValue(ctx, args[1]); - return res; -} - -static void js_promise_resolve_function_free_resolved(JSRuntime *rt, - JSPromiseFunctionDataResolved *sr) -{ - if (--sr->ref_count == 0) { - js_free_rt(rt, sr); - } -} - -static int js_create_resolving_functions(JSContext *ctx, - JSValue *resolving_funcs, - JSValueConst promise) - -{ - JSValue obj; - JSPromiseFunctionData *s; - JSPromiseFunctionDataResolved *sr; - int i, ret; - - sr = js_malloc(ctx, sizeof(*sr)); - if (!sr) - return -1; - sr->ref_count = 1; - sr->already_resolved = FALSE; /* must be shared between the two functions */ - ret = 0; - for(i = 0; i < 2; i++) { - obj = JS_NewObjectProtoClass(ctx, ctx->function_proto, - JS_CLASS_PROMISE_RESOLVE_FUNCTION + i); - if (JS_IsException(obj)) - goto fail; - s = js_malloc(ctx, sizeof(*s)); - if (!s) { - JS_FreeValue(ctx, obj); - fail: - - if (i != 0) - JS_FreeValue(ctx, resolving_funcs[0]); - ret = -1; - break; - } - sr->ref_count++; - s->presolved = sr; - s->promise = JS_DupValue(ctx, promise); - JS_SetOpaque(obj, s); - js_function_set_properties(ctx, obj, JS_ATOM_empty_string, 1); - resolving_funcs[i] = obj; - } - js_promise_resolve_function_free_resolved(ctx->rt, sr); - return ret; -} - -static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val) -{ - JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data; - if (s) { - js_promise_resolve_function_free_resolved(rt, s->presolved); - JS_FreeValueRT(rt, s->promise); - js_free_rt(rt, s); - } -} - -static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data; - if (s) { - JS_MarkValue(rt, s->promise, mark_func); - } -} - -static JSValue js_promise_resolve_function_call(JSContext *ctx, - JSValueConst func_obj, - JSValueConst this_val, - int argc, JSValueConst *argv, - int flags) -{ - JSObject *p = JS_VALUE_GET_OBJ(func_obj); - JSPromiseFunctionData *s; - JSValueConst resolution, args[3]; - JSValue then; - BOOL is_reject; - - s = p->u.promise_function_data; - if (!s || s->presolved->already_resolved) - return JS_UNDEFINED; - s->presolved->already_resolved = TRUE; - is_reject = p->class_id - JS_CLASS_PROMISE_RESOLVE_FUNCTION; - if (argc > 0) - resolution = argv[0]; - else - resolution = JS_UNDEFINED; -#ifdef DUMP_PROMISE - printf("js_promise_resolving_function_call: is_reject=%d resolution=", is_reject); - JS_DumpValue(ctx, resolution); - printf("\n"); -#endif - if (is_reject || !JS_IsObject(resolution)) { - goto done; - } else if (js_same_value(ctx, resolution, s->promise)) { - JS_ThrowTypeError(ctx, "promise self resolution"); - goto fail_reject; - } - then = JS_GetProperty(ctx, resolution, JS_ATOM_then); - if (JS_IsException(then)) { - JSValue error; - fail_reject: - error = JS_GetException(ctx); - reject_promise(ctx, s->promise, error); - JS_FreeValue(ctx, error); - } else if (!JS_IsFunction(ctx, then)) { - JS_FreeValue(ctx, then); - done: - fulfill_or_reject_promise(ctx, s->promise, resolution, is_reject); - } else { - args[0] = s->promise; - args[1] = resolution; - args[2] = then; - JS_EnqueueJob(ctx, js_promise_resolve_thenable_job, 3, args); - JS_FreeValue(ctx, then); - } - return JS_UNDEFINED; -} - -static void js_promise_finalizer(JSRuntime *rt, JSValue val) -{ - JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE); - struct list_head *el, *el1; - int i; - - if (!s) - return; - for(i = 0; i < 2; i++) { - list_for_each_safe(el, el1, &s->promise_reactions[i]) { - JSPromiseReactionData *rd = - list_entry(el, JSPromiseReactionData, link); - promise_reaction_data_free(rt, rd); - } - } - JS_FreeValueRT(rt, s->promise_result); - js_free_rt(rt, s); -} - -static void js_promise_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE); - struct list_head *el; - int i; - - if (!s) - return; - for(i = 0; i < 2; i++) { - list_for_each(el, &s->promise_reactions[i]) { - JSPromiseReactionData *rd = - list_entry(el, JSPromiseReactionData, link); - JS_MarkValue(rt, rd->resolving_funcs[0], mark_func); - JS_MarkValue(rt, rd->resolving_funcs[1], mark_func); - JS_MarkValue(rt, rd->handler, mark_func); - } - } - JS_MarkValue(rt, s->promise_result, mark_func); -} - -static JSValue js_promise_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) -{ - JSValueConst executor; - JSValue obj; - JSPromiseData *s; - JSValue args[2], ret; - int i; - - executor = argv[0]; - if (check_function(ctx, executor)) - return JS_EXCEPTION; - obj = js_create_from_ctor(ctx, new_target, JS_CLASS_PROMISE); - if (JS_IsException(obj)) - return JS_EXCEPTION; - s = js_mallocz(ctx, sizeof(*s)); - if (!s) - goto fail; - s->promise_state = JS_PROMISE_PENDING; - s->is_handled = FALSE; - for(i = 0; i < 2; i++) - init_list_head(&s->promise_reactions[i]); - s->promise_result = JS_UNDEFINED; - JS_SetOpaque(obj, s); - if (js_create_resolving_functions(ctx, args, obj)) - goto fail; - ret = JS_Call(ctx, executor, JS_UNDEFINED, 2, (JSValueConst *)args); - if (JS_IsException(ret)) { - JSValue ret2, error; - error = JS_GetException(ctx); - ret2 = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error); - JS_FreeValue(ctx, error); - if (JS_IsException(ret2)) - goto fail1; - JS_FreeValue(ctx, ret2); - } - JS_FreeValue(ctx, ret); - JS_FreeValue(ctx, args[0]); - JS_FreeValue(ctx, args[1]); - return obj; - fail1: - JS_FreeValue(ctx, args[0]); - JS_FreeValue(ctx, args[1]); - fail: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue js_promise_executor(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, - int magic, JSValue *func_data) -{ - int i; - - for(i = 0; i < 2; i++) { - if (!JS_IsUndefined(func_data[i])) - return JS_ThrowTypeError(ctx, "resolving function already set"); - func_data[i] = JS_DupValue(ctx, argv[i]); - } - return JS_UNDEFINED; -} - -static JSValue js_promise_executor_new(JSContext *ctx) -{ - JSValueConst func_data[2]; - - func_data[0] = JS_UNDEFINED; - func_data[1] = JS_UNDEFINED; - return JS_NewCFunctionData(ctx, js_promise_executor, 2, - 0, 2, func_data); -} - -static JSValue js_new_promise_capability(JSContext *ctx, - JSValue *resolving_funcs, - JSValueConst ctor) -{ - JSValue executor, result_promise; - JSCFunctionDataRecord *s; - int i; - - executor = js_promise_executor_new(ctx); - if (JS_IsException(executor)) - return executor; - - if (JS_IsUndefined(ctor)) { - result_promise = js_promise_constructor(ctx, ctor, 1, - (JSValueConst *)&executor); - } else { - result_promise = JS_CallConstructor(ctx, ctor, 1, - (JSValueConst *)&executor); - } - if (JS_IsException(result_promise)) - goto fail; - s = JS_GetOpaque(executor, JS_CLASS_C_FUNCTION_DATA); - for(i = 0; i < 2; i++) { - if (check_function(ctx, s->data[i])) - goto fail; - } - for(i = 0; i < 2; i++) - resolving_funcs[i] = JS_DupValue(ctx, s->data[i]); - JS_FreeValue(ctx, executor); - return result_promise; - fail: - JS_FreeValue(ctx, executor); - JS_FreeValue(ctx, result_promise); - return JS_EXCEPTION; -} - -JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs) -{ - return js_new_promise_capability(ctx, resolving_funcs, JS_UNDEFINED); -} - -JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSValue result_promise, resolving_funcs[2], ret; - BOOL is_reject = magic; - - if (!JS_IsObject(this_val)) - return JS_ThrowTypeErrorNotAnObject(ctx); - if (!is_reject && JS_GetOpaque(argv[0], JS_CLASS_PROMISE)) { - JSValue ctor; - BOOL is_same; - ctor = JS_GetProperty(ctx, argv[0], JS_ATOM_constructor); - if (JS_IsException(ctor)) - return ctor; - is_same = js_same_value(ctx, ctor, this_val); - JS_FreeValue(ctx, ctor); - if (is_same) - return JS_DupValue(ctx, argv[0]); - } - result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val); - if (JS_IsException(result_promise)) - return result_promise; - ret = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED, 1, argv); - JS_FreeValue(ctx, resolving_funcs[0]); - JS_FreeValue(ctx, resolving_funcs[1]); - if (JS_IsException(ret)) { - JS_FreeValue(ctx, result_promise); - return ret; - } - JS_FreeValue(ctx, ret); - return result_promise; -} - -#if 0 -static JSValue js_promise___newPromiseCapability(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue result_promise, resolving_funcs[2], obj; - JSValueConst ctor; - ctor = argv[0]; - if (!JS_IsObject(ctor)) - return JS_ThrowTypeErrorNotAnObject(ctx); - result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor); - if (JS_IsException(result_promise)) - return result_promise; - obj = JS_NewObject(ctx); - if (JS_IsException(obj)) { - JS_FreeValue(ctx, resolving_funcs[0]); - JS_FreeValue(ctx, resolving_funcs[1]); - JS_FreeValue(ctx, result_promise); - return JS_EXCEPTION; - } - JS_DefinePropertyValue(ctx, obj, JS_ATOM_promise, result_promise, JS_PROP_C_W_E); - JS_DefinePropertyValue(ctx, obj, JS_ATOM_resolve, resolving_funcs[0], JS_PROP_C_W_E); - JS_DefinePropertyValue(ctx, obj, JS_ATOM_reject, resolving_funcs[1], JS_PROP_C_W_E); - return obj; -} -#endif - -static __exception int remainingElementsCount_add(JSContext *ctx, - JSValueConst resolve_element_env, - int addend) -{ - JSValue val; - int remainingElementsCount; - - val = JS_GetPropertyUint32(ctx, resolve_element_env, 0); - if (JS_IsException(val)) - return -1; - if (JS_ToInt32Free(ctx, &remainingElementsCount, val)) - return -1; - remainingElementsCount += addend; - if (JS_SetPropertyUint32(ctx, resolve_element_env, 0, - JS_NewInt32(ctx, remainingElementsCount)) < 0) - return -1; - return (remainingElementsCount == 0); -} - -#define PROMISE_MAGIC_all 0 -#define PROMISE_MAGIC_allSettled 1 -#define PROMISE_MAGIC_any 2 - -/* used by C code. */ -static JSValue js_aggregate_error_constructor(JSContext *ctx, - JSValueConst errors) -{ - JSValue obj; - obj = JS_NewObjectProtoClass(ctx, - ctx->native_error_proto[JS_AGGREGATE_ERROR], - JS_CLASS_ERROR); - if (JS_IsException(obj)) - return obj; - JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, JS_DupValue(ctx, errors), - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - return obj; -} - -static JSValue js_promise_all_resolve_element(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, - int magic, - JSValue *func_data) -{ - int resolve_type = magic & 3; - int is_reject = magic & 4; - BOOL alreadyCalled = JS_ToBool(ctx, func_data[0]); - JSValueConst values = func_data[2]; - JSValueConst resolve = func_data[3]; - JSValueConst resolve_element_env = func_data[4]; - JSValue ret, obj; - int is_zero, index; - if (JS_ToInt32(ctx, &index, func_data[1])) - return JS_EXCEPTION; - if (alreadyCalled) - return JS_UNDEFINED; - func_data[0] = JS_NewBool(ctx, TRUE); - if (resolve_type == PROMISE_MAGIC_allSettled) { - JSValue str; - obj = JS_NewObject(ctx); - if (JS_IsException(obj)) - return JS_EXCEPTION; - str = JS_NewString(ctx, is_reject ? "rejected" : "fulfilled"); - if (JS_IsException(str)) - goto fail1; - if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_status, - str, - JS_PROP_C_W_E) < 0) - goto fail1; - if (JS_DefinePropertyValue(ctx, obj, - is_reject ? JS_ATOM_reason : JS_ATOM_value, - JS_DupValue(ctx, argv[0]), - JS_PROP_C_W_E) < 0) { - fail1: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - } else { - obj = JS_DupValue(ctx, argv[0]); - } - if (JS_DefinePropertyValueUint32(ctx, values, index, - obj, JS_PROP_C_W_E) < 0) - return JS_EXCEPTION; - is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1); - if (is_zero < 0) - return JS_EXCEPTION; - if (is_zero) { - if (resolve_type == PROMISE_MAGIC_any) { - JSValue error; - error = js_aggregate_error_constructor(ctx, values); - if (JS_IsException(error)) - return JS_EXCEPTION; - ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&error); - JS_FreeValue(ctx, error); - } else { - ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&values); - } - if (JS_IsException(ret)) - return ret; - JS_FreeValue(ctx, ret); - } - return JS_UNDEFINED; -} - -/* magic = 0: Promise.all 1: Promise.allSettled */ -static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSValue result_promise, resolving_funcs[2], item, next_promise, ret; - JSValue next_method = JS_UNDEFINED, values = JS_UNDEFINED; - JSValue resolve_element_env = JS_UNDEFINED, resolve_element, reject_element; - JSValue promise_resolve = JS_UNDEFINED, iter = JS_UNDEFINED; - JSValueConst then_args[2], resolve_element_data[5]; - BOOL done; - int index, is_zero, is_promise_any = (magic == PROMISE_MAGIC_any); - - if (!JS_IsObject(this_val)) - return JS_ThrowTypeErrorNotAnObject(ctx); - result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val); - if (JS_IsException(result_promise)) - return result_promise; - promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve); - if (JS_IsException(promise_resolve) || - check_function(ctx, promise_resolve)) - goto fail_reject; - iter = JS_GetIterator(ctx, argv[0], FALSE); - if (JS_IsException(iter)) { - JSValue error; - fail_reject: - error = JS_GetException(ctx); - ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1, - (JSValueConst *)&error); - JS_FreeValue(ctx, error); - if (JS_IsException(ret)) - goto fail; - JS_FreeValue(ctx, ret); - } else { - next_method = JS_GetProperty(ctx, iter, JS_ATOM_next); - if (JS_IsException(next_method)) - goto fail_reject; - values = JS_NewArray(ctx); - if (JS_IsException(values)) - goto fail_reject; - resolve_element_env = JS_NewArray(ctx); - if (JS_IsException(resolve_element_env)) - goto fail_reject; - /* remainingElementsCount field */ - if (JS_DefinePropertyValueUint32(ctx, resolve_element_env, 0, - JS_NewInt32(ctx, 1), - JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0) - goto fail_reject; - - index = 0; - for(;;) { - /* XXX: conformance: should close the iterator if error on 'done' - access, but not on 'value' access */ - item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done); - if (JS_IsException(item)) - goto fail_reject; - if (done) - break; - next_promise = JS_Call(ctx, promise_resolve, - this_val, 1, (JSValueConst *)&item); - JS_FreeValue(ctx, item); - if (JS_IsException(next_promise)) { - fail_reject1: - JS_IteratorClose(ctx, iter, TRUE); - goto fail_reject; - } - resolve_element_data[0] = JS_NewBool(ctx, FALSE); - resolve_element_data[1] = (JSValueConst)JS_NewInt32(ctx, index); - resolve_element_data[2] = values; - resolve_element_data[3] = resolving_funcs[is_promise_any]; - resolve_element_data[4] = resolve_element_env; - resolve_element = - JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1, - magic, 5, resolve_element_data); - if (JS_IsException(resolve_element)) { - JS_FreeValue(ctx, next_promise); - goto fail_reject1; - } - - if (magic == PROMISE_MAGIC_allSettled) { - reject_element = - JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1, - magic | 4, 5, resolve_element_data); - if (JS_IsException(reject_element)) { - JS_FreeValue(ctx, next_promise); - goto fail_reject1; - } - } else if (magic == PROMISE_MAGIC_any) { - if (JS_DefinePropertyValueUint32(ctx, values, index, - JS_UNDEFINED, JS_PROP_C_W_E) < 0) - goto fail_reject1; - reject_element = resolve_element; - resolve_element = JS_DupValue(ctx, resolving_funcs[0]); - } else { - reject_element = JS_DupValue(ctx, resolving_funcs[1]); - } - - if (remainingElementsCount_add(ctx, resolve_element_env, 1) < 0) { - JS_FreeValue(ctx, next_promise); - JS_FreeValue(ctx, resolve_element); - JS_FreeValue(ctx, reject_element); - goto fail_reject1; - } - - then_args[0] = resolve_element; - then_args[1] = reject_element; - ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2, then_args); - JS_FreeValue(ctx, resolve_element); - JS_FreeValue(ctx, reject_element); - if (check_exception_free(ctx, ret)) - goto fail_reject1; - index++; - } - - is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1); - if (is_zero < 0) - goto fail_reject; - if (is_zero) { - if (magic == PROMISE_MAGIC_any) { - JSValue error; - error = js_aggregate_error_constructor(ctx, values); - if (JS_IsException(error)) - goto fail_reject; - JS_FreeValue(ctx, values); - values = error; - } - ret = JS_Call(ctx, resolving_funcs[is_promise_any], JS_UNDEFINED, - 1, (JSValueConst *)&values); - if (check_exception_free(ctx, ret)) - goto fail_reject; - } - } - done: - JS_FreeValue(ctx, promise_resolve); - JS_FreeValue(ctx, resolve_element_env); - JS_FreeValue(ctx, values); - JS_FreeValue(ctx, next_method); - JS_FreeValue(ctx, iter); - JS_FreeValue(ctx, resolving_funcs[0]); - JS_FreeValue(ctx, resolving_funcs[1]); - return result_promise; - fail: - JS_FreeValue(ctx, result_promise); - result_promise = JS_EXCEPTION; - goto done; -} - -static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue result_promise, resolving_funcs[2], item, next_promise, ret; - JSValue next_method = JS_UNDEFINED, iter = JS_UNDEFINED; - JSValue promise_resolve = JS_UNDEFINED; - BOOL done; - - if (!JS_IsObject(this_val)) - return JS_ThrowTypeErrorNotAnObject(ctx); - result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val); - if (JS_IsException(result_promise)) - return result_promise; - promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve); - if (JS_IsException(promise_resolve) || - check_function(ctx, promise_resolve)) - goto fail_reject; - iter = JS_GetIterator(ctx, argv[0], FALSE); - if (JS_IsException(iter)) { - JSValue error; - fail_reject: - error = JS_GetException(ctx); - ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1, - (JSValueConst *)&error); - JS_FreeValue(ctx, error); - if (JS_IsException(ret)) - goto fail; - JS_FreeValue(ctx, ret); - } else { - next_method = JS_GetProperty(ctx, iter, JS_ATOM_next); - if (JS_IsException(next_method)) - goto fail_reject; - - for(;;) { - /* XXX: conformance: should close the iterator if error on 'done' - access, but not on 'value' access */ - item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done); - if (JS_IsException(item)) - goto fail_reject; - if (done) - break; - next_promise = JS_Call(ctx, promise_resolve, - this_val, 1, (JSValueConst *)&item); - JS_FreeValue(ctx, item); - if (JS_IsException(next_promise)) { - fail_reject1: - JS_IteratorClose(ctx, iter, TRUE); - goto fail_reject; - } - ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2, - (JSValueConst *)resolving_funcs); - if (check_exception_free(ctx, ret)) - goto fail_reject1; - } - } - done: - JS_FreeValue(ctx, promise_resolve); - JS_FreeValue(ctx, next_method); - JS_FreeValue(ctx, iter); - JS_FreeValue(ctx, resolving_funcs[0]); - JS_FreeValue(ctx, resolving_funcs[1]); - return result_promise; - fail: - //JS_FreeValue(ctx, next_method); // why not??? - JS_FreeValue(ctx, result_promise); - result_promise = JS_EXCEPTION; - goto done; -} - -int perform_promise_then(JSContext *ctx, - JSValueConst promise, - JSValueConst *resolve_reject, - JSValueConst *cap_resolving_funcs) -{ - JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE); - JSPromiseReactionData *rd_array[2], *rd; - int i, j; - rd_array[0] = NULL; - rd_array[1] = NULL; - for(i = 0; i < 2; i++) { - JSValueConst handler; - rd = js_mallocz(ctx, sizeof(*rd)); - if (!rd) { - if (i == 1) - promise_reaction_data_free(ctx->rt, rd_array[0]); - return -1; - } - for(j = 0; j < 2; j++) - rd->resolving_funcs[j] = JS_DupValue(ctx, cap_resolving_funcs[j]); - handler = resolve_reject[i]; - if (!JS_IsFunction(ctx, handler)) - handler = JS_UNDEFINED; - rd->handler = JS_DupValue(ctx, handler); - rd_array[i] = rd; - } - if (s->promise_state == JS_PROMISE_PENDING) { - for(i = 0; i < 2; i++) - list_add_tail(&rd_array[i]->link, &s->promise_reactions[i]); - } else { - JSValueConst args[5]; - if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) { - JSRuntime *rt = ctx->rt; - if (rt->host_promise_rejection_tracker) { - rt->host_promise_rejection_tracker(ctx, promise, s->promise_result, - TRUE, rt->host_promise_rejection_tracker_opaque); - } - } - i = s->promise_state - JS_PROMISE_FULFILLED; - rd = rd_array[i]; - args[0] = rd->resolving_funcs[0]; - args[1] = rd->resolving_funcs[1]; - args[2] = rd->handler; - args[3] = JS_NewBool(ctx, i); - args[4] = s->promise_result; - JS_EnqueueJob(ctx, promise_reaction_job, 5, args); - for(i = 0; i < 2; i++) - promise_reaction_data_free(ctx->rt, rd_array[i]); - } - s->is_handled = TRUE; - return 0; -} - -static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue ctor, result_promise, resolving_funcs[2]; - JSPromiseData *s; - int i, ret; - - s = JS_GetOpaque2(ctx, this_val, JS_CLASS_PROMISE); - if (!s) - return JS_EXCEPTION; - - ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED); - if (JS_IsException(ctor)) - return ctor; - result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor); - JS_FreeValue(ctx, ctor); - if (JS_IsException(result_promise)) - return result_promise; - ret = perform_promise_then(ctx, this_val, argv, - (JSValueConst *)resolving_funcs); - for(i = 0; i < 2; i++) - JS_FreeValue(ctx, resolving_funcs[i]); - if (ret) { - JS_FreeValue(ctx, result_promise); - return JS_EXCEPTION; - } - return result_promise; -} - -static JSValue js_promise_catch(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst args[2]; - args[0] = JS_UNDEFINED; - args[1] = argv[0]; - return JS_Invoke(ctx, this_val, JS_ATOM_then, 2, args); -} - -static JSValue js_promise_finally_value_thunk(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - int magic, JSValue *func_data) -{ - return JS_DupValue(ctx, func_data[0]); -} - -static JSValue js_promise_finally_thrower(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - int magic, JSValue *func_data) -{ - return JS_Throw(ctx, JS_DupValue(ctx, func_data[0])); -} - -static JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - int magic, JSValue *func_data) -{ - JSValueConst ctor = func_data[0]; - JSValueConst onFinally = func_data[1]; - JSValue res, promise, ret, then_func; - - res = JS_Call(ctx, onFinally, JS_UNDEFINED, 0, NULL); - if (JS_IsException(res)) - return res; - promise = js_promise_resolve(ctx, ctor, 1, (JSValueConst *)&res, 0); - JS_FreeValue(ctx, res); - if (JS_IsException(promise)) - return promise; - if (magic == 0) { - then_func = JS_NewCFunctionData(ctx, js_promise_finally_value_thunk, 0, - 0, 1, argv); - } else { - then_func = JS_NewCFunctionData(ctx, js_promise_finally_thrower, 0, - 0, 1, argv); - } - if (JS_IsException(then_func)) { - JS_FreeValue(ctx, promise); - return then_func; - } - ret = JS_InvokeFree(ctx, promise, JS_ATOM_then, 1, (JSValueConst *)&then_func); - JS_FreeValue(ctx, then_func); - return ret; -} - -static JSValue js_promise_finally(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst onFinally = argv[0]; - JSValue ctor, ret; - JSValue then_funcs[2]; - JSValueConst func_data[2]; - int i; - - ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED); - if (JS_IsException(ctor)) - return ctor; - if (!JS_IsFunction(ctx, onFinally)) { - then_funcs[0] = JS_DupValue(ctx, onFinally); - then_funcs[1] = JS_DupValue(ctx, onFinally); - } else { - func_data[0] = ctor; - func_data[1] = onFinally; - for(i = 0; i < 2; i++) { - then_funcs[i] = JS_NewCFunctionData(ctx, js_promise_then_finally_func, 1, i, 2, func_data); - if (JS_IsException(then_funcs[i])) { - if (i == 1) - JS_FreeValue(ctx, then_funcs[0]); - JS_FreeValue(ctx, ctor); - return JS_EXCEPTION; - } - } - } - JS_FreeValue(ctx, ctor); - ret = JS_Invoke(ctx, this_val, JS_ATOM_then, 2, (JSValueConst *)then_funcs); - JS_FreeValue(ctx, then_funcs[0]); - JS_FreeValue(ctx, then_funcs[1]); - return ret; -} - -static const JSCFunctionListEntry js_promise_funcs[] = { - JS_CFUNC_MAGIC_DEF("resolve", 1, js_promise_resolve, 0 ), - JS_CFUNC_MAGIC_DEF("reject", 1, js_promise_resolve, 1 ), - JS_CFUNC_MAGIC_DEF("all", 1, js_promise_all, PROMISE_MAGIC_all ), - JS_CFUNC_MAGIC_DEF("allSettled", 1, js_promise_all, PROMISE_MAGIC_allSettled ), - JS_CFUNC_MAGIC_DEF("any", 1, js_promise_all, PROMISE_MAGIC_any ), - JS_CFUNC_DEF("race", 1, js_promise_race ), - //JS_CFUNC_DEF("__newPromiseCapability", 1, js_promise___newPromiseCapability ), - JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL), -}; - -static const JSCFunctionListEntry js_promise_proto_funcs[] = { - JS_CFUNC_DEF("then", 2, js_promise_then ), - JS_CFUNC_DEF("catch", 1, js_promise_catch ), - JS_CFUNC_DEF("finally", 1, js_promise_finally ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Promise", JS_PROP_CONFIGURABLE ), -}; - -/* 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 const JSCFunctionListEntry js_async_generator_proto_funcs[] = { - JS_CFUNC_MAGIC_DEF("next", 1, js_async_generator_next, GEN_MAGIC_NEXT ), - JS_CFUNC_MAGIC_DEF("return", 1, js_async_generator_next, GEN_MAGIC_RETURN ), - JS_CFUNC_MAGIC_DEF("throw", 1, js_async_generator_next, GEN_MAGIC_THROW ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncGenerator", JS_PROP_CONFIGURABLE ), -}; - -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 void js_async_from_sync_iterator_finalizer(JSRuntime *rt, JSValue val) -{ - JSAsyncFromSyncIteratorData *s = - JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR); - if (s) { - JS_FreeValueRT(rt, s->sync_iter); - JS_FreeValueRT(rt, s->next_method); - js_free_rt(rt, s); - } -} - -static void js_async_from_sync_iterator_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSAsyncFromSyncIteratorData *s = - JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR); - if (s) { - JS_MarkValue(rt, s->sync_iter, mark_func); - JS_MarkValue(rt, s->next_method, mark_func); - } -} - -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 JSClassShortDef const js_async_class_def[] = { - { JS_ATOM_Promise, js_promise_finalizer, js_promise_mark }, /* JS_CLASS_PROMISE */ - { JS_ATOM_PromiseResolveFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_RESOLVE_FUNCTION */ - { JS_ATOM_PromiseRejectFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_REJECT_FUNCTION */ - { JS_ATOM_AsyncFunction, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_ASYNC_FUNCTION */ - { JS_ATOM_AsyncFunctionResolve, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_RESOLVE */ - { JS_ATOM_AsyncFunctionReject, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_REJECT */ - { JS_ATOM_empty_string, js_async_from_sync_iterator_finalizer, js_async_from_sync_iterator_mark }, /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */ - { JS_ATOM_AsyncGeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_ASYNC_GENERATOR_FUNCTION */ - { JS_ATOM_AsyncGenerator, js_async_generator_finalizer, js_async_generator_mark }, /* JS_CLASS_ASYNC_GENERATOR */ -}; - -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; - } -} - -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 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; -} - -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; -} - -/* AsyncFunction */ -static const JSCFunctionListEntry js_async_function_proto_funcs[] = { - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncFunction", JS_PROP_CONFIGURABLE ), -}; - -static const JSCFunctionListEntry js_async_iterator_proto_funcs[] = { - JS_CFUNC_DEF("[Symbol.asyncIterator]", 0, js_iterator_proto_iterator ), -}; - -static JSValue js_async_from_sync_iterator_unwrap(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, - int magic, JSValue *func_data) -{ - return js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]), - JS_ToBool(ctx, func_data[0])); -} - -static JSValue js_async_from_sync_iterator_unwrap_func_create(JSContext *ctx, - BOOL done) -{ - JSValueConst func_data[1]; - func_data[0] = (JSValueConst)JS_NewBool(ctx, done); - return JS_NewCFunctionData(ctx, js_async_from_sync_iterator_unwrap, - 1, 0, 1, func_data); -} - -static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - int magic) -{ - JSValue promise, resolving_funcs[2], value, err, method; - JSAsyncFromSyncIteratorData *s; - int done; - int is_reject; - promise = JS_NewPromiseCapability(ctx, resolving_funcs); - if (JS_IsException(promise)) - return JS_EXCEPTION; - s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR); - if (!s) { - JS_ThrowTypeError(ctx, "not an Async-from-Sync Iterator"); - goto reject; - } - if (magic == GEN_MAGIC_NEXT) { - method = JS_DupValue(ctx, s->next_method); - } else { - method = JS_GetProperty(ctx, s->sync_iter, - magic == GEN_MAGIC_RETURN ? JS_ATOM_return : - JS_ATOM_throw); - if (JS_IsException(method)) - goto reject; - if (JS_IsUndefined(method) || JS_IsNull(method)) { - if (magic == GEN_MAGIC_RETURN) { - err = js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]), TRUE); - is_reject = 0; - } else { - err = JS_DupValue(ctx, argv[0]); - is_reject = 1; - } - goto done_resolve; - } - } - value = JS_IteratorNext2(ctx, s->sync_iter, method, - argc >= 1 ? 1 : 0, argv, &done); - JS_FreeValue(ctx, method); - if (JS_IsException(value)) - goto reject; - if (done == 2) { - JSValue obj = value; - value = JS_IteratorGetCompleteValue(ctx, obj, &done); - JS_FreeValue(ctx, obj); - if (JS_IsException(value)) - goto reject; - } - if (JS_IsException(value)) { - JSValue res2; - reject: - err = JS_GetException(ctx); - is_reject = 1; - done_resolve: - res2 = JS_Call(ctx, resolving_funcs[is_reject], 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; - } - { - JSValue value_wrapper_promise, resolve_reject[2]; - int res; - value_wrapper_promise = js_promise_resolve(ctx, ctx->promise_ctor, - 1, (JSValueConst *)&value, 0); - if (JS_IsException(value_wrapper_promise)) { - JS_FreeValue(ctx, value); - goto reject; - } - resolve_reject[0] = - js_async_from_sync_iterator_unwrap_func_create(ctx, done); - if (JS_IsException(resolve_reject[0])) { - JS_FreeValue(ctx, value_wrapper_promise); - goto fail; - } - JS_FreeValue(ctx, value); - resolve_reject[1] = JS_UNDEFINED; - res = perform_promise_then(ctx, value_wrapper_promise, - (JSValueConst *)resolve_reject, - (JSValueConst *)resolving_funcs); - JS_FreeValue(ctx, resolve_reject[0]); - JS_FreeValue(ctx, value_wrapper_promise); - JS_FreeValue(ctx, resolving_funcs[0]); - JS_FreeValue(ctx, resolving_funcs[1]); - if (res) { - JS_FreeValue(ctx, promise); - return JS_EXCEPTION; - } - } - return promise; - fail: - JS_FreeValue(ctx, value); - JS_FreeValue(ctx, resolving_funcs[0]); - JS_FreeValue(ctx, resolving_funcs[1]); - JS_FreeValue(ctx, promise); - return JS_EXCEPTION; -} - -static const JSCFunctionListEntry js_async_from_sync_iterator_proto_funcs[] = { - JS_CFUNC_MAGIC_DEF("next", 1, js_async_from_sync_iterator_next, GEN_MAGIC_NEXT ), - JS_CFUNC_MAGIC_DEF("return", 1, js_async_from_sync_iterator_next, GEN_MAGIC_RETURN ), - JS_CFUNC_MAGIC_DEF("throw", 1, js_async_from_sync_iterator_next, GEN_MAGIC_THROW ), -}; - -static const JSCFunctionListEntry js_async_generator_function_proto_funcs[] = { - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncGeneratorFunction", JS_PROP_CONFIGURABLE ), -}; - -void JS_AddIntrinsicPromise(JSContext *ctx) -{ - JSRuntime *rt = ctx->rt; - JSValue obj1; - if (!JS_IsRegisteredClass(rt, JS_CLASS_PROMISE)) { - init_class_range(rt, js_async_class_def, JS_CLASS_PROMISE, - countof(js_async_class_def)); - rt->class_array[JS_CLASS_PROMISE_RESOLVE_FUNCTION].call = js_promise_resolve_function_call; - rt->class_array[JS_CLASS_PROMISE_REJECT_FUNCTION].call = js_promise_resolve_function_call; - rt->class_array[JS_CLASS_ASYNC_FUNCTION].call = js_async_function_call; - rt->class_array[JS_CLASS_ASYNC_FUNCTION_RESOLVE].call = js_async_function_resolve_call; - rt->class_array[JS_CLASS_ASYNC_FUNCTION_REJECT].call = js_async_function_resolve_call; - rt->class_array[JS_CLASS_ASYNC_GENERATOR_FUNCTION].call = js_async_generator_function_call; - } - /* Promise */ - ctx->class_proto[JS_CLASS_PROMISE] = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_PROMISE], - js_promise_proto_funcs, - countof(js_promise_proto_funcs)); - obj1 = JS_NewCFunction2(ctx, js_promise_constructor, "Promise", 1, - JS_CFUNC_constructor, 0); - ctx->promise_ctor = JS_DupValue(ctx, obj1); - JS_SetPropertyFunctionList(ctx, obj1, - js_promise_funcs, - countof(js_promise_funcs)); - JS_NewGlobalCConstructor2(ctx, obj1, "Promise", - ctx->class_proto[JS_CLASS_PROMISE]); - /* AsyncFunction */ - ctx->class_proto[JS_CLASS_ASYNC_FUNCTION] = JS_NewObjectProto(ctx, ctx->function_proto); - obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor, - "AsyncFunction", 1, - JS_CFUNC_constructor_or_func_magic, JS_FUNC_ASYNC, - ctx->function_ctor); - JS_SetPropertyFunctionList(ctx, - ctx->class_proto[JS_CLASS_ASYNC_FUNCTION], - js_async_function_proto_funcs, - countof(js_async_function_proto_funcs)); - JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_ASYNC_FUNCTION], - 0, JS_PROP_CONFIGURABLE); - JS_FreeValue(ctx, obj1); - /* AsyncIteratorPrototype */ - ctx->async_iterator_proto = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->async_iterator_proto, - js_async_iterator_proto_funcs, - countof(js_async_iterator_proto_funcs)); - /* AsyncFromSyncIteratorPrototype */ - ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR] = - JS_NewObjectProto(ctx, ctx->async_iterator_proto); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR], - js_async_from_sync_iterator_proto_funcs, - countof(js_async_from_sync_iterator_proto_funcs)); - /* AsyncGeneratorPrototype */ - ctx->class_proto[JS_CLASS_ASYNC_GENERATOR] = - JS_NewObjectProto(ctx, ctx->async_iterator_proto); - JS_SetPropertyFunctionList(ctx, - ctx->class_proto[JS_CLASS_ASYNC_GENERATOR], - js_async_generator_proto_funcs, - countof(js_async_generator_proto_funcs)); - /* AsyncGeneratorFunction */ - ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION] = - JS_NewObjectProto(ctx, ctx->function_proto); - obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor, - "AsyncGeneratorFunction", 1, - JS_CFUNC_constructor_or_func_magic, - JS_FUNC_ASYNC_GENERATOR, - ctx->function_ctor); - JS_SetPropertyFunctionList(ctx, - ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION], - js_async_generator_function_proto_funcs, - countof(js_async_generator_function_proto_funcs)); - JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION], - ctx->class_proto[JS_CLASS_ASYNC_GENERATOR], - JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE); - JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION], - 0, JS_PROP_CONFIGURABLE); - JS_FreeValue(ctx, obj1); -} diff --git a/third_party/quickjs/proxy.c b/third_party/quickjs/proxy.c deleted file mode 100644 index 5f51b5f18..000000000 --- a/third_party/quickjs/proxy.c +++ /dev/null @@ -1,964 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/assert.h" -#include "third_party/quickjs/internal.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -static void js_proxy_finalizer(JSRuntime *rt, JSValue val) -{ - JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY); - if (s) { - JS_FreeValueRT(rt, s->target); - JS_FreeValueRT(rt, s->handler); - js_free_rt(rt, s); - } -} - -static void js_proxy_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY); - if (s) { - JS_MarkValue(rt, s->target, mark_func); - JS_MarkValue(rt, s->handler, mark_func); - } -} - -static JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod, - JSValueConst obj, JSAtom name) -{ - JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY); - JSValue method; - /* safer to test recursion in all proxy methods */ - if (js_check_stack_overflow(ctx->rt, 0)) { - JS_ThrowStackOverflow(ctx); - return NULL; - } - /* 's' should never be NULL */ - if (s->is_revoked) { - JS_ThrowTypeErrorRevokedProxy(ctx); - return NULL; - } - method = JS_GetProperty(ctx, s->handler, name); - if (JS_IsException(method)) - return NULL; - if (JS_IsNull(method)) - method = JS_UNDEFINED; - *pmethod = method; - return s; -} - -JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj) -{ - JSProxyData *s; - JSValue method, ret, proto1; - int res; - - s = get_proxy_method(ctx, &method, obj, JS_ATOM_getPrototypeOf); - if (!s) - return JS_EXCEPTION; - if (JS_IsUndefined(method)) - return JS_GetPrototype(ctx, s->target); - ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target); - if (JS_IsException(ret)) - return ret; - if (JS_VALUE_GET_TAG(ret) != JS_TAG_NULL && - JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) { - goto fail; - } - res = JS_IsExtensible(ctx, s->target); - if (res < 0) { - JS_FreeValue(ctx, ret); - return JS_EXCEPTION; - } - if (!res) { - /* check invariant */ - proto1 = JS_GetPrototype(ctx, s->target); - if (JS_IsException(proto1)) { - JS_FreeValue(ctx, ret); - return JS_EXCEPTION; - } - if (JS_VALUE_GET_OBJ(proto1) != JS_VALUE_GET_OBJ(ret)) { - JS_FreeValue(ctx, proto1); - fail: - JS_FreeValue(ctx, ret); - return JS_ThrowTypeError(ctx, "proxy: inconsistent prototype"); - } - JS_FreeValue(ctx, proto1); - } - return ret; -} - -int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj, - JSValueConst proto_val, BOOL throw_flag) -{ - JSProxyData *s; - JSValue method, ret, proto1; - JSValueConst args[2]; - BOOL res; - int res2; - - s = get_proxy_method(ctx, &method, obj, JS_ATOM_setPrototypeOf); - if (!s) - return -1; - if (JS_IsUndefined(method)) - return JS_SetPrototypeInternal(ctx, s->target, proto_val, throw_flag); - args[0] = s->target; - args[1] = proto_val; - ret = JS_CallFree(ctx, method, s->handler, 2, args); - if (JS_IsException(ret)) - return -1; - res = JS_ToBoolFree(ctx, ret); - if (!res) { - if (throw_flag) { - JS_ThrowTypeError(ctx, "proxy: bad prototype"); - return -1; - } else { - return FALSE; - } - } - res2 = JS_IsExtensible(ctx, s->target); - if (res2 < 0) - return -1; - if (!res2) { - proto1 = JS_GetPrototype(ctx, s->target); - if (JS_IsException(proto1)) - return -1; - if (JS_VALUE_GET_OBJ(proto_val) != JS_VALUE_GET_OBJ(proto1)) { - JS_FreeValue(ctx, proto1); - JS_ThrowTypeError(ctx, "proxy: inconsistent prototype"); - return -1; - } - JS_FreeValue(ctx, proto1); - } - return TRUE; -} - -int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj) -{ - JSProxyData *s; - JSValue method, ret; - BOOL res; - int res2; - s = get_proxy_method(ctx, &method, obj, JS_ATOM_isExtensible); - if (!s) - return -1; - if (JS_IsUndefined(method)) - return JS_IsExtensible(ctx, s->target); - ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target); - if (JS_IsException(ret)) - return -1; - res = JS_ToBoolFree(ctx, ret); - res2 = JS_IsExtensible(ctx, s->target); - if (res2 < 0) - return res2; - if (res != res2) { - JS_ThrowTypeError(ctx, "proxy: inconsistent isExtensible"); - return -1; - } - return res; -} - -int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj) -{ - JSProxyData *s; - JSValue method, ret; - BOOL res; - int res2; - s = get_proxy_method(ctx, &method, obj, JS_ATOM_preventExtensions); - if (!s) - return -1; - if (JS_IsUndefined(method)) - return JS_PreventExtensions(ctx, s->target); - ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target); - if (JS_IsException(ret)) - return -1; - res = JS_ToBoolFree(ctx, ret); - if (res) { - res2 = JS_IsExtensible(ctx, s->target); - if (res2 < 0) - return res2; - if (res2) { - JS_ThrowTypeError(ctx, "proxy: inconsistent preventExtensions"); - return -1; - } - } - return res; -} - -static int js_proxy_has(JSContext *ctx, JSValueConst obj, JSAtom atom) -{ - JSProxyData *s; - JSValue method, ret1, atom_val; - int ret, res; - JSObject *p; - JSValueConst args[2]; - BOOL res2; - s = get_proxy_method(ctx, &method, obj, JS_ATOM_has); - if (!s) - return -1; - if (JS_IsUndefined(method)) - return JS_HasProperty(ctx, s->target, atom); - atom_val = JS_AtomToValue(ctx, atom); - if (JS_IsException(atom_val)) { - JS_FreeValue(ctx, method); - return -1; - } - args[0] = s->target; - args[1] = atom_val; - ret1 = JS_CallFree(ctx, method, s->handler, 2, args); - JS_FreeValue(ctx, atom_val); - if (JS_IsException(ret1)) - return -1; - ret = JS_ToBoolFree(ctx, ret1); - if (!ret) { - JSPropertyDescriptor desc; - p = JS_VALUE_GET_OBJ(s->target); - res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom); - if (res < 0) - return -1; - if (res) { - res2 = !(desc.flags & JS_PROP_CONFIGURABLE); - js_free_desc(ctx, &desc); - if (res2 || !p->extensible) { - JS_ThrowTypeError(ctx, "proxy: inconsistent has"); - return -1; - } - } - } - return ret; -} - -static JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom, - JSValueConst receiver) -{ - JSProxyData *s; - JSValue method, ret, atom_val; - int res; - JSValueConst args[3]; - JSPropertyDescriptor desc; - s = get_proxy_method(ctx, &method, obj, JS_ATOM_get); - if (!s) - return JS_EXCEPTION; - /* Note: recursion is possible thru the prototype of s->target */ - if (JS_IsUndefined(method)) - return JS_GetPropertyInternal(ctx, s->target, atom, receiver, FALSE); - atom_val = JS_AtomToValue(ctx, atom); - if (JS_IsException(atom_val)) { - JS_FreeValue(ctx, method); - return JS_EXCEPTION; - } - args[0] = s->target; - args[1] = atom_val; - args[2] = receiver; - ret = JS_CallFree(ctx, method, s->handler, 3, args); - JS_FreeValue(ctx, atom_val); - if (JS_IsException(ret)) - return JS_EXCEPTION; - res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom); - if (res < 0) - return JS_EXCEPTION; - if (res) { - if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) { - if (!js_same_value(ctx, desc.value, ret)) { - goto fail; - } - } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET) { - if (JS_IsUndefined(desc.getter) && !JS_IsUndefined(ret)) { - fail: - js_free_desc(ctx, &desc); - JS_FreeValue(ctx, ret); - return JS_ThrowTypeError(ctx, "proxy: inconsistent get"); - } - } - js_free_desc(ctx, &desc); - } - return ret; -} - -static int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom, - JSValueConst value, JSValueConst receiver, int flags) -{ - JSProxyData *s; - JSValue method, ret1, atom_val; - int ret, res; - JSValueConst args[4]; - s = get_proxy_method(ctx, &method, obj, JS_ATOM_set); - if (!s) - return -1; - if (JS_IsUndefined(method)) { - return JS_SetPropertyGeneric(ctx, s->target, atom, - JS_DupValue(ctx, value), receiver, - flags); - } - atom_val = JS_AtomToValue(ctx, atom); - if (JS_IsException(atom_val)) { - JS_FreeValue(ctx, method); - return -1; - } - args[0] = s->target; - args[1] = atom_val; - args[2] = value; - args[3] = receiver; - ret1 = JS_CallFree(ctx, method, s->handler, 4, args); - JS_FreeValue(ctx, atom_val); - if (JS_IsException(ret1)) - return -1; - ret = JS_ToBoolFree(ctx, ret1); - if (ret) { - JSPropertyDescriptor desc; - res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom); - if (res < 0) - return -1; - if (res) { - if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) { - if (!js_same_value(ctx, desc.value, value)) { - goto fail; - } - } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET && JS_IsUndefined(desc.setter)) { - fail: - js_free_desc(ctx, &desc); - JS_ThrowTypeError(ctx, "proxy: inconsistent set"); - return -1; - } - js_free_desc(ctx, &desc); - } - } else { - if ((flags & JS_PROP_THROW) || - ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) { - JS_ThrowTypeError(ctx, "proxy: cannot set property"); - return -1; - } - } - return ret; -} - -static JSValue js_create_desc(JSContext *ctx, JSValueConst val, - JSValueConst getter, JSValueConst setter, - int flags) -{ - JSValue ret; - ret = JS_NewObject(ctx); - if (JS_IsException(ret)) - return ret; - if (flags & JS_PROP_HAS_GET) { - JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, getter), - JS_PROP_C_W_E); - } - if (flags & JS_PROP_HAS_SET) { - JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, setter), - JS_PROP_C_W_E); - } - if (flags & JS_PROP_HAS_VALUE) { - JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, val), - JS_PROP_C_W_E); - } - if (flags & JS_PROP_HAS_WRITABLE) { - JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable, - JS_NewBool(ctx, (flags & JS_PROP_WRITABLE) != 0), - JS_PROP_C_W_E); - } - if (flags & JS_PROP_HAS_ENUMERABLE) { - JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable, - JS_NewBool(ctx, (flags & JS_PROP_ENUMERABLE) != 0), - JS_PROP_C_W_E); - } - if (flags & JS_PROP_HAS_CONFIGURABLE) { - JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable, - JS_NewBool(ctx, (flags & JS_PROP_CONFIGURABLE) != 0), - JS_PROP_C_W_E); - } - return ret; -} - -static int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc, - JSValueConst obj, JSAtom prop) -{ - JSProxyData *s; - JSValue method, trap_result_obj, prop_val; - int res, target_desc_ret, ret; - JSObject *p; - JSValueConst args[2]; - JSPropertyDescriptor result_desc, target_desc; - s = get_proxy_method(ctx, &method, obj, JS_ATOM_getOwnPropertyDescriptor); - if (!s) - return -1; - p = JS_VALUE_GET_OBJ(s->target); - if (JS_IsUndefined(method)) { - return JS_GetOwnPropertyInternal(ctx, pdesc, p, prop); - } - prop_val = JS_AtomToValue(ctx, prop); - if (JS_IsException(prop_val)) { - JS_FreeValue(ctx, method); - return -1; - } - args[0] = s->target; - args[1] = prop_val; - trap_result_obj = JS_CallFree(ctx, method, s->handler, 2, args); - JS_FreeValue(ctx, prop_val); - if (JS_IsException(trap_result_obj)) - return -1; - if (!JS_IsObject(trap_result_obj) && !JS_IsUndefined(trap_result_obj)) { - JS_FreeValue(ctx, trap_result_obj); - goto fail; - } - target_desc_ret = JS_GetOwnPropertyInternal(ctx, &target_desc, p, prop); - if (target_desc_ret < 0) { - JS_FreeValue(ctx, trap_result_obj); - return -1; - } - if (target_desc_ret) - js_free_desc(ctx, &target_desc); - if (JS_IsUndefined(trap_result_obj)) { - if (target_desc_ret) { - if (!(target_desc.flags & JS_PROP_CONFIGURABLE) || !p->extensible) - goto fail; - } - ret = FALSE; - } else { - int flags1, extensible_target; - extensible_target = JS_IsExtensible(ctx, s->target); - if (extensible_target < 0) { - JS_FreeValue(ctx, trap_result_obj); - return -1; - } - res = js_obj_to_desc(ctx, &result_desc, trap_result_obj); - JS_FreeValue(ctx, trap_result_obj); - if (res < 0) - return -1; - if (target_desc_ret) { - /* convert result_desc.flags to defineProperty flags */ - flags1 = result_desc.flags | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE; - if (result_desc.flags & JS_PROP_GETSET) - flags1 |= JS_PROP_HAS_GET | JS_PROP_HAS_SET; - else - flags1 |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE; - /* XXX: not complete check: need to compare value & - getter/setter as in defineproperty */ - if (!check_define_prop_flags(target_desc.flags, flags1)) - goto fail1; - } else { - if (!extensible_target) - goto fail1; - } - if (!(result_desc.flags & JS_PROP_CONFIGURABLE)) { - if (!target_desc_ret || (target_desc.flags & JS_PROP_CONFIGURABLE)) - goto fail1; - if ((result_desc.flags & - (JS_PROP_GETSET | JS_PROP_WRITABLE)) == 0 && - target_desc_ret && - (target_desc.flags & JS_PROP_WRITABLE) != 0) { - /* proxy-missing-checks */ - fail1: - js_free_desc(ctx, &result_desc); - fail: - JS_ThrowTypeError(ctx, "proxy: inconsistent getOwnPropertyDescriptor"); - return -1; - } - } - ret = TRUE; - if (pdesc) { - *pdesc = result_desc; - } else { - js_free_desc(ctx, &result_desc); - } - } - return ret; -} - -static int js_proxy_define_own_property(JSContext *ctx, JSValueConst obj, - JSAtom prop, JSValueConst val, - JSValueConst getter, JSValueConst setter, - int flags) -{ - JSProxyData *s; - JSValue method, ret1, prop_val, desc_val; - int res, ret; - JSObject *p; - JSValueConst args[3]; - JSPropertyDescriptor desc; - BOOL setting_not_configurable; - s = get_proxy_method(ctx, &method, obj, JS_ATOM_defineProperty); - if (!s) - return -1; - if (JS_IsUndefined(method)) { - return JS_DefineProperty(ctx, s->target, prop, val, getter, setter, flags); - } - prop_val = JS_AtomToValue(ctx, prop); - if (JS_IsException(prop_val)) { - JS_FreeValue(ctx, method); - return -1; - } - desc_val = js_create_desc(ctx, val, getter, setter, flags); - if (JS_IsException(desc_val)) { - JS_FreeValue(ctx, prop_val); - JS_FreeValue(ctx, method); - return -1; - } - args[0] = s->target; - args[1] = prop_val; - args[2] = desc_val; - ret1 = JS_CallFree(ctx, method, s->handler, 3, args); - JS_FreeValue(ctx, prop_val); - JS_FreeValue(ctx, desc_val); - if (JS_IsException(ret1)) - return -1; - ret = JS_ToBoolFree(ctx, ret1); - if (!ret) { - if (flags & JS_PROP_THROW) { - JS_ThrowTypeError(ctx, "proxy: defineProperty exception"); - return -1; - } else { - return 0; - } - } - p = JS_VALUE_GET_OBJ(s->target); - res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop); - if (res < 0) - return -1; - setting_not_configurable = ((flags & (JS_PROP_HAS_CONFIGURABLE | - JS_PROP_CONFIGURABLE)) == - JS_PROP_HAS_CONFIGURABLE); - if (!res) { - if (!p->extensible || setting_not_configurable) - goto fail; - } else { - if (!check_define_prop_flags(desc.flags, flags) || - ((desc.flags & JS_PROP_CONFIGURABLE) && setting_not_configurable)) { - goto fail1; - } - if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { - if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == - JS_PROP_GETSET) { - if ((flags & JS_PROP_HAS_GET) && - !js_same_value(ctx, getter, desc.getter)) { - goto fail1; - } - if ((flags & JS_PROP_HAS_SET) && - !js_same_value(ctx, setter, desc.setter)) { - goto fail1; - } - } - } else if (flags & JS_PROP_HAS_VALUE) { - if ((desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == - JS_PROP_WRITABLE && !(flags & JS_PROP_WRITABLE)) { - /* missing-proxy-check feature */ - goto fail1; - } else if ((desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 && - !js_same_value(ctx, val, desc.value)) { - goto fail1; - } - } - if (flags & JS_PROP_HAS_WRITABLE) { - if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | - JS_PROP_WRITABLE)) == JS_PROP_WRITABLE) { - /* proxy-missing-checks */ - fail1: - js_free_desc(ctx, &desc); - fail: - JS_ThrowTypeError(ctx, "proxy: inconsistent defineProperty"); - return -1; - } - } - js_free_desc(ctx, &desc); - } - return 1; -} - -static int js_proxy_delete_property(JSContext *ctx, JSValueConst obj, - JSAtom atom) -{ - JSProxyData *s; - JSValue method, ret, atom_val; - int res, res2, is_extensible; - JSValueConst args[2]; - - s = get_proxy_method(ctx, &method, obj, JS_ATOM_deleteProperty); - if (!s) - return -1; - if (JS_IsUndefined(method)) { - return JS_DeleteProperty(ctx, s->target, atom, 0); - } - atom_val = JS_AtomToValue(ctx, atom);; - if (JS_IsException(atom_val)) { - JS_FreeValue(ctx, method); - return -1; - } - args[0] = s->target; - args[1] = atom_val; - ret = JS_CallFree(ctx, method, s->handler, 2, args); - JS_FreeValue(ctx, atom_val); - if (JS_IsException(ret)) - return -1; - res = JS_ToBoolFree(ctx, ret); - if (res) { - JSPropertyDescriptor desc; - res2 = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom); - if (res2 < 0) - return -1; - if (res2) { - if (!(desc.flags & JS_PROP_CONFIGURABLE)) - goto fail; - is_extensible = JS_IsExtensible(ctx, s->target); - if (is_extensible < 0) - goto fail1; - if (!is_extensible) { - /* proxy-missing-checks */ - fail: - JS_ThrowTypeError(ctx, "proxy: inconsistent deleteProperty"); - fail1: - js_free_desc(ctx, &desc); - return -1; - } - js_free_desc(ctx, &desc); - } - } - return res; -} - -/* return the index of the property or -1 if not found */ -static int find_prop_key(const JSPropertyEnum *tab, int n, JSAtom atom) -{ - int i; - for(i = 0; i < n; i++) { - if (tab[i].atom == atom) - return i; - } - return -1; -} - -static int js_proxy_get_own_property_names(JSContext *ctx, - JSPropertyEnum **ptab, - uint32_t *plen, - JSValueConst obj) -{ - JSProxyData *s; - JSValue method, prop_array, val; - uint32_t len, i, len2; - JSPropertyEnum *tab, *tab2; - JSAtom atom; - JSPropertyDescriptor desc; - int res, is_extensible, idx; - s = get_proxy_method(ctx, &method, obj, JS_ATOM_ownKeys); - if (!s) - return -1; - if (JS_IsUndefined(method)) { - return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen, - JS_VALUE_GET_OBJ(s->target), - JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK); - } - prop_array = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target); - if (JS_IsException(prop_array)) - return -1; - tab = NULL; - len = 0; - tab2 = NULL; - len2 = 0; - if (js_get_length32(ctx, &len, prop_array)) - goto fail; - if (len > 0) { - tab = js_mallocz(ctx, sizeof(tab[0]) * len); - if (!tab) - goto fail; - } - for(i = 0; i < len; i++) { - val = JS_GetPropertyUint32(ctx, prop_array, i); - if (JS_IsException(val)) - goto fail; - if (!JS_IsString(val) && !JS_IsSymbol(val)) { - JS_FreeValue(ctx, val); - JS_ThrowTypeError(ctx, "proxy: properties must be strings or symbols"); - goto fail; - } - atom = JS_ValueToAtom(ctx, val); - JS_FreeValue(ctx, val); - if (atom == JS_ATOM_NULL) - goto fail; - tab[i].atom = atom; - tab[i].is_enumerable = FALSE; /* XXX: redundant? */ - } - /* check duplicate properties (XXX: inefficient, could store the - * properties an a temporary object to use the hash) */ - for(i = 1; i < len; i++) { - if (find_prop_key(tab, i, tab[i].atom) >= 0) { - JS_ThrowTypeError(ctx, "proxy: duplicate property"); - goto fail; - } - } - is_extensible = JS_IsExtensible(ctx, s->target); - if (is_extensible < 0) - goto fail; - /* check if there are non configurable properties */ - if (s->is_revoked) { - JS_ThrowTypeErrorRevokedProxy(ctx); - goto fail; - } - if (JS_GetOwnPropertyNamesInternal(ctx, &tab2, &len2, JS_VALUE_GET_OBJ(s->target), - JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK)) - goto fail; - for(i = 0; i < len2; i++) { - if (s->is_revoked) { - JS_ThrowTypeErrorRevokedProxy(ctx); - goto fail; - } - res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), - tab2[i].atom); - if (res < 0) - goto fail; - if (res) { /* safety, property should be found */ - js_free_desc(ctx, &desc); - if (!(desc.flags & JS_PROP_CONFIGURABLE) || !is_extensible) { - idx = find_prop_key(tab, len, tab2[i].atom); - if (idx < 0) { - JS_ThrowTypeError(ctx, "proxy: target property must be present in proxy ownKeys"); - goto fail; - } - /* mark the property as found */ - if (!is_extensible) - tab[idx].is_enumerable = TRUE; - } - } - } - if (!is_extensible) { - /* check that all property in 'tab' were checked */ - for(i = 0; i < len; i++) { - if (!tab[i].is_enumerable) { - JS_ThrowTypeError(ctx, "proxy: property not present in target were returned by non extensible proxy"); - goto fail; - } - } - } - js_free_prop_enum(ctx, tab2, len2); - JS_FreeValue(ctx, prop_array); - *ptab = tab; - *plen = len; - return 0; - fail: - js_free_prop_enum(ctx, tab2, len2); - js_free_prop_enum(ctx, tab, len); - JS_FreeValue(ctx, prop_array); - return -1; -} - -static JSValue js_proxy_call_constructor(JSContext *ctx, JSValueConst func_obj, - JSValueConst new_target, - int argc, JSValueConst *argv) -{ - JSProxyData *s; - JSValue method, arg_array, ret; - JSValueConst args[3]; - - s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_construct); - if (!s) - return JS_EXCEPTION; - if (!JS_IsConstructor(ctx, s->target)) - return JS_ThrowTypeError(ctx, "not a constructor"); - if (JS_IsUndefined(method)) - return JS_CallConstructor2(ctx, s->target, new_target, argc, argv); - arg_array = js_create_array(ctx, argc, argv); - if (JS_IsException(arg_array)) { - ret = JS_EXCEPTION; - goto fail; - } - args[0] = s->target; - args[1] = arg_array; - args[2] = new_target; - ret = JS_Call(ctx, method, s->handler, 3, args); - if (!JS_IsException(ret) && JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) { - JS_FreeValue(ctx, ret); - ret = JS_ThrowTypeErrorNotAnObject(ctx); - } - fail: - JS_FreeValue(ctx, method); - JS_FreeValue(ctx, arg_array); - return ret; -} - -static JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, - int argc, JSValueConst *argv, int flags) -{ - JSProxyData *s; - JSValue method, arg_array, ret; - JSValueConst args[3]; - - if (flags & JS_CALL_FLAG_CONSTRUCTOR) - return js_proxy_call_constructor(ctx, func_obj, this_obj, argc, argv); - - s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_apply); - if (!s) - return JS_EXCEPTION; - if (!s->is_func) { - JS_FreeValue(ctx, method); - return JS_ThrowTypeError(ctx, "not a function"); - } - if (JS_IsUndefined(method)) - return JS_Call(ctx, s->target, this_obj, argc, argv); - arg_array = js_create_array(ctx, argc, argv); - if (JS_IsException(arg_array)) { - ret = JS_EXCEPTION; - goto fail; - } - args[0] = s->target; - args[1] = this_obj; - args[2] = arg_array; - ret = JS_Call(ctx, method, s->handler, 3, args); - fail: - JS_FreeValue(ctx, method); - JS_FreeValue(ctx, arg_array); - return ret; -} - -int js_proxy_isArray(JSContext *ctx, JSValueConst obj) -{ - JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY); - if (!s) - return FALSE; - if (js_check_stack_overflow(ctx->rt, 0)) { - JS_ThrowStackOverflow(ctx); - return -1; - } - if (s->is_revoked) { - JS_ThrowTypeErrorRevokedProxy(ctx); - return -1; - } - return JS_IsArray(ctx, s->target); -} - -static const JSClassExoticMethods js_proxy_exotic_methods = { - .get_own_property = js_proxy_get_own_property, - .define_own_property = js_proxy_define_own_property, - .delete_property = js_proxy_delete_property, - .get_own_property_names = js_proxy_get_own_property_names, - .has_property = js_proxy_has, - .get_property = js_proxy_get, - .set_property = js_proxy_set, -}; - -static JSValue js_proxy_constructor(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst target, handler; - JSValue obj; - JSProxyData *s; - - target = argv[0]; - handler = argv[1]; - if (JS_VALUE_GET_TAG(target) != JS_TAG_OBJECT || - JS_VALUE_GET_TAG(handler) != JS_TAG_OBJECT) - return JS_ThrowTypeErrorNotAnObject(ctx); - - obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_PROXY); - if (JS_IsException(obj)) - return obj; - s = js_malloc(ctx, sizeof(JSProxyData)); - if (!s) { - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - s->target = JS_DupValue(ctx, target); - s->handler = JS_DupValue(ctx, handler); - s->is_func = JS_IsFunction(ctx, target); - s->is_revoked = FALSE; - JS_SetOpaque(obj, s); - JS_SetConstructorBit(ctx, obj, JS_IsConstructor(ctx, target)); - return obj; -} - -static JSValue js_proxy_revoke(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic, - JSValue *func_data) -{ - JSProxyData *s = JS_GetOpaque(func_data[0], JS_CLASS_PROXY); - if (s) { - /* We do not free the handler and target in case they are - referenced as constants in the C call stack */ - s->is_revoked = TRUE; - JS_FreeValue(ctx, func_data[0]); - func_data[0] = JS_NULL; - } - return JS_UNDEFINED; -} - -static JSValue js_proxy_revoke_constructor(JSContext *ctx, - JSValueConst proxy_obj) -{ - return JS_NewCFunctionData(ctx, js_proxy_revoke, 0, 0, 1, &proxy_obj); -} - -static JSValue js_proxy_revocable(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue proxy_obj, revoke_obj = JS_UNDEFINED, obj; - proxy_obj = js_proxy_constructor(ctx, JS_UNDEFINED, argc, argv); - if (JS_IsException(proxy_obj)) - goto fail; - revoke_obj = js_proxy_revoke_constructor(ctx, proxy_obj); - if (JS_IsException(revoke_obj)) - goto fail; - obj = JS_NewObject(ctx); - if (JS_IsException(obj)) - goto fail; - // XXX: exceptions? - JS_DefinePropertyValue(ctx, obj, JS_ATOM_proxy, proxy_obj, JS_PROP_C_W_E); - JS_DefinePropertyValue(ctx, obj, JS_ATOM_revoke, revoke_obj, JS_PROP_C_W_E); - return obj; - fail: - JS_FreeValue(ctx, proxy_obj); - JS_FreeValue(ctx, revoke_obj); - return JS_EXCEPTION; -} - -static const JSCFunctionListEntry js_proxy_funcs[] = { - JS_CFUNC_DEF("revocable", 2, js_proxy_revocable ), -}; - -static const JSClassShortDef js_proxy_class_def[] = { - { JS_ATOM_Object, js_proxy_finalizer, js_proxy_mark }, /* JS_CLASS_PROXY */ -}; - -void JS_AddIntrinsicProxy(JSContext *ctx) -{ - JSRuntime *rt = ctx->rt; - JSValue obj1; - if (!JS_IsRegisteredClass(rt, JS_CLASS_PROXY)) { - init_class_range(rt, js_proxy_class_def, JS_CLASS_PROXY, - countof(js_proxy_class_def)); - rt->class_array[JS_CLASS_PROXY].exotic = &js_proxy_exotic_methods; - rt->class_array[JS_CLASS_PROXY].call = js_proxy_call; - } - obj1 = JS_NewCFunction2(ctx, js_proxy_constructor, "Proxy", 2, - JS_CFUNC_constructor, 0); - JS_SetConstructorBit(ctx, obj1, TRUE); - JS_SetPropertyFunctionList(ctx, obj1, js_proxy_funcs, - countof(js_proxy_funcs)); - JS_DefinePropertyValueStr(ctx, ctx->global_obj, "Proxy", - obj1, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); -} diff --git a/third_party/quickjs/qjs.c b/third_party/quickjs/qjs.c deleted file mode 100644 index 2208806f4..000000000 --- a/third_party/quickjs/qjs.c +++ /dev/null @@ -1,578 +0,0 @@ -/* - * QuickJS stand alone interpreter - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/assert.h" -#include "libc/calls/calls.h" -#include "libc/calls/weirdtypes.h" -#include "libc/dce.h" -#include "libc/fmt/conv.h" -#include "libc/log/log.h" -#include "libc/mem/mem.h" -#include "libc/runtime/runtime.h" -#include "libc/runtime/stack.h" -#include "libc/stdio/stdio.h" -#include "libc/str/str.h" -#include "third_party/quickjs/cutils.h" -#include "third_party/quickjs/quickjs-libc.h" -#include "tool/args/args.h" - -STATIC_STACK_SIZE(0x80000); - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - - -extern const uint8_t qjsc_repl[]; -extern const uint32_t qjsc_repl_size; -#ifdef CONFIG_BIGNUM -extern const uint8_t qjsc_qjscalc[]; -extern const uint32_t qjsc_qjscalc_size; -static int bignum_ext; -#endif - -static int eval_buf(JSContext *ctx, const void *buf, int buf_len, - const char *filename, int eval_flags) -{ - JSValue val; - int ret; - - if ((eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_MODULE) { - /* for the modules, we compile then run to be able to set - import.meta */ - val = JS_Eval(ctx, buf, buf_len, filename, - eval_flags | JS_EVAL_FLAG_COMPILE_ONLY); - if (!JS_IsException(val)) { - js_module_set_import_meta(ctx, val, TRUE, TRUE); - val = JS_EvalFunction(ctx, val); - } - } else { - val = JS_Eval(ctx, buf, buf_len, filename, eval_flags); - } - if (JS_IsException(val)) { - js_std_dump_error(ctx); - ret = -1; - } else { - ret = 0; - } - JS_FreeValue(ctx, val); - return ret; -} - -static int eval_file(JSContext *ctx, const char *filename, int module) -{ - uint8_t *buf; - int ret, eval_flags; - size_t buf_len; - - buf = js_load_file(ctx, &buf_len, filename); - if (!buf) { - perror(filename); - exit(1); - } - - if (module < 0) { - module = (has_suffix(filename, ".mjs") || - JS_DetectModule((const char *)buf, buf_len)); - } - if (module) - eval_flags = JS_EVAL_TYPE_MODULE; - else - eval_flags = JS_EVAL_TYPE_GLOBAL; - ret = eval_buf(ctx, buf, buf_len, filename, eval_flags); - js_free(ctx, buf); - return ret; -} - -/* also used to initialize the worker context */ -static JSContext *JS_NewCustomContext(JSRuntime *rt) -{ - JSContext *ctx; - ctx = JS_NewContext(rt); - if (!ctx) - return NULL; -#ifdef CONFIG_BIGNUM - if (bignum_ext) { - JS_AddIntrinsicBigFloat(ctx); - JS_AddIntrinsicBigDecimal(ctx); - JS_AddIntrinsicOperators(ctx); - JS_EnableBignumExt(ctx, TRUE); - } -#endif - /* system modules */ - js_init_module_std(ctx, "std"); - js_init_module_os(ctx, "os"); - return ctx; -} - -#if defined(__APPLE__) -#define MALLOC_OVERHEAD 0 -#else -#define MALLOC_OVERHEAD 8 -#endif - -struct trace_malloc_data { - uint8_t *base; -}; - -static inline unsigned long long js_trace_malloc_ptr_offset(uint8_t *ptr, - struct trace_malloc_data *dp) -{ - return ptr - dp->base; -} - -/* default memory allocation functions with memory limitation */ -static inline size_t js_trace_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 malloc_usable_size(ptr); -#else - /* change this to `return 0;` if compilation fails */ - return malloc_usable_size(ptr); -#endif -} - -static void -#ifdef _WIN32 -/* mingw printf is used */ -__attribute__((format(gnu_printf, 2, 3))) -#else -__attribute__((format(printf, 2, 3))) -#endif - js_trace_malloc_printf(JSMallocState *s, const char *fmt, ...) -{ - va_list ap; - int c; - - va_start(ap, fmt); - while ((c = *fmt++) != '\0') { - if (c == '%') { - /* only handle %p and %zd */ - if (*fmt == 'p') { - uint8_t *ptr = va_arg(ap, void *); - if (ptr == NULL) { - printf("NULL"); - } else { - printf("H%+06lld.%zd", - js_trace_malloc_ptr_offset(ptr, s->opaque), - js_trace_malloc_usable_size(ptr)); - } - fmt++; - continue; - } - if (fmt[0] == 'z' && fmt[1] == 'd') { - size_t sz = va_arg(ap, size_t); - printf("%zd", sz); - fmt += 2; - continue; - } - } - putc(c, stdout); - } - va_end(ap); -} - -static void js_trace_malloc_init(struct trace_malloc_data *s) -{ - free(s->base = malloc(8)); -} - -static void *js_trace_malloc(JSMallocState *s, size_t size) -{ - void *ptr; - /* Do not allocate zero bytes: behavior is platform dependent */ - assert(size != 0); - if (UNLIKELY(s->malloc_size + size > s->malloc_limit)) - return NULL; - ptr = malloc(size); - js_trace_malloc_printf(s, "A %zd -> %p\n", size, ptr); - if (ptr) { - s->malloc_count++; - s->malloc_size += js_trace_malloc_usable_size(ptr) + MALLOC_OVERHEAD; - } - return ptr; -} - -static void js_trace_free(JSMallocState *s, void *ptr) -{ - if (!ptr) - return; - - js_trace_malloc_printf(s, "F %p\n", ptr); - s->malloc_count--; - s->malloc_size -= js_trace_malloc_usable_size(ptr) + MALLOC_OVERHEAD; - free(ptr); -} - -static void *js_trace_realloc(JSMallocState *s, void *ptr, size_t size) -{ - size_t old_size; - - if (!ptr) { - if (size == 0) - return NULL; - return js_trace_malloc(s, size); - } - old_size = js_trace_malloc_usable_size(ptr); - if (size == 0) { - js_trace_malloc_printf(s, "R %zd %p\n", size, ptr); - s->malloc_count--; - s->malloc_size -= old_size + MALLOC_OVERHEAD; - free(ptr); - return NULL; - } - if (s->malloc_size + size - old_size > s->malloc_limit) - return NULL; - - js_trace_malloc_printf(s, "R %zd %p", size, ptr); - - ptr = realloc(ptr, size); - js_trace_malloc_printf(s, " -> %p\n", ptr); - if (ptr) { - s->malloc_size += js_trace_malloc_usable_size(ptr) - old_size; - } - return ptr; -} - -static const JSMallocFunctions trace_mf = { - js_trace_malloc, - js_trace_free, - js_trace_realloc, -#if defined(__APPLE__) - malloc_size, -#elif defined(_WIN32) - (size_t (*)(const void *))_msize, -#elif defined(EMSCRIPTEN) - NULL, -#elif defined(__linux__) || defined(__COSMOPOLITAN__) - (size_t (*)(const void *))malloc_usable_size, -#else - /* change this to `NULL,` if compilation fails */ - malloc_usable_size, -#endif -}; - -#define PROG_NAME "qjs" - -void help(void) -{ - printf("QuickJS version " CONFIG_VERSION "\n" - "usage: " PROG_NAME " [options] [file [args]]\n" - "-h --help list options\n" - "-e --eval EXPR evaluate EXPR\n" - "-i --interactive go to interactive mode\n" - "-m --module load as ES6 module (default=autodetect)\n" - " --script load as ES6 script (default=autodetect)\n" - "-I --include file include an additional file\n" - " --std make 'std' and 'os' available to the loaded script\n" -#ifdef CONFIG_BIGNUM - " --bignum enable the bignum extensions (BigFloat, BigDecimal)\n" - " --qjscalc load the QJSCalc runtime (default if invoked as qjscalc)\n" -#endif - "-T --trace trace memory allocation\n" - "-d --dump dump the memory usage stats\n" - " --memory-limit n limit the memory usage to 'n' bytes\n" - " --stack-size n limit the stack size to 'n' bytes\n" - " --unhandled-rejection dump unhandled promise rejections\n" - "-q --quit just instantiate the interpreter and quit\n"); - exit(1); -} - -int main(int argc, char **argv) -{ - JSRuntime *rt; - JSContext *ctx; - struct trace_malloc_data trace_data = { NULL }; - int optind; - char *expr = NULL; - int interactive = 0; - int dump_memory = 0; - int trace_memory = 0; - int empty_run = 0; - int module = -1; - int load_std = 0; - int dump_unhandled_promise_rejection = 0; - size_t memory_limit = 0; - char *include_list[32]; - int i, include_count = 0; -#ifdef CONFIG_BIGNUM - int load_jscalc; -#endif - size_t stack_size = 0; - - LoadZipArgs(&argc, &argv); - -#if IsModeDbg() - ShowCrashReports(); -#endif - -#ifdef CONFIG_BIGNUM - /* load jscalc runtime if invoked as 'qjscalc' */ - { - const char *p, *exename; - exename = argv[0]; - p = strrchr(exename, '/'); - if (p) - exename = p + 1; - load_jscalc = !strcmp(exename, "qjscalc"); - } -#endif - - /* cannot use getopt because we want to pass the command line to - the script */ - optind = 1; - while (optind < argc && *argv[optind] == '-') { - char *arg = argv[optind] + 1; - const char *longopt = ""; - /* a single - is not an option, it also stops argument scanning */ - if (!*arg) - break; - optind++; - if (*arg == '-') { - longopt = arg + 1; - arg += strlen(arg); - /* -- stops argument scanning */ - if (!*longopt) - break; - } - for (; *arg || *longopt; longopt = "") { - char opt = *arg; - if (opt) - arg++; - if (opt == 'h' || opt == '?' || !strcmp(longopt, "help")) { - help(); - continue; - } - if (opt == 'e' || !strcmp(longopt, "eval")) { - if (*arg) { - expr = arg; - break; - } - if (optind < argc) { - expr = argv[optind++]; - break; - } - fprintf(stderr, "qjs: missing expression for -e\n"); - exit(2); - } - if (opt == 'I' || !strcmp(longopt, "include")) { - if (optind >= argc) { - fprintf(stderr, "expecting filename"); - exit(1); - } - if (include_count >= countof(include_list)) { - fprintf(stderr, "too many included files"); - exit(1); - } - include_list[include_count++] = argv[optind++]; - continue; - } - if (opt == 'i' || !strcmp(longopt, "interactive")) { - interactive++; - continue; - } - if (opt == 'm' || !strcmp(longopt, "module")) { - module = 1; - continue; - } - if (!strcmp(longopt, "script")) { - module = 0; - continue; - } - if (opt == 'd' || !strcmp(longopt, "dump")) { - dump_memory++; - continue; - } - if (opt == 'T' || !strcmp(longopt, "trace")) { - trace_memory++; - continue; - } - if (!strcmp(longopt, "std")) { - load_std = 1; - continue; - } - if (!strcmp(longopt, "unhandled-rejection")) { - dump_unhandled_promise_rejection = 1; - continue; - } -#ifdef CONFIG_BIGNUM - if (!strcmp(longopt, "bignum")) { - bignum_ext = 1; - continue; - } - if (!strcmp(longopt, "qjscalc")) { - load_jscalc = 1; - continue; - } -#endif - if (opt == 'q' || !strcmp(longopt, "quit")) { - empty_run++; - continue; - } - if (!strcmp(longopt, "memory-limit")) { - if (optind >= argc) { - fprintf(stderr, "expecting memory limit"); - exit(1); - } - memory_limit = (size_t)strtod(argv[optind++], NULL); - continue; - } - if (!strcmp(longopt, "stack-size")) { - if (optind >= argc) { - fprintf(stderr, "expecting stack size"); - exit(1); - } - stack_size = (size_t)strtod(argv[optind++], NULL); - continue; - } - if (opt) { - fprintf(stderr, "qjs: unknown option '-%c'\n", opt); - } else { - fprintf(stderr, "qjs: unknown option '--%s'\n", longopt); - } - help(); - } - } - -#ifdef CONFIG_BIGNUM - if (load_jscalc) - bignum_ext = 1; -#endif - - if (trace_memory) { - js_trace_malloc_init(&trace_data); - rt = JS_NewRuntime2(&trace_mf, &trace_data); - } else { - rt = JS_NewRuntime(); - } - if (!rt) { - fprintf(stderr, "qjs: cannot allocate JS runtime\n"); - exit(2); - } - if (memory_limit != 0) - JS_SetMemoryLimit(rt, memory_limit); - if (stack_size != 0) - JS_SetMaxStackSize(rt, stack_size); - js_std_set_worker_new_context_func(JS_NewCustomContext); - js_std_init_handlers(rt); - ctx = JS_NewCustomContext(rt); - if (!ctx) { - fprintf(stderr, "qjs: cannot allocate JS context\n"); - exit(2); - } - - /* loader for ES6 modules */ - JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); - - if (dump_unhandled_promise_rejection) { - JS_SetHostPromiseRejectionTracker(rt, js_std_promise_rejection_tracker, - NULL); - } - - if (!empty_run) { -#ifdef CONFIG_BIGNUM - if (load_jscalc) { - js_std_eval_binary(ctx, qjsc_qjscalc, qjsc_qjscalc_size, 0); - } -#endif - js_std_add_helpers(ctx, argc - optind, argv + optind); - - /* make 'std' and 'os' visible to non module code */ - if (load_std) { - const char *str = "import * as std from 'std';\n" - "import * as os from 'os';\n" - "globalThis.std = std;\n" - "globalThis.os = os;\n"; - eval_buf(ctx, str, strlen(str), "", JS_EVAL_TYPE_MODULE); - } - - for(i = 0; i < include_count; i++) { - if (eval_file(ctx, include_list[i], module)) - goto fail; - } - - if (expr) { - if (eval_buf(ctx, expr, strlen(expr), "", 0)) goto fail; - } else if (optind >= argc) { - /* interactive mode */ - interactive = 1; - } else { - const char *filename; - filename = argv[optind]; - if (eval_file(ctx, filename, module)) goto fail; - } - if (interactive) { - js_std_eval_binary(ctx, qjsc_repl, qjsc_repl_size, 0); - } - js_std_loop(ctx); - } - - if (dump_memory) { - JSMemoryUsage stats; - JS_ComputeMemoryUsage(rt, &stats); - JS_DumpMemoryUsage(stdout, &stats, rt); - } - js_std_free_handlers(rt); - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - - if (empty_run && dump_memory) { - clock_t t[5]; - double best[5] = {0}; - int i, j; - for (i = 0; i < 100; i++) { - t[0] = clock(); - rt = JS_NewRuntime(); - t[1] = clock(); - ctx = JS_NewContext(rt); - t[2] = clock(); - JS_FreeContext(ctx); - t[3] = clock(); - JS_FreeRuntime(rt); - t[4] = clock(); - for (j = 4; j > 0; j--) { - double ms = 1000.0 * (t[j] - t[j - 1]) / CLOCKS_PER_SEC; - if (i == 0 || best[j] > ms) - best[j] = ms; - } - } - printf("\nInstantiation times (ms): %.3f = %.3f+%.3f+%.3f+%.3f\n", - best[1] + best[2] + best[3] + best[4], - best[1], best[2], best[3], best[4]); - } - return 0; - fail: - js_std_free_handlers(rt); - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - return 1; -} diff --git a/third_party/quickjs/qjsc.c b/third_party/quickjs/qjsc.c deleted file mode 100644 index d24637d3b..000000000 --- a/third_party/quickjs/qjsc.c +++ /dev/null @@ -1,734 +0,0 @@ -/* - * QuickJS command line compiler - * - * Copyright (c) 2018-2021 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/assert.h" -#include "libc/calls/calls.h" -#include "libc/dce.h" -#include "libc/fmt/conv.h" -#include "libc/log/log.h" -#include "libc/mem/gc.h" -#include "libc/mem/mem.h" -#include "libc/runtime/runtime.h" -#include "libc/stdio/stdio.h" -#include "libc/str/str.h" -#include "libc/x/xasprintf.h" -#include "third_party/getopt/getopt.internal.h" -#include "third_party/quickjs/cutils.h" -#include "third_party/quickjs/quickjs-libc.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - - -typedef struct { - char *name; - char *short_name; - int flags; -} namelist_entry_t; - -typedef struct namelist_t { - namelist_entry_t *array; - int count; - int size; -} namelist_t; - -typedef struct { - const char *option_name; - const char *init_name; -} FeatureEntry; - -static namelist_t cname_list; -static namelist_t cmodule_list; -static namelist_t init_module_list; -static uint64_t feature_bitmap; -static FILE *outfile; -static BOOL byte_swap; -static BOOL dynamic_export; -static const char *c_ident_prefix = "qjsc_"; - -#define FE_ALL (-1) - -static const FeatureEntry feature_list[] = { - { "date", "Date" }, - { "eval", "Eval" }, - { "string-normalize", "StringNormalize" }, - { "regexp", "RegExp" }, - { "json", "JSON" }, - { "proxy", "Proxy" }, - { "map", "MapSet" }, - { "typedarray", "TypedArrays" }, - { "promise", "Promise" }, -#define FE_MODULE_LOADER 9 - { "module-loader", NULL }, -#ifdef CONFIG_BIGNUM - { "bigint", "BigInt" }, -#endif -}; - -void namelist_add(namelist_t *lp, const char *name, const char *short_name, - int flags) -{ - namelist_entry_t *e; - if (lp->count == lp->size) { - size_t newsize = lp->size + (lp->size >> 1) + 4; - namelist_entry_t *a = - realloc(lp->array, sizeof(lp->array[0]) * newsize); - /* XXX: check for realloc failure */ - lp->array = a; - lp->size = newsize; - } - e = &lp->array[lp->count++]; - e->name = strdup(name); - if (short_name) - e->short_name = strdup(short_name); - else - e->short_name = NULL; - e->flags = flags; -} - -void namelist_free(namelist_t *lp) -{ - while (lp->count > 0) { - namelist_entry_t *e = &lp->array[--lp->count]; - free(e->name); - free(e->short_name); - } - free(lp->array); - lp->array = NULL; - lp->size = 0; -} - -namelist_entry_t *namelist_find(namelist_t *lp, const char *name) -{ - int i; - for(i = 0; i < lp->count; i++) { - namelist_entry_t *e = &lp->array[i]; - if (!strcmp(e->name, name)) - return e; - } - return NULL; -} - -static void get_c_name(char *buf, size_t buf_size, const char *file) -{ - const char *p, *r; - size_t len, i; - int c; - char *q; - p = strrchr(file, '/'); - if (!p) - p = file; - else - p++; - r = strrchr(p, '.'); - if (!r) - len = strlen(p); - else - len = r - p; - pstrcpy(buf, buf_size, c_ident_prefix); - q = buf + strlen(buf); - for(i = 0; i < len; i++) { - c = p[i]; - if (!((c >= '0' && c <= '9') || - (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z'))) { - c = '_'; - } - if ((q - buf) < buf_size - 1) - *q++ = c; - } - *q = '\0'; -} - -static void dump_hex(FILE *f, const uint8_t *buf, size_t len) -{ - size_t i, col; - col = 0; - for(i = 0; i < len; i++) { - fprintf(f, " 0x%02x,", buf[i]); - if (++col == 8) { - fprintf(f, "\n"); - col = 0; - } - } - if (col != 0) - fprintf(f, "\n"); -} - -static void output_object_code(JSContext *ctx, - FILE *fo, JSValueConst obj, const char *c_name, - BOOL load_only) -{ - uint8_t *out_buf; - size_t out_buf_len; - int flags; - flags = JS_WRITE_OBJ_BYTECODE; - if (byte_swap) - flags |= JS_WRITE_OBJ_BSWAP; - out_buf = JS_WriteObject(ctx, &out_buf_len, obj, flags); - if (!out_buf) { - js_std_dump_error(ctx); - exit(1); - } - namelist_add(&cname_list, c_name, NULL, load_only); - fprintf(fo, "const uint32_t %s_size = %u;\n\n", - c_name, (unsigned int)out_buf_len); - fprintf(fo, "const uint8_t %s[%u] = {\n", - c_name, (unsigned int)out_buf_len); - dump_hex(fo, out_buf, out_buf_len); - fprintf(fo, "};\n\n"); - js_free(ctx, out_buf); -} - -static int js_module_dummy_init(JSContext *ctx, JSModuleDef *m) -{ - /* should never be called when compiling JS code */ - abort(); -} - -static void find_unique_cname(char *cname, size_t cname_size) -{ - char *cname1; - int suffix_num; - size_t len, max_len; - assert(cname_size >= 32); - /* find a C name not matching an existing module C name by - adding a numeric suffix */ - len = strlen(cname); - max_len = cname_size - 16; - if (len > max_len) - cname[max_len] = '\0'; - suffix_num = 1; - cname1 = NULL; - for(;;) { - free(cname1); - cname1 = xasprintf("%s_%d", cname, suffix_num); - if (!namelist_find(&cname_list, cname1)) - break; - suffix_num++; - } - pstrcpy(cname, cname_size, cname1); - free(cname1); -} - -JSModuleDef *jsc_module_loader(JSContext *ctx, - const char *module_name, void *opaque) -{ - JSModuleDef *m; - namelist_entry_t *e; - /* check if it is a declared C or system module */ - e = namelist_find(&cmodule_list, module_name); - if (e) { - /* add in the static init module list */ - namelist_add(&init_module_list, e->name, e->short_name, 0); - /* create a dummy module */ - m = JS_NewCModule(ctx, module_name, js_module_dummy_init); - } else if (has_suffix(module_name, ".so")) { - fprintf(stderr, "Warning: binary module '%s' will be dynamically loaded\n", module_name); - /* create a dummy module */ - m = JS_NewCModule(ctx, module_name, js_module_dummy_init); - /* the resulting executable will export its symbols for the - dynamic library */ - dynamic_export = TRUE; - } else { - size_t buf_len; - uint8_t *buf; - JSValue func_val; - char cname[1024]; - buf = js_load_file(ctx, &buf_len, module_name); - if (!buf) { - JS_ThrowReferenceError(ctx, "could not load module filename '%s'", - module_name); - return NULL; - } - /* compile the module */ - func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, - JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); - js_free(ctx, buf); - if (JS_IsException(func_val)) - return NULL; - get_c_name(cname, sizeof(cname), module_name); - if (namelist_find(&cname_list, cname)) { - find_unique_cname(cname, sizeof(cname)); - } - output_object_code(ctx, outfile, func_val, cname, TRUE); - /* the module is already referenced, so we must free it */ - m = JS_VALUE_GET_PTR(func_val); - JS_FreeValue(ctx, func_val); - } - return m; -} - -static void compile_file(JSContext *ctx, FILE *fo, - const char *filename, - const char *c_name1, - int module) -{ - uint8_t *buf; - char c_name[1024]; - int eval_flags; - JSValue obj; - size_t buf_len; - buf = js_load_file(ctx, &buf_len, filename); - if (!buf) { - fprintf(stderr, "Could not load '%s'\n", filename); - exit(1); - } - eval_flags = JS_EVAL_FLAG_COMPILE_ONLY; - if (module < 0) { - module = (has_suffix(filename, ".mjs") || - JS_DetectModule((const char *)buf, buf_len)); - } - if (module) - eval_flags |= JS_EVAL_TYPE_MODULE; - else - eval_flags |= JS_EVAL_TYPE_GLOBAL; - obj = JS_Eval(ctx, (const char *)buf, buf_len, filename, eval_flags); - if (JS_IsException(obj)) { - js_std_dump_error(ctx); - exit(1); - } - js_free(ctx, buf); - if (c_name1) { - pstrcpy(c_name, sizeof(c_name), c_name1); - } else { - get_c_name(c_name, sizeof(c_name), filename); - } - output_object_code(ctx, fo, obj, c_name, FALSE); - JS_FreeValue(ctx, obj); -} - -static const char main_c_template1[] = - "int main(int argc, char **argv)\n" - "{\n" - " JSRuntime *rt;\n" - " JSContext *ctx;\n" - " rt = JS_NewRuntime();\n" - " js_std_set_worker_new_context_func(JS_NewCustomContext);\n" - " js_std_init_handlers(rt);\n" - ; - -static const char main_c_template2[] = - " js_std_loop(ctx);\n" - " JS_FreeContext(ctx);\n" - " JS_FreeRuntime(rt);\n" - " return 0;\n" - "}\n"; - -#define PROG_NAME "qjsc" - -void help(void) -{ - printf("QuickJS Compiler version " CONFIG_VERSION "\n" - "usage: " PROG_NAME " [options] [files]\n" - "\n" - "options are:\n" - "-c only output bytecode in a C file\n" - "-e output main() and bytecode in a C file (default = executable output)\n" - "-o output set the output filename\n" - "-N cname set the C name of the generated data\n" - "-m compile as Javascript module (default=autodetect)\n" - "-D module_name compile a dynamically loaded module or worker\n" - "-M module_name[,cname] add initialization code for an external C module\n" - "-x byte swapped output\n" - "-p prefix set the prefix of the generated C names\n" - "-S n set the maximum stack size to 'n' bytes (default=%d)\n", - JS_DEFAULT_STACK_SIZE); -#ifdef CONFIG_LTO - { - int i; - printf("-flto use link time optimization\n"); - printf("-fbignum enable bignum extensions\n"); - printf("-fno-["); - for(i = 0; i < countof(feature_list); i++) { - if (i != 0) - printf("|"); - printf("%s", feature_list[i].option_name); - } - printf("]\n" - " disable selected language features (smaller code size)\n"); - } -#endif - exit(1); -} - -#if defined(CONFIG_CC) && !defined(_WIN32) - -int exec_cmd(char **argv) -{ - int pid, status, ret; - pid = fork(); - if (pid == 0) { - execvp(argv[0], argv); - exit(1); - } - for(;;) { - ret = waitpid(pid, &status, 0); - if (ret == pid && WIFEXITED(status)) - break; - } - return WEXITSTATUS(status); -} - -static int output_executable(const char *out_filename, const char *cfilename, - BOOL use_lto, BOOL verbose, const char *exename) -{ - const char *argv[64]; - const char **arg, *bn_suffix, *lto_suffix; - char libjsname[1024]; - char exe_dir[1024], inc_dir[1024], lib_dir[1024], buf[1024], *p; - int ret; - /* get the directory of the executable */ - pstrcpy(exe_dir, sizeof(exe_dir), exename); - p = strrchr(exe_dir, '/'); - if (p) { - *p = '\0'; - } else { - pstrcpy(exe_dir, sizeof(exe_dir), "."); - } - /* if 'quickjs.h' is present at the same path as the executable, we - use it as include and lib directory */ - snprintf(buf, sizeof(buf), "%s/quickjs.h", exe_dir); - if (access(buf, R_OK) == 0) { - pstrcpy(inc_dir, sizeof(inc_dir), exe_dir); - pstrcpy(lib_dir, sizeof(lib_dir), exe_dir); - } else { - snprintf(inc_dir, sizeof(inc_dir), "%s/include/quickjs", CONFIG_PREFIX); - snprintf(lib_dir, sizeof(lib_dir), "%s/lib/quickjs", CONFIG_PREFIX); - } - lto_suffix = ""; - bn_suffix = ""; - arg = argv; - *arg++ = CONFIG_CC; - *arg++ = "-O2"; -#ifdef CONFIG_LTO - if (use_lto) { - *arg++ = "-flto"; - lto_suffix = ".lto"; - } -#endif - /* XXX: use the executable path to find the includes files and - libraries */ - *arg++ = "-D"; - *arg++ = "_GNU_SOURCE"; - *arg++ = "-I"; - *arg++ = inc_dir; - *arg++ = "-o"; - *arg++ = out_filename; - if (dynamic_export) - *arg++ = "-rdynamic"; - *arg++ = cfilename; - snprintf(libjsname, sizeof(libjsname), "%s/libquickjs%s%s.a", - lib_dir, bn_suffix, lto_suffix); - *arg++ = libjsname; - *arg++ = "-lm"; - *arg++ = "-ldl"; - *arg++ = "-lpthread"; - *arg = NULL; - if (verbose) { - for(arg = argv; *arg != NULL; arg++) - printf("%s ", *arg); - printf("\n"); - } - ret = exec_cmd((char **)argv); - unlink(cfilename); - return ret; -} -#else -static int output_executable(const char *out_filename, const char *cfilename, - BOOL use_lto, BOOL verbose, const char *exename) -{ - fprintf(stderr, "Executable output is not supported for this target\n"); - exit(1); - return 0; -} -#endif - -typedef enum { - OUTPUT_C, - OUTPUT_C_MAIN, - OUTPUT_EXECUTABLE, -} OutputTypeEnum; - -int main(int argc, char **argv) -{ - int c, i, verbose; - const char *out_filename, *cname; - char *cfilename = gc(malloc(1024)); - FILE *fo; - JSRuntime *rt; - JSContext *ctx; - BOOL use_lto; - int module; - OutputTypeEnum output_type; - size_t stack_size; -#ifdef CONFIG_BIGNUM - BOOL bignum_ext = FALSE; -#endif - namelist_t dynamic_module_list; - -#if IsModeDbg() - ShowCrashReports(); -#endif - - if (argc == 2 && !strcmp(argv[1], "-n")) return 0; - out_filename = NULL; - output_type = OUTPUT_EXECUTABLE; - cname = NULL; - feature_bitmap = FE_ALL; - module = -1; - byte_swap = FALSE; - verbose = 0; - use_lto = FALSE; - stack_size = 0; - bzero(&dynamic_module_list, sizeof(dynamic_module_list)); - /* add system modules */ - namelist_add(&cmodule_list, "std", "std", 0); - namelist_add(&cmodule_list, "os", "os", 0); - for(;;) { - c = getopt(argc, argv, "ho:cN:f:mxevM:p:S:D:"); - if (c == -1) - break; - switch(c) { - case 'h': - help(); - case 'o': - out_filename = optarg; - break; - case 'c': - output_type = OUTPUT_C; - break; - case 'e': - output_type = OUTPUT_C_MAIN; - break; - case 'N': - cname = optarg; - break; - case 'f': - { - const char *p; - p = optarg; - if (!strcmp(optarg, "lto")) { - use_lto = TRUE; - } else if (strstart(p, "no-", &p)) { - use_lto = TRUE; - for(i = 0; i < countof(feature_list); i++) { - if (!strcmp(p, feature_list[i].option_name)) { - feature_bitmap &= ~((uint64_t)1 << i); - break; - } - } - if (i == countof(feature_list)) - goto bad_feature; - } else -#ifdef CONFIG_BIGNUM - if (!strcmp(optarg, "bignum")) { - bignum_ext = TRUE; - } else -#endif - { - bad_feature: - fprintf(stderr, "unsupported feature: %s\n", optarg); - exit(1); - } - } - break; - case 'm': - module = 1; - break; - case 'M': - { - char *p; - char path[1024]; - char cname[1024]; - pstrcpy(path, sizeof(path), optarg); - p = strchr(path, ','); - if (p) { - *p = '\0'; - pstrcpy(cname, sizeof(cname), p + 1); - } else { - get_c_name(cname, sizeof(cname), path); - } - namelist_add(&cmodule_list, path, cname, 0); - } - break; - case 'D': - namelist_add(&dynamic_module_list, optarg, NULL, 0); - break; - case 'x': - byte_swap = TRUE; - break; - case 'v': - verbose++; - break; - case 'p': - c_ident_prefix = optarg; - break; - case 'S': - stack_size = (size_t)strtod(optarg, NULL); - break; - default: - break; - } - } - if (optind >= argc) - help(); - if (!out_filename) { - if (output_type == OUTPUT_EXECUTABLE) { - out_filename = "a.out"; - } else { - out_filename = "out.c"; - } - } - if (output_type == OUTPUT_EXECUTABLE) { - snprintf(cfilename, 1024, "/tmp/out%d.c", getpid()); - } else { - pstrcpy(cfilename, 1024, out_filename); - } - fo = fopen(cfilename, "w"); - if (!fo) { - perror(cfilename); - exit(1); - } - outfile = fo; - rt = JS_NewRuntime(); - ctx = JS_NewContext(rt); -#ifdef CONFIG_BIGNUM - if (bignum_ext) { - JS_AddIntrinsicBigFloat(ctx); - JS_AddIntrinsicBigDecimal(ctx); - JS_AddIntrinsicOperators(ctx); - JS_EnableBignumExt(ctx, TRUE); - } -#endif - /* loader for ES6 modules */ - JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, NULL); - fprintf(fo, "/* File generated automatically by the QuickJS compiler. */\n" - "\n" - ); - if (output_type != OUTPUT_C) { - fprintf(fo, "#include \"quickjs-libc.h\"\n" - "\n" - ); - } else { -#ifndef _COSMO_SOURCE - fprintf(fo, "#include \n" - "\n" - ); -#endif - } - for(i = optind; i < argc; i++) { - const char *filename = argv[i]; - compile_file(ctx, fo, filename, cname, module); - cname = NULL; - } - for(i = 0; i < dynamic_module_list.count; i++) { - if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL)) { - fprintf(stderr, "Could not load dynamic module '%s'\n", - dynamic_module_list.array[i].name); - exit(1); - } - } - if (output_type != OUTPUT_C) { - fprintf(fo, - "static JSContext *JS_NewCustomContext(JSRuntime *rt)\n" - "{\n" - " JSContext *ctx = JS_NewContextRaw(rt);\n" - " if (!ctx)\n" - " return NULL;\n"); - /* add the basic objects */ - fprintf(fo, " JS_AddIntrinsicBaseObjects(ctx);\n"); - for(i = 0; i < countof(feature_list); i++) { - if ((feature_bitmap & ((uint64_t)1 << i)) && - feature_list[i].init_name) { - fprintf(fo, " JS_AddIntrinsic%s(ctx);\n", - feature_list[i].init_name); - } - } -#ifdef CONFIG_BIGNUM - if (bignum_ext) { - fprintf(fo, - " JS_AddIntrinsicBigFloat(ctx);\n" - " JS_AddIntrinsicBigDecimal(ctx);\n" - " JS_AddIntrinsicOperators(ctx);\n" - " JS_EnableBignumExt(ctx, 1);\n"); - } -#endif - /* add the precompiled modules (XXX: could modify the module - loader instead) */ - for(i = 0; i < init_module_list.count; i++) { - namelist_entry_t *e = &init_module_list.array[i]; - /* initialize the static C modules */ - fprintf(fo, - " {\n" - " extern JSModuleDef *js_init_module_%s(JSContext *ctx, const char *name);\n" - " js_init_module_%s(ctx, \"%s\");\n" - " }\n", - e->short_name, e->short_name, e->name); - } - for(i = 0; i < cname_list.count; i++) { - namelist_entry_t *e = &cname_list.array[i]; - if (e->flags) { - fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 1);\n", - e->name, e->name); - } - } - fprintf(fo, - " return ctx;\n" - "}\n\n"); - fputs(main_c_template1, fo); - if (stack_size != 0) { - fprintf(fo, " JS_SetMaxStackSize(rt, %u);\n", - (unsigned int)stack_size); - } - /* add the module loader if necessary */ - if (feature_bitmap & (1 << FE_MODULE_LOADER)) { - fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n"); - } - fprintf(fo, - " ctx = JS_NewCustomContext(rt);\n" - " js_std_add_helpers(ctx, argc, argv);\n"); - for(i = 0; i < cname_list.count; i++) { - namelist_entry_t *e = &cname_list.array[i]; - if (!e->flags) { - fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 0);\n", - e->name, e->name); - } - } - fputs(main_c_template2, fo); - } - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - fclose(fo); - if (output_type == OUTPUT_EXECUTABLE) { - return output_executable(out_filename, cfilename, use_lto, verbose, - argv[0]); - } - namelist_free(&cname_list); - namelist_free(&cmodule_list); - namelist_free(&init_module_list); - return 0; -} diff --git a/third_party/quickjs/qjscalc.js b/third_party/quickjs/qjscalc.js deleted file mode 100644 index b1ad1e895..000000000 --- a/third_party/quickjs/qjscalc.js +++ /dev/null @@ -1,2657 +0,0 @@ -/* - * QuickJS Javascript Calculator - * - * Copyright (c) 2017-2020 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. - */ -"use strict"; -"use math"; - -var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunction, Series, Matrix; - -(function(global) { - global.Integer = global.BigInt; - global.Float = global.BigFloat; - global.algebraicMode = true; - - /* add non enumerable properties */ - function add_props(obj, props) { - var i, val, prop, tab, desc; - tab = Reflect.ownKeys(props); - for(i = 0; i < tab.length; i++) { - prop = tab[i]; - desc = Object.getOwnPropertyDescriptor(props, prop); - desc.enumerable = false; - if ("value" in desc) { - if (typeof desc.value !== "function") { - desc.writable = false; - desc.configurable = false; - } - } else { - /* getter/setter */ - desc.configurable = false; - } - Object.defineProperty(obj, prop, desc); - } - } - - /* same as proto[Symbol.operatorSet] = Operators.create(..op_list) - but allow shortcuts: left: [], right: [] or both - */ - function operators_set(proto, ...op_list) - { - var new_op_list, i, a, j, b, k, obj, tab; - var fields = [ "left", "right" ]; - new_op_list = []; - for(i = 0; i < op_list.length; i++) { - a = op_list[i]; - if (a.left || a.right) { - tab = [ a.left, a.right ]; - delete a.left; - delete a.right; - for(k = 0; k < 2; k++) { - obj = tab[k]; - if (obj) { - if (!Array.isArray(obj)) { - obj = [ obj ]; - } - for(j = 0; j < obj.length; j++) { - b = {}; - Object.assign(b, a); - b[fields[k]] = obj[j]; - new_op_list.push(b); - } - } - } - } else { - new_op_list.push(a); - } - } - proto[Symbol.operatorSet] = - Operators.create.call(null, ...new_op_list); - } - - /* Integer */ - - function generic_pow(a, b) { - var r, is_neg, i; - if (!Integer.isInteger(b)) { - return exp(log(a) * b); - } - if (Array.isArray(a) && !(a instanceof Polynomial || - a instanceof Series)) { - r = idn(Matrix.check_square(a)); - } else { - r = 1; - } - if (b == 0) - return r; - is_neg = false; - if (b < 0) { - is_neg = true; - b = -b; - } - r = a; - for(i = Integer.floorLog2(b) - 1; i >= 0; i--) { - r *= r; - if ((b >> i) & 1) - r *= a; - } - if (is_neg) { - if (typeof r.inverse != "function") - throw "negative powers are not supported for this type"; - r = r.inverse(); - } - return r; - } - - var small_primes = [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499 ]; - - function miller_rabin_test(n, t) { - var d, r, s, i, j, a; - d = n - 1; - s = 0; - while ((d & 1) == 0) { - d >>= 1; - s++; - } - if (small_primes.length < t) - t = small_primes.length; - loop: for(j = 0; j < t; j++) { - a = small_primes[j]; - r = Integer.pmod(a, d, n); - if (r == 1 || r == (n - 1)) - continue; - for(i = 1; i < s; i++) { - r = (r * r) % n; - if (r == 1) - return false; - if (r == (n - 1)) - continue loop; - } - return false; /* n is composite */ - } - return true; /* n is probably prime with probability (1-0.5^t) */ - } - - function fact_rec(a, b) { /* assumes a <= b */ - var i, r; - if ((b - a) <= 5) { - r = a; - for(i = a + 1; i <= b; i++) - r *= i; - return r; - } else { - /* to avoid a quadratic running time it is better to - multiply numbers of similar size */ - i = (a + b) >> 1; - return fact_rec(a, i) * fact_rec(i + 1, b); - } - } - - /* math mode specific quirk to overload the integer division and power */ - Operators.updateBigIntOperators( - { - "/"(a, b) { - if (algebraicMode) { - return Fraction.toFraction(a, b); - } else { - return Float(a) / Float(b); - } - }, - "**"(a, b) { - if (algebraicMode) { - return generic_pow(a, b); - } else { - return Float(a) ** Float(b); - } - } - }); - - add_props(Integer, { - isInteger(a) { - /* integers are represented either as bigint or as number */ - return typeof a === "bigint" || - (typeof a === "number" && Number.isSafeInteger(a)); - }, - gcd(a, b) { - var r; - while (b != 0) { - r = a % b; - a = b; - b = r; - } - return a; - }, - fact(n) { - return n <= 0 ? 1 : fact_rec(1, n); - }, - /* binomial coefficient */ - comb(n, k) { - if (k < 0 || k > n) - return 0; - if (k > n - k) - k = n - k; - if (k == 0) - return 1; - return Integer.tdiv(fact_rec(n - k + 1, n), fact_rec(1, k)); - }, - /* inverse of x modulo y */ - invmod(x, y) { - var q, u, v, a, c, t; - u = x; - v = y; - c = 1; - a = 0; - while (u != 0) { - t = Integer.fdivrem(v, u); - q = t[0]; - v = u; - u = t[1]; - t = c; - c = a - q * c; - a = t; - } - /* v = gcd(x, y) */ - if (v != 1) - throw RangeError("not invertible"); - return a % y; - }, - /* return a ^ b modulo m */ - pmod(a, b, m) { - var r; - if (b == 0) - return 1; - if (b < 0) { - a = Integer.invmod(a, m); - b = -b; - } - r = 1; - for(;;) { - if (b & 1) { - r = (r * a) % m; - } - b >>= 1; - if (b == 0) - break; - a = (a * a) % m; - } - return r; - }, - - /* return true if n is prime (or probably prime with - probability 1-0.5^t) */ - isPrime(n, t) { - var i, d, n1; - if (!Integer.isInteger(n)) - throw TypeError("invalid type"); - if (n <= 1) - return false; - n1 = small_primes.length; - /* XXX: need Integer.sqrt() */ - for(i = 0; i < n1; i++) { - d = small_primes[i]; - if (d == n) - return true; - if (d > n) - return false; - if ((n % d) == 0) - return false; - } - if (n < d * d) - return true; - if (typeof t == "undefined") - t = 64; - return miller_rabin_test(n, t); - }, - nextPrime(n) { - if (!Integer.isInteger(n)) - throw TypeError("invalid type"); - if (n < 1) - n = 1; - for(;;) { - n++; - if (Integer.isPrime(n)) - return n; - } - }, - factor(n) { - var r, d; - if (!Integer.isInteger(n)) - throw TypeError("invalid type"); - r = []; - if (abs(n) <= 1) { - r.push(n); - return r; - } - if (n < 0) { - r.push(-1); - n = -n; - } - - while ((n % 2) == 0) { - n >>= 1; - r.push(2); - } - - d = 3; - while (n != 1) { - if (Integer.isPrime(n)) { - r.push(n); - break; - } - /* we are sure there is at least one divisor, so one test */ - for(;;) { - if ((n % d) == 0) - break; - d += 2; - } - for(;;) { - r.push(d); - n = Integer.tdiv(n, d); - if ((n % d) != 0) - break; - } - } - return r; - }, - }); - - add_props(Integer.prototype, { - inverse() { - return 1 / this; - }, - norm2() { - return this * this; - }, - abs() { - var v = this; - if (v < 0) - v = -v; - return v; - }, - conj() { - return this; - }, - arg() { - if (this >= 0) - return 0; - else - return Float.PI; - }, - exp() { - if (this == 0) - return 1; - else - return Float.exp(this); - }, - log() { - if (this == 1) - return 0; - else - return Float(this).log(); - }, - }); - - /* Fraction */ - - Fraction = function Fraction(a, b) - { - var d, r, obj; - - if (new.target) - throw TypeError("not a constructor"); - if (a instanceof Fraction) - return a; - if (!Integer.isInteger(a)) - throw TypeError("integer expected"); - if (typeof b === "undefined") { - b = 1; - } else { - if (!Integer.isInteger(b)) - throw TypeError("integer expected"); - if (b == 0) - throw RangeError("division by zero"); - d = Integer.gcd(a, b); - if (d != 1) { - a = Integer.tdiv(a, d); - b = Integer.tdiv(b, d); - } - - /* the fractions are normalized with den > 0 */ - if (b < 0) { - a = -a; - b = -b; - } - } - obj = Object.create(Fraction.prototype); - obj.num = a; - obj.den = b; - return obj; - } - - function fraction_add(a, b) { - a = Fraction(a); - b = Fraction(b); - return Fraction.toFraction(a.num * b.den + a.den * b.num, a.den * b.den); - } - function fraction_sub(a, b) { - a = Fraction(a); - b = Fraction(b); - return Fraction.toFraction(a.num * b.den - a.den * b.num, a.den * b.den); - } - function fraction_mul(a, b) { - a = Fraction(a); - b = Fraction(b); - return Fraction.toFraction(a.num * b.num, a.den * b.den); - } - function fraction_div(a, b) { - a = Fraction(a); - b = Fraction(b); - return Fraction.toFraction(a.num * b.den, a.den * b.num); - } - function fraction_mod(a, b) { - var a1 = Fraction(a); - var b1 = Fraction(b); - return a - Integer.ediv(a1.num * b1.den, a1.den * b1.num) * b; - } - function fraction_eq(a, b) { - a = Fraction(a); - b = Fraction(b); - /* we assume the fractions are normalized */ - return (a.num == b.num && a.den == b.den); - } - function fraction_lt(a, b) { - a = Fraction(a); - b = Fraction(b); - return (a.num * b.den < b.num * a.den); - } - - /* operators are needed for fractions */ - function float_add(a, b) { - return Float(a) + Float(b); - } - function float_sub(a, b) { - return Float(a) - Float(b); - } - function float_mul(a, b) { - return Float(a) * Float(b); - } - function float_div(a, b) { - return Float(a) / Float(b); - } - function float_mod(a, b) { - return Float(a) % Float(b); - } - function float_pow(a, b) { - return Float(a) ** Float(b); - } - function float_eq(a, b) { - /* XXX: may be better to use infinite precision for the comparison */ - return Float(a) === Float(b); - } - function float_lt(a, b) { - a = Float(a); - b = Float(b); - /* XXX: may be better to use infinite precision for the comparison */ - if (Float.isNaN(a) || Float.isNaN(b)) - return undefined; - else - return a < b; - } - - operators_set(Fraction.prototype, - { - "+": fraction_add, - "-": fraction_sub, - "*": fraction_mul, - "/": fraction_div, - "%": fraction_mod, - "**": generic_pow, - "==": fraction_eq, - "<": fraction_lt, - "pos"(a) { - return a; - }, - "neg"(a) { - return Fraction(-a.num, a.den); - }, - }, - { - left: [Number, BigInt], - right: [Number, BigInt], - "+": fraction_add, - "-": fraction_sub, - "*": fraction_mul, - "/": fraction_div, - "%": fraction_mod, - "**": generic_pow, - "==": fraction_eq, - "<": fraction_lt, - }, - { - left: Float, - right: Float, - "+": float_add, - "-": float_sub, - "*": float_mul, - "/": float_div, - "%": float_mod, - "**": float_pow, - "==": float_eq, - "<": float_lt, - }); - - add_props(Fraction, { - /* (internal use) simplify 'a' to an integer when possible */ - toFraction(a, b) { - var r = Fraction(a, b); - if (algebraicMode && r.den == 1) - return r.num; - else - return r; - }, - }); - - add_props(Fraction.prototype, { - [Symbol.toPrimitive](hint) { - if (hint === "string") { - return this.toString(); - } else { - return Float(this.num) / this.den; - } - }, - inverse() { - return Fraction(this.den, this.num); - }, - toString() { - return this.num + "/" + this.den; - }, - norm2() { - return this * this; - }, - abs() { - if (this.num < 0) - return -this; - else - return this; - }, - conj() { - return this; - }, - arg() { - if (this.num >= 0) - return 0; - else - return Float.PI; - }, - exp() { - return Float.exp(Float(this)); - }, - log() { - return Float(this).log(); - }, - }); - - /* Number (Float64) */ - - add_props(Number.prototype, { - inverse() { - return 1 / this; - }, - norm2() { - return this * this; - }, - abs() { - return Math.abs(this); - }, - conj() { - return this; - }, - arg() { - if (this >= 0) - return 0; - else - return Float.PI; - }, - exp() { - return Float.exp(this); - }, - log() { - if (this < 0) { - return Complex(this).log(); - } else { - return Float.log(this); - } - }, - }); - - /* Float */ - - var const_tab = []; - - /* we cache the constants for small precisions */ - function get_const(n) { - var t, c, p; - t = const_tab[n]; - p = BigFloatEnv.prec; - if (t && t.prec == p) { - return t.val; - } else { - switch(n) { - case 0: c = Float.exp(1); break; - case 1: c = Float.log(10); break; -// case 2: c = Float.log(2); break; - case 3: c = 1/Float.log(2); break; - case 4: c = 1/Float.log(10); break; -// case 5: c = Float.atan(1) * 4; break; - case 6: c = Float.sqrt(0.5); break; - case 7: c = Float.sqrt(2); break; - } - if (p <= 1024) { - const_tab[n] = { prec: p, val: c }; - } - return c; - } - } - - add_props(Float, { - isFloat(a) { - return typeof a === "number" || typeof a === "bigfloat"; - }, - bestappr(u, b) { - var num1, num0, den1, den0, u, num, den, n; - - if (typeof b === "undefined") - throw TypeError("second argument expected"); - num1 = 1; - num0 = 0; - den1 = 0; - den0 = 1; - for(;;) { - n = Integer(Float.floor(u)); - num = n * num1 + num0; - den = n * den1 + den0; - if (den > b) - break; - u = 1.0 / (u - n); - num0 = num1; - num1 = num; - den0 = den1; - den1 = den; - } - return Fraction(num1, den1); - }, - /* similar constants as Math.x */ - get E() { return get_const(0); }, - get LN10() { return get_const(1); }, -// get LN2() { return get_const(2); }, - get LOG2E() { return get_const(3); }, - get LOG10E() { return get_const(4); }, -// get PI() { return get_const(5); }, - get SQRT1_2() { return get_const(6); }, - get SQRT2() { return get_const(7); }, - }); - - add_props(Float.prototype, { - inverse() { - return 1.0 / this; - }, - norm2() { - return this * this; - }, - abs() { - return Float.abs(this); - }, - conj() { - return this; - }, - arg() { - if (this >= 0) - return 0; - else - return Float.PI; - }, - exp() { - return Float.exp(this); - }, - log() { - if (this < 0) { - return Complex(this).log(); - } else { - return Float.log(this); - } - }, - }); - - /* Complex */ - - Complex = function Complex(re, im) - { - var obj; - if (new.target) - throw TypeError("not a constructor"); - if (re instanceof Complex) - return re; - if (typeof im === "undefined") { - im = 0; - } - obj = Object.create(Complex.prototype); - obj.re = re; - obj.im = im; - return obj; - } - - - function complex_add(a, b) { - a = Complex(a); - b = Complex(b); - return Complex.toComplex(a.re + b.re, a.im + b.im); - } - function complex_sub(a, b) { - a = Complex(a); - b = Complex(b); - return Complex.toComplex(a.re - b.re, a.im - b.im); - } - function complex_mul(a, b) { - a = Complex(a); - b = Complex(b); - return Complex.toComplex(a.re * b.re - a.im * b.im, - a.re * b.im + a.im * b.re); - } - function complex_div(a, b) { - a = Complex(a); - b = Complex(b); - return a * b.inverse(); - } - function complex_eq(a, b) { - a = Complex(a); - b = Complex(b); - return a.re == b.re && a.im == b.im; - } - - operators_set(Complex.prototype, - { - "+": complex_add, - "-": complex_sub, - "*": complex_mul, - "/": complex_div, - "**": generic_pow, - "==": complex_eq, - "pos"(a) { - return a; - }, - "neg"(a) { - return Complex(-a.re, -a.im); - } - }, - { - left: [Number, BigInt, Float, Fraction], - right: [Number, BigInt, Float, Fraction], - "+": complex_add, - "-": complex_sub, - "*": complex_mul, - "/": complex_div, - "**": generic_pow, - "==": complex_eq, - }); - - add_props(Complex, { - /* simplify to real number when possible */ - toComplex(re, im) { - if (algebraicMode && im == 0) - return re; - else - return Complex(re, im); - }, - }); - - add_props(Complex.prototype, { - inverse() { - var c = this.norm2(); - return Complex(this.re / c, -this.im / c); - }, - toString() { - var v, s = "", a = this; - if (a.re != 0) - s += a.re.toString(); - if (a.im == 1) { - if (s != "") - s += "+"; - s += "I"; - } else if (a.im == -1) { - s += "-I"; - } else { - v = a.im.toString(); - if (v[0] != "-" && s != "") - s += "+"; - s += v + "*I"; - } - return s; - }, - norm2() { - return this.re * this.re + this.im * this.im; - }, - abs() { - return Float.sqrt(norm2(this)); - }, - conj() { - return Complex(this.re, -this.im); - }, - arg() { - return Float.atan2(this.im, this.re); - }, - exp() { - var arg = this.im, r = this.re.exp(); - return Complex(r * cos(arg), r * sin(arg)); - }, - log() { - return Complex(abs(this).log(), atan2(this.im, this.re)); - }, - }); - - /* Mod */ - - Mod = function Mod(a, m) { - var obj, t; - if (new.target) - throw TypeError("not a constructor"); - obj = Object.create(Mod.prototype); - if (Integer.isInteger(m)) { - if (m <= 0) - throw RangeError("the modulo cannot be <= 0"); - if (Integer.isInteger(a)) { - a %= m; - } else if (a instanceof Fraction) { - return Mod(a.num, m) / a.den; - } else { - throw TypeError("invalid types"); - } - } else { - throw TypeError("invalid types"); - } - obj.res = a; - obj.mod = m; - return obj; - }; - - function mod_add(a, b) { - if (!(a instanceof Mod)) { - return Mod(a + b.res, b.mod); - } else if (!(b instanceof Mod)) { - return Mod(a.res + b, a.mod); - } else { - if (a.mod != b.mod) - throw TypeError("different modulo for binary operator"); - return Mod(a.res + b.res, a.mod); - } - } - function mod_sub(a, b) { - if (!(a instanceof Mod)) { - return Mod(a - b.res, b.mod); - } else if (!(b instanceof Mod)) { - return Mod(a.res - b, a.mod); - } else { - if (a.mod != b.mod) - throw TypeError("different modulo for binary operator"); - return Mod(a.res - b.res, a.mod); - } - } - function mod_mul(a, b) { - if (!(a instanceof Mod)) { - return Mod(a * b.res, b.mod); - } else if (!(b instanceof Mod)) { - return Mod(a.res * b, a.mod); - } else { - if (a.mod != b.mod) - throw TypeError("different modulo for binary operator"); - return Mod(a.res * b.res, a.mod); - } - } - function mod_div(a, b) { - if (!(b instanceof Mod)) - b = Mod(b, a.mod); - return mod_mul(a, b.inverse()); - } - function mod_eq(a, b) { - return (a.mod == b.mod && a.res == b.res); - } - - operators_set(Mod.prototype, - { - "+": mod_add, - "-": mod_sub, - "*": mod_mul, - "/": mod_div, - "**": generic_pow, - "==": mod_eq, - "pos"(a) { - return a; - }, - "neg"(a) { - return Mod(-a.res, a.mod); - } - }, - { - left: [Number, BigInt, Float, Fraction], - right: [Number, BigInt, Float, Fraction], - "+": mod_add, - "-": mod_sub, - "*": mod_mul, - "/": mod_div, - "**": generic_pow, - }); - - add_props(Mod.prototype, { - inverse() { - var a = this, m = a.mod; - if (Integer.isInteger(m)) { - return Mod(Integer.invmod(a.res, m), m); - } else { - throw TypeError("unsupported type"); - } - }, - toString() { - return "Mod(" + this.res + "," + this.mod + ")"; - }, - }); - - /* Polynomial */ - - function polynomial_is_scalar(a) - { - if (typeof a === "number" || - typeof a === "bigint" || - typeof a === "bigfloat") - return true; - if (a instanceof Fraction || - a instanceof Complex || - a instanceof Mod) - return true; - return false; - } - - Polynomial = function Polynomial(a) - { - if (new.target) - throw TypeError("not a constructor"); - if (a instanceof Polynomial) { - return a; - } else if (Array.isArray(a)) { - if (a.length == 0) - a = [ 0 ]; - Object.setPrototypeOf(a, Polynomial.prototype); - return a.trim(); - } else if (polynomial_is_scalar(a)) { - a = [a]; - Object.setPrototypeOf(a, Polynomial.prototype); - return a; - } else { - throw TypeError("invalid type"); - } - } - - function number_need_paren(c) - { - return !(Integer.isInteger(c) || - Float.isFloat(c) || - c instanceof Fraction || - (c instanceof Complex && c.re == 0)); - } - - /* string for c*X^i */ - function monomial_toString(c, i) - { - var str1; - if (i == 0) { - str1 = c.toString(); - } else { - if (c == 1) { - str1 = ""; - } else if (c == -1) { - str1 = "-"; - } else { - if (number_need_paren(c)) { - str1 = "(" + c + ")"; - } else { - str1 = String(c); - } - str1 += "*"; - } - str1 += "X"; - if (i != 1) { - str1 += "^" + i; - } - } - return str1; - } - - /* find one complex root of 'p' starting from z at precision eps using - at most max_it iterations. Return null if could not find root. */ - function poly_root_laguerre1(p, z, max_it) - { - var p1, p2, i, z0, z1, z2, d, t0, t1, d1, d2, e, el, zl; - - d = p.deg(); - if (d == 1) { - /* monomial case */ - return -p[0] / p[1]; - } - /* trivial zero */ - if (p[0] == 0) - return 0.0; - - p1 = p.deriv(); - p2 = p1.deriv(); - el = 0.0; - zl = 0.0; - for(i = 0; i < max_it; i++) { - z0 = p.apply(z); - if (z0 == 0) - return z; /* simple exit case */ - - /* Ward stopping criteria */ - e = abs(z - zl); -// print("e", i, e); - if (i >= 2 && e >= el) { - if (abs(zl) < 1e-4) { - if (e < 1e-7) - return zl; - } else { - if (e < abs(zl) * 1e-3) - return zl; - } - } - el = e; - zl = z; - - z1 = p1.apply(z); - z2 = p2.apply(z); - t0 = (d - 1) * z1; - t0 = t0 * t0; - t1 = d * (d - 1) * z0 * z2; - t0 = sqrt(t0 - t1); - d1 = z1 + t0; - d2 = z1 - t0; - if (norm2(d2) > norm2(d1)) - d1 = d2; - if (d1 == 0) - return null; - z = z - d * z0 / d1; - } - return null; - } - - function poly_roots(p) - { - var d, i, roots, j, z, eps; - var start_points = [ 0.1, -1.4, 1.7 ]; - - if (!(p instanceof Polynomial)) - throw TypeError("polynomial expected"); - d = p.deg(); - if (d <= 0) - return []; - eps = 2.0 ^ (-BigFloatEnv.prec); - roots = []; - for(i = 0; i < d; i++) { - /* XXX: should select another start point if error */ - for(j = 0; j < 3; j++) { - z = poly_root_laguerre1(p, start_points[j], 100); - if (z !== null) - break; - } - if (j == 3) - throw RangeError("error in root finding algorithm"); - roots[i] = z; - p = Polynomial.divrem(p, X - z)[0]; - } - return roots; - } - - add_props(Polynomial.prototype, { - trim() { - var a = this, i; - i = a.length; - while (i > 1 && a[i - 1] == 0) - i--; - a.length = i; - return a; - }, - conj() { - var r, i, n, a; - a = this; - n = a.length; - r = []; - for(i = 0; i < n; i++) - r[i] = a[i].conj(); - return Polynomial(r); - }, - inverse() { - return RationalFunction(Polynomial([1]), this); - }, - toString() { - var i, str, str1, c, a = this; - if (a.length == 1) { - return a[0].toString(); - } - str=""; - for(i = a.length - 1; i >= 0; i--) { - c = a[i]; - if (c == 0 || - (c instanceof Mod) && c.res == 0) - continue; - str1 = monomial_toString(c, i); - if (str1[0] != "-") { - if (str != "") - str += "+"; - } - str += str1; - } - return str; - }, - deg() { - if (this.length == 1 && this[0] == 0) - return -Infinity; - else - return this.length - 1; - }, - apply(b) { - var i, n, r, a = this; - n = a.length - 1; - r = a[n]; - while (n > 0) { - n--; - r = r * b + a[n]; - } - return r; - }, - deriv() { - var a = this, n, r, i; - n = a.length; - if (n == 1) { - return Polynomial(0); - } else { - r = []; - for(i = 1; i < n; i++) { - r[i - 1] = i * a[i]; - } - return Polynomial(r); - } - }, - integ() { - var a = this, n, r, i; - n = a.length; - r = [0]; - for(i = 0; i < n; i++) { - r[i + 1] = a[i] / (i + 1); - } - return Polynomial(r); - }, - norm2() { - var a = this, n, r, i; - n = a.length; - r = 0; - for(i = 0; i < n; i++) { - r += a[i].norm2(); - } - return r; - }, - }); - - - function polynomial_add(a, b) { - var tmp, r, i, n1, n2; - a = Polynomial(a); - b = Polynomial(b); - if (a.length < b.length) { - tmp = a; - a = b; - b = tmp; - } - n1 = b.length; - n2 = a.length; - r = []; - for(i = 0; i < n1; i++) - r[i] = a[i] + b[i]; - for(i = n1; i < n2; i++) - r[i] = a[i]; - return Polynomial(r); - } - function polynomial_sub(a, b) { - return polynomial_add(a, -b); - } - function polynomial_mul(a, b) { - var i, j, n1, n2, n, r; - a = Polynomial(a); - b = Polynomial(b); - n1 = a.length; - n2 = b.length; - n = n1 + n2 - 1; - r = []; - for(i = 0; i < n; i++) - r[i] = 0; - for(i = 0; i < n1; i++) { - for(j = 0; j < n2; j++) { - r[i + j] += a[i] * b[j]; - } - } - return Polynomial(r); - } - function polynomial_div_scalar(a, b) { - return a * (1 / b); - } - function polynomial_div(a, b) - { - return RationalFunction(Polynomial(a), - Polynomial(b)); - } - function polynomial_mod(a, b) { - return Polynomial.divrem(a, b)[1]; - } - function polynomial_eq(a, b) { - var n, i; - n = a.length; - if (n != b.length) - return false; - for(i = 0; i < n; i++) { - if (a[i] != b[i]) - return false; - } - return true; - } - - operators_set(Polynomial.prototype, - { - "+": polynomial_add, - "-": polynomial_sub, - "*": polynomial_mul, - "/": polynomial_div, - "**": generic_pow, - "==": polynomial_eq, - "pos"(a) { - return a; - }, - "neg"(a) { - var r, i, n, a; - n = a.length; - r = []; - for(i = 0; i < n; i++) - r[i] = -a[i]; - return Polynomial(r); - }, - }, - { - left: [Number, BigInt, Float, Fraction, Complex, Mod], - "+": polynomial_add, - "-": polynomial_sub, - "*": polynomial_mul, - "/": polynomial_div, - "**": generic_pow, /* XXX: only for integer */ - }, - { - right: [Number, BigInt, Float, Fraction, Complex, Mod], - "+": polynomial_add, - "-": polynomial_sub, - "*": polynomial_mul, - "/": polynomial_div_scalar, - "**": generic_pow, /* XXX: only for integer */ - }); - - add_props(Polynomial, { - divrem(a, b) { - var n1, n2, i, j, q, r, n, c; - if (b.deg() < 0) - throw RangeError("division by zero"); - n1 = a.length; - n2 = b.length; - if (n1 < n2) - return [Polynomial([0]), a]; - r = Array.prototype.dup.call(a); - q = []; - n2--; - n = n1 - n2; - for(i = 0; i < n; i++) - q[i] = 0; - for(i = n - 1; i >= 0; i--) { - c = r[i + n2]; - if (c != 0) { - c = c / b[n2]; - r[i + n2] = 0; - for(j = 0; j < n2; j++) { - r[i + j] -= b[j] * c; - } - q[i] = c; - } - } - return [Polynomial(q), Polynomial(r)]; - }, - gcd(a, b) { - var t; - while (b.deg() >= 0) { - t = Polynomial.divrem(a, b); - a = b; - b = t[1]; - } - /* convert to monic form */ - return a / a[a.length - 1]; - }, - invmod(x, y) { - var q, u, v, a, c, t; - u = x; - v = y; - c = Polynomial([1]); - a = Polynomial([0]); - while (u.deg() >= 0) { - t = Polynomial.divrem(v, u); - q = t[0]; - v = u; - u = t[1]; - t = c; - c = a - q * c; - a = t; - } - /* v = gcd(x, y) */ - if (v.deg() > 0) - throw RangeError("not invertible"); - return Polynomial.divrem(a, y)[1]; - }, - roots(p) { - return poly_roots(p); - } - }); - - /* Polynomial Modulo Q */ - - PolyMod = function PolyMod(a, m) { - var obj, t; - if (new.target) - throw TypeError("not a constructor"); - obj = Object.create(PolyMod.prototype); - if (m instanceof Polynomial) { - if (m.deg() <= 0) - throw RangeError("the modulo cannot have a degree <= 0"); - if (a instanceof RationalFunction) { - return PolyMod(a.num, m) / a.den; - } else { - a = Polynomial(a); - t = Polynomial.divrem(a, m); - a = t[1]; - } - } else { - throw TypeError("invalid types"); - } - obj.res = a; - obj.mod = m; - return obj; - }; - - function polymod_add(a, b) { - if (!(a instanceof PolyMod)) { - return PolyMod(a + b.res, b.mod); - } else if (!(b instanceof PolyMod)) { - return PolyMod(a.res + b, a.mod); - } else { - if (a.mod != b.mod) - throw TypeError("different modulo for binary operator"); - return PolyMod(a.res + b.res, a.mod); - } - } - function polymod_sub(a, b) { - return polymod_add(a, -b); - } - function polymod_mul(a, b) { - if (!(a instanceof PolyMod)) { - return PolyMod(a * b.res, b.mod); - } else if (!(b instanceof PolyMod)) { - return PolyMod(a.res * b, a.mod); - } else { - if (a.mod != b.mod) - throw TypeError("different modulo for binary operator"); - return PolyMod(a.res * b.res, a.mod); - } - } - function polymod_div(a, b) { - if (!(b instanceof PolyMod)) - b = PolyMod(b, a.mod); - return polymod_mul(a, b.inverse()); - } - function polymod_eq(a, b) { - return (a.mod == b.mod && a.res == b.res); - } - - operators_set(PolyMod.prototype, - { - "+": polymod_add, - "-": polymod_sub, - "*": polymod_mul, - "/": polymod_div, - "**": generic_pow, - "==": polymod_eq, - "pos"(a) { - return a; - }, - "neg"(a) { - return PolyMod(-a.res, a.mod); - }, - }, - { - left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], - right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], - "+": polymod_add, - "-": polymod_sub, - "*": polymod_mul, - "/": polymod_div, - "**": generic_pow, /* XXX: only for integer */ - }); - - add_props(PolyMod.prototype, { - inverse() { - var a = this, m = a.mod; - if (m instanceof Polynomial) { - return PolyMod(Polynomial.invmod(a.res, m), m); - } else { - throw TypeError("unsupported type"); - } - }, - toString() { - return "PolyMod(" + this.res + "," + this.mod + ")"; - }, - }); - - /* Rational function */ - - RationalFunction = function RationalFunction(a, b) - { - var t, r, d, obj; - if (new.target) - throw TypeError("not a constructor"); - if (!(a instanceof Polynomial) || - !(b instanceof Polynomial)) - throw TypeError("polynomial expected"); - t = Polynomial.divrem(a, b); - r = t[1]; - if (r.deg() < 0) - return t[0]; /* no need for a fraction */ - d = Polynomial.gcd(b, r); - if (d.deg() > 0) { - a = Polynomial.divrem(a, d)[0]; - b = Polynomial.divrem(b, d)[0]; - } - obj = Object.create(RationalFunction.prototype); - obj.num = a; - obj.den = b; - return obj; - } - - add_props(RationalFunction.prototype, { - inverse() { - return RationalFunction(this.den, this.num); - }, - conj() { - return RationalFunction(this.num.conj(), this.den.conj()); - }, - toString() { - var str; - if (this.num.deg() <= 0 && - !number_need_paren(this.num[0])) - str = this.num.toString(); - else - str = "(" + this.num.toString() + ")"; - str += "/(" + this.den.toString() + ")" - return str; - }, - apply(b) { - return this.num.apply(b) / this.den.apply(b); - }, - deriv() { - var n = this.num, d = this.den; - return RationalFunction(n.deriv() * d - n * d.deriv(), d * d); - }, - }); - - function ratfunc_add(a, b) { - a = RationalFunction.toRationalFunction(a); - b = RationalFunction.toRationalFunction(b); - return RationalFunction(a.num * b.den + a.den * b.num, a.den * b.den); - } - function ratfunc_sub(a, b) { - a = RationalFunction.toRationalFunction(a); - b = RationalFunction.toRationalFunction(b); - return RationalFunction(a.num * b.den - a.den * b.num, a.den * b.den); - } - function ratfunc_mul(a, b) { - a = RationalFunction.toRationalFunction(a); - b = RationalFunction.toRationalFunction(b); - return RationalFunction(a.num * b.num, a.den * b.den); - } - function ratfunc_div(a, b) { - a = RationalFunction.toRationalFunction(a); - b = RationalFunction.toRationalFunction(b); - return RationalFunction(a.num * b.den, a.den * b.num); - } - function ratfunc_eq(a, b) { - a = RationalFunction.toRationalFunction(a); - b = RationalFunction.toRationalFunction(b); - /* we assume the fractions are normalized */ - return (a.num == b.num && a.den == b.den); - } - - operators_set(RationalFunction.prototype, - { - "+": ratfunc_add, - "-": ratfunc_sub, - "*": ratfunc_mul, - "/": ratfunc_div, - "**": generic_pow, - "==": ratfunc_eq, - "pos"(a) { - return a; - }, - "neg"(a) { - return RationalFunction(-this.num, this.den); - }, - }, - { - left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], - right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], - "+": ratfunc_add, - "-": ratfunc_sub, - "*": ratfunc_mul, - "/": ratfunc_div, - "**": generic_pow, /* should only be used with integers */ - }); - - add_props(RationalFunction, { - /* This function always return a RationalFunction object even - if it could simplified to a polynomial, so it is not - equivalent to RationalFunction(a) */ - toRationalFunction(a) { - var obj; - if (a instanceof RationalFunction) { - return a; - } else { - obj = Object.create(RationalFunction.prototype); - obj.num = Polynomial(a); - obj.den = Polynomial(1); - return obj; - } - }, - }); - - /* Power series */ - - /* 'a' is an array */ - function get_emin(a) { - var i, n; - n = a.length; - for(i = 0; i < n; i++) { - if (a[i] != 0) - return i; - } - return n; - }; - - function series_is_scalar_or_polynomial(a) - { - return polynomial_is_scalar(a) || - (a instanceof Polynomial); - } - - /* n is the maximum number of terms if 'a' is not a serie */ - Series = function Series(a, n) { - var emin, r, i; - - if (a instanceof Series) { - return a; - } else if (series_is_scalar_or_polynomial(a)) { - if (n <= 0) { - /* XXX: should still use the polynomial degree */ - return Series.zero(0, 0); - } else { - a = Polynomial(a); - emin = get_emin(a); - r = Series.zero(n, emin); - n = Math.min(a.length - emin, n); - for(i = 0; i < n; i++) - r[i] = a[i + emin]; - return r; - } - } else if (a instanceof RationalFunction) { - return Series(a.num, n) / a.den; - } else { - throw TypeError("invalid type"); - } - }; - - function series_add(v1, v2) { - var tmp, d, emin, n, r, i, j, v2_emin, c1, c2; - if (!(v1 instanceof Series)) { - tmp = v1; - v1 = v2; - v2 = tmp; - } - d = v1.emin + v1.length; - if (series_is_scalar_or_polynomial(v2)) { - v2 = Polynomial(v2); - if (d <= 0) - return v1; - v2_emin = 0; - } else if (v2 instanceof RationalFunction) { - /* compute the emin of the rational fonction */ - i = get_emin(v2.num) - get_emin(v2.den); - if (d <= i) - return v1; - /* compute the serie with the required terms */ - v2 = Series(v2, d - i); - v2_emin = v2.emin; - } else { - v2_emin = v2.emin; - d = Math.min(d, v2_emin + v2.length); - } - emin = Math.min(v1.emin, v2_emin); - n = d - emin; - r = Series.zero(n, emin); - /* XXX: slow */ - for(i = emin; i < d; i++) { - j = i - v1.emin; - if (j >= 0 && j < v1.length) - c1 = v1[j]; - else - c1 = 0; - j = i - v2_emin; - if (j >= 0 && j < v2.length) - c2 = v2[j]; - else - c2 = 0; - r[i - emin] = c1 + c2; - } - return r.trim(); - } - function series_sub(a, b) { - return series_add(a, -b); - } - function series_mul(v1, v2) { - var n, i, j, r, n, emin, n1, n2, k; - if (!(v1 instanceof Series)) - v1 = Series(v1, v2.length); - else if (!(v2 instanceof Series)) - v2 = Series(v2, v1.length); - emin = v1.emin + v2.emin; - n = Math.min(v1.length, v2.length); - n1 = v1.length; - n2 = v2.length; - r = Series.zero(n, emin); - for(i = 0; i < n1; i++) { - k = Math.min(n2, n - i); - for(j = 0; j < k; j++) { - r[i + j] += v1[i] * v2[j]; - } - } - return r.trim(); - } - function series_div(v1, v2) { - if (!(v2 instanceof Series)) - v2 = Series(v2, v1.length); - return series_mul(v1, v2.inverse()); - } - function series_pow(a, b) { - if (Integer.isInteger(b)) { - return generic_pow(a, b); - } else { - if (!(a instanceof Series)) - a = Series(a, b.length); - return exp(log(a) * b); - } - } - function series_eq(a, b) { - var n, i; - if (a.emin != b.emin) - return false; - n = a.length; - if (n != b.length) - return false; - for(i = 0; i < n; i++) { - if (a[i] != b[i]) - return false; - } - return true; - } - - operators_set(Series.prototype, - { - "+": series_add, - "-": series_sub, - "*": series_mul, - "/": series_div, - "**": series_pow, - "==": series_eq, - "pos"(a) { - return a; - }, - "neg"(a) { - var obj, n, i; - n = a.length; - obj = Series.zero(a.length, a.emin); - for(i = 0; i < n; i++) { - obj[i] = -a[i]; - } - return obj; - }, - }, - { - left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], - right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], - "+": series_add, - "-": series_sub, - "*": series_mul, - "/": series_div, - "**": series_pow, - }); - - add_props(Series.prototype, { - conj() { - var obj, n, i; - n = this.length; - obj = Series.zero(this.length, this.emin); - for(i = 0; i < n; i++) { - obj[i] = this[i].conj(); - } - return obj; - }, - inverse() { - var r, n, i, j, sum, v1 = this; - n = v1.length; - if (n == 0) - throw RangeError("division by zero"); - r = Series.zero(n, -v1.emin); - r[0] = 1 / v1[0]; - for(i = 1; i < n; i++) { - sum = 0; - for(j = 1; j <= i; j++) { - sum += v1[j] * r[i - j]; - } - r[i] = -sum * r[0]; - } - return r; - }, - /* remove leading zero terms */ - trim() { - var i, j, n, r, v1 = this; - n = v1.length; - i = 0; - while (i < n && v1[i] == 0) - i++; - if (i == 0) - return v1; - for(j = i; j < n; j++) - v1[j - i] = v1[j]; - v1.length = n - i; - v1.__proto__.emin += i; - return v1; - }, - toString() { - var i, j, str, str1, c, a = this, emin, n; - str=""; - emin = this.emin; - n = this.length; - for(j = 0; j < n; j++) { - i = j + emin; - c = a[j]; - if (c != 0) { - str1 = monomial_toString(c, i); - if (str1[0] != "-") { - if (str != "") - str += "+"; - } - str += str1; - } - } - if (str != "") - str += "+"; - str += "O(" + monomial_toString(1, n + emin) + ")"; - return str; - }, - apply(b) { - var i, n, r, a = this; - n = a.length; - if (n == 0) - return 0; - r = a[--n]; - while (n > 0) { - n--; - r = r * b + a[n]; - } - if (a.emin != 0) - r *= b ^ a.emin; - return r; - }, - deriv() { - var a = this, n = a.length, emin = a.emin, r, i, j; - if (n == 0 && emin == 0) { - return Series.zero(0, 0); - } else { - r = Series.zero(n, emin - 1); - for(i = 0; i < n; i++) { - j = emin + i; - if (j == 0) - r[i] = 0; - else - r[i] = j * a[i]; - } - return r.trim(); - } - }, - integ() { - var a = this, n = a.length, emin = a.emin, i, j, r; - r = Series.zero(n, emin + 1); - for(i = 0; i < n; i++) { - j = emin + i; - if (j == -1) { - if (a[i] != 0) - throw RangeError("cannot represent integ(1/X)"); - } else { - r[i] = a[i] / (j + 1); - } - } - return r.trim(); - }, - exp() { - var c, i, r, n, a = this; - if (a.emin < 0) - throw RangeError("negative exponent in exp"); - n = a.emin + a.length; - if (a.emin > 0 || a[0] == 0) { - c = 1; - } else { - c = global.exp(a[0]); - a -= a[0]; - } - r = Series.zero(n, 0); - for(i = 0; i < n; i++) { - r[i] = c / fact(i); - } - return r.apply(a); - }, - log() { - var a = this, r; - if (a.emin != 0) - throw RangeError("log argument must have a non zero constant term"); - r = integ(deriv(a) / a); - /* add the constant term */ - r += global.log(a[0]); - return r; - }, - }); - - add_props(Series, { - /* new series of length n and first exponent emin */ - zero(n, emin) { - var r, i, obj; - - r = []; - for(i = 0; i < n; i++) - r[i] = 0; - /* we return an array and store emin in its prototype */ - obj = Object.create(Series.prototype); - obj.emin = emin; - Object.setPrototypeOf(r, obj); - return r; - }, - O(a) { - function ErrorO() { - return TypeError("invalid O() argument"); - } - var n; - if (series_is_scalar_or_polynomial(a)) { - a = Polynomial(a); - n = a.deg(); - if (n < 0) - throw ErrorO(); - } else if (a instanceof RationalFunction) { - if (a.num.deg() != 0) - throw ErrorO(); - n = a.den.deg(); - if (n < 0) - throw ErrorO(); - n = -n; - } else - throw ErrorO(); - return Series.zero(0, n); - }, - }); - - /* Array (Matrix) */ - - Matrix = function Matrix(h, w) { - var i, j, r, rl; - if (typeof w === "undefined") - w = h; - r = []; - for(i = 0; i < h; i++) { - rl = []; - for(j = 0; j < w; j++) - rl[j] = 0; - r[i] = rl; - } - return r; - }; - - add_props(Matrix, { - idn(n) { - var r, i; - r = Matrix(n, n); - for(i = 0; i < n; i++) - r[i][i] = 1; - return r; - }, - diag(a) { - var r, i, n; - n = a.length; - r = Matrix(n, n); - for(i = 0; i < n; i++) - r[i][i] = a[i]; - return r; - }, - hilbert(n) { - var i, j, r; - r = Matrix(n); - for(i = 0; i < n; i++) { - for(j = 0; j < n; j++) { - r[i][j] = 1 / (1 + i + j); - } - } - return r; - }, - trans(a) { - var h, w, r, i, j; - if (!Array.isArray(a)) - throw TypeError("matrix expected"); - h = a.length; - if (!Array.isArray(a[0])) { - w = 1; - r = Matrix(w, h); - for(i = 0; i < h; i++) { - r[0][i] = a[i]; - } - } else { - w = a[0].length; - r = Matrix(w, h); - for(i = 0; i < h; i++) { - for(j = 0; j < w; j++) { - r[j][i] = a[i][j]; - } - } - } - return r; - }, - check_square(a) { - var a, n; - if (!Array.isArray(a)) - throw TypeError("array expected"); - n = a.length; - if (!Array.isArray(a[0]) || n != a[0].length) - throw TypeError("square matrix expected"); - return n; - }, - trace(a) { - var n, r, i; - n = Matrix.check_square(a); - r = a[0][0]; - for(i = 1; i < n; i++) { - r += a[i][i]; - } - return r; - }, - charpoly(a) { - var n, p, c, i, j, coef; - n = Matrix.check_square(a); - p = []; - for(i = 0; i < n + 1; i++) - p[i] = 0; - p[n] = 1; - c = Matrix.idn(n); - for(i = 0; i < n; i++) { - c = c * a; - coef = -trace(c) / (i + 1); - p[n - i - 1] = coef; - for(j = 0; j < n; j++) - c[j][j] += coef; - } - return Polynomial(p); - }, - eigenvals(a) { - return Polynomial.roots(Matrix.charpoly(a)); - }, - det(a) { - var n, i, j, k, s, src, v, c; - - n = Matrix.check_square(a); - s = 1; - src = a.dup(); - for(i=0;i") -DEF(_ret_, "") -DEF(_var_, "") -DEF(_arg_var_, "") -DEF(_with_, "") -DEF(lastIndex, "lastIndex") -DEF(target, "target") -DEF(index, "index") -DEF(input, "input") -DEF(defineProperties, "defineProperties") -DEF(apply, "apply") -DEF(join, "join") -DEF(concat, "concat") -DEF(split, "split") -DEF(construct, "construct") -DEF(getPrototypeOf, "getPrototypeOf") -DEF(setPrototypeOf, "setPrototypeOf") -DEF(isExtensible, "isExtensible") -DEF(preventExtensions, "preventExtensions") -DEF(has, "has") -DEF(deleteProperty, "deleteProperty") -DEF(defineProperty, "defineProperty") -DEF(getOwnPropertyDescriptor, "getOwnPropertyDescriptor") -DEF(ownKeys, "ownKeys") -DEF(add, "add") -DEF(done, "done") -DEF(next, "next") -DEF(values, "values") -DEF(source, "source") -DEF(flags, "flags") -DEF(global, "global") -DEF(unicode, "unicode") -DEF(raw, "raw") -DEF(new_target, "new.target") -DEF(this_active_func, "this.active_func") -DEF(home_object, "") -DEF(computed_field, "") -DEF(static_computed_field, "") /* must come after computed_fields */ -DEF(class_fields_init, "") -DEF(brand, "") -DEF(hash_constructor, "#constructor") -DEF(as, "as") -DEF(from, "from") -DEF(meta, "meta") -DEF(_default_, "*default*") -DEF(_star_, "*") -DEF(Module, "Module") -DEF(then, "then") -DEF(resolve, "resolve") -DEF(reject, "reject") -DEF(promise, "promise") -DEF(proxy, "proxy") -DEF(revoke, "revoke") -DEF(async, "async") -DEF(exec, "exec") -DEF(groups, "groups") -DEF(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/third_party/quickjs/quickjs-libc.c b/third_party/quickjs/quickjs-libc.c deleted file mode 100644 index 3a50a577d..000000000 --- a/third_party/quickjs/quickjs-libc.c +++ /dev/null @@ -1,3844 +0,0 @@ -/* - * QuickJS C library - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "third_party/quickjs/quickjs-libc.h" -#include "libc/assert.h" -#include "libc/calls/calls.h" -#include "libc/calls/internal.h" -#include "libc/calls/struct/dirent.h" -#include "libc/calls/struct/sigaction.h" -#include "libc/calls/struct/stat.h" -#include "libc/calls/struct/winsize.h" -#include "libc/calls/termios.h" -#include "libc/errno.h" -#include "libc/fmt/conv.h" -#include "libc/limits.h" -#include "libc/mem/mem.h" -#include "libc/nt/synchronization.h" -#include "libc/dlopen/dlfcn.h" -#include "libc/runtime/runtime.h" -#include "libc/runtime/sysconf.h" -#include "libc/sock/select.h" -#include "libc/temp.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/clock.h" -#include "libc/sysv/consts/o.h" -#include "libc/sysv/consts/s.h" -#include "libc/sysv/consts/sig.h" -#include "libc/sysv/consts/termios.h" -#include "libc/sysv/consts/w.h" -#include "libc/time/time.h" -#include "third_party/quickjs/cutils.h" -#include "third_party/quickjs/list.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -#define MAXPATH 1024 - - -/* TODO: - - add socket calls -*/ - -typedef struct { - struct list_head link; - int fd; - JSValue rw_func[2]; -} JSOSRWHandler; - -typedef struct { - struct list_head link; - int sig_num; - JSValue func; -} JSOSSignalHandler; - -typedef struct { - struct list_head link; - BOOL has_object; - int64_t timeout; - JSValue func; -} JSOSTimer; - -typedef struct { - struct list_head link; - uint8_t *data; - size_t data_len; - /* list of SharedArrayBuffers, necessary to free the message */ - uint8_t **sab_tab; - size_t sab_tab_len; -} JSWorkerMessage; - -typedef struct { - int ref_count; -#ifdef USE_WORKER - pthread_mutex_t mutex; -#endif - struct list_head msg_queue; /* list of JSWorkerMessage.link */ - int read_fd; - int write_fd; -} JSWorkerMessagePipe; - -typedef struct { - struct list_head link; - JSWorkerMessagePipe *recv_pipe; - JSValue on_message_func; -} JSWorkerMessageHandler; - -typedef struct JSThreadState { - struct list_head os_rw_handlers; /* list of JSOSRWHandler.link */ - struct list_head os_signal_handlers; /* list JSOSSignalHandler.link */ - struct list_head os_timers; /* list of JSOSTimer.link */ - struct list_head port_list; /* list of JSWorkerMessageHandler.link */ - int eval_script_recurse; /* only used in the main thread */ - /* not used in the main thread */ - JSWorkerMessagePipe *recv_pipe, *send_pipe; -} JSThreadState; - -static uint64_t os_pending_signals; -static int (*os_poll_func)(JSContext *ctx); - -static void js_std_dbuf_init(JSContext *ctx, DynBuf *s) -{ - dbuf_init2(s, JS_GetRuntime(ctx), (DynBufReallocFunc *)js_realloc_rt); -} - -static BOOL my_isdigit(int c) -{ - return (c >= '0' && c <= '9'); -} - -static JSValue js_printf_internal(JSContext *ctx, - int argc, JSValueConst *argv, FILE *fp) -{ - char fmtbuf[32]; - uint8_t cbuf[UTF8_CHAR_LEN_MAX+1]; - JSValue res; - DynBuf dbuf; - const char *fmt_str; - const uint8_t *fmt, *fmt_end; - const uint8_t *p; - char *q; - int i, c, len, mod; - size_t fmt_len; - int32_t int32_arg; - int64_t int64_arg; - double double_arg; - const char *string_arg; - /* Use indirect call to dbuf_printf to prevent gcc warning */ - int (*dbuf_printf_fun)(DynBuf *s, const char *fmt, ...) = (void*)dbuf_printf; - - js_std_dbuf_init(ctx, &dbuf); - - if (argc > 0) { - fmt_str = JS_ToCStringLen(ctx, &fmt_len, argv[0]); - if (!fmt_str) - goto fail; - - i = 1; - fmt = (const uint8_t *)fmt_str; - fmt_end = fmt + fmt_len; - while (fmt < fmt_end) { - for (p = fmt; fmt < fmt_end && *fmt != '%'; fmt++) - continue; - dbuf_put(&dbuf, p, fmt - p); - if (fmt >= fmt_end) - break; - q = fmtbuf; - *q++ = *fmt++; /* copy '%' */ - - /* flags */ - for(;;) { - c = *fmt; - if (c == '0' || c == '#' || c == '+' || c == '-' || c == ' ' || - c == '\'') { - if (q >= fmtbuf + sizeof(fmtbuf) - 1) - goto invalid; - *q++ = c; - fmt++; - } else { - break; - } - } - /* width */ - if (*fmt == '*') { - if (i >= argc) - goto missing; - if (JS_ToInt32(ctx, &int32_arg, argv[i++])) - goto fail; - q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg); - fmt++; - } else { - while (my_isdigit(*fmt)) { - if (q >= fmtbuf + sizeof(fmtbuf) - 1) - goto invalid; - *q++ = *fmt++; - } - } - if (*fmt == '.') { - if (q >= fmtbuf + sizeof(fmtbuf) - 1) - goto invalid; - *q++ = *fmt++; - if (*fmt == '*') { - if (i >= argc) - goto missing; - if (JS_ToInt32(ctx, &int32_arg, argv[i++])) - goto fail; - q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg); - fmt++; - } else { - while (my_isdigit(*fmt)) { - if (q >= fmtbuf + sizeof(fmtbuf) - 1) - goto invalid; - *q++ = *fmt++; - } - } - } - - /* we only support the "l" modifier for 64 bit numbers */ - mod = ' '; - if (*fmt == 'l') { - mod = *fmt++; - } - - /* type */ - c = *fmt++; - if (q >= fmtbuf + sizeof(fmtbuf) - 1) - goto invalid; - *q++ = c; - *q = '\0'; - - switch (c) { - case 'c': - if (i >= argc) - goto missing; - if (JS_IsString(argv[i])) { - string_arg = JS_ToCString(ctx, argv[i++]); - if (!string_arg) - goto fail; - int32_arg = unicode_from_utf8((uint8_t *)string_arg, UTF8_CHAR_LEN_MAX, &p); - JS_FreeCString(ctx, string_arg); - } else { - if (JS_ToInt32(ctx, &int32_arg, argv[i++])) - goto fail; - } - /* handle utf-8 encoding explicitly */ - if ((unsigned)int32_arg > 0x10FFFF) - int32_arg = 0xFFFD; - /* ignore conversion flags, width and precision */ - len = unicode_to_utf8(cbuf, int32_arg); - dbuf_put(&dbuf, cbuf, len); - break; - - case 'd': - case 'i': - case 'o': - case 'u': - case 'x': - case 'X': - if (i >= argc) - goto missing; - if (JS_ToInt64Ext(ctx, &int64_arg, argv[i++])) - goto fail; - if (mod == 'l') { - /* 64 bit number */ -#if defined(_WIN32) - if (q >= fmtbuf + sizeof(fmtbuf) - 3) - goto invalid; - q[2] = q[-1]; - q[-1] = 'I'; - q[0] = '6'; - q[1] = '4'; - q[3] = '\0'; - dbuf_printf_fun(&dbuf, fmtbuf, (int64_t)int64_arg); -#else - if (q >= fmtbuf + sizeof(fmtbuf) - 2) - goto invalid; - q[1] = q[-1]; - q[-1] = q[0] = 'l'; - q[2] = '\0'; - dbuf_printf_fun(&dbuf, fmtbuf, (long long)int64_arg); -#endif - } else { - dbuf_printf_fun(&dbuf, fmtbuf, (int)int64_arg); - } - break; - - case 's': - if (i >= argc) - goto missing; - /* XXX: handle strings containing null characters */ - string_arg = JS_ToCString(ctx, argv[i++]); - if (!string_arg) - goto fail; - dbuf_printf_fun(&dbuf, fmtbuf, string_arg); - JS_FreeCString(ctx, string_arg); - break; - - case 'e': - case 'f': - case 'g': - case 'a': - case 'E': - case 'F': - case 'G': - case 'A': - if (i >= argc) - goto missing; - if (JS_ToFloat64(ctx, &double_arg, argv[i++])) - goto fail; - dbuf_printf_fun(&dbuf, fmtbuf, double_arg); - break; - - case '%': - dbuf_putc(&dbuf, '%'); - break; - - default: - /* XXX: should support an extension mechanism */ - invalid: - JS_ThrowTypeError(ctx, "invalid conversion specifier in format string"); - goto fail; - missing: - JS_ThrowReferenceError(ctx, "missing argument for conversion specifier"); - goto fail; - } - } - JS_FreeCString(ctx, fmt_str); - } - if (dbuf.error) { - res = JS_ThrowOutOfMemory(ctx); - } else { - if (fp) { - len = fwrite(dbuf.buf, 1, dbuf.size, fp); - res = JS_NewInt32(ctx, len); - } else { - res = JS_NewStringLen(ctx, (char *)dbuf.buf, dbuf.size); - } - } - dbuf_free(&dbuf); - return res; - -fail: - dbuf_free(&dbuf); - return JS_EXCEPTION; -} - -uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename) -{ - FILE *f; - uint8_t *buf; - size_t buf_len; - long lret; - - f = fopen(filename, "rb"); - if (!f) - return NULL; - if (fseek(f, 0, SEEK_END) < 0) - goto fail; - lret = ftell(f); - if (lret < 0) - goto fail; - /* XXX: on Linux, ftell() return LONG_MAX for directories */ - if (lret == LONG_MAX) { - errno = EISDIR; - goto fail; - } - buf_len = lret; - if (fseek(f, 0, SEEK_SET) < 0) - goto fail; - if (ctx) - buf = js_malloc(ctx, buf_len + 1); - else - buf = malloc(buf_len + 1); - if (!buf) - goto fail; - if (fread(buf, 1, buf_len, f) != buf_len) { - errno = EIO; - if (ctx) - js_free(ctx, buf); - else - free(buf); - fail: - fclose(f); - return NULL; - } - buf[buf_len] = '\0'; - fclose(f); - *pbuf_len = buf_len; - return buf; -} - -/* load and evaluate a file */ -static JSValue js_loadScript(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - uint8_t *buf; - const char *filename; - JSValue ret; - size_t buf_len; - - filename = JS_ToCString(ctx, argv[0]); - if (!filename) - return JS_EXCEPTION; - buf = js_load_file(ctx, &buf_len, filename); - if (!buf) { - JS_ThrowReferenceError(ctx, "could not load '%s'", filename); - JS_FreeCString(ctx, filename); - return JS_EXCEPTION; - } - ret = JS_Eval(ctx, (char *)buf, buf_len, filename, - JS_EVAL_TYPE_GLOBAL); - js_free(ctx, buf); - JS_FreeCString(ctx, filename); - return ret; -} - -/* load a file as a UTF-8 encoded string */ -static JSValue js_std_loadFile(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - uint8_t *buf; - const char *filename; - JSValue ret; - size_t buf_len; - - filename = JS_ToCString(ctx, argv[0]); - if (!filename) - return JS_EXCEPTION; - buf = js_load_file(ctx, &buf_len, filename); - JS_FreeCString(ctx, filename); - if (!buf) - return JS_NULL; - ret = JS_NewStringLen(ctx, (char *)buf, buf_len); - js_free(ctx, buf); - return ret; -} - -typedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx, - const char *module_name); - - -#if defined(_WIN32) -static JSModuleDef *js_module_loader_so(JSContext *ctx, - const char *module_name) -{ - JS_ThrowReferenceError(ctx, "shared library modules are not supported yet"); - return NULL; -} -#else -static JSModuleDef *js_module_loader_so(JSContext *ctx, - const char *module_name) -{ - JSModuleDef *m; - void *hd; - JSInitModuleFunc *init; - char *filename; - - if (!strchr(module_name, '/')) { - /* must add a '/' so that the DLL is not searched in the - system library paths */ - filename = js_malloc(ctx, strlen(module_name) + 2 + 1); - if (!filename) - return NULL; - strcpy(filename, "./"); - strcpy(filename + 2, module_name); - } else { - filename = (char *)module_name; - } - - /* C module */ - hd = dlopen(filename, RTLD_NOW | RTLD_LOCAL); - if (filename != module_name) - js_free(ctx, filename); - if (!hd) { - JS_ThrowReferenceError(ctx, "could not load module filename '%s' as shared library", - module_name); - goto fail; - } - - init = dlsym(hd, "js_init_module"); - if (!init) { - JS_ThrowReferenceError(ctx, "could not load module filename '%s': js_init_module not found", - module_name); - goto fail; - } - - m = init(ctx, module_name); - if (!m) { - JS_ThrowReferenceError(ctx, "could not load module filename '%s': initialization error", - module_name); - fail: - if (hd) - dlclose(hd); - return NULL; - } - return m; -} -#endif /* !_WIN32 */ - -int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, - JS_BOOL use_realpath, JS_BOOL is_main) -{ - JSModuleDef *m; - char buf[MAXPATH + 16]; - JSValue meta_obj; - JSAtom module_name_atom; - const char *module_name; - - assert(JS_VALUE_GET_TAG(func_val) == JS_TAG_MODULE); - m = JS_VALUE_GET_PTR(func_val); - - module_name_atom = JS_GetModuleName(ctx, m); - module_name = JS_AtomToCString(ctx, module_name_atom); - JS_FreeAtom(ctx, module_name_atom); - if (!module_name) - return -1; - if (!strchr(module_name, ':')) { - strcpy(buf, "file://"); -#if !defined(_WIN32) - /* realpath() cannot be used with modules compiled with qjsc - because the corresponding module source code is not - necessarily present */ - if (use_realpath) { - char *res = realpath(module_name, buf + strlen(buf)); - if (!res) { - JS_ThrowTypeError(ctx, "realpath failure"); - JS_FreeCString(ctx, module_name); - return -1; - } - } else -#endif - { - pstrcat(buf, sizeof(buf), module_name); - } - } else { - pstrcpy(buf, sizeof(buf), module_name); - } - JS_FreeCString(ctx, module_name); - - meta_obj = JS_GetImportMeta(ctx, m); - if (JS_IsException(meta_obj)) - return -1; - JS_DefinePropertyValueStr(ctx, meta_obj, "url", - JS_NewString(ctx, buf), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, meta_obj, "main", - JS_NewBool(ctx, is_main), - JS_PROP_C_W_E); - JS_FreeValue(ctx, meta_obj); - return 0; -} - -JSModuleDef *js_module_loader(JSContext *ctx, - const char *module_name, void *opaque) -{ - JSModuleDef *m; - - if (has_suffix(module_name, ".so")) { - m = js_module_loader_so(ctx, module_name); - } else { - size_t buf_len; - uint8_t *buf; - JSValue func_val; - - buf = js_load_file(ctx, &buf_len, module_name); - if (!buf) { - JS_ThrowReferenceError(ctx, "could not load module filename '%s'", - module_name); - return NULL; - } - - /* compile the module */ - func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, - JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); - js_free(ctx, buf); - if (JS_IsException(func_val)) - return NULL; - /* XXX: could propagate the exception */ - js_module_set_import_meta(ctx, func_val, TRUE, FALSE); - /* the module is already referenced, so we must free it */ - m = JS_VALUE_GET_PTR(func_val); - JS_FreeValue(ctx, func_val); - } - return m; -} - -static JSValue js_std_exit(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int status; - if (JS_ToInt32(ctx, &status, argv[0])) - status = -1; - exit(status); - return JS_UNDEFINED; -} - -static JSValue js_std_getenv(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *name, *str; - name = JS_ToCString(ctx, argv[0]); - if (!name) - return JS_EXCEPTION; - str = getenv(name); - JS_FreeCString(ctx, name); - if (!str) - return JS_UNDEFINED; - else - return JS_NewString(ctx, str); -} - -static JSValue js_std_setenv(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *name, *value; - name = JS_ToCString(ctx, argv[0]); - if (!name) - return JS_EXCEPTION; - value = JS_ToCString(ctx, argv[1]); - if (!value) { - JS_FreeCString(ctx, name); - return JS_EXCEPTION; - } - setenv(name, value, TRUE); - JS_FreeCString(ctx, name); - JS_FreeCString(ctx, value); - return JS_UNDEFINED; -} - -static JSValue js_std_unsetenv(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *name; - name = JS_ToCString(ctx, argv[0]); - if (!name) - return JS_EXCEPTION; - unsetenv(name); - JS_FreeCString(ctx, name); - return JS_UNDEFINED; -} - -/* return an object containing the list of the available environment - variables. */ -static JSValue js_std_getenviron(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - char **envp; - const char *name, *p, *value; - JSValue obj; - uint32_t idx; - size_t name_len; - JSAtom atom; - int ret; - - obj = JS_NewObject(ctx); - if (JS_IsException(obj)) - return JS_EXCEPTION; - envp = environ; - for(idx = 0; envp[idx] != NULL; idx++) { - name = envp[idx]; - p = strchr(name, '='); - name_len = p - name; - if (!p) - continue; - value = p + 1; - atom = JS_NewAtomLen(ctx, name, name_len); - if (atom == JS_ATOM_NULL) - goto fail; - ret = JS_DefinePropertyValue(ctx, obj, atom, JS_NewString(ctx, value), - JS_PROP_C_W_E); - JS_FreeAtom(ctx, atom); - if (ret < 0) - goto fail; - } - return obj; - fail: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue js_std_gc(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JS_RunGC(JS_GetRuntime(ctx)); - return JS_UNDEFINED; -} - -static int interrupt_handler(JSRuntime *rt, void *opaque) -{ - return (os_pending_signals >> SIGINT) & 1; -} - -static int get_bool_option(JSContext *ctx, BOOL *pbool, - JSValueConst obj, - const char *option) -{ - JSValue val; - val = JS_GetPropertyStr(ctx, obj, option); - if (JS_IsException(val)) - return -1; - if (!JS_IsUndefined(val)) { - *pbool = JS_ToBool(ctx, val); - } - JS_FreeValue(ctx, val); - return 0; -} - -static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - const char *str; - size_t len; - JSValue ret; - JSValueConst options_obj; - BOOL backtrace_barrier = FALSE; - int flags; - - if (argc >= 2) { - options_obj = argv[1]; - if (get_bool_option(ctx, &backtrace_barrier, options_obj, - "backtrace_barrier")) - return JS_EXCEPTION; - } - - str = JS_ToCStringLen(ctx, &len, argv[0]); - if (!str) - return JS_EXCEPTION; - if (!ts->recv_pipe && ++ts->eval_script_recurse == 1) { - /* install the interrupt handler */ - JS_SetInterruptHandler(JS_GetRuntime(ctx), interrupt_handler, NULL); - } - flags = JS_EVAL_TYPE_GLOBAL; - if (backtrace_barrier) - flags |= JS_EVAL_FLAG_BACKTRACE_BARRIER; - ret = JS_Eval(ctx, str, len, "", flags); - JS_FreeCString(ctx, str); - if (!ts->recv_pipe && --ts->eval_script_recurse == 0) { - /* remove the interrupt handler */ - JS_SetInterruptHandler(JS_GetRuntime(ctx), NULL, NULL); - os_pending_signals &= ~((uint64_t)1 << SIGINT); - /* convert the uncatchable "interrupted" error into a normal error - so that it can be caught by the REPL */ - if (JS_IsException(ret)) - JS_ResetUncatchableError(ctx); - } - return ret; -} - -static JSClassID js_std_file_class_id; - -typedef struct { - FILE *f; - BOOL close_in_finalizer; - BOOL is_popen; -} JSSTDFile; - -static void js_std_file_finalizer(JSRuntime *rt, JSValue val) -{ - JSSTDFile *s = JS_GetOpaque(val, js_std_file_class_id); - if (s) { - if (s->f && s->close_in_finalizer) { - if (s->is_popen) - pclose(s->f); - else - fclose(s->f); - } - js_free_rt(rt, s); - } -} - -static ssize_t js_get_errno(ssize_t ret) -{ - if (ret == -1) - ret = -errno; - return ret; -} - -static JSValue js_std_strerror(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int err; - if (JS_ToInt32(ctx, &err, argv[0])) - return JS_EXCEPTION; - return JS_NewString(ctx, strerror(err)); -} - -static JSValue js_std_parseExtJSON(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj; - const char *str; - size_t len; - - str = JS_ToCStringLen(ctx, &len, argv[0]); - if (!str) - return JS_EXCEPTION; - obj = JS_ParseJSON2(ctx, str, len, "", JS_PARSE_JSON_EXT); - JS_FreeCString(ctx, str); - return obj; -} - -static JSValue js_new_std_file(JSContext *ctx, FILE *f, - BOOL close_in_finalizer, - BOOL is_popen) -{ - JSSTDFile *s; - JSValue obj; - obj = JS_NewObjectClass(ctx, js_std_file_class_id); - if (JS_IsException(obj)) - return obj; - s = js_mallocz(ctx, sizeof(*s)); - if (!s) { - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - s->close_in_finalizer = close_in_finalizer; - s->is_popen = is_popen; - s->f = f; - JS_SetOpaque(obj, s); - return obj; -} - -static void js_set_error_object(JSContext *ctx, JSValue obj, int err) -{ - if (!JS_IsUndefined(obj)) { - JS_SetPropertyStr(ctx, obj, "errno", JS_NewInt32(ctx, err)); - } -} - -static JSValue js_std_open(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *filename, *mode = NULL; - FILE *f; - int err; - - filename = JS_ToCString(ctx, argv[0]); - if (!filename) - goto fail; - mode = JS_ToCString(ctx, argv[1]); - if (!mode) - goto fail; - if (mode[strspn(mode, "rwa+b")] != '\0') { - JS_ThrowTypeError(ctx, "invalid file mode"); - goto fail; - } - - f = fopen(filename, mode); - if (!f) - err = errno; - else - err = 0; - if (argc >= 3) - js_set_error_object(ctx, argv[2], err); - JS_FreeCString(ctx, filename); - JS_FreeCString(ctx, mode); - if (!f) - return JS_NULL; - return js_new_std_file(ctx, f, TRUE, FALSE); - fail: - JS_FreeCString(ctx, filename); - JS_FreeCString(ctx, mode); - return JS_EXCEPTION; -} - -static JSValue js_std_popen(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *filename, *mode = NULL; - FILE *f; - int err; - - filename = JS_ToCString(ctx, argv[0]); - if (!filename) - goto fail; - mode = JS_ToCString(ctx, argv[1]); - if (!mode) - goto fail; - if (mode[strspn(mode, "rw")] != '\0') { - JS_ThrowTypeError(ctx, "invalid file mode"); - goto fail; - } - - f = popen(filename, mode); - if (!f) - err = errno; - else - err = 0; - if (argc >= 3) - js_set_error_object(ctx, argv[2], err); - JS_FreeCString(ctx, filename); - JS_FreeCString(ctx, mode); - if (!f) - return JS_NULL; - return js_new_std_file(ctx, f, TRUE, TRUE); - fail: - JS_FreeCString(ctx, filename); - JS_FreeCString(ctx, mode); - return JS_EXCEPTION; -} - -static JSValue js_std_fdopen(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *mode; - FILE *f; - int fd, err; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - mode = JS_ToCString(ctx, argv[1]); - if (!mode) - goto fail; - if (mode[strspn(mode, "rwa+")] != '\0') { - JS_ThrowTypeError(ctx, "invalid file mode"); - goto fail; - } - - f = fdopen(fd, mode); - if (!f) - err = errno; - else - err = 0; - if (argc >= 3) - js_set_error_object(ctx, argv[2], err); - JS_FreeCString(ctx, mode); - if (!f) - return JS_NULL; - return js_new_std_file(ctx, f, TRUE, FALSE); - fail: - JS_FreeCString(ctx, mode); - return JS_EXCEPTION; -} - -static JSValue js_std_tmpfile(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f; - f = tmpfile(); - if (argc >= 1) - js_set_error_object(ctx, argv[0], f ? 0 : errno); - if (!f) - return JS_NULL; - return js_new_std_file(ctx, f, TRUE, FALSE); -} - -static JSValue js_std_sprintf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return js_printf_internal(ctx, argc, argv, NULL); -} - -static JSValue js_std_printf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return js_printf_internal(ctx, argc, argv, stdout); -} - -static FILE *js_std_file_get(JSContext *ctx, JSValueConst obj) -{ - JSSTDFile *s = JS_GetOpaque2(ctx, obj, js_std_file_class_id); - if (!s) - return NULL; - if (!s->f) { - JS_ThrowTypeError(ctx, "invalid file handle"); - return NULL; - } - return s->f; -} - -static JSValue js_std_file_puts(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - FILE *f; - int i; - const char *str; - size_t len; - - if (magic == 0) { - f = stdout; - } else { - f = js_std_file_get(ctx, this_val); - if (!f) - return JS_EXCEPTION; - } - - for(i = 0; i < argc; i++) { - str = JS_ToCStringLen(ctx, &len, argv[i]); - if (!str) - return JS_EXCEPTION; - fwrite(str, 1, len, f); - JS_FreeCString(ctx, str); - } - return JS_UNDEFINED; -} - -static JSValue js_std_file_close(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSSTDFile *s = JS_GetOpaque2(ctx, this_val, js_std_file_class_id); - int err; - if (!s) - return JS_EXCEPTION; - if (!s->f) - return JS_ThrowTypeError(ctx, "invalid file handle"); - if (s->is_popen) - err = js_get_errno(pclose(s->f)); - else - err = js_get_errno(fclose(s->f)); - s->f = NULL; - return JS_NewInt32(ctx, err); -} - -static JSValue js_std_file_printf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - if (!f) - return JS_EXCEPTION; - return js_printf_internal(ctx, argc, argv, f); -} - -static JSValue js_std_file_flush(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - if (!f) - return JS_EXCEPTION; - fflush(f); - return JS_UNDEFINED; -} - -static JSValue js_std_file_tell(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int is_bigint) -{ - FILE *f = js_std_file_get(ctx, this_val); - int64_t pos; - if (!f) - return JS_EXCEPTION; -#if defined(__linux__) || defined(__COSMOPOLITAN__) - pos = ftello(f); -#else - pos = ftell(f); -#endif - if (is_bigint) - return JS_NewBigInt64(ctx, pos); - else - return JS_NewInt64(ctx, pos); -} - -static JSValue js_std_file_seek(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - int64_t pos; - int whence, ret; - if (!f) - return JS_EXCEPTION; - if (JS_ToInt64Ext(ctx, &pos, argv[0])) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &whence, argv[1])) - return JS_EXCEPTION; -#if defined(__linux__) || defined(__COSMOPOLITAN__) - ret = fseeko(f, pos, whence); -#else - ret = fseek(f, pos, whence); -#endif - if (ret < 0) - ret = -errno; - return JS_NewInt32(ctx, ret); -} - -static JSValue js_std_file_eof(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - if (!f) - return JS_EXCEPTION; - return JS_NewBool(ctx, feof(f)); -} - -static JSValue js_std_file_error(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - if (!f) - return JS_EXCEPTION; - return JS_NewBool(ctx, ferror(f)); -} - -static JSValue js_std_file_clearerr(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - if (!f) - return JS_EXCEPTION; - clearerr(f); - return JS_UNDEFINED; -} - -static JSValue js_std_file_fileno(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - if (!f) - return JS_EXCEPTION; - return JS_NewInt32(ctx, fileno(f)); -} - -static JSValue js_std_file_read_write(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - FILE *f = js_std_file_get(ctx, this_val); - uint64_t pos, len; - size_t size, ret; - uint8_t *buf; - - if (!f) - return JS_EXCEPTION; - if (JS_ToIndex(ctx, &pos, argv[1])) - return JS_EXCEPTION; - if (JS_ToIndex(ctx, &len, argv[2])) - return JS_EXCEPTION; - buf = JS_GetArrayBuffer(ctx, &size, argv[0]); - if (!buf) - return JS_EXCEPTION; - if (pos + len > size) - return JS_ThrowRangeError(ctx, "read/write array buffer overflow"); - if (magic) - ret = fwrite(buf + pos, 1, len, f); - else - ret = fread(buf + pos, 1, len, f); - return JS_NewInt64(ctx, ret); -} - -/* XXX: could use less memory and go faster */ -static JSValue js_std_file_getline(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - int c; - DynBuf dbuf; - JSValue obj; - - if (!f) - return JS_EXCEPTION; - - js_std_dbuf_init(ctx, &dbuf); - for(;;) { - c = fgetc(f); - if (c == EOF) { - if (dbuf.size == 0) { - /* EOF */ - dbuf_free(&dbuf); - return JS_NULL; - } else { - break; - } - } - if (c == '\n') - break; - if (dbuf_putc(&dbuf, c)) { - dbuf_free(&dbuf); - return JS_ThrowOutOfMemory(ctx); - } - } - obj = JS_NewStringLen(ctx, (const char *)dbuf.buf, dbuf.size); - dbuf_free(&dbuf); - return obj; -} - -/* XXX: could use less memory and go faster */ -static JSValue js_std_file_readAsString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - int c; - DynBuf dbuf; - JSValue obj; - uint64_t max_size64; - size_t max_size; - JSValueConst max_size_val; - - if (!f) - return JS_EXCEPTION; - - if (argc >= 1) - max_size_val = argv[0]; - else - max_size_val = JS_UNDEFINED; - max_size = (size_t)-1; - if (!JS_IsUndefined(max_size_val)) { - if (JS_ToIndex(ctx, &max_size64, max_size_val)) - return JS_EXCEPTION; - if (max_size64 < max_size) - max_size = max_size64; - } - - js_std_dbuf_init(ctx, &dbuf); - while (max_size != 0) { - c = fgetc(f); - if (c == EOF) - break; - if (dbuf_putc(&dbuf, c)) { - dbuf_free(&dbuf); - return JS_EXCEPTION; - } - max_size--; - } - obj = JS_NewStringLen(ctx, (const char *)dbuf.buf, dbuf.size); - dbuf_free(&dbuf); - return obj; -} - -static JSValue js_std_file_getByte(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - if (!f) - return JS_EXCEPTION; - return JS_NewInt32(ctx, fgetc(f)); -} - -static JSValue js_std_file_putByte(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - FILE *f = js_std_file_get(ctx, this_val); - int c; - if (!f) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &c, argv[0])) - return JS_EXCEPTION; - c = fputc(c, f); - return JS_NewInt32(ctx, c); -} - -/* urlGet */ - -#define URL_GET_PROGRAM "curl -s -i" -#define URL_GET_BUF_SIZE 4096 - -static int http_get_header_line(FILE *f, char *buf, size_t buf_size, - DynBuf *dbuf) -{ - int c; - char *p; - - p = buf; - for(;;) { - c = fgetc(f); - if (c < 0) - return -1; - if ((p - buf) < buf_size - 1) - *p++ = c; - if (dbuf) - dbuf_putc(dbuf, c); - if (c == '\n') - break; - } - *p = '\0'; - return 0; -} - -static int http_get_status(const char *buf) -{ - const char *p = buf; - while (*p != ' ' && *p != '\0') - p++; - if (*p != ' ') - return 0; - while (*p == ' ') - p++; - return atoi(p); -} - -static JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *url; - DynBuf cmd_buf; - DynBuf data_buf_s, *data_buf = &data_buf_s; - DynBuf header_buf_s, *header_buf = &header_buf_s; - char *buf; - size_t i, len; - int c, status; - JSValue response = JS_UNDEFINED, ret_obj; - JSValueConst options_obj; - FILE *f; - BOOL binary_flag, full_flag; - - url = JS_ToCString(ctx, argv[0]); - if (!url) - return JS_EXCEPTION; - - binary_flag = FALSE; - full_flag = FALSE; - - if (argc >= 2) { - options_obj = argv[1]; - - if (get_bool_option(ctx, &binary_flag, options_obj, "binary")) - goto fail_obj; - - if (get_bool_option(ctx, &full_flag, options_obj, "full")) { - fail_obj: - JS_FreeCString(ctx, url); - return JS_EXCEPTION; - } - } - - js_std_dbuf_init(ctx, &cmd_buf); - dbuf_printf(&cmd_buf, "%s ''", URL_GET_PROGRAM); - len = strlen(url); - for(i = 0; i < len; i++) { - c = url[i]; - if (c == '\'' || c == '\\') - dbuf_putc(&cmd_buf, '\\'); - dbuf_putc(&cmd_buf, c); - } - JS_FreeCString(ctx, url); - dbuf_putstr(&cmd_buf, "''"); - dbuf_putc(&cmd_buf, '\0'); - if (dbuf_error(&cmd_buf)) { - dbuf_free(&cmd_buf); - return JS_EXCEPTION; - } - // printf("%s\n", (char *)cmd_buf.buf); - f = popen((char *)cmd_buf.buf, "r"); - dbuf_free(&cmd_buf); - if (!f) { - return JS_ThrowTypeError(ctx, "could not start curl"); - } - - js_std_dbuf_init(ctx, data_buf); - js_std_dbuf_init(ctx, header_buf); - - buf = js_malloc(ctx, URL_GET_BUF_SIZE); - if (!buf) - goto fail; - - /* get the HTTP status */ - if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, NULL) < 0) { - status = 0; - goto bad_header; - } - status = http_get_status(buf); - if (!full_flag && !(status >= 200 && status <= 299)) { - goto bad_header; - } - - /* wait until there is an empty line */ - for(;;) { - if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, header_buf) < 0) { - bad_header: - response = JS_NULL; - goto done; - } - if (!strcmp(buf, "\r\n")) - break; - } - if (dbuf_error(header_buf)) - goto fail; - header_buf->size -= 2; /* remove the trailing CRLF */ - - /* download the data */ - for(;;) { - len = fread(buf, 1, URL_GET_BUF_SIZE, f); - if (len == 0) - break; - dbuf_put(data_buf, (uint8_t *)buf, len); - } - if (dbuf_error(data_buf)) - goto fail; - if (binary_flag) { - response = JS_NewArrayBufferCopy(ctx, - data_buf->buf, data_buf->size); - } else { - response = JS_NewStringLen(ctx, (char *)data_buf->buf, data_buf->size); - } - if (JS_IsException(response)) - goto fail; - done: - js_free(ctx, buf); - buf = NULL; - pclose(f); - f = NULL; - dbuf_free(data_buf); - data_buf = NULL; - - if (full_flag) { - ret_obj = JS_NewObject(ctx); - if (JS_IsException(ret_obj)) - goto fail; - JS_DefinePropertyValueStr(ctx, ret_obj, "response", - response, - JS_PROP_C_W_E); - if (!JS_IsNull(response)) { - JS_DefinePropertyValueStr(ctx, ret_obj, "responseHeaders", - JS_NewStringLen(ctx, (char *)header_buf->buf, - header_buf->size), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, ret_obj, "status", - JS_NewInt32(ctx, status), - JS_PROP_C_W_E); - } - } else { - ret_obj = response; - } - dbuf_free(header_buf); - return ret_obj; - fail: - if (f) - pclose(f); - js_free(ctx, buf); - if (data_buf) - dbuf_free(data_buf); - if (header_buf) - dbuf_free(header_buf); - JS_FreeValue(ctx, response); - return JS_EXCEPTION; -} - -static JSClassDef js_std_file_class = { - "FILE", - .finalizer = js_std_file_finalizer, -}; - -static JSCFunctionListEntry js_std_error_props[11]; -static textstartup void js_std_error_props_init() { - JSCFunctionListEntry props[] = { - /* various errno values */ -#define DEF(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE ) - DEF(EINVAL), - DEF(EIO), - DEF(EACCES), - DEF(EEXIST), - DEF(ENOSPC), - DEF(ENOSYS), - DEF(EBUSY), - DEF(ENOENT), - DEF(EPERM), - DEF(EPIPE), - DEF(EBADF), -#undef DEF - }; - _Static_assert(sizeof(js_std_error_props) == sizeof(props), ""); - memcpy(js_std_error_props, props, sizeof(props)); -} -const void *const js_std_error_props_ctor[] initarray = {js_std_error_props_init}; - -static const JSCFunctionListEntry js_std_funcs[] = { - JS_CFUNC_DEF("exit", 1, js_std_exit ), - JS_CFUNC_DEF("gc", 0, js_std_gc ), - JS_CFUNC_DEF("evalScript", 1, js_evalScript ), - JS_CFUNC_DEF("loadScript", 1, js_loadScript ), - JS_CFUNC_DEF("getenv", 1, js_std_getenv ), - JS_CFUNC_DEF("setenv", 1, js_std_setenv ), - JS_CFUNC_DEF("unsetenv", 1, js_std_unsetenv ), - JS_CFUNC_DEF("getenviron", 1, js_std_getenviron ), - JS_CFUNC_DEF("urlGet", 1, js_std_urlGet ), - JS_CFUNC_DEF("loadFile", 1, js_std_loadFile ), - JS_CFUNC_DEF("strerror", 1, js_std_strerror ), - JS_CFUNC_DEF("parseExtJSON", 1, js_std_parseExtJSON ), - - /* FILE I/O */ - JS_CFUNC_DEF("open", 2, js_std_open ), - JS_CFUNC_DEF("popen", 2, js_std_popen ), - JS_CFUNC_DEF("fdopen", 2, js_std_fdopen ), - JS_CFUNC_DEF("tmpfile", 0, js_std_tmpfile ), - JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 0 ), - JS_CFUNC_DEF("printf", 1, js_std_printf ), - JS_CFUNC_DEF("sprintf", 1, js_std_sprintf ), - JS_PROP_INT32_DEF("SEEK_SET", SEEK_SET, JS_PROP_CONFIGURABLE ), - JS_PROP_INT32_DEF("SEEK_CUR", SEEK_CUR, JS_PROP_CONFIGURABLE ), - JS_PROP_INT32_DEF("SEEK_END", SEEK_END, JS_PROP_CONFIGURABLE ), - JS_OBJECT_DEF("Error", js_std_error_props, countof(js_std_error_props), JS_PROP_CONFIGURABLE), -}; - -static const JSCFunctionListEntry js_std_file_proto_funcs[] = { - JS_CFUNC_DEF("close", 0, js_std_file_close ), - JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 1 ), - JS_CFUNC_DEF("printf", 1, js_std_file_printf ), - JS_CFUNC_DEF("flush", 0, js_std_file_flush ), - JS_CFUNC_MAGIC_DEF("tell", 0, js_std_file_tell, 0 ), - JS_CFUNC_MAGIC_DEF("tello", 0, js_std_file_tell, 1 ), - JS_CFUNC_DEF("seek", 2, js_std_file_seek ), - JS_CFUNC_DEF("eof", 0, js_std_file_eof ), - JS_CFUNC_DEF("fileno", 0, js_std_file_fileno ), - JS_CFUNC_DEF("error", 0, js_std_file_error ), - JS_CFUNC_DEF("clearerr", 0, js_std_file_clearerr ), - JS_CFUNC_MAGIC_DEF("read", 3, js_std_file_read_write, 0 ), - JS_CFUNC_MAGIC_DEF("write", 3, js_std_file_read_write, 1 ), - JS_CFUNC_DEF("getline", 0, js_std_file_getline ), - JS_CFUNC_DEF("readAsString", 0, js_std_file_readAsString ), - JS_CFUNC_DEF("getByte", 0, js_std_file_getByte ), - JS_CFUNC_DEF("putByte", 1, js_std_file_putByte ), - /* setvbuf, ... */ -}; - -static int js_std_init(JSContext *ctx, JSModuleDef *m) -{ - JSValue proto; - - /* FILE class */ - /* the class ID is created once */ - JS_NewClassID(&js_std_file_class_id); - /* the class is created once per runtime */ - JS_NewClass(JS_GetRuntime(ctx), js_std_file_class_id, &js_std_file_class); - proto = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, proto, js_std_file_proto_funcs, - countof(js_std_file_proto_funcs)); - JS_SetClassProto(ctx, js_std_file_class_id, proto); - - JS_SetModuleExportList(ctx, m, js_std_funcs, - countof(js_std_funcs)); - JS_SetModuleExport(ctx, m, "in", js_new_std_file(ctx, stdin, FALSE, FALSE)); - JS_SetModuleExport(ctx, m, "out", js_new_std_file(ctx, stdout, FALSE, FALSE)); - JS_SetModuleExport(ctx, m, "err", js_new_std_file(ctx, stderr, FALSE, FALSE)); - return 0; -} - -JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name) -{ - JSModuleDef *m; - m = JS_NewCModule(ctx, module_name, js_std_init); - if (!m) - return NULL; - JS_AddModuleExportList(ctx, m, js_std_funcs, countof(js_std_funcs)); - JS_AddModuleExport(ctx, m, "in"); - JS_AddModuleExport(ctx, m, "out"); - JS_AddModuleExport(ctx, m, "err"); - return m; -} - -/**********************************************************/ -/* 'os' object */ - -static JSValue js_os_open(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *filename; - int flags, mode, ret; - - filename = JS_ToCString(ctx, argv[0]); - if (!filename) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &flags, argv[1])) - goto fail; - if (argc >= 3 && !JS_IsUndefined(argv[2])) { - if (JS_ToInt32(ctx, &mode, argv[2])) { - fail: - JS_FreeCString(ctx, filename); - return JS_EXCEPTION; - } - } else { - mode = 0666; - } -#if defined(_WIN32) - /* force binary mode by default */ - if (!(flags & O_TEXT)) - flags |= O_BINARY; -#endif - ret = js_get_errno(open(filename, flags, mode)); - JS_FreeCString(ctx, filename); - return JS_NewInt32(ctx, ret); -} - -static JSValue js_os_close(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int fd, ret; - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - ret = js_get_errno(close(fd)); - return JS_NewInt32(ctx, ret); -} - -static JSValue js_os_seek(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int fd, whence; - int64_t pos, ret; - BOOL is_bigint; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - is_bigint = JS_IsBigInt(ctx, argv[1]); - if (JS_ToInt64Ext(ctx, &pos, argv[1])) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &whence, argv[2])) - return JS_EXCEPTION; - ret = lseek(fd, pos, whence); - if (ret == -1) - ret = -errno; - if (is_bigint) - return JS_NewBigInt64(ctx, ret); - else - return JS_NewInt64(ctx, ret); -} - -static JSValue js_os_read_write(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - int fd; - uint64_t pos, len; - size_t size; - ssize_t ret; - uint8_t *buf; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - if (JS_ToIndex(ctx, &pos, argv[2])) - return JS_EXCEPTION; - if (JS_ToIndex(ctx, &len, argv[3])) - return JS_EXCEPTION; - buf = JS_GetArrayBuffer(ctx, &size, argv[1]); - if (!buf) - return JS_EXCEPTION; - if (pos + len > size) - return JS_ThrowRangeError(ctx, "read/write array buffer overflow"); - if (magic) - ret = js_get_errno(write(fd, buf + pos, len)); - else - ret = js_get_errno(read(fd, buf + pos, len)); - return JS_NewInt64(ctx, ret); -} - -static JSValue js_os_isatty(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int fd; - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - return JS_NewBool(ctx, (isatty(fd) != 0)); -} - -#if defined(_WIN32) -static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int fd; - HANDLE handle; - CONSOLE_SCREEN_BUFFER_INFO info; - JSValue obj; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - handle = (HANDLE)_get_osfhandle(fd); - - if (!GetConsoleScreenBufferInfo(handle, &info)) - return JS_NULL; - obj = JS_NewArray(ctx); - if (JS_IsException(obj)) - return obj; - JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, info.dwSize.X), JS_PROP_C_W_E); - JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, info.dwSize.Y), JS_PROP_C_W_E); - return obj; -} - -/* Windows 10 built-in VT100 emulation */ -#define __ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 -#define __ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200 - -static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int fd; - HANDLE handle; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - handle = (HANDLE)_get_osfhandle(fd); - SetConsoleMode(handle, ENABLE_WINDOW_INPUT | __ENABLE_VIRTUAL_TERMINAL_INPUT); - _setmode(fd, _O_BINARY); - if (fd == 0) { - handle = (HANDLE)_get_osfhandle(1); /* corresponding output */ - SetConsoleMode(handle, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | __ENABLE_VIRTUAL_TERMINAL_PROCESSING); - } - return JS_UNDEFINED; -} -#else -static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int fd; - struct winsize ws; - JSValue obj; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - if (tcgetwinsize(fd, &ws) == 0 && - ws.ws_col >= 4 && ws.ws_row >= 4) { - obj = JS_NewArray(ctx); - if (JS_IsException(obj)) - return obj; - JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, ws.ws_col), JS_PROP_C_W_E); - JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, ws.ws_row), JS_PROP_C_W_E); - return obj; - } else { - return JS_NULL; - } -} - -static struct termios oldtty; - -static void term_exit(void) -{ - tcsetattr(0, TCSANOW, &oldtty); -} - -/* XXX: should add a way to go back to normal mode */ -static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - struct termios tty; - int fd; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - bzero(&tty, sizeof(tty)); - tcgetattr(fd, &tty); - oldtty = tty; - - tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP - |INLCR|IGNCR|ICRNL|IXON); - tty.c_oflag |= OPOST; - tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); - tty.c_cflag &= ~(CSIZE|PARENB); - tty.c_cflag |= CS8; - tty.c_cc[VMIN] = 1; - tty.c_cc[VTIME] = 0; - - tcsetattr(fd, TCSANOW, &tty); - - atexit(term_exit); - return JS_UNDEFINED; -} - -#endif /* !_WIN32 */ - -static JSValue js_os_remove(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *filename; - int ret; - - filename = JS_ToCString(ctx, argv[0]); - if (!filename) - return JS_EXCEPTION; -#if defined(_WIN32) - { - struct stat st; - if (stat(filename, &st) == 0 && S_ISDIR(st.st_mode)) { - ret = rmdir(filename); - } else { - ret = unlink(filename); - } - } -#else - ret = remove(filename); -#endif - ret = js_get_errno(ret); - JS_FreeCString(ctx, filename); - return JS_NewInt32(ctx, ret); -} - -static JSValue js_os_rename(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *oldpath, *newpath; - int ret; - - oldpath = JS_ToCString(ctx, argv[0]); - if (!oldpath) - return JS_EXCEPTION; - newpath = JS_ToCString(ctx, argv[1]); - if (!newpath) { - JS_FreeCString(ctx, oldpath); - return JS_EXCEPTION; - } - ret = js_get_errno(rename(oldpath, newpath)); - JS_FreeCString(ctx, oldpath); - JS_FreeCString(ctx, newpath); - return JS_NewInt32(ctx, ret); -} - -static BOOL is_main_thread(JSRuntime *rt) -{ - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - return !ts->recv_pipe; -} - -static JSOSRWHandler *find_rh(JSThreadState *ts, int fd) -{ - JSOSRWHandler *rh; - struct list_head *el; - - list_for_each(el, &ts->os_rw_handlers) { - rh = list_entry(el, JSOSRWHandler, link); - if (rh->fd == fd) - return rh; - } - return NULL; -} - -static void free_rw_handler(JSRuntime *rt, JSOSRWHandler *rh) -{ - int i; - list_del(&rh->link); - for(i = 0; i < 2; i++) { - JS_FreeValueRT(rt, rh->rw_func[i]); - } - js_free_rt(rt, rh); -} - -static JSValue js_os_setReadHandler(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - JSOSRWHandler *rh; - int fd; - JSValueConst func; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - func = argv[1]; - if (JS_IsNull(func)) { - rh = find_rh(ts, fd); - if (rh) { - JS_FreeValue(ctx, rh->rw_func[magic]); - rh->rw_func[magic] = JS_NULL; - if (JS_IsNull(rh->rw_func[0]) && - JS_IsNull(rh->rw_func[1])) { - /* remove the entry */ - free_rw_handler(JS_GetRuntime(ctx), rh); - } - } - } else { - if (!JS_IsFunction(ctx, func)) - return JS_ThrowTypeError(ctx, "not a function"); - rh = find_rh(ts, fd); - if (!rh) { - rh = js_mallocz(ctx, sizeof(*rh)); - if (!rh) - return JS_EXCEPTION; - rh->fd = fd; - rh->rw_func[0] = JS_NULL; - rh->rw_func[1] = JS_NULL; - list_add_tail(&rh->link, &ts->os_rw_handlers); - } - JS_FreeValue(ctx, rh->rw_func[magic]); - rh->rw_func[magic] = JS_DupValue(ctx, func); - } - return JS_UNDEFINED; -} - -static JSOSSignalHandler *find_sh(JSThreadState *ts, int sig_num) -{ - JSOSSignalHandler *sh; - struct list_head *el; - list_for_each(el, &ts->os_signal_handlers) { - sh = list_entry(el, JSOSSignalHandler, link); - if (sh->sig_num == sig_num) - return sh; - } - return NULL; -} - -static void free_sh(JSRuntime *rt, JSOSSignalHandler *sh) -{ - list_del(&sh->link); - JS_FreeValueRT(rt, sh->func); - js_free_rt(rt, sh); -} - -static void os_signal_handler(int sig_num) -{ - os_pending_signals |= ((uint64_t)1 << sig_num); -} - -#if defined(_WIN32) -typedef void (*sighandler_t)(int sig_num); -#endif - -static JSValue js_os_signal(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - JSOSSignalHandler *sh; - uint32_t sig_num; - JSValueConst func; - sighandler_t handler; - - if (!is_main_thread(rt)) - return JS_ThrowTypeError(ctx, "signal handler can only be set in the main thread"); - - if (JS_ToUint32(ctx, &sig_num, argv[0])) - return JS_EXCEPTION; - if (sig_num >= 64) - return JS_ThrowRangeError(ctx, "invalid signal number"); - func = argv[1]; - /* func = null: SIG_DFL, func = undefined, SIG_IGN */ - if (JS_IsNull(func) || JS_IsUndefined(func)) { - sh = find_sh(ts, sig_num); - if (sh) { - free_sh(JS_GetRuntime(ctx), sh); - } - if (JS_IsNull(func)) - handler = SIG_DFL; - else - handler = SIG_IGN; - signal(sig_num, handler); - } else { - if (!JS_IsFunction(ctx, func)) - return JS_ThrowTypeError(ctx, "not a function"); - sh = find_sh(ts, sig_num); - if (!sh) { - sh = js_mallocz(ctx, sizeof(*sh)); - if (!sh) - return JS_EXCEPTION; - sh->sig_num = sig_num; - list_add_tail(&sh->link, &ts->os_signal_handlers); - } - JS_FreeValue(ctx, sh->func); - sh->func = JS_DupValue(ctx, func); - signal(sig_num, os_signal_handler); - } - return JS_UNDEFINED; -} - -#if defined(__linux__) || defined(__APPLE__) || defined(__COSMOPOLITAN__) -static int64_t get_time_ms(void) -{ - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (uint64_t)ts.tv_sec * 1000 + (ts.tv_nsec / 1000000); -} -#else -/* more portable, but does not work if the date is updated */ -static int64_t get_time_ms(void) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000); -} -#endif - -static void unlink_timer(JSRuntime *rt, JSOSTimer *th) -{ - if (th->link.prev) { - list_del(&th->link); - th->link.prev = th->link.next = NULL; - } -} - -static void free_timer(JSRuntime *rt, JSOSTimer *th) -{ - JS_FreeValueRT(rt, th->func); - js_free_rt(rt, th); -} - -static JSClassID js_os_timer_class_id; - -static void js_os_timer_finalizer(JSRuntime *rt, JSValue val) -{ - JSOSTimer *th = JS_GetOpaque(val, js_os_timer_class_id); - if (th) { - th->has_object = FALSE; - if (!th->link.prev) - free_timer(rt, th); - } -} - -static void js_os_timer_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSOSTimer *th = JS_GetOpaque(val, js_os_timer_class_id); - if (th) { - JS_MarkValue(rt, th->func, mark_func); - } -} - -static JSValue js_os_setTimeout(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - int64_t delay; - JSValueConst func; - JSOSTimer *th; - JSValue obj; - - func = argv[0]; - if (!JS_IsFunction(ctx, func)) - return JS_ThrowTypeError(ctx, "not a function"); - if (JS_ToInt64(ctx, &delay, argv[1])) - return JS_EXCEPTION; - obj = JS_NewObjectClass(ctx, js_os_timer_class_id); - if (JS_IsException(obj)) - return obj; - th = js_mallocz(ctx, sizeof(*th)); - if (!th) { - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - th->has_object = TRUE; - th->timeout = get_time_ms() + delay; - th->func = JS_DupValue(ctx, func); - list_add_tail(&th->link, &ts->os_timers); - JS_SetOpaque(obj, th); - return obj; -} - -static JSValue js_os_clearTimeout(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSOSTimer *th = JS_GetOpaque2(ctx, argv[0], js_os_timer_class_id); - if (!th) - return JS_EXCEPTION; - unlink_timer(JS_GetRuntime(ctx), th); - return JS_UNDEFINED; -} - -static JSClassDef js_os_timer_class = { - "OSTimer", - .finalizer = js_os_timer_finalizer, - .gc_mark = js_os_timer_mark, -}; - -static void call_handler(JSContext *ctx, JSValueConst func) -{ - JSValue ret, func1; - /* 'func' might be destroyed when calling itself (if it frees the - handler), so must take extra care */ - func1 = JS_DupValue(ctx, func); - ret = JS_Call(ctx, func1, JS_UNDEFINED, 0, NULL); - JS_FreeValue(ctx, func1); - if (JS_IsException(ret)) - js_std_dump_error(ctx); - JS_FreeValue(ctx, ret); -} - -#if defined(_COSMO_SOURCE) -#define DWORD uint32_t -#define HANDLE int64_t -#define _get_osfhandle(fd) g_fds.p[fd].handle -#define INFINITE ((DWORD)-1) -#define WAIT_OBJECT_0 ((DWORD)0) - -static int js_os_poll_nt(JSContext *ctx) -{ - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - int min_delay, console_fd; - int64_t cur_time, delay; - JSOSRWHandler *rh; - struct list_head *el; - - /* XXX: handle signals if useful */ - - if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers)) - return -1; /* no more events */ - - /* XXX: only timers and basic console input are supported */ - if (!list_empty(&ts->os_timers)) { - cur_time = get_time_ms(); - min_delay = 10000; - list_for_each(el, &ts->os_timers) { - JSOSTimer *th = list_entry(el, JSOSTimer, link); - delay = th->timeout - cur_time; - if (delay <= 0) { - JSValue func; - /* the timer expired */ - func = th->func; - th->func = JS_UNDEFINED; - unlink_timer(rt, th); - if (!th->has_object) - free_timer(rt, th); - call_handler(ctx, func); - JS_FreeValue(ctx, func); - return 0; - } else if (delay < min_delay) { - min_delay = delay; - } - } - } else { - min_delay = -1; - } - - console_fd = -1; - list_for_each(el, &ts->os_rw_handlers) { - rh = list_entry(el, JSOSRWHandler, link); - if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) { - console_fd = rh->fd; - break; - } - } - - if (console_fd >= 0) { - DWORD ti, ret; - HANDLE handle; - if (min_delay == -1) - ti = INFINITE; - else - ti = min_delay; - handle = (HANDLE)_get_osfhandle(console_fd); - ret = WaitForSingleObject(handle, ti); - if (ret == WAIT_OBJECT_0) { - list_for_each(el, &ts->os_rw_handlers) { - rh = list_entry(el, JSOSRWHandler, link); - if (rh->fd == console_fd && !JS_IsNull(rh->rw_func[0])) { - call_handler(ctx, rh->rw_func[0]); - /* must stop because the list may have been modified */ - break; - } - } - } - } else { - Sleep(min_delay); - } - return 0; -} - -#ifdef USE_WORKER - -static void js_free_message(JSWorkerMessage *msg); - -/* return 1 if a message was handled, 0 if no message */ -static int handle_posted_message(JSRuntime *rt, JSContext *ctx, - JSWorkerMessageHandler *port) -{ - JSWorkerMessagePipe *ps = port->recv_pipe; - int ret; - struct list_head *el; - JSWorkerMessage *msg; - JSValue obj, data_obj, func, retval; - - pthread_mutex_lock(&ps->mutex); - if (!list_empty(&ps->msg_queue)) { - el = ps->msg_queue.next; - msg = list_entry(el, JSWorkerMessage, link); - - /* remove the message from the queue */ - list_del(&msg->link); - - if (list_empty(&ps->msg_queue)) { - uint8_t buf[16]; - int ret; - for(;;) { - ret = read(ps->read_fd, buf, sizeof(buf)); - if (ret >= 0) - break; - if (errno != EAGAIN && errno != EINTR) - break; - } - } - - pthread_mutex_unlock(&ps->mutex); - - data_obj = JS_ReadObject(ctx, msg->data, msg->data_len, - JS_READ_OBJ_SAB | JS_READ_OBJ_REFERENCE); - - js_free_message(msg); - - if (JS_IsException(data_obj)) - goto fail; - obj = JS_NewObject(ctx); - if (JS_IsException(obj)) { - JS_FreeValue(ctx, data_obj); - goto fail; - } - JS_DefinePropertyValueStr(ctx, obj, "data", data_obj, JS_PROP_C_W_E); - - /* 'func' might be destroyed when calling itself (if it frees the - handler), so must take extra care */ - func = JS_DupValue(ctx, port->on_message_func); - retval = JS_Call(ctx, func, JS_UNDEFINED, 1, (JSValueConst *)&obj); - JS_FreeValue(ctx, obj); - JS_FreeValue(ctx, func); - if (JS_IsException(retval)) { - fail: - js_std_dump_error(ctx); - } else { - JS_FreeValue(ctx, retval); - } - ret = 1; - } else { - pthread_mutex_unlock(&ps->mutex); - ret = 0; - } - return ret; -} -#else -static int handle_posted_message(JSRuntime *rt, JSContext *ctx, - JSWorkerMessageHandler *port) -{ - return 0; -} -#endif - -static int js_os_poll(JSContext *ctx) -{ - if (IsWindows()) { - return js_os_poll_nt(ctx); - } - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - int ret, fd_max, min_delay; - int64_t cur_time, delay; - fd_set rfds, wfds; - JSOSRWHandler *rh; - struct list_head *el; - struct timeval tv, *tvp; - - /* only check signals in the main thread */ - if (!ts->recv_pipe && UNLIKELY(os_pending_signals != 0)) { - JSOSSignalHandler *sh; - uint64_t mask; - - list_for_each(el, &ts->os_signal_handlers) { - sh = list_entry(el, JSOSSignalHandler, link); - mask = (uint64_t)1 << sh->sig_num; - if (os_pending_signals & mask) { - os_pending_signals &= ~mask; - call_handler(ctx, sh->func); - return 0; - } - } - } - - if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers) && - list_empty(&ts->port_list)) - return -1; /* no more events */ - - if (!list_empty(&ts->os_timers)) { - cur_time = get_time_ms(); - min_delay = 10000; - list_for_each(el, &ts->os_timers) { - JSOSTimer *th = list_entry(el, JSOSTimer, link); - delay = th->timeout - cur_time; - if (delay <= 0) { - JSValue func; - /* the timer expired */ - func = th->func; - th->func = JS_UNDEFINED; - unlink_timer(rt, th); - if (!th->has_object) - free_timer(rt, th); - call_handler(ctx, func); - JS_FreeValue(ctx, func); - return 0; - } else if (delay < min_delay) { - min_delay = delay; - } - } - tv.tv_sec = min_delay / 1000; - tv.tv_usec = (min_delay % 1000) * 1000; - tvp = &tv; - } else { - tvp = NULL; - } - - FD_ZERO(&rfds); - FD_ZERO(&wfds); - fd_max = -1; - list_for_each(el, &ts->os_rw_handlers) { - rh = list_entry(el, JSOSRWHandler, link); - fd_max = max_int(fd_max, rh->fd); - if (!JS_IsNull(rh->rw_func[0])) - FD_SET(rh->fd, &rfds); - if (!JS_IsNull(rh->rw_func[1])) - FD_SET(rh->fd, &wfds); - } - - list_for_each(el, &ts->port_list) { - JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link); - if (!JS_IsNull(port->on_message_func)) { - JSWorkerMessagePipe *ps = port->recv_pipe; - fd_max = max_int(fd_max, ps->read_fd); - FD_SET(ps->read_fd, &rfds); - } - } - - ret = select(fd_max + 1, &rfds, &wfds, NULL, tvp); - if (ret > 0) { - list_for_each(el, &ts->os_rw_handlers) { - rh = list_entry(el, JSOSRWHandler, link); - if (!JS_IsNull(rh->rw_func[0]) && - FD_ISSET(rh->fd, &rfds)) { - call_handler(ctx, rh->rw_func[0]); - /* must stop because the list may have been modified */ - goto done; - } - if (!JS_IsNull(rh->rw_func[1]) && - FD_ISSET(rh->fd, &wfds)) { - call_handler(ctx, rh->rw_func[1]); - /* must stop because the list may have been modified */ - goto done; - } - } - - list_for_each(el, &ts->port_list) { - JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link); - if (!JS_IsNull(port->on_message_func)) { - JSWorkerMessagePipe *ps = port->recv_pipe; - if (FD_ISSET(ps->read_fd, &rfds)) { - if (handle_posted_message(rt, ctx, port)) - goto done; - } - } - } - } - done: - return 0; -} -#endif /* !_WIN32 */ - -static JSValue make_obj_error(JSContext *ctx, - JSValue obj, - int err) -{ - JSValue arr; - if (JS_IsException(obj)) - return obj; - arr = JS_NewArray(ctx); - if (JS_IsException(arr)) - return JS_EXCEPTION; - JS_DefinePropertyValueUint32(ctx, arr, 0, obj, - JS_PROP_C_W_E); - JS_DefinePropertyValueUint32(ctx, arr, 1, JS_NewInt32(ctx, err), - JS_PROP_C_W_E); - return arr; -} - -static JSValue make_string_error(JSContext *ctx, - const char *buf, - int err) -{ - return make_obj_error(ctx, JS_NewString(ctx, buf), err); -} - -/* return [cwd, errorcode] */ -static JSValue js_os_getcwd(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - char buf[MAXPATH]; - int err; - - if (!getcwd(buf, sizeof(buf))) { - buf[0] = '\0'; - err = errno; - } else { - err = 0; - } - return make_string_error(ctx, buf, err); -} - -static JSValue js_os_chdir(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *target; - int err; - - target = JS_ToCString(ctx, argv[0]); - if (!target) - return JS_EXCEPTION; - err = js_get_errno(chdir(target)); - JS_FreeCString(ctx, target); - return JS_NewInt32(ctx, err); -} - -static JSValue js_os_mkdir(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int mode, ret; - const char *path; - - if (argc >= 2) { - if (JS_ToInt32(ctx, &mode, argv[1])) - return JS_EXCEPTION; - } else { - mode = 0777; - } - path = JS_ToCString(ctx, argv[0]); - if (!path) - return JS_EXCEPTION; -#if defined(_WIN32) - (void)mode; - ret = js_get_errno(mkdir(path)); -#else - ret = js_get_errno(mkdir(path, mode)); -#endif - JS_FreeCString(ctx, path); - return JS_NewInt32(ctx, ret); -} - -/* return [array, errorcode] */ -static JSValue js_os_readdir(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *path; - DIR *f; - struct dirent *d; - JSValue obj; - int err; - uint32_t len; - - path = JS_ToCString(ctx, argv[0]); - if (!path) - return JS_EXCEPTION; - obj = JS_NewArray(ctx); - if (JS_IsException(obj)) { - JS_FreeCString(ctx, path); - return JS_EXCEPTION; - } - f = opendir(path); - if (!f) - err = errno; - else - err = 0; - JS_FreeCString(ctx, path); - if (!f) - goto done; - len = 0; - for(;;) { - errno = 0; - d = readdir(f); - if (!d) { - err = errno; - break; - } - JS_DefinePropertyValueUint32(ctx, obj, len++, - JS_NewString(ctx, d->d_name), - JS_PROP_C_W_E); - } - closedir(f); - done: - return make_obj_error(ctx, obj, err); -} - -#if !defined(_WIN32) -static int64_t timespec_to_ms(const struct timespec *tv) -{ - return (int64_t)tv->tv_sec * 1000 + (tv->tv_nsec / 1000000); -} -#endif - -/* return [obj, errcode] */ -static JSValue js_os_stat(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int is_lstat) -{ - const char *path; - int err, res; - struct stat st; - JSValue obj; - - path = JS_ToCString(ctx, argv[0]); - if (!path) - return JS_EXCEPTION; -#if defined(_WIN32) - res = stat(path, &st); -#else - if (is_lstat) - res = lstat(path, &st); - else - res = stat(path, &st); -#endif - JS_FreeCString(ctx, path); - if (res < 0) { - err = errno; - obj = JS_NULL; - } else { - err = 0; - obj = JS_NewObject(ctx); - if (JS_IsException(obj)) - return JS_EXCEPTION; - JS_DefinePropertyValueStr(ctx, obj, "dev", - JS_NewInt64(ctx, st.st_dev), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "ino", - JS_NewInt64(ctx, st.st_ino), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "mode", - JS_NewInt32(ctx, st.st_mode), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "nlink", - JS_NewInt64(ctx, st.st_nlink), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "uid", - JS_NewInt64(ctx, st.st_uid), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "gid", - JS_NewInt64(ctx, st.st_gid), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "rdev", - JS_NewInt64(ctx, st.st_rdev), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "size", - JS_NewInt64(ctx, st.st_size), - JS_PROP_C_W_E); -#if !defined(_WIN32) - JS_DefinePropertyValueStr(ctx, obj, "blocks", - JS_NewInt64(ctx, st.st_blocks), - JS_PROP_C_W_E); -#endif -#if defined(_WIN32) - JS_DefinePropertyValueStr(ctx, obj, "atime", - JS_NewInt64(ctx, (int64_t)st.st_atime * 1000), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "mtime", - JS_NewInt64(ctx, (int64_t)st.st_mtime * 1000), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "ctime", - JS_NewInt64(ctx, (int64_t)st.st_ctime * 1000), - JS_PROP_C_W_E); -#elif defined(__APPLE__) - JS_DefinePropertyValueStr(ctx, obj, "atime", - JS_NewInt64(ctx, timespec_to_ms(&st.st_atimespec)), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "mtime", - JS_NewInt64(ctx, timespec_to_ms(&st.st_mtimespec)), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "ctime", - JS_NewInt64(ctx, timespec_to_ms(&st.st_ctimespec)), - JS_PROP_C_W_E); -#else - JS_DefinePropertyValueStr(ctx, obj, "atime", - JS_NewInt64(ctx, timespec_to_ms(&st.st_atim)), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "mtime", - JS_NewInt64(ctx, timespec_to_ms(&st.st_mtim)), - JS_PROP_C_W_E); - JS_DefinePropertyValueStr(ctx, obj, "ctime", - JS_NewInt64(ctx, timespec_to_ms(&st.st_ctim)), - JS_PROP_C_W_E); -#endif - } - return make_obj_error(ctx, obj, err); -} - -#if !defined(_WIN32) -static void ms_to_timeval(struct timeval *tv, uint64_t v) -{ - tv->tv_sec = v / 1000; - tv->tv_usec = (v % 1000) * 1000; -} -#endif - -static JSValue js_os_utimes(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *path; - int64_t atime, mtime; - int ret; - - if (JS_ToInt64(ctx, &atime, argv[1])) - return JS_EXCEPTION; - if (JS_ToInt64(ctx, &mtime, argv[2])) - return JS_EXCEPTION; - path = JS_ToCString(ctx, argv[0]); - if (!path) - return JS_EXCEPTION; -#if defined(_WIN32) - { - struct _utimbuf times; - times.actime = atime / 1000; - times.modtime = mtime / 1000; - ret = js_get_errno(_utime(path, ×)); - } -#else - { - struct timeval times[2]; - ms_to_timeval(×[0], atime); - ms_to_timeval(×[1], mtime); - ret = js_get_errno(utimes(path, times)); - } -#endif - JS_FreeCString(ctx, path); - return JS_NewInt32(ctx, ret); -} - -/* sleep(delay_ms) */ -static JSValue js_os_sleep(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int64_t delay; - int ret; - - if (JS_ToInt64(ctx, &delay, argv[0])) - return JS_EXCEPTION; - if (delay < 0) - delay = 0; -#if defined(_WIN32) - { - if (delay > INT32_MAX) - delay = INT32_MAX; - Sleep(delay); - ret = 0; - } -#else - { - struct timespec ts; - - ts.tv_sec = delay / 1000; - ts.tv_nsec = (delay % 1000) * 1000000; - ret = js_get_errno(nanosleep(&ts, NULL)); - } -#endif - return JS_NewInt32(ctx, ret); -} - -/* return [path, errorcode] */ -static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *path; - char buf[MAXPATH], *res; - int err; - - path = JS_ToCString(ctx, argv[0]); - if (!path) - return JS_EXCEPTION; - res = realpath(path, buf); - JS_FreeCString(ctx, path); - if (!res) { - buf[0] = '\0'; - err = errno; - } else { - err = 0; - } - return make_string_error(ctx, buf, err); -} - -#if !defined(_WIN32) -static JSValue js_os_symlink(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *target, *linkpath; - int err; - - target = JS_ToCString(ctx, argv[0]); - if (!target) - return JS_EXCEPTION; - linkpath = JS_ToCString(ctx, argv[1]); - if (!linkpath) { - JS_FreeCString(ctx, target); - return JS_EXCEPTION; - } - err = js_get_errno(symlink(target, linkpath)); - JS_FreeCString(ctx, target); - JS_FreeCString(ctx, linkpath); - return JS_NewInt32(ctx, err); -} - -/* return [path, errorcode] */ -static JSValue js_os_readlink(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *path; - char buf[MAXPATH]; - int err; - ssize_t res; - - path = JS_ToCString(ctx, argv[0]); - if (!path) - return JS_EXCEPTION; - res = readlink(path, buf, sizeof(buf) - 1); - if (res < 0) { - buf[0] = '\0'; - err = errno; - } else { - buf[res] = '\0'; - err = 0; - } - JS_FreeCString(ctx, path); - return make_string_error(ctx, buf, err); -} - -static char **build_envp(JSContext *ctx, JSValueConst obj) -{ - uint32_t len, i; - JSPropertyEnum *tab; - char **envp, *pair; - const char *key, *str; - JSValue val; - size_t key_len, str_len; - - if (JS_GetOwnPropertyNames(ctx, &tab, &len, obj, - JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0) - return NULL; - envp = js_mallocz(ctx, sizeof(envp[0]) * ((size_t)len + 1)); - if (!envp) - goto fail; - for(i = 0; i < len; i++) { - val = JS_GetProperty(ctx, obj, tab[i].atom); - if (JS_IsException(val)) - goto fail; - str = JS_ToCString(ctx, val); - JS_FreeValue(ctx, val); - if (!str) - goto fail; - key = JS_AtomToCString(ctx, tab[i].atom); - if (!key) { - JS_FreeCString(ctx, str); - goto fail; - } - key_len = strlen(key); - str_len = strlen(str); - pair = js_malloc(ctx, key_len + str_len + 2); - if (!pair) { - JS_FreeCString(ctx, key); - JS_FreeCString(ctx, str); - goto fail; - } - memcpy(pair, key, key_len); - pair[key_len] = '='; - memcpy(pair + key_len + 1, str, str_len); - pair[key_len + 1 + str_len] = '\0'; - envp[i] = pair; - JS_FreeCString(ctx, key); - JS_FreeCString(ctx, str); - } - done: - for(i = 0; i < len; i++) - JS_FreeAtom(ctx, tab[i].atom); - js_free(ctx, tab); - return envp; - fail: - if (envp) { - for(i = 0; i < len; i++) - js_free(ctx, envp[i]); - js_free(ctx, envp); - envp = NULL; - } - goto done; -} - -/* exec(args[, options]) -> exitcode */ -static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst options, args = argv[0]; - JSValue val, ret_val; - const char **exec_argv, *file = NULL, *str, *cwd = NULL; - char **envp = environ; - uint32_t exec_argc, i; - int ret, pid, status; - BOOL block_flag = TRUE, use_path = TRUE; - static const char *std_name[3] = { "stdin", "stdout", "stderr" }; - int std_fds[3]; - uint32_t uid = -1, gid = -1; - - val = JS_GetPropertyStr(ctx, args, "length"); - if (JS_IsException(val)) - return JS_EXCEPTION; - ret = JS_ToUint32(ctx, &exec_argc, val); - JS_FreeValue(ctx, val); - if (ret) - return JS_EXCEPTION; - /* arbitrary limit to avoid overflow */ - if (exec_argc < 1 || exec_argc > 65535) { - return JS_ThrowTypeError(ctx, "invalid number of arguments"); - } - exec_argv = js_mallocz(ctx, sizeof(exec_argv[0]) * (exec_argc + 1)); - if (!exec_argv) - return JS_EXCEPTION; - for(i = 0; i < exec_argc; i++) { - val = JS_GetPropertyUint32(ctx, args, i); - if (JS_IsException(val)) - goto exception; - str = JS_ToCString(ctx, val); - JS_FreeValue(ctx, val); - if (!str) - goto exception; - exec_argv[i] = str; - } - exec_argv[exec_argc] = NULL; - - for(i = 0; i < 3; i++) - std_fds[i] = i; - - /* get the options, if any */ - if (argc >= 2) { - options = argv[1]; - - if (get_bool_option(ctx, &block_flag, options, "block")) - goto exception; - if (get_bool_option(ctx, &use_path, options, "usePath")) - goto exception; - - val = JS_GetPropertyStr(ctx, options, "file"); - if (JS_IsException(val)) - goto exception; - if (!JS_IsUndefined(val)) { - file = JS_ToCString(ctx, val); - JS_FreeValue(ctx, val); - if (!file) - goto exception; - } - - val = JS_GetPropertyStr(ctx, options, "cwd"); - if (JS_IsException(val)) - goto exception; - if (!JS_IsUndefined(val)) { - cwd = JS_ToCString(ctx, val); - JS_FreeValue(ctx, val); - if (!cwd) - goto exception; - } - - /* stdin/stdout/stderr handles */ - for(i = 0; i < 3; i++) { - val = JS_GetPropertyStr(ctx, options, std_name[i]); - if (JS_IsException(val)) - goto exception; - if (!JS_IsUndefined(val)) { - int fd; - ret = JS_ToInt32(ctx, &fd, val); - JS_FreeValue(ctx, val); - if (ret) - goto exception; - std_fds[i] = fd; - } - } - - val = JS_GetPropertyStr(ctx, options, "env"); - if (JS_IsException(val)) - goto exception; - if (!JS_IsUndefined(val)) { - envp = build_envp(ctx, val); - JS_FreeValue(ctx, val); - if (!envp) - goto exception; - } - - val = JS_GetPropertyStr(ctx, options, "uid"); - if (JS_IsException(val)) - goto exception; - if (!JS_IsUndefined(val)) { - ret = JS_ToUint32(ctx, &uid, val); - JS_FreeValue(ctx, val); - if (ret) - goto exception; - } - - val = JS_GetPropertyStr(ctx, options, "gid"); - if (JS_IsException(val)) - goto exception; - if (!JS_IsUndefined(val)) { - ret = JS_ToUint32(ctx, &gid, val); - JS_FreeValue(ctx, val); - if (ret) - goto exception; - } - } - - pid = fork(); - if (pid < 0) { - JS_ThrowTypeError(ctx, "fork error"); - goto exception; - } - if (pid == 0) { - /* child */ - int fd_max = 128 /* sysconf(_SC_OPEN_MAX) */; - - /* remap the stdin/stdout/stderr handles if necessary */ - for(i = 0; i < 3; i++) { - if (std_fds[i] != i) { - if (dup2(std_fds[i], i) < 0) - _exit(127); - } - } - - for(i = 3; i < fd_max; i++) - close(i); - if (cwd) { - if (chdir(cwd) < 0) - _exit(127); - } - if (uid != -1) { - if (setuid(uid) < 0) - _exit(127); - } - if (gid != -1) { - if (setgid(gid) < 0) - _exit(127); - } - - if (!file) - file = exec_argv[0]; - if (use_path) - ret = execvpe(file, (char **)exec_argv, envp); - else - ret = execve(file, (char **)exec_argv, envp); - _exit(127); - } - /* parent */ - if (block_flag) { - for(;;) { - ret = waitpid(pid, &status, 0); - if (ret == pid) { - if (WIFEXITED(status)) { - ret = WEXITSTATUS(status); - break; - } else if (WIFSIGNALED(status)) { - ret = -WTERMSIG(status); - break; - } - } - } - } else { - ret = pid; - } - ret_val = JS_NewInt32(ctx, ret); - done: - JS_FreeCString(ctx, file); - JS_FreeCString(ctx, cwd); - for(i = 0; i < exec_argc; i++) - JS_FreeCString(ctx, exec_argv[i]); - js_free(ctx, exec_argv); - if (envp != environ) { - char **p; - p = envp; - while (*p != NULL) { - js_free(ctx, *p); - p++; - } - js_free(ctx, envp); - } - return ret_val; - exception: - ret_val = JS_EXCEPTION; - goto done; -} - -/* waitpid(pid, block) -> [pid, status] */ -static JSValue js_os_waitpid(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int pid, status, options, ret; - JSValue obj; - - if (JS_ToInt32(ctx, &pid, argv[0])) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &options, argv[1])) - return JS_EXCEPTION; - - ret = waitpid(pid, &status, options); - if (ret < 0) { - ret = -errno; - status = 0; - } - - obj = JS_NewArray(ctx); - if (JS_IsException(obj)) - return obj; - JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, ret), - JS_PROP_C_W_E); - JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, status), - JS_PROP_C_W_E); - return obj; -} - -/* pipe() -> [read_fd, write_fd] or null if error */ -static JSValue js_os_pipe(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int pipe_fds[2], ret; - JSValue obj; - - ret = pipe(pipe_fds); - if (ret < 0) - return JS_NULL; - obj = JS_NewArray(ctx); - if (JS_IsException(obj)) - return obj; - JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, pipe_fds[0]), - JS_PROP_C_W_E); - JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, pipe_fds[1]), - JS_PROP_C_W_E); - return obj; -} - -/* kill(pid, sig) */ -static JSValue js_os_kill(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int pid, sig, ret; - - if (JS_ToInt32(ctx, &pid, argv[0])) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &sig, argv[1])) - return JS_EXCEPTION; - ret = js_get_errno(kill(pid, sig)); - return JS_NewInt32(ctx, ret); -} - -/* dup(fd) */ -static JSValue js_os_dup(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int fd, ret; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - ret = js_get_errno(dup(fd)); - return JS_NewInt32(ctx, ret); -} - -/* dup2(fd) */ -static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int fd, fd2, ret; - - if (JS_ToInt32(ctx, &fd, argv[0])) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &fd2, argv[1])) - return JS_EXCEPTION; - ret = js_get_errno(dup2(fd, fd2)); - return JS_NewInt32(ctx, ret); -} - -#endif /* !_WIN32 */ - -#ifdef USE_WORKER - -/* Worker */ - -typedef struct { - JSWorkerMessagePipe *recv_pipe; - JSWorkerMessagePipe *send_pipe; - JSWorkerMessageHandler *msg_handler; -} JSWorkerData; - -typedef struct { - char *filename; /* module filename */ - char *basename_; /* module base name */ - JSWorkerMessagePipe *recv_pipe, *send_pipe; -} WorkerFuncArgs; - -typedef struct { - int ref_count; - uint64_t buf[0]; -} JSSABHeader; - -static JSClassID js_worker_class_id; -static JSContext *(*js_worker_new_context_func)(JSRuntime *rt); - -static int atomic_add_int(int *ptr, int v) -{ - return atomic_fetch_add((_Atomic(uint32_t) *)ptr, v) + v; -} - -/* shared array buffer allocator */ -static void *js_sab_alloc(void *opaque, size_t size) -{ - JSSABHeader *sab; - sab = malloc(sizeof(JSSABHeader) + size); - if (!sab) - return NULL; - sab->ref_count = 1; - return sab->buf; -} - -static void js_sab_free(void *opaque, void *ptr) -{ - JSSABHeader *sab; - int ref_count; - sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader)); - ref_count = atomic_add_int(&sab->ref_count, -1); - assert(ref_count >= 0); - if (ref_count == 0) { - free(sab); - } -} - -static void js_sab_dup(void *opaque, void *ptr) -{ - JSSABHeader *sab; - sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader)); - atomic_add_int(&sab->ref_count, 1); -} - -static JSWorkerMessagePipe *js_new_message_pipe(void) -{ - JSWorkerMessagePipe *ps; - int pipe_fds[2]; - - if (pipe(pipe_fds) < 0) - return NULL; - - ps = malloc(sizeof(*ps)); - if (!ps) { - close(pipe_fds[0]); - close(pipe_fds[1]); - return NULL; - } - ps->ref_count = 1; - init_list_head(&ps->msg_queue); - pthread_mutex_init(&ps->mutex, NULL); - ps->read_fd = pipe_fds[0]; - ps->write_fd = pipe_fds[1]; - return ps; -} - -static JSWorkerMessagePipe *js_dup_message_pipe(JSWorkerMessagePipe *ps) -{ - atomic_add_int(&ps->ref_count, 1); - return ps; -} - -static void js_free_message(JSWorkerMessage *msg) -{ - size_t i; - /* free the SAB */ - for(i = 0; i < msg->sab_tab_len; i++) { - js_sab_free(NULL, msg->sab_tab[i]); - } - free(msg->sab_tab); - free(msg->data); - free(msg); -} - -static void js_free_message_pipe(JSWorkerMessagePipe *ps) -{ - struct list_head *el, *el1; - JSWorkerMessage *msg; - int ref_count; - - if (!ps) - return; - - ref_count = atomic_add_int(&ps->ref_count, -1); - assert(ref_count >= 0); - if (ref_count == 0) { - list_for_each_safe(el, el1, &ps->msg_queue) { - msg = list_entry(el, JSWorkerMessage, link); - js_free_message(msg); - } - pthread_mutex_destroy(&ps->mutex); - close(ps->read_fd); - close(ps->write_fd); - free(ps); - } -} - -static void js_free_port(JSRuntime *rt, JSWorkerMessageHandler *port) -{ - if (port) { - js_free_message_pipe(port->recv_pipe); - JS_FreeValueRT(rt, port->on_message_func); - list_del(&port->link); - js_free_rt(rt, port); - } -} - -static void js_worker_finalizer(JSRuntime *rt, JSValue val) -{ - JSWorkerData *worker = JS_GetOpaque(val, js_worker_class_id); - if (worker) { - js_free_message_pipe(worker->recv_pipe); - js_free_message_pipe(worker->send_pipe); - js_free_port(rt, worker->msg_handler); - js_free_rt(rt, worker); - } -} - -static JSClassDef js_worker_class = { - "Worker", - .finalizer = js_worker_finalizer, -}; - -static void *worker_func(void *opaque) -{ - WorkerFuncArgs *args = opaque; - JSRuntime *rt; - JSThreadState *ts; - JSContext *ctx; - - rt = JS_NewRuntime(); - if (rt == NULL) { - fprintf(stderr, "JS_NewRuntime failure"); - exit(1); - } - js_std_init_handlers(rt); - - JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); - - /* set the pipe to communicate with the parent */ - ts = JS_GetRuntimeOpaque(rt); - ts->recv_pipe = args->recv_pipe; - ts->send_pipe = args->send_pipe; - - /* function pointer to avoid linking the whole JS_NewContext() if - not needed */ - ctx = js_worker_new_context_func(rt); - if (ctx == NULL) { - fprintf(stderr, "JS_NewContext failure"); - } - - JS_SetCanBlock(rt, TRUE); - - js_std_add_helpers(ctx, -1, NULL); - - if (!JS_RunModule(ctx, args->basename_, args->filename)) - js_std_dump_error(ctx); - free(args->filename); - free(args->basename_); - free(args); - - js_std_loop(ctx); - - JS_FreeContext(ctx); - js_std_free_handlers(rt); - JS_FreeRuntime(rt); - return NULL; -} - -static JSValue js_worker_ctor_internal(JSContext *ctx, JSValueConst new_target, - JSWorkerMessagePipe *recv_pipe, - JSWorkerMessagePipe *send_pipe) -{ - JSValue obj = JS_UNDEFINED, proto; - JSWorkerData *s; - - /* create the object */ - if (JS_IsUndefined(new_target)) { - proto = JS_GetClassProto(ctx, js_worker_class_id); - } else { - proto = JS_GetPropertyStr(ctx, new_target, "prototype"); - if (JS_IsException(proto)) - goto fail; - } - obj = JS_NewObjectProtoClass(ctx, proto, js_worker_class_id); - JS_FreeValue(ctx, proto); - if (JS_IsException(obj)) - goto fail; - s = js_mallocz(ctx, sizeof(*s)); - if (!s) - goto fail; - s->recv_pipe = js_dup_message_pipe(recv_pipe); - s->send_pipe = js_dup_message_pipe(send_pipe); - - JS_SetOpaque(obj, s); - return obj; - fail: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) -{ - JSRuntime *rt = JS_GetRuntime(ctx); - WorkerFuncArgs *args = NULL; - pthread_t tid; - pthread_attr_t attr; - JSValue obj = JS_UNDEFINED; - int ret; - const char *filename = NULL, *basename; - JSAtom basename_atom; - - /* XXX: in order to avoid problems with resource liberation, we - don't support creating workers inside workers */ - if (!is_main_thread(rt)) - return JS_ThrowTypeError(ctx, "cannot create a worker inside a worker"); - - /* base name, assuming the calling function is a normal JS - function */ - basename_atom = JS_GetScriptOrModuleName(ctx, 1); - if (basename_atom == JS_ATOM_NULL) { - return JS_ThrowTypeError(ctx, "could not determine calling script or module name"); - } - basename = JS_AtomToCString(ctx, basename_atom); - JS_FreeAtom(ctx, basename_atom); - if (!basename) - goto fail; - - /* module name */ - filename = JS_ToCString(ctx, argv[0]); - if (!filename) - goto fail; - - args = malloc(sizeof(*args)); - if (!args) - goto oom_fail; - bzero(args, sizeof(*args)); - args->filename = strdup(filename); - args->basename_ = strdup(basename); - - /* ports */ - args->recv_pipe = js_new_message_pipe(); - if (!args->recv_pipe) - goto oom_fail; - args->send_pipe = js_new_message_pipe(); - if (!args->send_pipe) - goto oom_fail; - - obj = js_worker_ctor_internal(ctx, new_target, - args->send_pipe, args->recv_pipe); - if (JS_IsException(obj)) - goto fail; - - pthread_attr_init(&attr); - /* no join at the end */ - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - ret = pthread_create(&tid, &attr, worker_func, args); - pthread_attr_destroy(&attr); - if (ret != 0) { - JS_ThrowTypeError(ctx, "could not create worker"); - goto fail; - } - JS_FreeCString(ctx, basename); - JS_FreeCString(ctx, filename); - return obj; - oom_fail: - JS_ThrowOutOfMemory(ctx); - fail: - JS_FreeCString(ctx, basename); - JS_FreeCString(ctx, filename); - if (args) { - free(args->filename); - free(args->basename_); - js_free_message_pipe(args->recv_pipe); - js_free_message_pipe(args->send_pipe); - free(args); - } - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue js_worker_postMessage(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id); - JSWorkerMessagePipe *ps; - size_t data_len, sab_tab_len, i; - uint8_t *data; - JSWorkerMessage *msg; - uint8_t **sab_tab; - - if (!worker) - return JS_EXCEPTION; - - data = JS_WriteObject2(ctx, &data_len, argv[0], - JS_WRITE_OBJ_SAB | JS_WRITE_OBJ_REFERENCE, - &sab_tab, &sab_tab_len); - if (!data) - return JS_EXCEPTION; - - msg = malloc(sizeof(*msg)); - if (!msg) - goto fail; - msg->data = NULL; - msg->sab_tab = NULL; - - /* must reallocate because the allocator may be different */ - msg->data = malloc(data_len); - if (!msg->data) - goto fail; - memcpy(msg->data, data, data_len); - msg->data_len = data_len; - - msg->sab_tab = malloc(sizeof(msg->sab_tab[0]) * sab_tab_len); - if (!msg->sab_tab) - goto fail; - memcpy(msg->sab_tab, sab_tab, sizeof(msg->sab_tab[0]) * sab_tab_len); - msg->sab_tab_len = sab_tab_len; - - js_free(ctx, data); - js_free(ctx, sab_tab); - - /* increment the SAB reference counts */ - for(i = 0; i < msg->sab_tab_len; i++) { - js_sab_dup(NULL, msg->sab_tab[i]); - } - - ps = worker->send_pipe; - pthread_mutex_lock(&ps->mutex); - /* indicate that data is present */ - if (list_empty(&ps->msg_queue)) { - uint8_t ch = '\0'; - int ret; - for(;;) { - ret = write(ps->write_fd, &ch, 1); - if (ret == 1) - break; - if (ret < 0 && (errno != EAGAIN || errno != EINTR)) - break; - } - } - list_add_tail(&msg->link, &ps->msg_queue); - pthread_mutex_unlock(&ps->mutex); - return JS_UNDEFINED; - fail: - if (msg) { - free(msg->data); - free(msg->sab_tab); - free(msg); - } - js_free(ctx, data); - js_free(ctx, sab_tab); - return JS_EXCEPTION; - -} - -static JSValue js_worker_set_onmessage(JSContext *ctx, JSValueConst this_val, - JSValueConst func) -{ - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id); - JSWorkerMessageHandler *port; - - if (!worker) - return JS_EXCEPTION; - - port = worker->msg_handler; - if (JS_IsNull(func)) { - if (port) { - js_free_port(rt, port); - worker->msg_handler = NULL; - } - } else { - if (!JS_IsFunction(ctx, func)) - return JS_ThrowTypeError(ctx, "not a function"); - if (!port) { - port = js_mallocz(ctx, sizeof(*port)); - if (!port) - return JS_EXCEPTION; - port->recv_pipe = js_dup_message_pipe(worker->recv_pipe); - port->on_message_func = JS_NULL; - list_add_tail(&port->link, &ts->port_list); - worker->msg_handler = port; - } - JS_FreeValue(ctx, port->on_message_func); - port->on_message_func = JS_DupValue(ctx, func); - } - return JS_UNDEFINED; -} - -static JSValue js_worker_get_onmessage(JSContext *ctx, JSValueConst this_val) -{ - JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id); - JSWorkerMessageHandler *port; - if (!worker) - return JS_EXCEPTION; - port = worker->msg_handler; - if (port) { - return JS_DupValue(ctx, port->on_message_func); - } else { - return JS_NULL; - } -} - -static const JSCFunctionListEntry js_worker_proto_funcs[] = { - JS_CFUNC_DEF("postMessage", 1, js_worker_postMessage ), - JS_CGETSET_DEF("onmessage", js_worker_get_onmessage, js_worker_set_onmessage ), -}; - -#endif /* USE_WORKER */ - -void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt)) -{ -#ifdef USE_WORKER - js_worker_new_context_func = func; -#endif -} - -#if defined(_WIN32) -#define OS_PLATFORM "win32" -#elif defined(__APPLE__) -#define OS_PLATFORM "darwin" -#elif defined(EMSCRIPTEN) -#define OS_PLATFORM "js" -#else -#define OS_PLATFORM "linux" -#endif - -#define OS_FLAG(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE ) - -static JSCFunctionListEntry js_os_funcs[68]; -static textstartup void js_os_funcs_init() { - JSCFunctionListEntry funcs[] = { - JS_CFUNC_DEF("open", 2, js_os_open ), - OS_FLAG(O_RDONLY), - OS_FLAG(O_WRONLY), - OS_FLAG(O_RDWR), - OS_FLAG(O_APPEND), - OS_FLAG(O_CREAT), - OS_FLAG(O_EXCL), - OS_FLAG(O_TRUNC), -#if defined(_WIN32) - OS_FLAG(O_BINARY), - OS_FLAG(O_TEXT), -#endif - JS_CFUNC_DEF("close", 1, js_os_close ), - JS_CFUNC_DEF("seek", 3, js_os_seek ), - JS_CFUNC_MAGIC_DEF("read", 4, js_os_read_write, 0 ), - JS_CFUNC_MAGIC_DEF("write", 4, js_os_read_write, 1 ), - JS_CFUNC_DEF("isatty", 1, js_os_isatty ), - JS_CFUNC_DEF("ttyGetWinSize", 1, js_os_ttyGetWinSize ), - JS_CFUNC_DEF("ttySetRaw", 1, js_os_ttySetRaw ), - JS_CFUNC_DEF("remove", 1, js_os_remove ), - JS_CFUNC_DEF("rename", 2, js_os_rename ), - JS_CFUNC_MAGIC_DEF("setReadHandler", 2, js_os_setReadHandler, 0 ), - JS_CFUNC_MAGIC_DEF("setWriteHandler", 2, js_os_setReadHandler, 1 ), - JS_CFUNC_DEF("signal", 2, js_os_signal ), - OS_FLAG(SIGINT), - OS_FLAG(SIGABRT), - OS_FLAG(SIGFPE), - OS_FLAG(SIGILL), - OS_FLAG(SIGSEGV), - OS_FLAG(SIGTERM), -#if !defined(_WIN32) - OS_FLAG(SIGQUIT), - OS_FLAG(SIGPIPE), - OS_FLAG(SIGALRM), - OS_FLAG(SIGUSR1), - OS_FLAG(SIGUSR2), - OS_FLAG(SIGCHLD), - OS_FLAG(SIGCONT), - OS_FLAG(SIGSTOP), - OS_FLAG(SIGTSTP), - OS_FLAG(SIGTTIN), - OS_FLAG(SIGTTOU), -#endif - JS_CFUNC_DEF("setTimeout", 2, js_os_setTimeout ), - JS_CFUNC_DEF("clearTimeout", 1, js_os_clearTimeout ), - JS_PROP_STRING_DEF("platform", OS_PLATFORM, 0 ), - JS_CFUNC_DEF("getcwd", 0, js_os_getcwd ), - JS_CFUNC_DEF("chdir", 0, js_os_chdir ), - JS_CFUNC_DEF("mkdir", 1, js_os_mkdir ), - JS_CFUNC_DEF("readdir", 1, js_os_readdir ), - /* st_mode constants */ - OS_FLAG(S_IFMT), - OS_FLAG(S_IFIFO), - OS_FLAG(S_IFCHR), - OS_FLAG(S_IFDIR), - OS_FLAG(S_IFBLK), - OS_FLAG(S_IFREG), -#if !defined(_WIN32) - OS_FLAG(S_IFSOCK), - OS_FLAG(S_IFLNK), - OS_FLAG(S_ISGID), - OS_FLAG(S_ISUID), -#endif - JS_CFUNC_MAGIC_DEF("stat", 1, js_os_stat, 0 ), - JS_CFUNC_DEF("utimes", 3, js_os_utimes ), - JS_CFUNC_DEF("sleep", 1, js_os_sleep ), - JS_CFUNC_DEF("realpath", 1, js_os_realpath ), -#if !defined(_WIN32) - JS_CFUNC_MAGIC_DEF("lstat", 1, js_os_stat, 1 ), - JS_CFUNC_DEF("symlink", 2, js_os_symlink ), - JS_CFUNC_DEF("readlink", 1, js_os_readlink ), - JS_CFUNC_DEF("exec", 1, js_os_exec ), - JS_CFUNC_DEF("waitpid", 2, js_os_waitpid ), - OS_FLAG(WNOHANG), - JS_CFUNC_DEF("pipe", 0, js_os_pipe ), - JS_CFUNC_DEF("kill", 2, js_os_kill ), - JS_CFUNC_DEF("dup", 1, js_os_dup ), - JS_CFUNC_DEF("dup2", 2, js_os_dup2 ), -#endif - }; - _Static_assert(sizeof(js_os_funcs) == sizeof(funcs), ""); - memcpy(js_os_funcs, funcs, sizeof(funcs)); -} -const void *const js_os_funcs_ctor[] initarray = {js_os_funcs_init}; - -static int js_os_init(JSContext *ctx, JSModuleDef *m) -{ - os_poll_func = js_os_poll; - - /* OSTimer class */ - JS_NewClassID(&js_os_timer_class_id); - JS_NewClass(JS_GetRuntime(ctx), js_os_timer_class_id, &js_os_timer_class); - -#ifdef USE_WORKER - { - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - JSValue proto, obj; - /* Worker class */ - JS_NewClassID(&js_worker_class_id); - JS_NewClass(JS_GetRuntime(ctx), js_worker_class_id, &js_worker_class); - proto = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, proto, js_worker_proto_funcs, countof(js_worker_proto_funcs)); - - obj = JS_NewCFunction2(ctx, js_worker_ctor, "Worker", 1, - JS_CFUNC_constructor, 0); - JS_SetConstructor(ctx, obj, proto); - - JS_SetClassProto(ctx, js_worker_class_id, proto); - - /* set 'Worker.parent' if necessary */ - if (ts->recv_pipe && ts->send_pipe) { - JS_DefinePropertyValueStr(ctx, obj, "parent", - js_worker_ctor_internal(ctx, JS_UNDEFINED, ts->recv_pipe, ts->send_pipe), - JS_PROP_C_W_E); - } - - JS_SetModuleExport(ctx, m, "Worker", obj); - } -#endif /* USE_WORKER */ - - return JS_SetModuleExportList(ctx, m, js_os_funcs, - countof(js_os_funcs)); -} - -JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name) -{ - JSModuleDef *m; - m = JS_NewCModule(ctx, module_name, js_os_init); - if (!m) - return NULL; - JS_AddModuleExportList(ctx, m, js_os_funcs, countof(js_os_funcs)); -#ifdef USE_WORKER - JS_AddModuleExport(ctx, m, "Worker"); -#endif - return m; -} - -/**********************************************************/ - -static JSValue js_print(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int i; - const char *str; - size_t len; - - for(i = 0; i < argc; i++) { - if (i != 0) - putchar(' '); - str = JS_ToCStringLen(ctx, &len, argv[i]); - if (!str) - return JS_EXCEPTION; - fwrite(str, 1, len, stdout); - JS_FreeCString(ctx, str); - } - putchar('\n'); - return JS_UNDEFINED; -} - -void js_std_add_helpers(JSContext *ctx, int argc, char **argv) -{ - JSValue global_obj, console, args; - int i; - - /* XXX: should these global definitions be enumerable? */ - global_obj = JS_GetGlobalObject(ctx); - - console = JS_NewObject(ctx); - JS_SetPropertyStr(ctx, console, "log", - JS_NewCFunction(ctx, js_print, "log", 1)); - JS_SetPropertyStr(ctx, global_obj, "console", console); - - /* same methods as the mozilla JS shell */ - if (argc >= 0) { - args = JS_NewArray(ctx); - for(i = 0; i < argc; i++) { - JS_SetPropertyUint32(ctx, args, i, JS_NewString(ctx, argv[i])); - } - JS_SetPropertyStr(ctx, global_obj, "scriptArgs", args); - } - - JS_SetPropertyStr(ctx, global_obj, "print", - JS_NewCFunction(ctx, js_print, "print", 1)); - JS_SetPropertyStr(ctx, global_obj, "__loadScript", - JS_NewCFunction(ctx, js_loadScript, "__loadScript", 1)); - - JS_FreeValue(ctx, global_obj); -} - -void js_std_init_handlers(JSRuntime *rt) -{ - JSThreadState *ts; - - ts = malloc(sizeof(*ts)); - if (!ts) { - fprintf(stderr, "Could not allocate memory for the worker"); - exit(1); - } - bzero(ts, sizeof(*ts)); - init_list_head(&ts->os_rw_handlers); - init_list_head(&ts->os_signal_handlers); - init_list_head(&ts->os_timers); - init_list_head(&ts->port_list); - - JS_SetRuntimeOpaque(rt, ts); - -#ifdef USE_WORKER - /* set the SharedArrayBuffer memory handlers */ - { - JSSharedArrayBufferFunctions sf; - bzero(&sf, sizeof(sf)); - sf.sab_alloc = js_sab_alloc; - sf.sab_free = js_sab_free; - sf.sab_dup = js_sab_dup; - JS_SetSharedArrayBufferFunctions(rt, &sf); - } -#endif -} - -void js_std_free_handlers(JSRuntime *rt) -{ - JSThreadState *ts = JS_GetRuntimeOpaque(rt); - struct list_head *el, *el1; - - list_for_each_safe(el, el1, &ts->os_rw_handlers) { - JSOSRWHandler *rh = list_entry(el, JSOSRWHandler, link); - free_rw_handler(rt, rh); - } - - list_for_each_safe(el, el1, &ts->os_signal_handlers) { - JSOSSignalHandler *sh = list_entry(el, JSOSSignalHandler, link); - free_sh(rt, sh); - } - - list_for_each_safe(el, el1, &ts->os_timers) { - JSOSTimer *th = list_entry(el, JSOSTimer, link); - unlink_timer(rt, th); - if (!th->has_object) - free_timer(rt, th); - } - -#ifdef USE_WORKER - /* XXX: free port_list ? */ - js_free_message_pipe(ts->recv_pipe); - js_free_message_pipe(ts->send_pipe); -#endif - - free(ts); - JS_SetRuntimeOpaque(rt, NULL); /* fail safe */ -} - -static void js_dump_obj(JSContext *ctx, FILE *f, JSValueConst val) -{ - const char *str; - - str = JS_ToCString(ctx, val); - if (str) { - fprintf(f, "%s\n", str); - JS_FreeCString(ctx, str); - } else { - fprintf(f, "[exception]\n"); - } -} - -static void js_std_dump_error1(JSContext *ctx, JSValueConst exception_val) -{ - JSValue val; - BOOL is_error; - - is_error = JS_IsError(ctx, exception_val); - js_dump_obj(ctx, stderr, exception_val); - if (is_error) { - val = JS_GetPropertyStr(ctx, exception_val, "stack"); - if (!JS_IsUndefined(val)) { - js_dump_obj(ctx, stderr, val); - } - JS_FreeValue(ctx, val); - } -} - -void js_std_dump_error(JSContext *ctx) -{ - JSValue exception_val; - - exception_val = JS_GetException(ctx); - js_std_dump_error1(ctx, exception_val); - JS_FreeValue(ctx, exception_val); -} - -void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise, - JSValueConst reason, - BOOL is_handled, void *opaque) -{ - if (!is_handled) { - fprintf(stderr, "Possibly unhandled promise rejection: "); - js_std_dump_error1(ctx, reason); - } -} - -/* main loop which calls the user JS callbacks */ -void js_std_loop(JSContext *ctx) -{ - JSContext *ctx1; - int err; - - for(;;) { - /* execute the pending jobs */ - for(;;) { - err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); - if (err <= 0) { - if (err < 0) { - js_std_dump_error(ctx1); - } - break; - } - } - - if (!os_poll_func || os_poll_func(ctx)) - break; - } -} - -void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len, - int load_only) -{ - JSValue obj, val; - obj = JS_ReadObject(ctx, buf, buf_len, JS_READ_OBJ_BYTECODE); - if (JS_IsException(obj)) - goto exception; - if (load_only) { - if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) { - js_module_set_import_meta(ctx, obj, FALSE, FALSE); - } - } else { - if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) { - if (JS_ResolveModule(ctx, obj) < 0) { - JS_FreeValue(ctx, obj); - goto exception; - } - js_module_set_import_meta(ctx, obj, FALSE, TRUE); - } - val = JS_EvalFunction(ctx, obj); - if (JS_IsException(val)) { - exception: - js_std_dump_error(ctx); - exit(1); - } - JS_FreeValue(ctx, val); - } -} diff --git a/third_party/quickjs/quickjs-libc.h b/third_party/quickjs/quickjs-libc.h deleted file mode 100644 index f34c4b623..000000000 --- a/third_party/quickjs/quickjs-libc.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBC_H_ -#define COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBC_H_ -#include "third_party/quickjs/quickjs.h" -COSMOPOLITAN_C_START_ - -JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name); -JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name); -void js_std_add_helpers(JSContext *ctx, int argc, char **argv); -void js_std_loop(JSContext *ctx); -void js_std_init_handlers(JSRuntime *rt); -void js_std_free_handlers(JSRuntime *rt); -void js_std_dump_error(JSContext *ctx); -uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename); -int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, - JS_BOOL use_realpath, JS_BOOL is_main); -JSModuleDef *js_module_loader(JSContext *ctx, - const char *module_name, void *opaque); -void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len, - int flags); -void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise, - JSValueConst reason, - JS_BOOL is_handled, void *opaque); -void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt)); - -/* clang-format on */ -COSMOPOLITAN_C_END_ -#endif /* COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBC_H_ */ diff --git a/third_party/quickjs/quickjs-opcode.inc b/third_party/quickjs/quickjs-opcode.inc deleted file mode 100644 index 11b30df23..000000000 --- a/third_party/quickjs/quickjs-opcode.inc +++ /dev/null @@ -1,366 +0,0 @@ -/* - * QuickJS opcode definitions - * - * Copyright (c) 2017-2018 Fabrice Bellard - * Copyright (c) 2017-2018 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - - -#ifdef FMT -FMT(none) -FMT(none_int) -FMT(none_loc) -FMT(none_arg) -FMT(none_var_ref) -FMT(u8) -FMT(i8) -FMT(loc8) -FMT(const8) -FMT(label8) -FMT(u16) -FMT(i16) -FMT(label16) -FMT(npop) -FMT(npopx) -FMT(npop_u16) -FMT(loc) -FMT(arg) -FMT(var_ref) -FMT(u32) -FMT(i32) -FMT(const) -FMT(label) -FMT(atom) -FMT(atom_u8) -FMT(atom_u16) -FMT(atom_label_u8) -FMT(atom_label_u16) -FMT(label_u16) -#undef FMT -#endif /* FMT */ - -#ifdef DEF - -#ifndef def -#define def(id, size, n_pop, n_push, f) DEF(id, size, n_pop, n_push, f) -#endif - -DEF(invalid, 1, 0, 0, none) /* never emitted */ - -/* push values */ -DEF( push_i32, 5, 0, 1, i32) -DEF( push_const, 5, 0, 1, const) -DEF( fclosure, 5, 0, 1, const) /* must follow push_const */ -DEF(push_atom_value, 5, 0, 1, atom) -DEF( private_symbol, 5, 0, 1, atom) -DEF( undefined, 1, 0, 1, none) -DEF( null, 1, 0, 1, none) -DEF( push_this, 1, 0, 1, none) /* only used at the start of a function */ -DEF( push_false, 1, 0, 1, none) -DEF( push_true, 1, 0, 1, none) -DEF( object, 1, 0, 1, none) -DEF( special_object, 2, 0, 1, u8) /* only used at the start of a function */ -DEF( rest, 3, 0, 1, u16) /* only used at the start of a function */ - -DEF( drop, 1, 1, 0, none) /* a -> */ -DEF( nip, 1, 2, 1, none) /* a b -> b */ -DEF( nip1, 1, 3, 2, none) /* a b c -> b c */ -DEF( dup, 1, 1, 2, none) /* a -> a a */ -DEF( dup1, 1, 2, 3, none) /* a b -> a a b */ -DEF( dup2, 1, 2, 4, none) /* a b -> a b a b */ -DEF( dup3, 1, 3, 6, none) /* a b c -> a b c a b c */ -DEF( insert2, 1, 2, 3, none) /* obj a -> a obj a (dup_x1) */ -DEF( insert3, 1, 3, 4, none) /* obj prop a -> a obj prop a (dup_x2) */ -DEF( insert4, 1, 4, 5, none) /* this obj prop a -> a this obj prop a */ -DEF( perm3, 1, 3, 3, none) /* obj a b -> a obj b */ -DEF( perm4, 1, 4, 4, none) /* obj prop a b -> a obj prop b */ -DEF( perm5, 1, 5, 5, none) /* this obj prop a b -> a this obj prop b */ -DEF( swap, 1, 2, 2, none) /* a b -> b a */ -DEF( swap2, 1, 4, 4, none) /* a b c d -> c d a b */ -DEF( rot3l, 1, 3, 3, none) /* x a b -> a b x */ -DEF( rot3r, 1, 3, 3, none) /* a b x -> x a b */ -DEF( rot4l, 1, 4, 4, none) /* x a b c -> a b c x */ -DEF( rot5l, 1, 5, 5, none) /* x a b c d -> a b c d x */ - -DEF(call_constructor, 3, 2, 1, npop) /* func new.target args -> ret. arguments are not counted in n_pop */ -DEF( call, 3, 1, 1, npop) /* arguments are not counted in n_pop */ -DEF( tail_call, 3, 1, 0, npop) /* arguments are not counted in n_pop */ -DEF( call_method, 3, 2, 1, npop) /* arguments are not counted in n_pop */ -DEF(tail_call_method, 3, 2, 0, npop) /* arguments are not counted in n_pop */ -DEF( array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */ -DEF( apply, 3, 3, 1, u16) -DEF( return, 1, 1, 0, none) -DEF( return_undef, 1, 0, 0, none) -DEF(check_ctor_return, 1, 1, 2, none) -DEF( check_ctor, 1, 0, 0, none) -DEF( check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */ -DEF( add_brand, 1, 2, 0, none) /* this_obj home_obj -> */ -DEF( return_async, 1, 1, 0, none) -DEF( throw, 1, 1, 0, none) -DEF( throw_error, 6, 0, 0, atom_u8) -DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */ -DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */ -DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a - bytecode string */ -DEF( get_super, 1, 1, 1, none) -DEF( import, 1, 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(iterator_check_object, 1, 1, 1, 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( iterator_next, 1, 4, 4, none) -DEF( iterator_call, 2, 4, 5, u8) -DEF( initial_yield, 1, 0, 0, none) -DEF( yield, 1, 1, 2, none) -DEF( yield_star, 1, 1, 2, none) -DEF(async_yield_star, 1, 1, 2, none) -DEF( await, 1, 1, 1, none) - -/* arithmetic/logic operations */ -DEF( neg, 1, 1, 1, none) -DEF( plus, 1, 1, 1, none) -DEF( dec, 1, 1, 1, none) -DEF( inc, 1, 1, 1, none) -DEF( post_dec, 1, 1, 2, none) -DEF( post_inc, 1, 1, 2, none) -DEF( dec_loc, 2, 0, 0, loc8) -DEF( inc_loc, 2, 0, 0, loc8) -DEF( add_loc, 2, 1, 0, loc8) -DEF( not, 1, 1, 1, none) -DEF( lnot, 1, 1, 1, none) -DEF( typeof, 1, 1, 1, none) -DEF( delete, 1, 2, 1, none) -DEF( delete_var, 5, 0, 1, atom) - -DEF( mul, 1, 2, 1, none) -DEF( div, 1, 2, 1, none) -DEF( mod, 1, 2, 1, none) -DEF( add, 1, 2, 1, none) -DEF( sub, 1, 2, 1, none) -DEF( pow, 1, 2, 1, none) -DEF( shl, 1, 2, 1, none) -DEF( sar, 1, 2, 1, none) -DEF( shr, 1, 2, 1, none) -DEF( lt, 1, 2, 1, none) -DEF( lte, 1, 2, 1, none) -DEF( gt, 1, 2, 1, none) -DEF( gte, 1, 2, 1, none) -DEF( instanceof, 1, 2, 1, none) -DEF( in, 1, 2, 1, none) -DEF( eq, 1, 2, 1, none) -DEF( neq, 1, 2, 1, none) -DEF( strict_eq, 1, 2, 1, none) -DEF( strict_neq, 1, 2, 1, none) -DEF( and, 1, 2, 1, none) -DEF( xor, 1, 2, 1, none) -DEF( or, 1, 2, 1, none) -DEF(is_undefined_or_null, 1, 1, 1, none) -#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( 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(typeof_is_undefined, 1, 1, 1, none) -DEF( typeof_is_function, 1, 1, 1, none) -#endif - -#undef DEF -#undef def -#endif /* DEF */ diff --git a/third_party/quickjs/quickjs.c b/third_party/quickjs/quickjs.c deleted file mode 100644 index ae51202fa..000000000 --- a/third_party/quickjs/quickjs.c +++ /dev/null @@ -1,14986 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "third_party/quickjs/cutils.h" -#include "third_party/quickjs/libregexp.h" -#include "third_party/quickjs/list.h" -#include "third_party/quickjs/quickjs.h" -#include "libc/assert.h" -#include "libc/inttypes.h" -#include "libc/mem/alloca.h" -#include "third_party/gdtoa/gdtoa.h" -#include "libc/fmt/conv.h" -#include "libc/runtime/fenv.h" -#include "libc/time/time.h" -#include "libc/time/time.h" -#include "libc/calls/weirdtypes.h" -#include "libc/time/struct/tm.h" -#include "libc/log/log.h" -#include "third_party/quickjs/internal.h" -#include "third_party/quickjs/leb128.h" -#include "third_party/quickjs/internal.h" -#include "third_party/quickjs/internal.h" -#include "third_party/quickjs/internal.h" -#include "third_party/quickjs/internal.h" -#include "libc/str/str.h" -#include "libc/mem/mem.h" -#include "libc/runtime/runtime.h" -#include "third_party/quickjs/libbf.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - - -static const char js_atom_init[] = -#define DEF(name, str) str "\0" -#include "third_party/quickjs/quickjs-atom.inc" -#undef DEF -; - -static int JS_InitAtoms(JSRuntime *rt); -static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len, - int atom_type); -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 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_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_proxy_finalizer(JSRuntime *rt, JSValue val); -static void js_proxy_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 void gc_decref(JSRuntime *rt); -static int JS_NewClass1(JSRuntime *rt, JSClassID class_id, - const JSClassDef *class_def, JSAtom name); - -#ifdef CONFIG_BIGNUM -static void js_float_env_finalizer(JSRuntime *rt, JSValue val); -static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val, - BOOL allow_null_or_undefined); -#endif -static int JS_CreateProperty(JSContext *ctx, JSObject *p, - JSAtom prop, JSValueConst val, - JSValueConst getter, JSValueConst setter, - int flags); -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 JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier); -static JSValue js_new_promise_capability(JSContext *ctx, - JSValue *resolving_funcs, - JSValueConst ctor); -static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val); -static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val); -static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val); -static void JS_AddIntrinsicBasicObjects(JSContext *ctx); -static int js_shape_prepare_update(JSContext *ctx, JSObject *p, - JSShapeProperty **pprs); -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 JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); -static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom, - void *opaque); -static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p, - JSAtom atom, void *opaque); -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 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; - bzero(ptr, size); - return ptr; -} - -#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)); -} - -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; -} - -static void js_float_env_finalizer(JSRuntime *rt, JSValue val) -{ - JSFloatEnv *fe = JS_GetOpaque(val, JS_CLASS_FLOAT_ENV); - js_free_rt(rt, fe); -} - -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 */ -}; - -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; - bzero(cm, 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 */ - -JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) -{ - JSRuntime *rt; - JSMallocState ms; - bzero(&ms, sizeof(ms)); - ms.opaque = opaque; - ms.malloc_limit = -1; - rt = mf->js_malloc(&ms, sizeof(JSRuntime)); - if (!rt) - return NULL; - bzero(rt, 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_size = JS_DEFAULT_STACK_SIZE; - JS_UpdateStackTop(rt); - 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 malloc_usable_size(ptr); -#else - /* change this to `return 0;` if compilation fails */ - return 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__) || defined(__COSMOPOLITAN__) - (size_t (*)(const void *))malloc_usable_size, -#else - /* change this to `NULL,` if compilation fails */ - 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; -} - -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; -} - -void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj) -{ - JSRuntime *rt = ctx->rt; - (void)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; - (void)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; -} - -void JS_FreeContext(JSContext *ctx) -{ - JSRuntime *rt = ctx->rt; - int i; - if (--ctx->header.ref_count > 0) - return; - assert(ctx->header.ref_count == 0); -#ifdef DUMP_ATOMS - JS_DumpAtoms(ctx->rt); -#endif -#ifdef DUMP_SHAPES - JS_DumpShapes(ctx->rt); -#endif -#ifdef DUMP_OBJECTS - { - struct list_head *el; - JSGCObjectHeader *p; - printf("JSObjects: {\n"); - JS_DumpObjectHeader(ctx->rt); - list_for_each(el, &rt->gc_obj_list) { - p = list_entry(el, JSGCObjectHeader, link); - JS_DumpGCObject(rt, p); - } - printf("}\n"); - } -#endif -#ifdef DUMP_MEM - { - JSMemoryUsage stats; - JS_ComputeMemoryUsage(rt, &stats); - JS_DumpMemoryUsage(stdout, &stats, rt); - } -#endif - js_free_modules(ctx, JS_FREE_MODULE_ALL); - JS_FreeValue(ctx, ctx->global_obj); - JS_FreeValue(ctx, ctx->global_var_obj); - JS_FreeValue(ctx, ctx->throw_type_error); - JS_FreeValue(ctx, ctx->eval_obj); - JS_FreeValue(ctx, ctx->array_proto_values); - for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) { - JS_FreeValue(ctx, ctx->native_error_proto[i]); - } - for(i = 0; i < rt->class_count; i++) { - JS_FreeValue(ctx, ctx->class_proto[i]); - } - js_free_rt(rt, ctx->class_proto); - JS_FreeValue(ctx, ctx->iterator_proto); - JS_FreeValue(ctx, ctx->async_iterator_proto); - JS_FreeValue(ctx, ctx->promise_ctor); - JS_FreeValue(ctx, ctx->array_ctor); - JS_FreeValue(ctx, ctx->regexp_ctor); - JS_FreeValue(ctx, ctx->function_ctor); - JS_FreeValue(ctx, ctx->function_proto); - js_free_shape_null(ctx->rt, ctx->array_shape); - list_del(&ctx->link); - remove_gc_object(&ctx->header); - js_free_rt(ctx->rt, ctx); -} - -JSRuntime *JS_GetRuntime(JSContext *ctx) -{ - return ctx->rt; -} - -static void update_stack_limit(JSRuntime *rt) -{ - if (rt->stack_size == 0) { - rt->stack_limit = 0; /* no limit */ - } else { - rt->stack_limit = rt->stack_top - rt->stack_size; - } -} - -void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size) -{ - rt->stack_size = stack_size; - update_stack_limit(rt); -} - -void JS_UpdateStackTop(JSRuntime *rt) -{ - rt->stack_top = js_get_stack_pointer(); - update_stack_limit(rt); -} - -/* JSAtom support */ - -/* 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; -} - -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; -} - -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(); - } -} - -/* 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_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 */ -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 || !isdigit(*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); - } -} - -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 */ -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]); -} - -/* 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 (!isdigit(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 (!isdigit(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; -} - -/* 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 >= (1 << 16)) - return -1; - if (class_id < rt->class_count && - rt->class_array[class_id].class_id != 0) - return -1; - if (class_id >= rt->class_count) { - new_size = max_int(JS_CLASS_INIT_COUNT, - max_int(class_id + 1, rt->class_count * 3 / 2)); - /* reallocate the context class prototype array, if any */ - list_for_each(el, &rt->context_list) { - JSContext *ctx = list_entry(el, JSContext, link); - JSValue *new_tab; - new_tab = js_realloc_rt(rt, ctx->class_proto, - sizeof(ctx->class_proto[0]) * new_size); - if (!new_tab) - return -1; - for(i = rt->class_count; i < new_size; i++) - new_tab[i] = JS_NULL; - ctx->class_proto = new_tab; - } - /* reallocate the class array */ - new_class_array = js_realloc_rt(rt, rt->class_array, - sizeof(JSClass) * new_size); - if (!new_class_array) - return -1; - bzero(new_class_array + rt->class_count, - (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; -} - -/* 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; -} - -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 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. */ -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; -} - -/* make space to hold at least 'count' properties */ -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; - bzero(prop_hash_end(sh) - new_hash_size, - sizeof(prop_hash_end(sh)[0]) * new_hash_size); - for(i = 0, pr = sh->prop; i < sh->prop_count; i++, pr++) { - if (pr->atom != JS_ATOM_NULL) { - h = ((uintptr_t)pr->atom & new_hash_mask); - pr->hash_next = prop_hash_end(sh)[-h - 1]; - prop_hash_end(sh)[-h - 1] = i + 1; - } - } - 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); - bzero(prop_hash_end(sh) - new_hash_size, - sizeof(prop_hash_end(sh)[0]) * new_hash_size); - j = 0; - old_pr = old_sh->prop; - pr = sh->prop; - prop = p->prop; - for(i = 0; i < sh->prop_count; i++) { - if (old_pr->atom != JS_ATOM_NULL) { - pr->atom = old_pr->atom; - pr->flags = old_pr->flags; - h = ((uintptr_t)old_pr->atom & new_hash_mask); - pr->hash_next = prop_hash_end(sh)[-h - 1]; - prop_hash_end(sh)[-h - 1] = j + 1; - prop[j] = prop[i]; - j++; - pr++; - } - old_pr++; - } - assert(j == (sh->prop_count - sh->deleted_prop_count)); - sh->prop_hash_mask = new_hash_mask; - sh->prop_size = new_size; - sh->deleted_prop_count = 0; - sh->prop_count = j; - p->shape = sh; - js_free(ctx, get_alloc_from_shape(old_sh)); - /* reduce the size of the object properties */ - new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size); - if (new_prop) - p->prop = new_prop; - return 0; -} - -/* 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 - -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); -} - -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); -} - -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; - } -} - -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; -} - -/* Note: at least 'length' arguments will be readable in 'argv' */ -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); -} - -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)); -} - -void js_autoinit_mark(JSRuntime *rt, JSProperty *pr, JS_MarkFunc *mark_func) -{ - mark_func(rt, &js_autoinit_get_realm(pr)->header); -} - -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); - } -} - -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_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_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); -} - -/* garbage collection */ - -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; -} - -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; -} - -/* return -1 (exception) or TRUE/FALSE */ -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; -} - -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); -} - -/* return the value associated to the autoinit property or an exception */ -typedef JSValue JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); - -static JSAutoInitFunc *js_autoinit_func_table[] = { - js_instantiate_prototype, /* JS_AUTOINIT_ID_PROTOTYPE */ - js_module_ns_autoinit, /* JS_AUTOINIT_ID_MODULE_NS */ - JS_InstantiateFunctionListItem2, /* JS_AUTOINIT_ID_PROP */ -}; - -/* warning: 'prs' is reallocated after it */ -static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop, - JSProperty *pr, JSShapeProperty *prs) -{ - JSValue val; - JSContext *realm; - JSAutoInitFunc *func; - if (js_shape_prepare_update(ctx, p, &prs)) - return -1; - realm = js_autoinit_get_realm(pr); - func = js_autoinit_func_table[js_autoinit_get_id(pr)]; - /* 'func' shall not modify the object properties 'pr' */ - val = func(realm, p, prop, pr->u.init.opaque); - js_autoinit_free(ctx->rt, pr); - prs->flags &= ~JS_PROP_TMASK; - pr->u.value = JS_UNDEFINED; - if (JS_IsException(val)) - return -1; - pr->u.value = val; - return 0; -} - -JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, - JSAtom prop, JSValueConst this_obj, - BOOL throw_ref_error) -{ - JSObject *p; - JSProperty *pr; - JSShapeProperty *prs; - uint32_t tag; - tag = JS_VALUE_GET_TAG(obj); - if (UNLIKELY(tag != JS_TAG_OBJECT)) { - switch(tag) { - case JS_TAG_NULL: - return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", prop); - case JS_TAG_UNDEFINED: - return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of undefined", prop); - case JS_TAG_EXCEPTION: - return JS_EXCEPTION; - case JS_TAG_STRING: - { - JSString *p1 = JS_VALUE_GET_STRING(obj); - if (__JS_AtomIsTaggedInt(prop)) { - uint32_t idx, 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, prs)) - return JS_EXCEPTION; - continue; - } - } else { - return JS_DupValue(ctx, pr->u.value); - } - } - if (UNLIKELY(p->is_exotic)) { - /* exotic behaviors */ - if (p->fast_array) { - if (__JS_AtomIsTaggedInt(prop)) { - uint32_t idx = __JS_AtomToUInt32(prop); - if (idx < p->u.array.count) { - /* we avoid duplicating the code */ - return JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx); - } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) { - return JS_UNDEFINED; - } - } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) { - int ret; - ret = JS_AtomIsNumericIndex(ctx, prop); - if (ret != 0) { - if (ret < 0) - return JS_EXCEPTION; - return JS_UNDEFINED; - } - } - } else { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em) { - if (em->get_property) { - JSValue obj1, retval; - /* XXX: should pass throw_ref_error */ - /* Note: if 'p' is a prototype, it can be - freed in the called function */ - obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); - retval = em->get_property(ctx, obj1, prop, this_obj); - JS_FreeValue(ctx, obj1); - return retval; - } - if (em->get_own_property) { - JSPropertyDescriptor desc; - int ret; - JSValue obj1; - /* Note: if 'p' is a prototype, it can be - freed in the called function */ - obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); - ret = em->get_own_property(ctx, &desc, obj1, prop); - JS_FreeValue(ctx, obj1); - if (ret < 0) - return JS_EXCEPTION; - if (ret) { - if (desc.flags & JS_PROP_GETSET) { - JS_FreeValue(ctx, desc.setter); - return JS_CallFree(ctx, desc.getter, this_obj, 0, NULL); - } else { - return desc.value; - } - } - } - } - } - } - p = p->shape->proto; - if (!p) - break; - } - if (UNLIKELY(throw_ref_error)) { - return JS_ThrowReferenceErrorNotDefined(ctx, prop); - } else { - return JS_UNDEFINED; - } -} - -uint32_t js_string_obj_get_length(JSContext *ctx, JSValueConst obj) -{ - JSObject *p; - JSString *p1; - uint32_t len = 0; - /* This is a class exotic method: obj class_id is JS_CLASS_STRING */ - p = JS_VALUE_GET_OBJ(obj); - if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) { - p1 = JS_VALUE_GET_STRING(p->u.object_data); - len = p1->len; - } - return len; -} - -static int num_keys_cmp(const void *p1, const void *p2, void *opaque) -{ - JSContext *ctx = opaque; - JSAtom atom1 = ((const JSPropertyEnum *)p1)->atom; - JSAtom atom2 = ((const JSPropertyEnum *)p2)->atom; - uint32_t v1, v2; - BOOL atom1_is_integer, atom2_is_integer; - atom1_is_integer = JS_AtomIsArrayIndex(ctx, &v1, atom1); - atom2_is_integer = JS_AtomIsArrayIndex(ctx, &v2, atom2); - unassert(atom1_is_integer && atom2_is_integer); - if (v1 < v2) - return -1; - else if (v1 == v2) - return 0; - else - return 1; -} - -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. */ -int JS_GetOwnPropertyNamesInternal(JSContext *ctx, - JSPropertyEnum **ptab, - uint32_t *plen, - JSObject *p, int flags) -{ - int i, j; - JSShape *sh; - JSShapeProperty *prs; - JSPropertyEnum *tab_atom, *tab_exotic; - JSAtom atom; - uint32_t num_keys_count, str_keys_count, sym_keys_count, atom_count; - uint32_t num_index, str_index, sym_index, exotic_count, exotic_keys_count; - BOOL is_enumerable, num_sorted; - uint32_t num_key; - JSAtomKindEnum kind; - /* clear pointer for consistency in case of failure */ - *ptab = NULL; - *plen = 0; - /* compute the number of returned properties */ - num_keys_count = 0; - str_keys_count = 0; - sym_keys_count = 0; - exotic_keys_count = 0; - exotic_count = 0; - tab_exotic = NULL; - sh = p->shape; - for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { - atom = prs->atom; - if (atom != JS_ATOM_NULL) { - is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0); - kind = JS_AtomGetKind(ctx, atom); - if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) && - ((flags >> kind) & 1) != 0) { - /* need to raise an exception in case of the module - name space (implicit GetOwnProperty) */ - if (UNLIKELY((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) && - (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY))) { - JSVarRef *var_ref = p->prop[i].u.var_ref; - if (UNLIKELY(JS_IsUninitialized(*var_ref->pvalue))) { - JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); - return -1; - } - } - if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) { - num_keys_count++; - } else if (kind == JS_ATOM_KIND_STRING) { - str_keys_count++; - } else { - sym_keys_count++; - } - } - } - } - if (p->is_exotic) { - if (p->fast_array) { - if (flags & JS_GPN_STRING_MASK) { - num_keys_count += p->u.array.count; - } - } else if (p->class_id == JS_CLASS_STRING) { - if (flags & JS_GPN_STRING_MASK) { - num_keys_count += js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); - } - } else { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em && em->get_own_property_names) { - if (em->get_own_property_names(ctx, &tab_exotic, &exotic_count, - JS_MKPTR(JS_TAG_OBJECT, p))) - return -1; - for(i = 0; i < exotic_count; i++) { - atom = tab_exotic[i].atom; - kind = JS_AtomGetKind(ctx, atom); - if (((flags >> kind) & 1) != 0) { - is_enumerable = FALSE; - if (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY)) { - JSPropertyDescriptor desc; - int res; - /* set the "is_enumerable" field if necessary */ - res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom); - if (res < 0) { - js_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) { - exotic_keys_count++; - } - } - } - } - } - } - /* fill them */ - atom_count = num_keys_count + str_keys_count + sym_keys_count + exotic_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) { - int len; - if (p->fast_array) { - if (flags & JS_GPN_STRING_MASK) { - len = p->u.array.count; - goto add_array_keys; - } - } else if (p->class_id == JS_CLASS_STRING) { - if (flags & JS_GPN_STRING_MASK) { - len = js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); - add_array_keys: - for(i = 0; i < len; i++) { - tab_atom[num_index].atom = __JS_AtomFromUInt32(i); - if (tab_atom[num_index].atom == JS_ATOM_NULL) { - js_free_prop_enum(ctx, tab_atom, num_index); - return -1; - } - tab_atom[num_index].is_enumerable = TRUE; - num_index++; - } - } - } else { - /* Note: exotic keys are not reordered and comes after the object own properties. */ - for(i = 0; i < exotic_count; i++) { - atom = tab_exotic[i].atom; - is_enumerable = tab_exotic[i].is_enumerable; - kind = JS_AtomGetKind(ctx, atom); - if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) && - ((flags >> kind) & 1) != 0) { - tab_atom[sym_index].atom = atom; - tab_atom[sym_index].is_enumerable = is_enumerable; - sym_index++; - } else { - JS_FreeAtom(ctx, atom); - } - } - js_free(ctx, tab_exotic); - } - } - assert(num_index == num_keys_count); - assert(str_index == num_keys_count + str_keys_count); - assert(sym_index == atom_count); - if (num_keys_count != 0 && !num_sorted) { - rqsort(tab_atom, num_keys_count, sizeof(tab_atom[0]), num_keys_cmp, - ctx); - } - *ptab = tab_atom; - *plen = atom_count; - return 0; -} - -int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, - uint32_t *plen, JSValueConst obj, int flags) -{ - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) { - JS_ThrowTypeErrorNotAnObject(ctx); - return -1; - } - return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen, - JS_VALUE_GET_OBJ(obj), flags); -} - -/* Return -1 if exception, - FALSE if the property does not exist, TRUE if it exists. If TRUE is - returned, the property descriptor 'desc' is filled present. */ -int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, - JSObject *p, JSAtom prop) -{ - JSShapeProperty *prs; - JSProperty *pr; -retry: - prs = find_own_property(&pr, p, prop); - if (prs) { - if (desc) { - desc->flags = prs->flags & JS_PROP_C_W_E; - desc->getter = JS_UNDEFINED; - desc->setter = JS_UNDEFINED; - desc->value = JS_UNDEFINED; - if (UNLIKELY(prs->flags & JS_PROP_TMASK)) { - if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { - desc->flags |= JS_PROP_GETSET; - if (pr->u.getset.getter) - desc->getter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter)); - if (pr->u.getset.setter) - desc->setter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter)); - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { - JSValue val = *pr->u.var_ref->pvalue; - if (UNLIKELY(JS_IsUninitialized(val))) { - JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); - return -1; - } - desc->value = JS_DupValue(ctx, val); - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { - /* Instantiate property and retry */ - if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) - return -1; - goto retry; - } - } else { - desc->value = JS_DupValue(ctx, pr->u.value); - } - } else { - /* for consistency, send the exception even if desc is NULL */ - if (UNLIKELY((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF)) { - if (UNLIKELY(JS_IsUninitialized(*pr->u.var_ref->pvalue))) { - JS_ThrowReferenceErrorUninitialized(ctx, prs->atom); - return -1; - } - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { - /* nothing to do: delay instantiation until actual value and/or attributes are read */ - } - } - return TRUE; - } - if (p->is_exotic) { - if (p->fast_array) { - /* specific case for fast arrays */ - if (__JS_AtomIsTaggedInt(prop)) { - uint32_t idx; - idx = __JS_AtomToUInt32(prop); - if (idx < p->u.array.count) { - if (desc) { - desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE | - JS_PROP_CONFIGURABLE; - desc->getter = JS_UNDEFINED; - desc->setter = JS_UNDEFINED; - desc->value = JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx); - } - return TRUE; - } - } - } else { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em && em->get_own_property) { - return em->get_own_property(ctx, desc, - JS_MKPTR(JS_TAG_OBJECT, p), prop); - } - } - } - return FALSE; -} - -int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc, - JSValueConst obj, JSAtom prop) -{ - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) { - JS_ThrowTypeErrorNotAnObject(ctx); - return -1; - } - return JS_GetOwnPropertyInternal(ctx, desc, JS_VALUE_GET_OBJ(obj), prop); -} - -/* return -1 if exception (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; - return FALSE; - } - } - p = p->shape->proto; - if (!p) - break; - } - return FALSE; -} - -/* 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; -} - -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)); -} - -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. */ -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 dontinline __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; -} - -int delete_property(JSContext *ctx, JSObject *p, JSAtom atom) -{ - JSShape *sh; - JSShapeProperty *pr, *lpr, *prop; - JSProperty *pr1; - uint32_t lpr_idx; - intptr_t h, h1; - redo: - sh = p->shape; - h1 = atom & sh->prop_hash_mask; - h = prop_hash_end(sh)[-h1 - 1]; - prop = get_shape_prop(sh); - lpr = NULL; - lpr_idx = 0; /* prevent warning */ - while (h != 0) { - pr = &prop[h - 1]; - if (LIKELY(pr->atom == atom)) { - /* found ! */ - if (!(pr->flags & JS_PROP_CONFIGURABLE)) - return FALSE; - /* realloc the shape if needed */ - if (lpr) - lpr_idx = lpr - get_shape_prop(sh); - if (js_shape_prepare_update(ctx, p, &pr)) - return -1; - sh = p->shape; - /* remove property */ - if (lpr) { - lpr = get_shape_prop(sh) + lpr_idx; - lpr->hash_next = pr->hash_next; - } else { - prop_hash_end(sh)[-h1 - 1] = pr->hash_next; - } - sh->deleted_prop_count++; - /* free the entry */ - pr1 = &p->prop[h - 1]; - free_property(ctx->rt, pr1, pr->flags); - JS_FreeAtom(ctx, pr->atom); - /* put default values */ - pr->flags = 0; - pr->atom = JS_ATOM_NULL; - pr1->u.value = JS_UNDEFINED; - /* compact the properties if too many deleted properties */ - if (sh->deleted_prop_count >= 8 && - sh->deleted_prop_count >= ((unsigned)sh->prop_count / 2)) { - compact_properties(ctx, p); - } - return TRUE; - } - lpr = pr; - h = pr->hash_next; - } - if (p->is_exotic) { - if (p->fast_array) { - uint32_t idx; - if (JS_AtomIsArrayIndex(ctx, &idx, atom) && - idx < p->u.array.count) { - if (p->class_id == JS_CLASS_ARRAY || - p->class_id == JS_CLASS_ARGUMENTS) { - /* Special case deleting the last element of a fast Array */ - if (idx == p->u.array.count - 1) { - JS_FreeValue(ctx, p->u.array.u.values[idx]); - p->u.array.count = idx; - return TRUE; - } - if (convert_fast_array_to_array(ctx, p)) - return -1; - goto redo; - } else { - return FALSE; - } - } - } else { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em && em->delete_property) { - return em->delete_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), atom); - } - } - } - /* not found */ - return TRUE; -} - -static int call_setter(JSContext *ctx, JSObject *setter, - JSValueConst this_obj, JSValue val, int flags) -{ - JSValue ret, func; - if (LIKELY(setter)) { - func = JS_MKPTR(JS_TAG_OBJECT, setter); - /* Note: the field could be removed in the setter */ - func = JS_DupValue(ctx, func); - ret = JS_CallFree(ctx, func, this_obj, 1, (JSValueConst *)&val); - JS_FreeValue(ctx, val); - if (JS_IsException(ret)) - return -1; - JS_FreeValue(ctx, ret); - return TRUE; - } else { - JS_FreeValue(ctx, val); - if ((flags & JS_PROP_THROW) || - ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) { - JS_ThrowTypeError(ctx, "no setter for property"); - return -1; - } - return FALSE; - } -} - -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(). 'obj' must be an object. */ -int JS_SetPropertyGeneric(JSContext *ctx, - JSValueConst obj, JSAtom prop, - JSValue val, JSValueConst this_obj, - int flags) -{ - int ret; - JSPropertyDescriptor desc; - JSValue obj1; - JSObject *p; - obj1 = JS_DupValue(ctx, obj); - for(;;) { - p = JS_VALUE_GET_OBJ(obj1); - if (p->is_exotic) { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em && em->set_property) { - 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) { - JS_FreeValue(ctx, obj1); - 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); - JS_FreeValue(ctx, obj1); - return ret; - } else { - JS_FreeValue(ctx, desc.value); - if (!(desc.flags & JS_PROP_WRITABLE)) { - JS_FreeValue(ctx, obj1); - goto read_only_error; - } - } - break; - } - /* Note: at this point 'obj1' cannot be a proxy. XXX: may have - to check recursion */ - obj1 = JS_GetPrototypeFree(ctx, obj1); - if (JS_IsNull(obj1)) - break; - } - JS_FreeValue(ctx, obj1); - if (!JS_IsObject(this_obj)) { - JS_FreeValue(ctx, val); - 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) { - JS_FreeValue(ctx, val); - return ret; - } - if (ret) { - if (desc.flags & JS_PROP_GETSET) { - JS_FreeValue(ctx, desc.getter); - JS_FreeValue(ctx, desc.setter); - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden"); - } else { - JS_FreeValue(ctx, desc.value); - if (!(desc.flags & JS_PROP_WRITABLE) || - p->class_id == JS_CLASS_MODULE_NS) { - read_only_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) { - assert(p->class_id == JS_CLASS_ARRAY); - assert(prop == JS_ATOM_length); - return set_array_length(ctx, p, val, flags); - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { - return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags); - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { - /* JS_PROP_WRITABLE is always true for variable - references, but they are write protected in module name - spaces. */ - if (p->class_id == JS_CLASS_MODULE_NS) - goto read_only_prop; - set_value(ctx, pr->u.var_ref->pvalue, val); - return TRUE; - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { - /* Instantiate property and retry (potentially useless) */ - if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) { - JS_FreeValue(ctx, val); - return -1; - } - goto retry; - } else { - goto read_only_prop; - } - } - 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; - 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, prs)) - 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 */ -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: - 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 */ -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; -} - -int js_update_property_flags(JSContext *ctx, JSObject *p, - JSShapeProperty **pprs, int flags) -{ - if (flags != (*pprs)->flags) { - if (js_shape_prepare_update(ctx, p, pprs)) - return -1; - (*pprs)->flags = flags; - } - return 0; -} - -/* allowed flags: - JS_PROP_CONFIGURABLE, JS_PROP_WRITABLE, JS_PROP_ENUMERABLE - JS_PROP_HAS_GET, JS_PROP_HAS_SET, JS_PROP_HAS_VALUE, - JS_PROP_HAS_CONFIGURABLE, JS_PROP_HAS_WRITABLE, JS_PROP_HAS_ENUMERABLE, - JS_PROP_THROW, JS_PROP_NO_EXOTIC. - If JS_PROP_THROW is set, return an exception instead of FALSE. - if JS_PROP_NO_EXOTIC is set, do not call the exotic - define_own_property callback. - return -1 (exception), FALSE or TRUE. -*/ -int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValueConst val, - JSValueConst getter, JSValueConst setter, int flags) -{ - JSObject *p; - JSShapeProperty *prs; - JSProperty *pr; - int mask, res; - if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT) { - JS_ThrowTypeErrorNotAnObject(ctx); - return -1; - } - p = JS_VALUE_GET_OBJ(this_obj); - redo_prop_update: - prs = find_own_property(&pr, p, prop); - if (prs) { - /* the range of the Array length property is always tested before */ - if ((prs->flags & JS_PROP_LENGTH) && (flags & JS_PROP_HAS_VALUE)) { - uint32_t array_length; - if (JS_ToArrayLengthFree(ctx, &array_length, - JS_DupValue(ctx, val), FALSE)) { - return -1; - } - /* this code relies on the fact that Uint32 are never allocated */ - val = (JSValueConst)JS_NewUint32(ctx, array_length); - /* prs may have been modified */ - prs = find_own_property(&pr, p, prop); - assert(prs != NULL); - } - /* property already exists */ - if (!check_define_prop_flags(prs->flags, flags)) { - not_configurable: - return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable"); - } - if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { - /* Instantiate property and retry */ - if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) - return -1; - goto redo_prop_update; - } - if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | - JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { - if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { - JSObject *new_getter, *new_setter; - if (JS_IsFunction(ctx, getter)) { - new_getter = JS_VALUE_GET_OBJ(getter); - } else { - new_getter = NULL; - } - if (JS_IsFunction(ctx, setter)) { - new_setter = JS_VALUE_GET_OBJ(setter); - } else { - new_setter = NULL; - } - if ((prs->flags & JS_PROP_TMASK) != JS_PROP_GETSET) { - if (js_shape_prepare_update(ctx, p, &prs)) - return -1; - /* convert to getset */ - if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { - free_var_ref(ctx->rt, pr->u.var_ref); - } else { - JS_FreeValue(ctx, pr->u.value); - } - prs->flags = (prs->flags & - (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) | - JS_PROP_GETSET; - pr->u.getset.getter = NULL; - pr->u.getset.setter = NULL; - } else { - if (!(prs->flags & JS_PROP_CONFIGURABLE)) { - if ((flags & JS_PROP_HAS_GET) && - new_getter != pr->u.getset.getter) { - goto not_configurable; - } - if ((flags & JS_PROP_HAS_SET) && - new_setter != pr->u.getset.setter) { - goto not_configurable; - } - } - } - if (flags & JS_PROP_HAS_GET) { - if (pr->u.getset.getter) - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter)); - if (new_getter) - JS_DupValue(ctx, getter); - pr->u.getset.getter = new_getter; - } - if (flags & JS_PROP_HAS_SET) { - if (pr->u.getset.setter) - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter)); - if (new_setter) - JS_DupValue(ctx, setter); - pr->u.getset.setter = new_setter; - } - } else { - if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { - /* convert to data descriptor */ - if (js_shape_prepare_update(ctx, p, &prs)) - return -1; - if (pr->u.getset.getter) - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter)); - if (pr->u.getset.setter) - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter)); - prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE); - pr->u.value = JS_UNDEFINED; - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { - /* Note: JS_PROP_VARREF is always writable */ - } else { - if ((prs->flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 && - (flags & JS_PROP_HAS_VALUE)) { - if (!js_same_value(ctx, val, pr->u.value)) { - goto not_configurable; - } else { - return TRUE; - } - } - } - if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { - if (flags & JS_PROP_HAS_VALUE) { - if (p->class_id == JS_CLASS_MODULE_NS) { - /* JS_PROP_WRITABLE is always true for variable - references, but they are write protected in module name - spaces. */ - if (!js_same_value(ctx, val, *pr->u.var_ref->pvalue)) - goto not_configurable; - } - /* 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_LENGTH) { - if (flags & JS_PROP_HAS_VALUE) { - /* Note: no JS code is executable because - 'val' is guaranted to be a Uint32 */ - res = set_array_length(ctx, p, JS_DupValue(ctx, val), - flags); - } else { - res = TRUE; - } - /* still need to reset the writable flag if - needed. The JS_PROP_LENGTH is kept because the - Uint32 test is still done if the length - property is read-only. */ - if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == - JS_PROP_HAS_WRITABLE) { - prs = get_shape_prop(p->shape); - if (js_update_property_flags(ctx, p, &prs, - prs->flags & ~JS_PROP_WRITABLE)) - return -1; - } - return res; - } else { - if (flags & JS_PROP_HAS_VALUE) { - JS_FreeValue(ctx, pr->u.value); - pr->u.value = JS_DupValue(ctx, val); - } - if (flags & JS_PROP_HAS_WRITABLE) { - if (js_update_property_flags(ctx, p, &prs, - (prs->flags & ~JS_PROP_WRITABLE) | - (flags & JS_PROP_WRITABLE))) - return -1; - } - } - } - } - mask = 0; - if (flags & JS_PROP_HAS_CONFIGURABLE) - mask |= JS_PROP_CONFIGURABLE; - if (flags & JS_PROP_HAS_ENUMERABLE) - mask |= JS_PROP_ENUMERABLE; - if (js_update_property_flags(ctx, p, &prs, - (prs->flags & ~mask) | (flags & mask))) - return -1; - return TRUE; - } - /* handle modification of fast array elements */ - if (p->fast_array) { - uint32_t idx; - uint32_t prop_flags; - if (p->class_id == JS_CLASS_ARRAY) { - if (__JS_AtomIsTaggedInt(prop)) { - idx = __JS_AtomToUInt32(prop); - if (idx < p->u.array.count) { - prop_flags = get_prop_flags(flags, JS_PROP_C_W_E); - if (prop_flags != JS_PROP_C_W_E) - goto convert_to_slow_array; - if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { - convert_to_slow_array: - if (convert_fast_array_to_array(ctx, p)) - return -1; - else - goto redo_prop_update; - } - if (flags & JS_PROP_HAS_VALUE) { - set_value(ctx, &p->u.array.u.values[idx], JS_DupValue(ctx, val)); - } - return TRUE; - } - } - } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) { - JSValue num; - int ret; - if (!__JS_AtomIsTaggedInt(prop)) { - /* slow path with to handle all numeric indexes */ - num = JS_AtomIsNumericIndex1(ctx, prop); - if (JS_IsUndefined(num)) - goto typed_array_done; - if (JS_IsException(num)) - return -1; - ret = JS_NumberIsInteger(ctx, num); - if (ret < 0) { - JS_FreeValue(ctx, num); - return -1; - } - if (!ret) { - JS_FreeValue(ctx, num); - return JS_ThrowTypeErrorOrFalse(ctx, flags, "non integer index in typed array"); - } - ret = JS_NumberIsNegativeOrMinusZero(ctx, num); - JS_FreeValue(ctx, num); - if (ret) { - return JS_ThrowTypeErrorOrFalse(ctx, flags, "negative index in typed array"); - } - if (!__JS_AtomIsTaggedInt(prop)) - goto typed_array_oob; - } - idx = __JS_AtomToUInt32(prop); - /* if the typed array is detached, p->u.array.count = 0 */ - if (idx >= 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 | JS_PROP_CONFIGURABLE); - if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET) || - prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE)) { - return JS_ThrowTypeErrorOrFalse(ctx, flags, "invalid descriptor flags"); - } - if (flags & JS_PROP_HAS_VALUE) { - return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), JS_DupValue(ctx, val), flags); - } - return TRUE; - typed_array_done: ; - } - } - return JS_CreateProperty(ctx, p, prop, val, getter, setter, flags); -} - -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; -} - -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); -} - -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; -} - -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; -} - -/* 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; -} - -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_IsArrayBuffer(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_ARRAY_BUFFER || p->class_id == JS_CLASS_SHARED_ARRAY_BUFFER); -} - -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); -} - -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; -} - -void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj) -{ - JSObject *p; - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - return; - p = JS_VALUE_GET_OBJ(obj); - p->is_HTMLDDA = TRUE; -} - -static inline BOOL JS_IsHTMLDDA(JSContext *ctx, JSValueConst obj) -{ - JSObject *p; - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - return FALSE; - p = JS_VALUE_GET_OBJ(obj); - return p->is_HTMLDDA; -} - -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; -} - -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; -} - -JSValue JS_ToNumberFree(JSContext *ctx, JSValue val) -{ - return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER); -} - -JSValue JS_ToNumericFree(JSContext *ctx, JSValue val) -{ - return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC); -} - -JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val) -{ - return JS_ToNumericFree(ctx, JS_DupValue(ctx, val)); -} - -__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; -} - -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; -} - -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 > (double)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 */ -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); -} - -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 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 */ -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; - } -} - -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 __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: - case JS_CLASS_INT8_ARRAY: - case JS_CLASS_UINT8_ARRAY: - case JS_CLASS_INT16_ARRAY: - case JS_CLASS_UINT16_ARRAY: - case JS_CLASS_INT32_ARRAY: - case JS_CLASS_UINT32_ARRAY: -#ifdef CONFIG_BIGNUM - case JS_CLASS_BIG_INT64_ARRAY: - case JS_CLASS_BIG_UINT64_ARRAY: -#endif - case JS_CLASS_FLOAT32_ARRAY: - case 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; - } -} - -#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; -} - -/* must be kept in sync with JSOverloadableOperatorEnum */ -/* XXX: use atoms ? */ -static const char js_overloadable_operator_names[JS_OVOP_COUNT][4] = { - "+", - "-", - "*", - "/", - "%", - "**", - "|", - "&", - "^", - "<<", - ">>", - ">>>", - "==", - "<", - "pos", - "neg", - "++", - "--", - "~", -}; - -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 */ -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; -} - -/* 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; -} - -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; -} - -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); -} - -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; -} - -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; -} - -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; -} - -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; -} - -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)) { - /* fast path for float64/int */ - goto float64_compare; - } 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; - } - } - tag1 = JS_VALUE_GET_NORM_TAG(op1); - tag2 = JS_VALUE_GET_NORM_TAG(op2); - if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { - res = ctx->rt->bigdecimal_ops.compare(ctx, op, 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, op1, op2); - if (res < 0) - goto exception; - } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { - res = ctx->rt->bigint_ops.compare(ctx, op, op1, op2); - if (res < 0) - goto exception; - } else { - double d1, d2; - float64_compare: - /* can use floating point comparison */ - if (tag1 == JS_TAG_FLOAT64) { - d1 = JS_VALUE_GET_FLOAT64(op1); - } else { - d1 = JS_VALUE_GET_INT(op1); - } - if (tag2 == JS_TAG_FLOAT64) { - d2 = JS_VALUE_GET_FLOAT64(op2); - } else { - d2 = JS_VALUE_GET_INT(op2); - } - switch(op) { - case OP_lt: - res = (d1 < d2); /* if NaN return false */ - break; - case OP_lte: - res = (d1 <= d2); /* if NaN return false */ - break; - case OP_gt: - res = (d1 > d2); /* if NaN return false */ - break; - default: - case OP_gte: - res = (d1 >= d2); /* if NaN return false */ - break; - } - } - } - done: - sp[-2] = JS_NewBool(ctx, res); - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -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; -} - -#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; -} - -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 */ -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; -} - -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; -} - -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; -} - -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; -} - -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; -} - -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; -} - -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 */ - -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 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, -}; - -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; -} - -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 */ -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; -} - -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 */ -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) */ -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; -} - -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; -} - -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; -} - -int JS_CopyDataProperties(JSContext *ctx, - JSValueConst target, - JSValueConst source, - JSValueConst excluded, - BOOL setprop) -{ - JSPropertyEnum *tab_atom; - JSValue val; - uint32_t i, tab_atom_count; - JSObject *p; - JSObject *pexcl = NULL; - int ret, gpn_flags; - JSPropertyDescriptor desc; - BOOL is_enumerable; - if (JS_VALUE_GET_TAG(source) != JS_TAG_OBJECT) - return 0; - if (JS_VALUE_GET_TAG(excluded) == JS_TAG_OBJECT) - pexcl = JS_VALUE_GET_OBJ(excluded); - p = JS_VALUE_GET_OBJ(source); - gpn_flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK | JS_GPN_ENUM_ONLY; - if (p->is_exotic) { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - /* cannot use JS_GPN_ENUM_ONLY with e.g. proxies because it - introduces a visible change */ - if (em && em->get_own_property_names) { - gpn_flags &= ~JS_GPN_ENUM_ONLY; - } - } - if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p, - gpn_flags)) - return -1; - for (i = 0; i < tab_atom_count; i++) { - if (pexcl) { - ret = JS_GetOwnPropertyInternal(ctx, NULL, pexcl, tab_atom[i].atom); - if (ret) { - if (ret < 0) - goto exception; - continue; - } - } - if (!(gpn_flags & JS_GPN_ENUM_ONLY)) { - /* test if the property is enumerable */ - ret = JS_GetOwnPropertyInternal(ctx, &desc, p, tab_atom[i].atom); - if (ret < 0) - goto exception; - if (!ret) - continue; - is_enumerable = (desc.flags & JS_PROP_ENUMERABLE) != 0; - js_free_desc(ctx, &desc); - if (!is_enumerable) - continue; - } - val = JS_GetProperty(ctx, source, tab_atom[i].atom); - if (JS_IsException(val)) - goto exception; - if (setprop) - ret = JS_SetProperty(ctx, target, tab_atom[i].atom, val); - else - ret = JS_DefinePropertyValue(ctx, target, tab_atom[i].atom, val, - JS_PROP_C_W_E); - if (ret < 0) - goto exception; - } - js_free_prop_enum(ctx, tab_atom, tab_atom_count); - return 0; - exception: - js_free_prop_enum(ctx, tab_atom, tab_atom_count); - return -1; -} - -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_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque) -{ - JSValue obj, this_val; - int ret; - this_val = JS_MKPTR(JS_TAG_OBJECT, p); - obj = JS_NewObject(ctx); - if (JS_IsException(obj)) - return JS_EXCEPTION; - set_cycle_flag(ctx, obj); - set_cycle_flag(ctx, this_val); - ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_constructor, - JS_DupValue(ctx, this_val), - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - if (ret < 0) { - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - return obj; -} - -/* AsyncFunction */ - -/* AsyncGenerator */ - -/* JS parser */ - -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 "third_party/quickjs/quickjs-opcode.inc" -#undef DEF -#undef FMT -}; - -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 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; -} - -/** - * Returns true if 'input' contains the source of a module - * (heuristic). 'input' must be a zero terminated. - * - * Heuristic: skip comments and expect 'import' keyword not followed - * by '(' or '.' or export keyword. - */ -BOOL JS_DetectModule(const char *input, size_t input_len) -{ - const uint8_t *p = (const uint8_t *)input; - int tok; - switch(simple_next_token(&p, FALSE)) { - case TOK_IMPORT: - tok = simple_next_token(&p, FALSE); - return (tok != '.' && tok != '('); - case TOK_EXPORT: - return TRUE; - default: - return FALSE; - } -} - -void emit_op(JSParseState *s, uint8_t val) -{ - JSFunctionDef *fd = s->cur_func; - DynBuf *bc = &fd->byte_code; - /* Use the line number of the last token used, not the next token, - nor the current offset in the source file. - */ - if (UNLIKELY(fd->last_opcode_line_num != s->last_line_num)) { - dbuf_putc(bc, OP_line_num); - dbuf_put_u32(bc, s->last_line_num); - fd->last_opcode_line_num = s->last_line_num; - } - fd->last_opcode_pos = bc->size; - dbuf_putc(bc, val); -} - -void emit_atom(JSParseState *s, JSAtom name) -{ - emit_u32(s, JS_DupAtom(s->ctx, name)); -} - -int update_label(JSFunctionDef *s, int label, int delta) -{ - LabelSlot *ls; - assert(label >= 0 && label < s->label_count); - ls = &s->label_slots[label]; - ls->ref_count += delta; - assert(ls->ref_count >= 0); - return ls->ref_count; -} - -static int new_label_fd(JSFunctionDef *fd, int label) -{ - LabelSlot *ls; - - if (label < 0) { - if (js_resize_array(fd->ctx, (void *)&fd->label_slots, - sizeof(fd->label_slots[0]), - &fd->label_size, fd->label_count + 1)) - return -1; - label = fd->label_count++; - ls = &fd->label_slots[label]; - ls->ref_count = 0; - ls->pos = -1; - ls->pos2 = -1; - ls->addr = -1; - ls->first_reloc = NULL; - } - return label; -} - -int new_label(JSParseState *s) -{ - return new_label_fd(s->cur_func, -1); -} - -/* return the label ID offset */ -int emit_label(JSParseState *s, int label) -{ - if (label >= 0) { - emit_op(s, OP_label); - emit_u32(s, label); - s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size; - return s->cur_func->byte_code.size - 4; - } else { - return -1; - } -} - -/* return the constant pool index. 'val' is not duplicated. */ -int cpool_add(JSParseState *s, JSValue val) -{ - JSFunctionDef *fd = s->cur_func; - if (js_resize_array(s->ctx, (void *)&fd->cpool, sizeof(fd->cpool[0]), - &fd->cpool_size, fd->cpool_count + 1)) - return -1; - fd->cpool[fd->cpool_count++] = val; - return fd->cpool_count - 1; -} - -/* return the variable index or -1 if not found, - add ARGUMENT_VAR_OFFSET for argument variables */ -static int find_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name) -{ - int i; - for(i = fd->arg_count; i-- > 0;) { - if (fd->args[i].var_name == name) - return i | ARGUMENT_VAR_OFFSET; - } - return -1; -} - -int find_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name) -{ - int i; - for(i = fd->var_count; i-- > 0;) { - if (fd->vars[i].var_name == name && fd->vars[i].scope_level == 0) - return i; - } - return find_arg(ctx, fd, name); -} - -/* find a variable declaration in a given scope */ -static int find_var_in_scope(JSContext *ctx, JSFunctionDef *fd, - JSAtom name, int scope_level) -{ - int scope_idx; - for(scope_idx = fd->scopes[scope_level].first; scope_idx >= 0; - scope_idx = fd->vars[scope_idx].scope_next) { - if (fd->vars[scope_idx].scope_level != scope_level) - break; - if (fd->vars[scope_idx].var_name == name) - return scope_idx; - } - return -1; -} - -/* return true if scope == parent_scope or if scope is a child of - parent_scope */ -static BOOL is_child_scope(JSContext *ctx, JSFunctionDef *fd, - int scope, int parent_scope) -{ - while (scope >= 0) { - if (scope == parent_scope) - return TRUE; - scope = fd->scopes[scope].parent; - } - return FALSE; -} - -/* find a 'var' declaration in the same scope or a child scope */ -static int find_var_in_child_scope(JSContext *ctx, JSFunctionDef *fd, - JSAtom name, int scope_level) -{ - int i; - for(i = 0; i < fd->var_count; i++) { - JSVarDef *vd = &fd->vars[i]; - if (vd->var_name == name && vd->scope_level == 0) { - if (is_child_scope(ctx, fd, vd->scope_next, - scope_level)) - return i; - } - } - return -1; -} - - -JSGlobalVar *find_global_var(JSFunctionDef *fd, JSAtom name) -{ - int i; - for(i = 0; i < fd->global_var_count; i++) { - JSGlobalVar *hf = &fd->global_vars[i]; - if (hf->var_name == name) - return hf; - } - return NULL; - -} - -static JSGlobalVar *find_lexical_global_var(JSFunctionDef *fd, JSAtom name) -{ - JSGlobalVar *hf = find_global_var(fd, name); - if (hf && hf->is_lexical) - return hf; - else - return NULL; -} - -int find_lexical_decl(JSContext *ctx, JSFunctionDef *fd, JSAtom name, - int scope_idx, BOOL check_catch_var) -{ - while (scope_idx >= 0) { - JSVarDef *vd = &fd->vars[scope_idx]; - if (vd->var_name == name && - (vd->is_lexical || (vd->var_kind == JS_VAR_CATCH && - check_catch_var))) - return scope_idx; - scope_idx = vd->scope_next; - } - if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_GLOBAL) { - if (find_lexical_global_var(fd, name)) - return GLOBAL_VAR_OFFSET; - } - return -1; -} - -int push_scope(JSParseState *s) { - if (s->cur_func) { - JSFunctionDef *fd = s->cur_func; - int scope = fd->scope_count; - /* XXX: should check for scope overflow */ - if ((fd->scope_count + 1) > fd->scope_size) { - int new_size; - size_t slack; - JSVarScope *new_buf; - /* XXX: potential arithmetic overflow */ - new_size = max_int(fd->scope_count + 1, fd->scope_size * 3 / 2); - if (fd->scopes == fd->def_scope_array) { - new_buf = js_realloc2(s->ctx, NULL, new_size * sizeof(*fd->scopes), &slack); - if (!new_buf) - return -1; - memcpy(new_buf, fd->scopes, fd->scope_count * sizeof(*fd->scopes)); - } else { - new_buf = js_realloc2(s->ctx, fd->scopes, new_size * sizeof(*fd->scopes), &slack); - if (!new_buf) - return -1; - } - new_size += slack / sizeof(*new_buf); - fd->scopes = new_buf; - fd->scope_size = new_size; - } - fd->scope_count++; - fd->scopes[scope].parent = fd->scope_level; - fd->scopes[scope].first = fd->scope_first; - emit_op(s, OP_enter_scope); - emit_u16(s, scope); - return fd->scope_level = scope; - } - return 0; -} - -void close_scopes(JSParseState *s, int scope, int scope_stop) -{ - while (scope > scope_stop) { - emit_op(s, OP_leave_scope); - emit_u16(s, scope); - scope = s->cur_func->scopes[scope].parent; - } -} - -/* return the variable index or -1 if error */ -int add_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name) -{ - JSVarDef *vd; - /* the local variable indexes are currently stored on 16 bits */ - if (fd->var_count >= JS_MAX_LOCAL_VARS) { - JS_ThrowInternalError(ctx, "too many local variables"); - return -1; - } - if (js_resize_array(ctx, (void **)&fd->vars, sizeof(fd->vars[0]), - &fd->var_size, fd->var_count + 1)) - return -1; - vd = &fd->vars[fd->var_count++]; - bzero(vd, sizeof(*vd)); - vd->var_name = JS_DupAtom(ctx, name); - vd->func_pool_idx = -1; - return fd->var_count - 1; -} - -int add_scope_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name, JSVarKindEnum var_kind) -{ - int idx = add_var(ctx, fd, name); - if (idx >= 0) { - JSVarDef *vd = &fd->vars[idx]; - vd->var_kind = var_kind; - vd->scope_level = fd->scope_level; - vd->scope_next = fd->scope_first; - fd->scopes[fd->scope_level].first = idx; - fd->scope_first = idx; - } - return idx; -} - -static int add_func_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name) -{ - int idx = fd->func_var_idx; - if (idx < 0 && (idx = add_var(ctx, fd, name)) >= 0) { - fd->func_var_idx = idx; - fd->vars[idx].var_kind = JS_VAR_FUNCTION_NAME; - if (fd->js_mode & JS_MODE_STRICT) - fd->vars[idx].is_const = TRUE; - } - return idx; -} - -static int add_arguments_var(JSContext *ctx, JSFunctionDef *fd) -{ - int idx = fd->arguments_var_idx; - if (idx < 0 && (idx = add_var(ctx, fd, JS_ATOM_arguments)) >= 0) { - fd->arguments_var_idx = idx; - } - return idx; -} - -/* add an argument definition in the argument scope. Only needed when - "eval()" may be called in the argument scope. Return 0 if OK. */ -static int add_arguments_arg(JSContext *ctx, JSFunctionDef *fd) -{ - int idx; - if (fd->arguments_arg_idx < 0) { - idx = find_var_in_scope(ctx, fd, JS_ATOM_arguments, ARG_SCOPE_INDEX); - if (idx < 0) { - /* XXX: the scope links are not fully updated. May be an - issue if there are child scopes of the argument - scope */ - idx = add_var(ctx, fd, JS_ATOM_arguments); - if (idx < 0) - return -1; - fd->vars[idx].scope_next = fd->scopes[ARG_SCOPE_INDEX].first; - fd->scopes[ARG_SCOPE_INDEX].first = idx; - fd->vars[idx].scope_level = ARG_SCOPE_INDEX; - fd->vars[idx].is_lexical = TRUE; - - fd->arguments_arg_idx = idx; - } - } - return 0; -} - -/* add a global variable definition */ -JSGlobalVar *add_global_var(JSContext *ctx, JSFunctionDef *s, JSAtom name) -{ - JSGlobalVar *hf; - if (js_resize_array(ctx, (void **)&s->global_vars, - sizeof(s->global_vars[0]), - &s->global_var_size, s->global_var_count + 1)) - return NULL; - hf = &s->global_vars[s->global_var_count++]; - hf->cpool_idx = -1; - hf->force_init = FALSE; - hf->is_lexical = FALSE; - hf->is_const = FALSE; - hf->scope_level = s->scope_level; - hf->var_name = JS_DupAtom(ctx, name); - return hf; -} - -int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name, JSVarDefEnum var_def_type) -{ - JSContext *ctx = s->ctx; - JSVarDef *vd; - int idx; - switch (var_def_type) { - case JS_VAR_DEF_WITH: - idx = add_scope_var(ctx, fd, name, JS_VAR_NORMAL); - break; - case JS_VAR_DEF_LET: - case JS_VAR_DEF_CONST: - case JS_VAR_DEF_FUNCTION_DECL: - case JS_VAR_DEF_NEW_FUNCTION_DECL: - idx = find_lexical_decl(ctx, fd, name, fd->scope_first, TRUE); - if (idx >= 0) { - if (idx < GLOBAL_VAR_OFFSET) { - if (fd->vars[idx].scope_level == fd->scope_level) { - /* same scope: in non strict mode, functions - can be redefined (annex B.3.3.4). */ - if (!(!(fd->js_mode & JS_MODE_STRICT) && - var_def_type == JS_VAR_DEF_FUNCTION_DECL && - fd->vars[idx].var_kind == JS_VAR_FUNCTION_DECL)) { - goto redef_lex_error; - } - } else if (fd->vars[idx].var_kind == JS_VAR_CATCH && (fd->vars[idx].scope_level + 2) == fd->scope_level) { - goto redef_lex_error; - } - } else { - if (fd->scope_level == fd->body_scope) { - redef_lex_error: - /* redefining a scoped var in the same scope: error */ - return js_parse_error(s, "invalid redefinition of lexical identifier"); - } - } - } - if (var_def_type != JS_VAR_DEF_FUNCTION_DECL && - var_def_type != JS_VAR_DEF_NEW_FUNCTION_DECL && - fd->scope_level == fd->body_scope && - find_arg(ctx, fd, name) >= 0) { - /* lexical variable redefines a parameter name */ - return js_parse_error(s, "invalid redefinition of parameter name"); - } - if (find_var_in_child_scope(ctx, fd, name, fd->scope_level) >= 0) { - return js_parse_error(s, "invalid redefinition of a variable"); - } - if (fd->is_global_var) { - JSGlobalVar *hf; - hf = find_global_var(fd, name); - if (hf && is_child_scope(ctx, fd, hf->scope_level, - fd->scope_level)) { - return js_parse_error(s, "invalid redefinition of global identifier"); - } - } - if (fd->is_eval && - (fd->eval_type == JS_EVAL_TYPE_GLOBAL || - fd->eval_type == JS_EVAL_TYPE_MODULE) && - fd->scope_level == fd->body_scope) { - JSGlobalVar *hf; - hf = add_global_var(s->ctx, fd, name); - if (!hf) - return -1; - hf->is_lexical = TRUE; - hf->is_const = (var_def_type == JS_VAR_DEF_CONST); - idx = GLOBAL_VAR_OFFSET; - } else { - JSVarKindEnum var_kind; - if (var_def_type == JS_VAR_DEF_FUNCTION_DECL) - var_kind = JS_VAR_FUNCTION_DECL; - else if (var_def_type == JS_VAR_DEF_NEW_FUNCTION_DECL) - var_kind = JS_VAR_NEW_FUNCTION_DECL; - else - var_kind = JS_VAR_NORMAL; - idx = add_scope_var(ctx, fd, name, var_kind); - if (idx >= 0) { - vd = &fd->vars[idx]; - vd->is_lexical = 1; - vd->is_const = (var_def_type == JS_VAR_DEF_CONST); - } - } - break; - case JS_VAR_DEF_CATCH: - idx = add_scope_var(ctx, fd, name, JS_VAR_CATCH); - break; - case JS_VAR_DEF_VAR: - if (find_lexical_decl(ctx, fd, name, fd->scope_first, - FALSE) >= 0) { - invalid_lexical_redefinition: - /* error to redefine a var that inside a lexical scope */ - return js_parse_error(s, "invalid redefinition of lexical identifier"); - } - if (fd->is_global_var) { - JSGlobalVar *hf; - hf = find_global_var(fd, name); - if (hf && hf->is_lexical && hf->scope_level == fd->scope_level && - fd->eval_type == JS_EVAL_TYPE_MODULE) { - goto invalid_lexical_redefinition; - } - hf = add_global_var(s->ctx, fd, name); - if (!hf) - return -1; - idx = GLOBAL_VAR_OFFSET; - } else { - /* if the variable already exists, don't add it again */ - idx = find_var(ctx, fd, name); - if (idx >= 0) - break; - idx = add_var(ctx, fd, name); - if (idx >= 0) { - if (name == JS_ATOM_arguments && fd->has_arguments_binding) - fd->arguments_var_idx = idx; - fd->vars[idx].scope_next = fd->scope_level; - } - } - break; - default: - abort(); - } - return idx; -} - -/* find field in the current scope */ -int find_private_class_field(JSContext *ctx, JSFunctionDef *fd, JSAtom name, int scope_level) -{ - int idx; - idx = fd->scopes[scope_level].first; - while (idx != -1) { - if (fd->vars[idx].scope_level != scope_level) - break; - if (fd->vars[idx].var_name == name) - return idx; - idx = fd->vars[idx].scope_next; - } - return -1; -} - -/* build a private setter function name from the private getter name */ -JSAtom get_private_setter_name(JSContext *ctx, JSAtom name) -{ - return js_atom_concat_str(ctx, name, ""); -} - -/* 'name' is freed */ -JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name) -{ - JSModuleDef *m; - m = js_mallocz(ctx, sizeof(*m)); - if (!m) { - JS_FreeAtom(ctx, name); - return NULL; - } - m->header.ref_count = 1; - m->module_name = name; - m->module_ns = JS_UNDEFINED; - m->func_obj = JS_UNDEFINED; - m->eval_exception = JS_UNDEFINED; - m->meta_obj = JS_UNDEFINED; - list_add_tail(&m->link, &ctx->loaded_modules); - return m; -} - -void js_free_module_def(JSContext *ctx, JSModuleDef *m) -{ - int i; - JS_FreeAtom(ctx, m->module_name); - for(i = 0; i < m->req_module_entries_count; i++) { - JSReqModuleEntry *rme = &m->req_module_entries[i]; - JS_FreeAtom(ctx, rme->module_name); - } - js_free(ctx, m->req_module_entries); - for(i = 0; i < m->export_entries_count; i++) { - JSExportEntry *me = &m->export_entries[i]; - if (me->export_type == JS_EXPORT_TYPE_LOCAL) - free_var_ref(ctx->rt, me->u.local.var_ref); - JS_FreeAtom(ctx, me->export_name); - JS_FreeAtom(ctx, me->local_name); - } - js_free(ctx, m->export_entries); - js_free(ctx, m->star_export_entries); - for(i = 0; i < m->import_entries_count; i++) { - JSImportEntry *mi = &m->import_entries[i]; - JS_FreeAtom(ctx, mi->import_name); - } - js_free(ctx, m->import_entries); - JS_FreeValue(ctx, m->module_ns); - JS_FreeValue(ctx, m->func_obj); - JS_FreeValue(ctx, m->eval_exception); - JS_FreeValue(ctx, m->meta_obj); - list_del(&m->link); - js_free(ctx, m); -} - -static JSExportEntry *find_export_entry(JSContext *ctx, JSModuleDef *m, - JSAtom export_name) -{ - JSExportEntry *me; - int i; - for(i = 0; i < m->export_entries_count; i++) { - me = &m->export_entries[i]; - if (me->export_name == export_name) - return me; - } - return NULL; -} - -static JSExportEntry *add_export_entry2(JSContext *ctx, - JSParseState *s, JSModuleDef *m, - JSAtom local_name, JSAtom export_name, - JSExportTypeEnum export_type) -{ - JSExportEntry *me; - if (find_export_entry(ctx, m, export_name)) { - char buf1[ATOM_GET_STR_BUF_SIZE]; - if (s) { - js_parse_error(s, "duplicate exported name '%s'", - JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name)); - } else { - JS_ThrowSyntaxErrorAtom(ctx, "duplicate exported name '%s'", export_name); - } - return NULL; - } - if (js_resize_array(ctx, (void **)&m->export_entries, - sizeof(JSExportEntry), - &m->export_entries_size, - m->export_entries_count + 1)) - return NULL; - me = &m->export_entries[m->export_entries_count++]; - bzero(me, sizeof(*me)); - me->local_name = JS_DupAtom(ctx, local_name); - me->export_name = JS_DupAtom(ctx, export_name); - me->export_type = export_type; - return me; -} - -JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m, - JSAtom local_name, JSAtom export_name, - JSExportTypeEnum export_type) -{ - return add_export_entry2(s->ctx, s, m, local_name, export_name, - export_type); -} - -/* create a C module */ -JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str, - JSModuleInitFunc *func) -{ - JSModuleDef *m; - JSAtom name; - name = JS_NewAtom(ctx, name_str); - if (name == JS_ATOM_NULL) - return NULL; - m = js_new_module_def(ctx, name); - m->init_func = func; - return m; -} - -int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name) -{ - JSExportEntry *me; - JSAtom name; - name = JS_NewAtom(ctx, export_name); - if (name == JS_ATOM_NULL) - return -1; - me = add_export_entry2(ctx, NULL, m, JS_ATOM_NULL, name, - JS_EXPORT_TYPE_LOCAL); - JS_FreeAtom(ctx, name); - if (!me) - return -1; - else - return 0; -} - -int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name, - JSValue val) -{ - JSExportEntry *me; - JSAtom name; - name = JS_NewAtom(ctx, export_name); - if (name == JS_ATOM_NULL) - goto fail; - me = find_export_entry(ctx, m, name); - JS_FreeAtom(ctx, name); - if (!me) - goto fail; - set_value(ctx, me->u.local.var_ref->pvalue, val); - return 0; - fail: - JS_FreeValue(ctx, val); - return -1; -} - -void JS_SetModuleLoaderFunc(JSRuntime *rt, - JSModuleNormalizeFunc *module_normalize, - JSModuleLoaderFunc *module_loader, void *opaque) -{ - rt->module_normalize_func = module_normalize; - rt->module_loader_func = module_loader; - rt->module_loader_opaque = opaque; -} - -/* default module filename normalizer */ -static char *js_default_module_normalize_name(JSContext *ctx, - const char *base_name, - const char *name) -{ - char *filename, *p; - const char *r; - int len; - if (name[0] != '.') { - /* if no initial dot, the module name is not modified */ - return js_strdup(ctx, name); - } - p = strrchr(base_name, '/'); - if (p) - len = p - base_name; - else - len = 0; - filename = js_malloc(ctx, len + strlen(name) + 1 + 1); - if (!filename) - return NULL; - memcpy(filename, base_name, len); - filename[len] = '\0'; - /* we only normalize the leading '..' or '.' */ - r = name; - for(;;) { - if (r[0] == '.' && r[1] == '/') { - r += 2; - } else if (r[0] == '.' && r[1] == '.' && r[2] == '/') { - /* remove the last path element of filename, except if "." - or ".." */ - if (filename[0] == '\0') - break; - p = strrchr(filename, '/'); - if (!p) - p = filename; - else - p++; - if (!strcmp(p, ".") || !strcmp(p, "..")) - break; - if (p > filename) - p--; - *p = '\0'; - r += 3; - } else { - break; - } - } - if (filename[0] != '\0') - strcat(filename, "/"); - strcat(filename, r); - // printf("normalize: %s %s -> %s\n", base_name, name, filename); - return filename; -} - -JSModuleDef *js_find_loaded_module(JSContext *ctx, JSAtom name) -{ - struct list_head *el; - JSModuleDef *m; - /* first look at the loaded modules */ - list_for_each(el, &ctx->loaded_modules) { - m = list_entry(el, JSModuleDef, link); - if (m->module_name == name) - return m; - } - return NULL; -} - -/* return NULL in case of exception (e.g. module could not be loaded) */ -static JSModuleDef *js_host_resolve_imported_module(JSContext *ctx, - const char *base_cname, - const char *cname1) -{ - JSRuntime *rt = ctx->rt; - JSModuleDef *m; - char *cname; - JSAtom module_name; - if (!rt->module_normalize_func) { - cname = js_default_module_normalize_name(ctx, base_cname, cname1); - } else { - cname = rt->module_normalize_func(ctx, base_cname, cname1, - rt->module_loader_opaque); - } - if (!cname) - return NULL; - module_name = JS_NewAtom(ctx, cname); - if (module_name == JS_ATOM_NULL) { - js_free(ctx, cname); - return NULL; - } - /* first look at the loaded modules */ - m = js_find_loaded_module(ctx, module_name); - if (m) { - js_free(ctx, cname); - JS_FreeAtom(ctx, module_name); - return m; - } - JS_FreeAtom(ctx, module_name); - /* load the module */ - if (!rt->module_loader_func) { - /* XXX: use a syntax error ? */ - JS_ThrowReferenceError(ctx, "could not load module '%s'", - cname); - js_free(ctx, cname); - return NULL; - } - m = rt->module_loader_func(ctx, cname, rt->module_loader_opaque); - js_free(ctx, cname); - return m; -} - -static JSModuleDef *js_host_resolve_imported_module_atom(JSContext *ctx, - JSAtom base_module_name, - JSAtom module_name1) -{ - const char *base_cname, *cname; - JSModuleDef *m; - base_cname = JS_AtomToCString(ctx, base_module_name); - if (!base_cname) - return NULL; - cname = JS_AtomToCString(ctx, module_name1); - if (!cname) { - JS_FreeCString(ctx, base_cname); - return NULL; - } - m = js_host_resolve_imported_module(ctx, base_cname, cname); - JS_FreeCString(ctx, base_cname); - JS_FreeCString(ctx, cname); - return m; -} - -typedef struct JSResolveEntry { - JSModuleDef *module; - JSAtom name; -} JSResolveEntry; - -typedef struct JSResolveState { - JSResolveEntry *array; - int size; - int count; -} JSResolveState; - -static int find_resolve_entry(JSResolveState *s, - JSModuleDef *m, JSAtom name) -{ - int i; - for(i = 0; i < s->count; i++) { - JSResolveEntry *re = &s->array[i]; - if (re->module == m && re->name == name) - return i; - } - return -1; -} - -static int add_resolve_entry(JSContext *ctx, JSResolveState *s, - JSModuleDef *m, JSAtom name) -{ - JSResolveEntry *re; - if (js_resize_array(ctx, (void **)&s->array, - sizeof(JSResolveEntry), - &s->size, s->count + 1)) - return -1; - re = &s->array[s->count++]; - re->module = m; - re->name = JS_DupAtom(ctx, name); - return 0; -} - -typedef enum JSResolveResultEnum { - JS_RESOLVE_RES_EXCEPTION = -1, /* memory alloc error */ - JS_RESOLVE_RES_FOUND = 0, - JS_RESOLVE_RES_NOT_FOUND, - JS_RESOLVE_RES_CIRCULAR, - JS_RESOLVE_RES_AMBIGUOUS, -} JSResolveResultEnum; - -static JSResolveResultEnum js_resolve_export1(JSContext *ctx, - JSModuleDef **pmodule, - JSExportEntry **pme, - JSModuleDef *m, - JSAtom export_name, - JSResolveState *s) -{ - JSExportEntry *me; - *pmodule = NULL; - *pme = NULL; - if (find_resolve_entry(s, m, export_name) >= 0) - return JS_RESOLVE_RES_CIRCULAR; - if (add_resolve_entry(ctx, s, m, export_name) < 0) - return JS_RESOLVE_RES_EXCEPTION; - me = find_export_entry(ctx, m, export_name); - if (me) { - if (me->export_type == JS_EXPORT_TYPE_LOCAL) { - /* local export */ - *pmodule = m; - *pme = me; - return JS_RESOLVE_RES_FOUND; - } else { - /* indirect export */ - JSModuleDef *m1; - m1 = m->req_module_entries[me->u.req_module_idx].module; - if (me->local_name == JS_ATOM__star_) { - /* export ns from */ - *pmodule = m; - *pme = me; - return JS_RESOLVE_RES_FOUND; - } else { - return js_resolve_export1(ctx, pmodule, pme, m1, - me->local_name, s); - } - } - } else { - if (export_name != JS_ATOM_default) { - /* not found in direct or indirect exports: try star exports */ - int i; - for(i = 0; i < m->star_export_entries_count; i++) { - JSStarExportEntry *se = &m->star_export_entries[i]; - JSModuleDef *m1, *res_m; - JSExportEntry *res_me; - JSResolveResultEnum ret; - m1 = m->req_module_entries[se->req_module_idx].module; - ret = js_resolve_export1(ctx, &res_m, &res_me, m1, - export_name, s); - if (ret == JS_RESOLVE_RES_AMBIGUOUS || - ret == JS_RESOLVE_RES_EXCEPTION) { - return ret; - } else if (ret == JS_RESOLVE_RES_FOUND) { - if (*pme != NULL) { - if (*pmodule != res_m || - res_me->local_name != (*pme)->local_name) { - *pmodule = NULL; - *pme = NULL; - return JS_RESOLVE_RES_AMBIGUOUS; - } - } else { - *pmodule = res_m; - *pme = res_me; - } - } - } - if (*pme != NULL) - return JS_RESOLVE_RES_FOUND; - } - return JS_RESOLVE_RES_NOT_FOUND; - } -} - -/* If the return value is JS_RESOLVE_RES_FOUND, return the module - (*pmodule) and the corresponding local export entry - (*pme). Otherwise return (NULL, NULL) */ -static JSResolveResultEnum js_resolve_export(JSContext *ctx, - JSModuleDef **pmodule, - JSExportEntry **pme, - JSModuleDef *m, - JSAtom export_name) -{ - JSResolveState ss, *s = &ss; - int i; - JSResolveResultEnum ret; - s->array = NULL; - s->size = 0; - s->count = 0; - ret = js_resolve_export1(ctx, pmodule, pme, m, export_name, s); - for(i = 0; i < s->count; i++) - JS_FreeAtom(ctx, s->array[i].name); - js_free(ctx, s->array); - return ret; -} - -static void js_resolve_export_throw_error(JSContext *ctx, - JSResolveResultEnum res, - JSModuleDef *m, JSAtom export_name) -{ - char buf1[ATOM_GET_STR_BUF_SIZE]; - char buf2[ATOM_GET_STR_BUF_SIZE]; - switch(res) { - case JS_RESOLVE_RES_EXCEPTION: - break; - default: - case JS_RESOLVE_RES_NOT_FOUND: - JS_ThrowSyntaxError(ctx, "Could not find export '%s' in module '%s'", - JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name), - JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name)); - break; - case JS_RESOLVE_RES_CIRCULAR: - JS_ThrowSyntaxError(ctx, "circular reference when looking for export '%s' in module '%s'", - JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name), - JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name)); - break; - case JS_RESOLVE_RES_AMBIGUOUS: - JS_ThrowSyntaxError(ctx, "export '%s' in module '%s' is ambiguous", - JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name), - JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name)); - break; - } -} - -typedef enum { - EXPORTED_NAME_AMBIGUOUS, - EXPORTED_NAME_NORMAL, - EXPORTED_NAME_NS, -} ExportedNameEntryEnum; - -typedef struct ExportedNameEntry { - JSAtom export_name; - ExportedNameEntryEnum export_type; - union { - JSExportEntry *me; /* using when the list is built */ - JSVarRef *var_ref; /* EXPORTED_NAME_NORMAL */ - JSModuleDef *module; /* for EXPORTED_NAME_NS */ - } u; -} ExportedNameEntry; - -typedef struct GetExportNamesState { - JSModuleDef **modules; - int modules_size; - int modules_count; - ExportedNameEntry *exported_names; - int exported_names_size; - int exported_names_count; -} GetExportNamesState; - -static int find_exported_name(GetExportNamesState *s, JSAtom name) -{ - int i; - for(i = 0; i < s->exported_names_count; i++) { - if (s->exported_names[i].export_name == name) - return i; - } - return -1; -} - -static __exception int get_exported_names(JSContext *ctx, - GetExportNamesState *s, - JSModuleDef *m, BOOL from_star) -{ - ExportedNameEntry *en; - int i, j; - /* check circular reference */ - for(i = 0; i < s->modules_count; i++) { - if (s->modules[i] == m) - return 0; - } - if (js_resize_array(ctx, (void **)&s->modules, sizeof(s->modules[0]), - &s->modules_size, s->modules_count + 1)) - return -1; - s->modules[s->modules_count++] = m; - for(i = 0; i < m->export_entries_count; i++) { - JSExportEntry *me = &m->export_entries[i]; - if (from_star && me->export_name == JS_ATOM_default) - continue; - j = find_exported_name(s, me->export_name); - if (j < 0) { - if (js_resize_array(ctx, (void **)&s->exported_names, sizeof(s->exported_names[0]), - &s->exported_names_size, - s->exported_names_count + 1)) - return -1; - en = &s->exported_names[s->exported_names_count++]; - en->export_name = me->export_name; - /* avoid a second lookup for simple module exports */ - if (from_star || me->export_type != JS_EXPORT_TYPE_LOCAL) - en->u.me = NULL; - else - en->u.me = me; - } else { - en = &s->exported_names[j]; - en->u.me = NULL; - } - } - for(i = 0; i < m->star_export_entries_count; i++) { - JSStarExportEntry *se = &m->star_export_entries[i]; - JSModuleDef *m1; - m1 = m->req_module_entries[se->req_module_idx].module; - if (get_exported_names(ctx, s, m1, TRUE)) - return -1; - } - return 0; -} - -/* Unfortunately, the spec gives a different behavior from GetOwnProperty ! */ -static int js_module_ns_has(JSContext *ctx, JSValueConst obj, JSAtom atom) -{ - return (find_own_property1(JS_VALUE_GET_OBJ(obj), atom) != NULL); -} - -static const JSClassExoticMethods js_module_ns_exotic_methods = { - .has_property = js_module_ns_has, -}; - -static int exported_names_cmp(const void *p1, const void *p2, void *opaque) -{ - JSContext *ctx = opaque; - const ExportedNameEntry *me1 = p1; - const ExportedNameEntry *me2 = p2; - JSValue str1, str2; - int ret; - /* XXX: should avoid allocation memory in atom comparison */ - str1 = JS_AtomToString(ctx, me1->export_name); - str2 = JS_AtomToString(ctx, me2->export_name); - if (JS_IsException(str1) || JS_IsException(str2)) { - /* XXX: raise an error ? */ - ret = 0; - } else { - ret = js_string_compare(ctx, JS_VALUE_GET_STRING(str1), - JS_VALUE_GET_STRING(str2)); - } - JS_FreeValue(ctx, str1); - JS_FreeValue(ctx, str2); - return ret; -} - -static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom, - void *opaque) -{ - JSModuleDef *m = opaque; - return js_get_module_ns(ctx, m); -} - -static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m) -{ - JSValue obj; - JSObject *p; - GetExportNamesState s_s, *s = &s_s; - int i, ret; - JSProperty *pr; - obj = JS_NewObjectClass(ctx, JS_CLASS_MODULE_NS); - if (JS_IsException(obj)) - return obj; - p = JS_VALUE_GET_OBJ(obj); - bzero(s, sizeof(*s)); - ret = get_exported_names(ctx, s, m, FALSE); - js_free(ctx, s->modules); - if (ret) - goto fail; - /* Resolve the exported names. The ambiguous exports are removed */ - for(i = 0; i < s->exported_names_count; i++) { - ExportedNameEntry *en = &s->exported_names[i]; - JSResolveResultEnum res; - JSExportEntry *res_me; - JSModuleDef *res_m; - if (en->u.me) { - res_me = en->u.me; /* fast case: no resolution needed */ - res_m = m; - res = JS_RESOLVE_RES_FOUND; - } else { - res = js_resolve_export(ctx, &res_m, &res_me, m, - en->export_name); - } - if (res != JS_RESOLVE_RES_FOUND) { - if (res != JS_RESOLVE_RES_AMBIGUOUS) { - js_resolve_export_throw_error(ctx, res, m, en->export_name); - goto fail; - } - en->export_type = EXPORTED_NAME_AMBIGUOUS; - } else { - if (res_me->local_name == JS_ATOM__star_) { - en->export_type = EXPORTED_NAME_NS; - en->u.module = res_m->req_module_entries[res_me->u.req_module_idx].module; - } else { - en->export_type = EXPORTED_NAME_NORMAL; - if (res_me->u.local.var_ref) { - en->u.var_ref = res_me->u.local.var_ref; - } else { - JSObject *p1 = JS_VALUE_GET_OBJ(res_m->func_obj); - p1 = JS_VALUE_GET_OBJ(res_m->func_obj); - en->u.var_ref = p1->u.func.var_refs[res_me->u.local.var_idx]; - } - } - } - } - /* sort the exported names */ - rqsort(s->exported_names, s->exported_names_count, - sizeof(s->exported_names[0]), exported_names_cmp, ctx); - for(i = 0; i < s->exported_names_count; i++) { - ExportedNameEntry *en = &s->exported_names[i]; - switch(en->export_type) { - case EXPORTED_NAME_NORMAL: - { - JSVarRef *var_ref = en->u.var_ref; - pr = add_property(ctx, p, en->export_name, - JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | - JS_PROP_VARREF); - if (!pr) - goto fail; - var_ref->header.ref_count++; - pr->u.var_ref = var_ref; - } - break; - case EXPORTED_NAME_NS: - /* the exported namespace must be created on demand */ - if (JS_DefineAutoInitProperty(ctx, obj, - en->export_name, - JS_AUTOINIT_ID_MODULE_NS, - en->u.module, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0) - goto fail; - break; - default: - break; - } - } - js_free(ctx, s->exported_names); - JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_toStringTag, - JS_AtomToString(ctx, JS_ATOM_Module), - 0); - p->extensible = FALSE; - return obj; - fail: - js_free(ctx, s->exported_names); - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -JSValue js_get_module_ns(JSContext *ctx, JSModuleDef *m) -{ - if (JS_IsUndefined(m->module_ns)) { - JSValue val; - val = js_build_module_ns(ctx, m); - if (JS_IsException(val)) - return JS_EXCEPTION; - m->module_ns = val; - } - return JS_DupValue(ctx, m->module_ns); -} - -/* Load all the required modules for module 'm' */ -static int js_resolve_module(JSContext *ctx, JSModuleDef *m) -{ - int i; - JSModuleDef *m1; - if (m->resolved) - return 0; -#ifdef DUMP_MODULE_RESOLVE - { - char buf1[ATOM_GET_STR_BUF_SIZE]; - printf("resolving module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); - } -#endif - m->resolved = TRUE; - /* resolve each requested module */ - for(i = 0; i < m->req_module_entries_count; i++) { - JSReqModuleEntry *rme = &m->req_module_entries[i]; - m1 = js_host_resolve_imported_module_atom(ctx, m->module_name, - rme->module_name); - if (!m1) - return -1; - rme->module = m1; - /* already done in js_host_resolve_imported_module() except if - the module was loaded with JS_EvalBinary() */ - if (js_resolve_module(ctx, m1) < 0) - return -1; - } - return 0; -} - -static JSVarRef *js_create_module_var(JSContext *ctx, BOOL is_lexical) -{ - JSVarRef *var_ref; - var_ref = js_malloc(ctx, sizeof(JSVarRef)); - if (!var_ref) - return NULL; - var_ref->header.ref_count = 1; - if (is_lexical) - var_ref->value = JS_UNINITIALIZED; - else - var_ref->value = JS_UNDEFINED; - var_ref->pvalue = &var_ref->value; - var_ref->is_detached = TRUE; - add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF); - return var_ref; -} - -/* Create the function associated with the module */ -static int js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m) -{ - JSFunctionBytecode *b; - int i; - JSVarRef **var_refs; - JSValue func_obj, bfunc; - JSObject *p; - bfunc = m->func_obj; - func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto, - JS_CLASS_BYTECODE_FUNCTION); - if (JS_IsException(func_obj)) - return -1; - b = JS_VALUE_GET_PTR(bfunc); - p = JS_VALUE_GET_OBJ(func_obj); - p->u.func.function_bytecode = b; - b->header.ref_count++; - 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; - /* create the global variables. The other variables are - imported from other modules */ - for(i = 0; i < b->closure_var_count; i++) { - JSClosureVar *cv = &b->closure_var[i]; - JSVarRef *var_ref; - if (cv->is_local) { - var_ref = js_create_module_var(ctx, cv->is_lexical); - if (!var_ref) - goto fail; -#ifdef DUMP_MODULE_RESOLVE - printf("local %d: %p\n", i, var_ref); -#endif - var_refs[i] = var_ref; - } - } - } - m->func_obj = func_obj; - JS_FreeValue(ctx, bfunc); - return 0; - fail: - JS_FreeValue(ctx, func_obj); - return -1; -} - -/* must be done before js_link_module() because of cyclic references */ -static int js_create_module_function(JSContext *ctx, JSModuleDef *m) -{ - BOOL is_c_module; - int i; - JSVarRef *var_ref; - if (m->func_created) - return 0; - is_c_module = (m->init_func != NULL); - if (is_c_module) { - /* initialize the exported variables */ - for(i = 0; i < m->export_entries_count; i++) { - JSExportEntry *me = &m->export_entries[i]; - if (me->export_type == JS_EXPORT_TYPE_LOCAL) { - var_ref = js_create_module_var(ctx, FALSE); - if (!var_ref) - return -1; - me->u.local.var_ref = var_ref; - } - } - } else { - if (js_create_module_bytecode_function(ctx, m)) - return -1; - } - m->func_created = TRUE; - /* do it on the dependencies */ - for(i = 0; i < m->req_module_entries_count; i++) { - JSReqModuleEntry *rme = &m->req_module_entries[i]; - if (js_create_module_function(ctx, rme->module) < 0) - return -1; - } - return 0; -} - -/* Prepare a module to be executed by resolving all the imported - variables. */ -static int js_link_module(JSContext *ctx, JSModuleDef *m) -{ - int i; - JSImportEntry *mi; - JSModuleDef *m1; - JSVarRef **var_refs, *var_ref; - JSObject *p; - BOOL is_c_module; - JSValue ret_val; - if (m->instantiated) - return 0; - m->instantiated = TRUE; -#ifdef DUMP_MODULE_RESOLVE - { - char buf1[ATOM_GET_STR_BUF_SIZE]; - printf("start instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); - } -#endif - for(i = 0; i < m->req_module_entries_count; i++) { - JSReqModuleEntry *rme = &m->req_module_entries[i]; - if (js_link_module(ctx, rme->module) < 0) - goto fail; - } -#ifdef DUMP_MODULE_RESOLVE - { - char buf1[ATOM_GET_STR_BUF_SIZE]; - printf("instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); - } -#endif - /* check the indirect exports */ - for(i = 0; i < m->export_entries_count; i++) { - JSExportEntry *me = &m->export_entries[i]; - if (me->export_type == JS_EXPORT_TYPE_INDIRECT && - me->local_name != JS_ATOM__star_) { - JSResolveResultEnum ret; - JSExportEntry *res_me; - JSModuleDef *res_m, *m1; - m1 = m->req_module_entries[me->u.req_module_idx].module; - ret = js_resolve_export(ctx, &res_m, &res_me, m1, me->local_name); - if (ret != JS_RESOLVE_RES_FOUND) { - js_resolve_export_throw_error(ctx, ret, m, me->export_name); - goto fail; - } - } - } -#ifdef DUMP_MODULE_RESOLVE - { - printf("exported bindings:\n"); - for(i = 0; i < m->export_entries_count; i++) { - JSExportEntry *me = &m->export_entries[i]; - printf(" name="); print_atom(ctx, me->export_name); - printf(" local="); print_atom(ctx, me->local_name); - printf(" type=%d idx=%d\n", me->export_type, me->u.local.var_idx); - } - } -#endif - is_c_module = (m->init_func != NULL); - if (!is_c_module) { - p = JS_VALUE_GET_OBJ(m->func_obj); - var_refs = p->u.func.var_refs; - for(i = 0; i < m->import_entries_count; i++) { - mi = &m->import_entries[i]; -#ifdef DUMP_MODULE_RESOLVE - printf("import var_idx=%d name=", mi->var_idx); - print_atom(ctx, mi->import_name); - printf(": "); -#endif - m1 = m->req_module_entries[mi->req_module_idx].module; - if (mi->import_name == JS_ATOM__star_) { - JSValue val; - /* name space import */ - val = js_get_module_ns(ctx, m1); - if (JS_IsException(val)) - goto fail; - set_value(ctx, &var_refs[mi->var_idx]->value, val); -#ifdef DUMP_MODULE_RESOLVE - printf("namespace\n"); -#endif - } else { - JSResolveResultEnum ret; - JSExportEntry *res_me; - JSModuleDef *res_m; - JSObject *p1; - ret = js_resolve_export(ctx, &res_m, - &res_me, m1, mi->import_name); - if (ret != JS_RESOLVE_RES_FOUND) { - js_resolve_export_throw_error(ctx, ret, m1, mi->import_name); - goto fail; - } - if (res_me->local_name == JS_ATOM__star_) { - JSValue val; - JSModuleDef *m2; - /* name space import from */ - m2 = res_m->req_module_entries[res_me->u.req_module_idx].module; - val = js_get_module_ns(ctx, m2); - if (JS_IsException(val)) - goto fail; - var_ref = js_create_module_var(ctx, TRUE); - if (!var_ref) { - JS_FreeValue(ctx, val); - goto fail; - } - set_value(ctx, &var_ref->value, val); - var_refs[mi->var_idx] = var_ref; -#ifdef DUMP_MODULE_RESOLVE - printf("namespace from\n"); -#endif - } else { - var_ref = res_me->u.local.var_ref; - if (!var_ref) { - p1 = JS_VALUE_GET_OBJ(res_m->func_obj); - var_ref = p1->u.func.var_refs[res_me->u.local.var_idx]; - } - var_ref->header.ref_count++; - var_refs[mi->var_idx] = var_ref; -#ifdef DUMP_MODULE_RESOLVE - printf("local export (var_ref=%p)\n", var_ref); -#endif - } - } - } - /* keep the exported variables in the module export entries (they - are used when the eval function is deleted and cannot be - initialized before in case imports are exported) */ - for(i = 0; i < m->export_entries_count; i++) { - JSExportEntry *me = &m->export_entries[i]; - if (me->export_type == JS_EXPORT_TYPE_LOCAL) { - var_ref = var_refs[me->u.local.var_idx]; - var_ref->header.ref_count++; - me->u.local.var_ref = var_ref; - } - } - /* initialize the global variables */ - ret_val = JS_Call(ctx, m->func_obj, JS_TRUE, 0, NULL); - if (JS_IsException(ret_val)) - goto fail; - JS_FreeValue(ctx, ret_val); - } -#ifdef DUMP_MODULE_RESOLVE - printf("done instantiate\n"); -#endif - return 0; - fail: - return -1; -} - -/* return JS_ATOM_NULL if the name cannot be found. Only works with - not striped bytecode functions. */ -JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels) -{ - JSStackFrame *sf; - JSFunctionBytecode *b; - JSObject *p; - /* XXX: currently we just use the filename of the englobing - function. It does not work for eval(). Need to add a - ScriptOrModule info in JSFunctionBytecode */ - sf = ctx->rt->current_stack_frame; - if (!sf) - return JS_ATOM_NULL; - while (n_stack_levels-- > 0) { - sf = sf->prev_frame; - if (!sf) - return JS_ATOM_NULL; - } - if (JS_VALUE_GET_TAG(sf->cur_func) != JS_TAG_OBJECT) - return JS_ATOM_NULL; - p = JS_VALUE_GET_OBJ(sf->cur_func); - if (!js_class_has_bytecode(p->class_id)) - return JS_ATOM_NULL; - b = p->u.func.function_bytecode; - if (!b->has_debug) - return JS_ATOM_NULL; - return JS_DupAtom(ctx, b->debug.filename); -} - -JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m) -{ - return JS_DupAtom(ctx, m->module_name); -} - -JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m) -{ - JSValue obj; - /* allocate meta_obj only if requested to save memory */ - obj = m->meta_obj; - if (JS_IsUndefined(obj)) { - obj = JS_NewObjectProto(ctx, JS_NULL); - if (JS_IsException(obj)) - return JS_EXCEPTION; - m->meta_obj = obj; - } - return JS_DupValue(ctx, obj); -} - -/* used by os.Worker() and import() */ -JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename, - const char *filename) -{ - JSModuleDef *m; - JSValue ret, func_obj; - m = js_host_resolve_imported_module(ctx, basename, filename); - if (!m) - return NULL; - if (js_resolve_module(ctx, m) < 0) { - js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED); - return NULL; - } - /* Evaluate the module code */ - func_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); - ret = JS_EvalFunction(ctx, func_obj); - if (JS_IsException(ret)) - return NULL; - JS_FreeValue(ctx, ret); - return m; -} - -/* Run the function of the module and of all its requested - modules. */ -static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m) -{ - JSModuleDef *m1; - int i; - JSValue ret_val; - if (m->eval_mark) - return JS_UNDEFINED; /* avoid cycles */ - if (m->evaluated) { - /* if the module was already evaluated, rethrow the exception - it raised */ - if (m->eval_has_exception) { - return JS_Throw(ctx, JS_DupValue(ctx, m->eval_exception)); - } else { - return JS_UNDEFINED; - } - } - m->eval_mark = TRUE; - for(i = 0; i < m->req_module_entries_count; i++) { - JSReqModuleEntry *rme = &m->req_module_entries[i]; - m1 = rme->module; - if (!m1->eval_mark) { - ret_val = js_evaluate_module(ctx, m1); - if (JS_IsException(ret_val)) { - m->eval_mark = FALSE; - return ret_val; - } - JS_FreeValue(ctx, ret_val); - } - } - if (m->init_func) { - /* C module init */ - if (m->init_func(ctx, m) < 0) - ret_val = JS_EXCEPTION; - else - ret_val = JS_UNDEFINED; - } else { - ret_val = JS_CallFree(ctx, m->func_obj, JS_UNDEFINED, 0, NULL); - m->func_obj = JS_UNDEFINED; - } - if (JS_IsException(ret_val)) { - /* save the thrown exception value */ - m->eval_has_exception = TRUE; - m->eval_exception = JS_DupValue(ctx, ctx->rt->current_exception); - } - m->eval_mark = FALSE; - m->evaluated = TRUE; - return ret_val; -} - -JSFunctionDef *js_new_function_def(JSContext *ctx, - JSFunctionDef *parent, - BOOL is_eval, - BOOL is_func_expr, - const char *filename, int line_num) -{ - JSFunctionDef *fd; - fd = js_mallocz(ctx, sizeof(*fd)); - if (!fd) - return NULL; - fd->ctx = ctx; - init_list_head(&fd->child_list); - /* insert in parent list */ - fd->parent = parent; - fd->parent_cpool_idx = -1; - if (parent) { - list_add_tail(&fd->link, &parent->child_list); - fd->js_mode = parent->js_mode; - fd->parent_scope_level = parent->scope_level; - } - fd->is_eval = is_eval; - fd->is_func_expr = is_func_expr; - js_dbuf_init(ctx, &fd->byte_code); - fd->last_opcode_pos = -1; - fd->func_name = JS_ATOM_NULL; - fd->var_object_idx = -1; - fd->arg_var_object_idx = -1; - fd->arguments_var_idx = -1; - fd->arguments_arg_idx = -1; - fd->func_var_idx = -1; - fd->eval_ret_idx = -1; - fd->this_var_idx = -1; - fd->new_target_var_idx = -1; - fd->this_active_func_var_idx = -1; - fd->home_object_var_idx = -1; - /* XXX: should distinguish arg, var and var object and body scopes */ - fd->scopes = fd->def_scope_array; - fd->scope_size = countof(fd->def_scope_array); - fd->scope_count = 1; - fd->scopes[0].first = -1; - fd->scopes[0].parent = -1; - fd->scope_level = 0; /* 0: var/arg scope */ - fd->scope_first = -1; - fd->body_scope = -1; - fd->filename = JS_NewAtom(ctx, filename); - fd->line_num = line_num; - js_dbuf_init(ctx, &fd->pc2line); - //fd->pc2line_last_line_num = line_num; - //fd->pc2line_last_pc = 0; - fd->last_opcode_line_num = line_num; - return fd; -} - -void free_bytecode_atoms(JSRuntime *rt, - const uint8_t *bc_buf, int bc_len, - BOOL use_short_opcodes) -{ - int pos, len, op; - JSAtom atom; - const JSOpCode *oi; - pos = 0; - while (pos < bc_len) { - op = bc_buf[pos]; - if (use_short_opcodes) - oi = &short_opcode_info(op); - else - oi = &opcode_info[op]; - len = oi->size; - switch(oi->fmt) { - case OP_FMT_atom: - case OP_FMT_atom_u8: - case OP_FMT_atom_u16: - case OP_FMT_atom_label_u8: - case OP_FMT_atom_label_u16: - atom = get_u32(bc_buf + pos + 1); - JS_FreeAtomRT(rt, atom); - break; - default: - break; - } - pos += len; - } -} - -void js_free_function_def(JSContext *ctx, JSFunctionDef *fd) -{ - int i; - struct list_head *el, *el1; - /* free the child functions */ - list_for_each_safe(el, el1, &fd->child_list) { - JSFunctionDef *fd1; - fd1 = list_entry(el, JSFunctionDef, link); - js_free_function_def(ctx, fd1); - } - free_bytecode_atoms(ctx->rt, fd->byte_code.buf, fd->byte_code.size, - fd->use_short_opcodes); - dbuf_free(&fd->byte_code); - js_free(ctx, fd->jump_slots); - js_free(ctx, fd->label_slots); - js_free(ctx, fd->line_number_slots); - for(i = 0; i < fd->cpool_count; i++) { - JS_FreeValue(ctx, fd->cpool[i]); - } - js_free(ctx, fd->cpool); - JS_FreeAtom(ctx, fd->func_name); - for(i = 0; i < fd->var_count; i++) { - JS_FreeAtom(ctx, fd->vars[i].var_name); - } - js_free(ctx, fd->vars); - for(i = 0; i < fd->arg_count; i++) { - JS_FreeAtom(ctx, fd->args[i].var_name); - } - js_free(ctx, fd->args); - for(i = 0; i < fd->global_var_count; i++) { - JS_FreeAtom(ctx, fd->global_vars[i].var_name); - } - js_free(ctx, fd->global_vars); - for(i = 0; i < fd->closure_var_count; i++) { - JSClosureVar *cv = &fd->closure_var[i]; - JS_FreeAtom(ctx, cv->var_name); - } - js_free(ctx, fd->closure_var); - if (fd->scopes != fd->def_scope_array) - js_free(ctx, fd->scopes); - JS_FreeAtom(ctx, fd->filename); - dbuf_free(&fd->pc2line); - js_free(ctx, fd->source); - if (fd->parent) { - /* remove in parent list */ - list_del(&fd->link); - } - js_free(ctx, fd); -} - -#ifdef DUMP_BYTECODE -static const char *skip_lines(const char *p, int n) { - while (n-- > 0 && *p) { - while (*p && *p++ != '\n') - continue; - } - return p; -} - -static void print_lines(const char *source, int line, int line1) { - const char *s = source; - const char *p = skip_lines(s, line); - if (*p) { - while (line++ < line1) { - p = skip_lines(s = p, 1); - printf(";; %.*s", (int)(p - s), s); - if (!*p) { - if (p[-1] != '\n') - printf("\n"); - break; - } - } - } -} - -static void dump_byte_code(JSContext *ctx, int pass, - const uint8_t *tab, int len, - const JSVarDef *args, int arg_count, - const JSVarDef *vars, int var_count, - const JSClosureVar *closure_var, int closure_var_count, - const JSValue *cpool, uint32_t cpool_count, - const char *source, int line_num, - const LabelSlot *label_slots, JSFunctionBytecode *b) -{ - const JSOpCode *oi; - int pos, pos_next, op, size, idx, addr, line, line1, in_source; - uint8_t *bits = js_mallocz(ctx, len * sizeof(*bits)); - BOOL use_short_opcodes = (b != NULL); - /* scan for jump targets */ - for (pos = 0; pos < len; pos = pos_next) { - op = tab[pos]; - if (use_short_opcodes) - oi = &short_opcode_info(op); - else - oi = &opcode_info[op]; - pos_next = pos + oi->size; - if (op < OP_COUNT) { - switch (oi->fmt) { -#if SHORT_OPCODES - case OP_FMT_label8: - pos++; - addr = (int8_t)tab[pos]; - goto has_addr; - case OP_FMT_label16: - pos++; - addr = (int16_t)get_u16(tab + pos); - goto has_addr; -#endif - case OP_FMT_atom_label_u8: - case OP_FMT_atom_label_u16: - pos += 4; - /* fall thru */ - case OP_FMT_label: - case OP_FMT_label_u16: - pos++; - addr = get_u32(tab + pos); - goto has_addr; - has_addr: - if (pass == 1) - addr = label_slots[addr].pos; - if (pass == 2) - addr = label_slots[addr].pos2; - if (pass == 3) - addr += pos; - if (addr >= 0 && addr < len) - bits[addr] |= 1; - break; - } - } - } - in_source = 0; - if (source) { - /* Always print first line: needed if single line */ - print_lines(source, 0, 1); - in_source = 1; - } - line1 = line = 1; - pos = 0; - while (pos < len) { - op = tab[pos]; - if (source) { - if (b) { - line1 = find_line_num(ctx, b, pos) - line_num + 1; - } else if (op == OP_line_num) { - line1 = get_u32(tab + pos + 1) - line_num + 1; - } - if (line1 > line) { - if (!in_source) - printf("\n"); - in_source = 1; - print_lines(source, line, line1); - line = line1; - //bits[pos] |= 2; - } - } - if (in_source) - printf("\n"); - in_source = 0; - if (op >= OP_COUNT) { - printf("invalid opcode (0x%02x)\n", op); - pos++; - continue; - } - if (use_short_opcodes) - oi = &short_opcode_info(op); - else - oi = &opcode_info[op]; - size = oi->size; - if (pos + size > len) { - printf("truncated opcode (0x%02x)\n", op); - break; - } -#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 16) - { - int i, x, x0; - x = x0 = printf("%5d ", pos); - for (i = 0; i < size; i++) { - if (i == 6) { - printf("\n%*s", x = x0, ""); - } - x += printf(" %02X", tab[pos + i]); - } - printf("%*s", x0 + 20 - x, ""); - } -#endif - if (bits[pos]) { - printf("%5d: ", pos); - } else { - printf(" "); - } - printf("%s", oi->name); - pos++; - switch(oi->fmt) { - case OP_FMT_none_int: - printf(" %d", op - OP_push_0); - break; - case OP_FMT_npopx: - printf(" %d", op - OP_call0); - break; - case OP_FMT_u8: - printf(" %u", get_u8(tab + pos)); - break; - case OP_FMT_i8: - printf(" %d", get_i8(tab + pos)); - break; - case OP_FMT_u16: - case OP_FMT_npop: - printf(" %u", get_u16(tab + pos)); - break; - case OP_FMT_npop_u16: - printf(" %u,%u", get_u16(tab + pos), get_u16(tab + pos + 2)); - break; - case OP_FMT_i16: - printf(" %d", get_i16(tab + pos)); - break; - case OP_FMT_i32: - printf(" %d", get_i32(tab + pos)); - break; - case OP_FMT_u32: - printf(" %u", get_u32(tab + pos)); - break; -#if SHORT_OPCODES - case OP_FMT_label8: - addr = get_i8(tab + pos); - goto has_addr1; - case OP_FMT_label16: - addr = get_i16(tab + pos); - goto has_addr1; -#endif - case OP_FMT_label: - addr = get_u32(tab + pos); - goto has_addr1; - has_addr1: - if (pass == 1) - printf(" %u:%u", addr, label_slots[addr].pos); - if (pass == 2) - printf(" %u:%u", addr, label_slots[addr].pos2); - if (pass == 3) - printf(" %u", addr + pos); - break; - case OP_FMT_label_u16: - addr = get_u32(tab + pos); - if (pass == 1) - printf(" %u:%u", addr, label_slots[addr].pos); - if (pass == 2) - printf(" %u:%u", addr, label_slots[addr].pos2); - if (pass == 3) - printf(" %u", addr + pos); - printf(",%u", get_u16(tab + pos + 4)); - break; -#if SHORT_OPCODES - case OP_FMT_const8: - idx = get_u8(tab + pos); - goto has_pool_idx; -#endif - case OP_FMT_const: - idx = get_u32(tab + pos); - goto has_pool_idx; - has_pool_idx: - printf(" %u: ", idx); - if (idx < cpool_count) { - JS_DumpValue(ctx, cpool[idx]); - } - break; - case OP_FMT_atom: - printf(" "); - print_atom(ctx, get_u32(tab + pos)); - break; - case OP_FMT_atom_u8: - printf(" "); - print_atom(ctx, get_u32(tab + pos)); - printf(",%d", get_u8(tab + pos + 4)); - break; - case OP_FMT_atom_u16: - printf(" "); - print_atom(ctx, get_u32(tab + pos)); - printf(",%d", get_u16(tab + pos + 4)); - break; - case OP_FMT_atom_label_u8: - case OP_FMT_atom_label_u16: - printf(" "); - print_atom(ctx, get_u32(tab + pos)); - addr = get_u32(tab + pos + 4); - if (pass == 1) - printf(",%u:%u", addr, label_slots[addr].pos); - if (pass == 2) - printf(",%u:%u", addr, label_slots[addr].pos2); - if (pass == 3) - printf(",%u", addr + pos + 4); - if (oi->fmt == OP_FMT_atom_label_u8) - printf(",%u", get_u8(tab + pos + 8)); - else - printf(",%u", get_u16(tab + pos + 8)); - break; - case OP_FMT_none_loc: - idx = (op - OP_get_loc0) % 4; - goto has_loc; - case OP_FMT_loc8: - idx = get_u8(tab + pos); - goto has_loc; - case OP_FMT_loc: - idx = get_u16(tab + pos); - has_loc: - printf(" %d: ", idx); - if (idx < var_count) { - print_atom(ctx, vars[idx].var_name); - } - break; - case OP_FMT_none_arg: - idx = (op - OP_get_arg0) % 4; - goto has_arg; - case OP_FMT_arg: - idx = get_u16(tab + pos); - has_arg: - printf(" %d: ", idx); - if (idx < arg_count) { - print_atom(ctx, args[idx].var_name); - } - break; - case OP_FMT_none_var_ref: - idx = (op - OP_get_var_ref0) % 4; - goto has_var_ref; - case OP_FMT_var_ref: - idx = get_u16(tab + pos); - has_var_ref: - printf(" %d: ", idx); - if (idx < closure_var_count) { - print_atom(ctx, closure_var[idx].var_name); - } - break; - default: - break; - } - printf("\n"); - pos += oi->size - 1; - } - if (source) { - if (!in_source) - printf("\n"); - print_lines(source, line, INT32_MAX); - } - js_free(ctx, bits); -} - -static __maybe_unused void dump_pc2line(JSContext *ctx, const uint8_t *buf, int len, - int line_num) -{ - const uint8_t *p_end, *p_next, *p; - int pc, v; - unsigned int op; - if (len <= 0) - return; - printf("%5s %5s\n", "PC", "LINE"); - p = buf; - p_end = buf + len; - pc = 0; - while (p < p_end) { - op = *p++; - if (op == 0) { - v = unicode_from_utf8(p, p_end - p, &p_next); - if (v < 0) - goto fail; - pc += v; - p = p_next; - v = unicode_from_utf8(p, p_end - p, &p_next); - if (v < 0) { - fail: - printf("invalid pc2line encode pos=%d\n", (int)(p - buf)); - return; - } - if (!(v & 1)) { - v = v >> 1; - } else { - v = -(v >> 1) - 1; - } - line_num += v; - p = p_next; - } else { - op -= PC2LINE_OP_FIRST; - pc += (op / PC2LINE_RANGE); - line_num += (op % PC2LINE_RANGE) + PC2LINE_BASE; - } - printf("%5d %5d\n", pc, line_num); - } -} - -void js_dump_function_bytecode(JSContext *ctx, JSFunctionBytecode *b) -{ - int i; - char atom_buf[ATOM_GET_STR_BUF_SIZE]; - const char *str; - if (b->has_debug && b->debug.filename != JS_ATOM_NULL) { - str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->debug.filename); - printf("%s:%d: ", str, b->debug.line_num); - } - str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->func_name); - printf("function: %s%s\n", &"*"[b->func_kind != JS_FUNC_GENERATOR], str); - if (b->js_mode) { - printf(" mode:"); - if (b->js_mode & JS_MODE_STRICT) - printf(" strict"); -#ifdef CONFIG_BIGNUM - if (b->js_mode & JS_MODE_MATH) - printf(" math"); -#endif - printf("\n"); - } - if (b->arg_count && b->vardefs) { - printf(" args:"); - for(i = 0; i < b->arg_count; i++) { - printf(" %s", JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), - b->vardefs[i].var_name)); - } - printf("\n"); - } - if (b->var_count && b->vardefs) { - printf(" locals:\n"); - for(i = 0; i < b->var_count; i++) { - JSVarDef *vd = &b->vardefs[b->arg_count + i]; - printf("%5d: %s %s", i, - vd->var_kind == JS_VAR_CATCH ? "catch" : - (vd->var_kind == JS_VAR_FUNCTION_DECL || - vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) ? "function" : - vd->is_const ? "const" : - vd->is_lexical ? "let" : "var", - JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), vd->var_name)); - if (vd->scope_level) - printf(" [level:%d next:%d]", vd->scope_level, vd->scope_next); - printf("\n"); - } - } - if (b->closure_var_count) { - printf(" closure vars:\n"); - for(i = 0; i < b->closure_var_count; i++) { - JSClosureVar *cv = &b->closure_var[i]; - printf("%5d: %s %s:%s%d %s\n", i, - JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), cv->var_name), - cv->is_local ? "local" : "parent", - cv->is_arg ? "arg" : "loc", cv->var_idx, - cv->is_const ? "const" : - cv->is_lexical ? "let" : "var"); - } - } - printf(" stack_size: %d\n", b->stack_size); - printf(" opcodes:\n"); - dump_byte_code(ctx, 3, b->byte_code_buf, b->byte_code_len, - b->vardefs, b->arg_count, - b->vardefs ? b->vardefs + b->arg_count : NULL, b->var_count, - b->closure_var, b->closure_var_count, - b->cpool, b->cpool_count, - b->has_debug ? b->debug.source : NULL, - b->has_debug ? b->debug.line_num : -1, NULL, b); -#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 32) - if (b->has_debug) - dump_pc2line(ctx, b->debug.pc2line_buf, b->debug.pc2line_len, b->debug.line_num); -#endif - printf("\n"); -} -#endif - -int add_closure_var(JSContext *ctx, JSFunctionDef *s, - BOOL is_local, BOOL is_arg, - int var_idx, JSAtom var_name, - BOOL is_const, BOOL is_lexical, - JSVarKindEnum var_kind) -{ - JSClosureVar *cv; - /* the closure variable indexes are currently stored on 16 bits */ - if (s->closure_var_count >= JS_MAX_LOCAL_VARS) { - JS_ThrowInternalError(ctx, "too many closure variables"); - return -1; - } - if (js_resize_array(ctx, (void **)&s->closure_var, - sizeof(s->closure_var[0]), - &s->closure_var_size, s->closure_var_count + 1)) - return -1; - cv = &s->closure_var[s->closure_var_count++]; - cv->is_local = is_local; - cv->is_arg = is_arg; - cv->is_const = is_const; - cv->is_lexical = is_lexical; - cv->var_kind = var_kind; - cv->var_idx = var_idx; - cv->var_name = JS_DupAtom(ctx, var_name); - return s->closure_var_count - 1; -} - -static int find_closure_var(JSContext *ctx, JSFunctionDef *s, - JSAtom var_name) -{ - int i; - for(i = 0; i < s->closure_var_count; i++) { - JSClosureVar *cv = &s->closure_var[i]; - if (cv->var_name == var_name) - return i; - } - return -1; -} - -/* 'fd' must be a parent of 's'. Create in 's' a closure referencing a - local variable (is_local = TRUE) or a closure (is_local = FALSE) in - 'fd' */ -static int get_closure_var2(JSContext *ctx, JSFunctionDef *s, - JSFunctionDef *fd, BOOL is_local, - BOOL is_arg, int var_idx, JSAtom var_name, - BOOL is_const, BOOL is_lexical, - JSVarKindEnum var_kind) -{ - int i; - if (fd != s->parent) { - var_idx = get_closure_var2(ctx, s->parent, fd, is_local, - is_arg, var_idx, var_name, - is_const, is_lexical, var_kind); - if (var_idx < 0) - return -1; - is_local = FALSE; - } - for(i = 0; i < s->closure_var_count; i++) { - JSClosureVar *cv = &s->closure_var[i]; - if (cv->var_idx == var_idx && cv->is_arg == is_arg && - cv->is_local == is_local) - return i; - } - return add_closure_var(ctx, s, is_local, is_arg, var_idx, var_name, - is_const, is_lexical, var_kind); -} - -static int get_closure_var(JSContext *ctx, JSFunctionDef *s, - JSFunctionDef *fd, BOOL is_arg, - int var_idx, JSAtom var_name, - BOOL is_const, BOOL is_lexical, - JSVarKindEnum var_kind) -{ - return get_closure_var2(ctx, s, fd, TRUE, is_arg, - var_idx, var_name, is_const, is_lexical, - var_kind); -} - -static int get_with_scope_opcode(int op) -{ - if (op == OP_scope_get_var_undef) - return OP_with_get_var; - else - return OP_with_get_var + (op - OP_scope_get_var); -} - -static BOOL can_opt_put_ref_value(const uint8_t *bc_buf, int pos) -{ - int opcode = bc_buf[pos]; - return (bc_buf[pos + 1] == OP_put_ref_value && - (opcode == OP_insert3 || - opcode == OP_perm4 || - opcode == OP_nop || - opcode == OP_rot3l)); -} - -static BOOL can_opt_put_global_ref_value(const uint8_t *bc_buf, int pos) -{ - int opcode = bc_buf[pos]; - return (bc_buf[pos + 1] == OP_put_ref_value && - (opcode == OP_insert3 || - opcode == OP_perm4 || - opcode == OP_nop || - opcode == OP_rot3l)); -} - -static int optimize_scope_make_ref(JSContext *ctx, JSFunctionDef *s, - DynBuf *bc, uint8_t *bc_buf, - LabelSlot *ls, int pos_next, - int get_op, int var_idx) -{ - int label_pos, end_pos, pos; - /* XXX: should optimize `loc(a) += expr` as `expr add_loc(a)` - but only if expr does not modify `a`. - should scan the code between pos_next and label_pos - for operations that can potentially change `a`: - OP_scope_make_ref(a), function calls, jumps and gosub. - */ - /* replace the reference get/put with normal variable - accesses */ - if (bc_buf[pos_next] == OP_get_ref_value) { - dbuf_putc(bc, get_op); - dbuf_put_u16(bc, var_idx); - pos_next++; - } - /* remove the OP_label to make room for replacement */ - /* label should have a refcount of 0 anyway */ - /* XXX: should avoid this patch by inserting nops in phase 1 */ - label_pos = ls->pos; - pos = label_pos - 5; - assert(bc_buf[pos] == OP_label); - /* label points to an instruction pair: - - insert3 / put_ref_value - - perm4 / put_ref_value - - rot3l / put_ref_value - - nop / put_ref_value - */ - end_pos = label_pos + 2; - if (bc_buf[label_pos] == OP_insert3) - bc_buf[pos++] = OP_dup; - bc_buf[pos] = get_op + 1; - put_u16(bc_buf + pos + 1, var_idx); - pos += 3; - /* pad with OP_nop */ - while (pos < end_pos) - bc_buf[pos++] = OP_nop; - return pos_next; -} - -static int optimize_scope_make_global_ref(JSContext *ctx, JSFunctionDef *s, - DynBuf *bc, uint8_t *bc_buf, - LabelSlot *ls, int pos_next, - JSAtom var_name) -{ - int label_pos, end_pos, pos, op; - BOOL is_strict; - is_strict = ((s->js_mode & JS_MODE_STRICT) != 0); - /* replace the reference get/put with normal variable - accesses */ - if (is_strict) { - /* need to check if the variable exists before evaluating the right - expression */ - /* XXX: need an extra OP_true if destructuring an array */ - dbuf_putc(bc, OP_check_var); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - } else { - /* XXX: need 2 extra OP_true if destructuring an array */ - } - if (bc_buf[pos_next] == OP_get_ref_value) { - dbuf_putc(bc, OP_get_var); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - pos_next++; - } - /* remove the OP_label to make room for replacement */ - /* label should have a refcount of 0 anyway */ - /* XXX: should have emitted several OP_nop to avoid this kludge */ - label_pos = ls->pos; - pos = label_pos - 5; - assert(bc_buf[pos] == OP_label); - end_pos = label_pos + 2; - op = bc_buf[label_pos]; - if (is_strict) { - if (op != OP_nop) { - switch(op) { - case OP_insert3: - op = OP_insert2; - break; - case OP_perm4: - op = OP_perm3; - break; - case OP_rot3l: - op = OP_swap; - break; - default: - abort(); - } - bc_buf[pos++] = op; - } - } else { - if (op == OP_insert3) - bc_buf[pos++] = OP_dup; - } - if (is_strict) { - bc_buf[pos] = OP_put_var_strict; - /* XXX: need 1 extra OP_drop if destructuring an array */ - } else { - bc_buf[pos] = OP_put_var; - /* XXX: need 2 extra OP_drop if destructuring an array */ - } - put_u32(bc_buf + pos + 1, JS_DupAtom(ctx, var_name)); - pos += 5; - /* pad with OP_nop */ - while (pos < end_pos) - bc_buf[pos++] = OP_nop; - return pos_next; -} - -static int add_var_this(JSContext *ctx, JSFunctionDef *fd) -{ - int idx; - idx = add_var(ctx, fd, JS_ATOM_this); - if (idx >= 0 && fd->is_derived_class_constructor) { - JSVarDef *vd = &fd->vars[idx]; - /* XXX: should have is_this flag or var type */ - vd->is_lexical = 1; /* used to trigger 'uninitialized' checks - in a derived class constructor */ - } - return idx; -} - -static int resolve_pseudo_var(JSContext *ctx, JSFunctionDef *s, - JSAtom var_name) -{ - int var_idx; - if (!s->has_this_binding) - return -1; - switch(var_name) { - case JS_ATOM_home_object: - /* 'home_object' pseudo variable */ - if (s->home_object_var_idx < 0) - s->home_object_var_idx = add_var(ctx, s, var_name); - var_idx = s->home_object_var_idx; - break; - case JS_ATOM_this_active_func: - /* 'this.active_func' pseudo variable */ - if (s->this_active_func_var_idx < 0) - s->this_active_func_var_idx = add_var(ctx, s, var_name); - var_idx = s->this_active_func_var_idx; - break; - case JS_ATOM_new_target: - /* 'new.target' pseudo variable */ - if (s->new_target_var_idx < 0) - s->new_target_var_idx = add_var(ctx, s, var_name); - var_idx = s->new_target_var_idx; - break; - case JS_ATOM_this: - /* 'this' pseudo variable */ - if (s->this_var_idx < 0) - s->this_var_idx = add_var_this(ctx, s); - var_idx = s->this_var_idx; - break; - default: - var_idx = -1; - break; - } - return var_idx; -} - -/* test if 'var_name' is in the variable object on the stack. If is it - the case, handle it and jump to 'label_done' */ -static void var_object_test(JSContext *ctx, JSFunctionDef *s, - JSAtom var_name, int op, DynBuf *bc, - int *plabel_done, BOOL is_with) -{ - dbuf_putc(bc, get_with_scope_opcode(op)); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - *plabel_done = new_label_fd(s, *plabel_done); - dbuf_put_u32(bc, *plabel_done); - dbuf_putc(bc, is_with); - update_label(s, *plabel_done, 1); - s->jump_size++; -} - -/* return the position of the next opcode */ -static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, - JSAtom var_name, int scope_level, int op, - DynBuf *bc, uint8_t *bc_buf, - LabelSlot *ls, int pos_next) -{ - int idx, var_idx, is_put; - int label_done; - JSFunctionDef *fd; - JSVarDef *vd; - BOOL is_pseudo_var, is_arg_scope; - label_done = -1; - /* XXX: could be simpler to use a specific function to - resolve the pseudo variables */ - is_pseudo_var = (var_name == JS_ATOM_home_object || - var_name == JS_ATOM_this_active_func || - var_name == JS_ATOM_new_target || - var_name == JS_ATOM_this); - /* resolve local scoped variables */ - var_idx = -1; - for (idx = s->scopes[scope_level].first; idx >= 0;) { - vd = &s->vars[idx]; - if (vd->var_name == var_name) { - if (op == OP_scope_put_var || op == OP_scope_make_ref) { - if (vd->is_const) { - dbuf_putc(bc, OP_throw_error); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - dbuf_putc(bc, JS_THROW_VAR_RO); - goto done; - } - } - var_idx = idx; - break; - } else - if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) { - dbuf_putc(bc, OP_get_loc); - dbuf_put_u16(bc, idx); - var_object_test(ctx, s, var_name, op, bc, &label_done, 1); - } - idx = vd->scope_next; - } - is_arg_scope = (idx == ARG_SCOPE_END); - if (var_idx < 0) { - /* argument scope: variables are not visible but pseudo - variables are visible */ - if (!is_arg_scope) { - var_idx = find_var(ctx, s, var_name); - } - if (var_idx < 0 && is_pseudo_var) - var_idx = resolve_pseudo_var(ctx, s, var_name); - if (var_idx < 0 && var_name == JS_ATOM_arguments && - s->has_arguments_binding) { - /* 'arguments' pseudo variable */ - var_idx = add_arguments_var(ctx, s); - } - if (var_idx < 0 && s->is_func_expr && var_name == s->func_name) { - /* add a new variable with the function name */ - var_idx = add_func_var(ctx, s, var_name); - } - } - if (var_idx >= 0) { - if ((op == OP_scope_put_var || op == OP_scope_make_ref) && - !(var_idx & ARGUMENT_VAR_OFFSET) && - s->vars[var_idx].is_const) { - /* only happens when assigning a function expression name - in strict mode */ - dbuf_putc(bc, OP_throw_error); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - dbuf_putc(bc, JS_THROW_VAR_RO); - goto done; - } - /* OP_scope_put_var_init is only used to initialize a - lexical variable, so it is never used in a with or var object. It - can be used with a closure (module global variable case). */ - switch (op) { - case OP_scope_make_ref: - if (!(var_idx & ARGUMENT_VAR_OFFSET) && - s->vars[var_idx].var_kind == JS_VAR_FUNCTION_NAME) { - /* Create a dummy object reference for the func_var */ - dbuf_putc(bc, OP_object); - dbuf_putc(bc, OP_get_loc); - dbuf_put_u16(bc, var_idx); - dbuf_putc(bc, OP_define_field); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - dbuf_putc(bc, OP_push_atom_value); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - } else - if (label_done == -1 && can_opt_put_ref_value(bc_buf, ls->pos)) { - int get_op; - if (var_idx & ARGUMENT_VAR_OFFSET) { - get_op = OP_get_arg; - var_idx -= ARGUMENT_VAR_OFFSET; - } else { - if (s->vars[var_idx].is_lexical) - get_op = OP_get_loc_check; - else - get_op = OP_get_loc; - } - pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls, - pos_next, get_op, var_idx); - } else { - /* Create a dummy object with a named slot that is - a reference to the local variable */ - if (var_idx & ARGUMENT_VAR_OFFSET) { - dbuf_putc(bc, OP_make_arg_ref); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET); - } else { - dbuf_putc(bc, OP_make_loc_ref); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - dbuf_put_u16(bc, var_idx); - } - } - break; - case OP_scope_get_ref: - dbuf_putc(bc, OP_undefined); - /* fall thru */ - case OP_scope_get_var_undef: - case OP_scope_get_var: - case OP_scope_put_var: - case OP_scope_put_var_init: - is_put = (op == OP_scope_put_var || op == OP_scope_put_var_init); - if (var_idx & ARGUMENT_VAR_OFFSET) { - dbuf_putc(bc, OP_get_arg + is_put); - dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET); - } else { - if (is_put) { - if (s->vars[var_idx].is_lexical) { - if (op == OP_scope_put_var_init) { - /* 'this' can only be initialized once */ - if (var_name == JS_ATOM_this) - dbuf_putc(bc, OP_put_loc_check_init); - else - dbuf_putc(bc, OP_put_loc); - } else { - dbuf_putc(bc, OP_put_loc_check); - } - } else { - dbuf_putc(bc, OP_put_loc); - } - } else { - if (s->vars[var_idx].is_lexical) { - dbuf_putc(bc, OP_get_loc_check); - } else { - dbuf_putc(bc, OP_get_loc); - } - } - dbuf_put_u16(bc, var_idx); - } - break; - case OP_scope_delete_var: - dbuf_putc(bc, OP_push_false); - break; - } - goto done; - } - /* check eval object */ - if (!is_arg_scope && s->var_object_idx >= 0 && !is_pseudo_var) { - dbuf_putc(bc, OP_get_loc); - dbuf_put_u16(bc, s->var_object_idx); - var_object_test(ctx, s, var_name, op, bc, &label_done, 0); - } - /* check eval object in argument scope */ - if (s->arg_var_object_idx >= 0 && !is_pseudo_var) { - dbuf_putc(bc, OP_get_loc); - dbuf_put_u16(bc, s->arg_var_object_idx); - var_object_test(ctx, s, var_name, op, bc, &label_done, 0); - } - /* check parent scopes */ - for (fd = s; fd->parent;) { - scope_level = fd->parent_scope_level; - fd = fd->parent; - for (idx = fd->scopes[scope_level].first; idx >= 0;) { - vd = &fd->vars[idx]; - if (vd->var_name == var_name) { - if (op == OP_scope_put_var || op == OP_scope_make_ref) { - if (vd->is_const) { - dbuf_putc(bc, OP_throw_error); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - dbuf_putc(bc, JS_THROW_VAR_RO); - goto done; - } - } - var_idx = idx; - break; - } else if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) { - vd->is_captured = 1; - idx = get_closure_var(ctx, s, fd, FALSE, idx, vd->var_name, FALSE, FALSE, JS_VAR_NORMAL); - if (idx >= 0) { - dbuf_putc(bc, OP_get_var_ref); - dbuf_put_u16(bc, idx); - var_object_test(ctx, s, var_name, op, bc, &label_done, 1); - } - } - idx = vd->scope_next; - } - is_arg_scope = (idx == ARG_SCOPE_END); - if (var_idx >= 0) - break; - if (!is_arg_scope) { - var_idx = find_var(ctx, fd, var_name); - if (var_idx >= 0) - break; - } - if (is_pseudo_var) { - var_idx = resolve_pseudo_var(ctx, fd, var_name); - if (var_idx >= 0) - break; - } - if (var_name == JS_ATOM_arguments && fd->has_arguments_binding) { - var_idx = add_arguments_var(ctx, fd); - break; - } - if (fd->is_func_expr && fd->func_name == var_name) { - /* add a new variable with the function name */ - var_idx = add_func_var(ctx, fd, var_name); - break; - } - /* check eval object */ - if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) { - vd = &fd->vars[fd->var_object_idx]; - vd->is_captured = 1; - idx = get_closure_var(ctx, s, fd, FALSE, - fd->var_object_idx, vd->var_name, - FALSE, FALSE, JS_VAR_NORMAL); - dbuf_putc(bc, OP_get_var_ref); - dbuf_put_u16(bc, idx); - var_object_test(ctx, s, var_name, op, bc, &label_done, 0); - } - /* check eval object in argument scope */ - if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) { - vd = &fd->vars[fd->arg_var_object_idx]; - vd->is_captured = 1; - idx = get_closure_var(ctx, s, fd, FALSE, - fd->arg_var_object_idx, vd->var_name, - FALSE, FALSE, JS_VAR_NORMAL); - dbuf_putc(bc, OP_get_var_ref); - dbuf_put_u16(bc, idx); - var_object_test(ctx, s, var_name, op, bc, &label_done, 0); - } - if (fd->is_eval) - break; /* it it necessarily the top level function */ - } - /* check direct eval scope (in the closure of the eval function - which is necessarily at the top level) */ - if (!fd) - fd = s; - if (var_idx < 0 && fd->is_eval) { - int idx1; - for (idx1 = 0; idx1 < fd->closure_var_count; idx1++) { - JSClosureVar *cv = &fd->closure_var[idx1]; - if (var_name == cv->var_name) { - if (fd != s) { - idx = get_closure_var2(ctx, s, fd, - FALSE, - cv->is_arg, idx1, - cv->var_name, cv->is_const, - cv->is_lexical, cv->var_kind); - } else { - idx = idx1; - } - goto has_idx; - } else if ((cv->var_name == JS_ATOM__var_ || - cv->var_name == JS_ATOM__arg_var_ || - cv->var_name == JS_ATOM__with_) && !is_pseudo_var) { - int is_with = (cv->var_name == JS_ATOM__with_); - if (fd != s) { - idx = get_closure_var2(ctx, s, fd, - FALSE, - cv->is_arg, idx1, - cv->var_name, FALSE, FALSE, - JS_VAR_NORMAL); - } else { - idx = idx1; - } - dbuf_putc(bc, OP_get_var_ref); - dbuf_put_u16(bc, idx); - var_object_test(ctx, s, var_name, op, bc, &label_done, is_with); - } - } - } - if (var_idx >= 0) { - /* find the corresponding closure variable */ - if (var_idx & ARGUMENT_VAR_OFFSET) { - fd->args[var_idx - ARGUMENT_VAR_OFFSET].is_captured = 1; - idx = get_closure_var(ctx, s, fd, - TRUE, var_idx - ARGUMENT_VAR_OFFSET, - var_name, FALSE, FALSE, JS_VAR_NORMAL); - } else { - fd->vars[var_idx].is_captured = 1; - idx = get_closure_var(ctx, s, fd, - FALSE, var_idx, - var_name, - fd->vars[var_idx].is_const, - fd->vars[var_idx].is_lexical, - fd->vars[var_idx].var_kind); - } - if (idx >= 0) { - has_idx: - if ((op == OP_scope_put_var || op == OP_scope_make_ref) && - s->closure_var[idx].is_const) { - dbuf_putc(bc, OP_throw_error); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - dbuf_putc(bc, JS_THROW_VAR_RO); - goto done; - } - switch (op) { - case OP_scope_make_ref: - if (s->closure_var[idx].var_kind == JS_VAR_FUNCTION_NAME) { - /* Create a dummy object reference for the func_var */ - dbuf_putc(bc, OP_object); - dbuf_putc(bc, OP_get_var_ref); - dbuf_put_u16(bc, idx); - dbuf_putc(bc, OP_define_field); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - dbuf_putc(bc, OP_push_atom_value); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - } else - if (label_done == -1 && - can_opt_put_ref_value(bc_buf, ls->pos)) { - int get_op; - if (s->closure_var[idx].is_lexical) - get_op = OP_get_var_ref_check; - else - get_op = OP_get_var_ref; - pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls, - pos_next, - get_op, idx); - } else { - /* Create a dummy object with a named slot that is - a reference to the closure variable */ - dbuf_putc(bc, OP_make_var_ref_ref); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - dbuf_put_u16(bc, idx); - } - break; - case OP_scope_get_ref: - /* XXX: should create a dummy object with a named slot that is - a reference to the closure variable */ - dbuf_putc(bc, OP_undefined); - /* fall thru */ - case OP_scope_get_var_undef: - case OP_scope_get_var: - case OP_scope_put_var: - case OP_scope_put_var_init: - is_put = (op == OP_scope_put_var || - op == OP_scope_put_var_init); - if (is_put) { - if (s->closure_var[idx].is_lexical) { - if (op == OP_scope_put_var_init) { - /* 'this' can only be initialized once */ - if (var_name == JS_ATOM_this) - dbuf_putc(bc, OP_put_var_ref_check_init); - else - dbuf_putc(bc, OP_put_var_ref); - } else { - dbuf_putc(bc, OP_put_var_ref_check); - } - } else { - dbuf_putc(bc, OP_put_var_ref); - } - } else { - if (s->closure_var[idx].is_lexical) { - dbuf_putc(bc, OP_get_var_ref_check); - } else { - dbuf_putc(bc, OP_get_var_ref); - } - } - dbuf_put_u16(bc, idx); - break; - case OP_scope_delete_var: - dbuf_putc(bc, OP_push_false); - break; - } - goto done; - } - } - /* global variable access */ - switch (op) { - case OP_scope_make_ref: - if (label_done == -1 && can_opt_put_global_ref_value(bc_buf, ls->pos)) { - pos_next = optimize_scope_make_global_ref(ctx, s, bc, bc_buf, ls, - pos_next, var_name); - } else { - dbuf_putc(bc, OP_make_var_ref); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - } - break; - case OP_scope_get_ref: - /* XXX: should create a dummy object with a named slot that is - a reference to the global variable */ - dbuf_putc(bc, OP_undefined); - dbuf_putc(bc, OP_get_var); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - break; - case OP_scope_get_var_undef: - case OP_scope_get_var: - case OP_scope_put_var: - dbuf_putc(bc, OP_get_var_undef + (op - OP_scope_get_var_undef)); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - break; - case OP_scope_put_var_init: - dbuf_putc(bc, OP_put_var_init); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - break; - case OP_scope_delete_var: - dbuf_putc(bc, OP_delete_var); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - break; - } -done: - if (label_done >= 0) { - dbuf_putc(bc, OP_label); - dbuf_put_u32(bc, label_done); - s->label_slots[label_done].pos2 = bc->size; - } - return pos_next; -} - -/* search in all scopes */ -static int find_private_class_field_all(JSContext *ctx, JSFunctionDef *fd, - JSAtom name, int scope_level) -{ - int idx; - idx = fd->scopes[scope_level].first; - while (idx >= 0) { - if (fd->vars[idx].var_name == name) - return idx; - idx = fd->vars[idx].scope_next; - } - return -1; -} - -static void get_loc_or_ref(DynBuf *bc, BOOL is_ref, int idx) -{ - /* if the field is not initialized, the error is catched when - accessing it */ - if (is_ref) - dbuf_putc(bc, OP_get_var_ref); - else - dbuf_putc(bc, OP_get_loc); - dbuf_put_u16(bc, idx); -} - -static int resolve_scope_private_field1(JSContext *ctx, - BOOL *pis_ref, int *pvar_kind, - JSFunctionDef *s, - JSAtom var_name, int scope_level) -{ - int idx, var_kind; - JSFunctionDef *fd; - BOOL is_ref; - fd = s; - is_ref = FALSE; - for(;;) { - idx = find_private_class_field_all(ctx, fd, var_name, scope_level); - if (idx >= 0) { - var_kind = fd->vars[idx].var_kind; - if (is_ref) { - idx = get_closure_var(ctx, s, fd, FALSE, idx, var_name, - TRUE, TRUE, JS_VAR_NORMAL); - if (idx < 0) - return -1; - } - break; - } - scope_level = fd->parent_scope_level; - if (!fd->parent) { - if (fd->is_eval) { - /* closure of the eval function (top level) */ - for (idx = 0; idx < fd->closure_var_count; idx++) { - JSClosureVar *cv = &fd->closure_var[idx]; - if (cv->var_name == var_name) { - var_kind = cv->var_kind; - is_ref = TRUE; - if (fd != s) { - idx = get_closure_var2(ctx, s, fd, - FALSE, - cv->is_arg, idx, - cv->var_name, cv->is_const, - cv->is_lexical, - cv->var_kind); - if (idx < 0) - return -1; - } - goto done; - } - } - } - /* XXX: no line number info */ - JS_ThrowSyntaxErrorAtom(ctx, "undefined private field '%s'", - var_name); - return -1; - } else { - fd = fd->parent; - } - is_ref = TRUE; - } - done: - *pis_ref = is_ref; - *pvar_kind = var_kind; - return idx; -} - -/* return 0 if OK or -1 if the private field could not be resolved */ -static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s, - JSAtom var_name, int scope_level, int op, - DynBuf *bc) -{ - int idx, var_kind; - BOOL is_ref; - idx = resolve_scope_private_field1(ctx, &is_ref, &var_kind, s, - var_name, scope_level); - if (idx < 0) - return -1; - assert(var_kind != JS_VAR_NORMAL); - switch (op) { - case OP_scope_get_private_field: - case OP_scope_get_private_field2: - switch(var_kind) { - case JS_VAR_PRIVATE_FIELD: - if (op == OP_scope_get_private_field2) - dbuf_putc(bc, OP_dup); - get_loc_or_ref(bc, is_ref, idx); - dbuf_putc(bc, OP_get_private_field); - break; - case JS_VAR_PRIVATE_METHOD: - get_loc_or_ref(bc, is_ref, idx); - dbuf_putc(bc, OP_check_brand); - if (op != OP_scope_get_private_field2) - dbuf_putc(bc, OP_nip); - break; - case JS_VAR_PRIVATE_GETTER: - case JS_VAR_PRIVATE_GETTER_SETTER: - if (op == OP_scope_get_private_field2) - dbuf_putc(bc, OP_dup); - get_loc_or_ref(bc, is_ref, idx); - dbuf_putc(bc, OP_check_brand); - dbuf_putc(bc, OP_call_method); - dbuf_put_u16(bc, 0); - break; - case JS_VAR_PRIVATE_SETTER: - /* XXX: add clearer error message */ - dbuf_putc(bc, OP_throw_error); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - dbuf_putc(bc, JS_THROW_VAR_RO); - break; - default: - abort(); - } - break; - case OP_scope_put_private_field: - switch(var_kind) { - case JS_VAR_PRIVATE_FIELD: - get_loc_or_ref(bc, is_ref, idx); - dbuf_putc(bc, OP_put_private_field); - break; - case JS_VAR_PRIVATE_METHOD: - case JS_VAR_PRIVATE_GETTER: - /* XXX: add clearer error message */ - dbuf_putc(bc, OP_throw_error); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - dbuf_putc(bc, JS_THROW_VAR_RO); - break; - case JS_VAR_PRIVATE_SETTER: - case JS_VAR_PRIVATE_GETTER_SETTER: - { - JSAtom setter_name = get_private_setter_name(ctx, var_name); - if (setter_name == JS_ATOM_NULL) - return -1; - idx = resolve_scope_private_field1(ctx, &is_ref, - &var_kind, s, - setter_name, scope_level); - JS_FreeAtom(ctx, setter_name); - if (idx < 0) - return -1; - assert(var_kind == JS_VAR_PRIVATE_SETTER); - get_loc_or_ref(bc, is_ref, idx); - dbuf_putc(bc, OP_swap); - /* obj func value */ - dbuf_putc(bc, OP_rot3r); - /* value obj func */ - dbuf_putc(bc, OP_check_brand); - dbuf_putc(bc, OP_rot3l); - /* obj func value */ - dbuf_putc(bc, OP_call_method); - dbuf_put_u16(bc, 1); - } - break; - default: - abort(); - } - break; - default: - abort(); - } - return 0; -} - -static void mark_eval_captured_variables(JSContext *ctx, JSFunctionDef *s, - int scope_level) -{ - int idx; - JSVarDef *vd; - for (idx = s->scopes[scope_level].first; idx >= 0;) { - vd = &s->vars[idx]; - vd->is_captured = 1; - idx = vd->scope_next; - } -} - -/* XXX: should handle the argument scope generically */ -static BOOL is_var_in_arg_scope(const JSVarDef *vd) -{ - return (vd->var_name == JS_ATOM_home_object || - vd->var_name == JS_ATOM_this_active_func || - vd->var_name == JS_ATOM_new_target || - vd->var_name == JS_ATOM_this || - vd->var_name == JS_ATOM__arg_var_ || - vd->var_kind == JS_VAR_FUNCTION_NAME); -} - -static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) -{ - JSFunctionDef *fd; - JSVarDef *vd; - int i, scope_level, scope_idx; - BOOL has_arguments_binding, has_this_binding, is_arg_scope; - /* in non strict mode, variables are created in the caller's - environment object */ - if (!s->is_eval && !(s->js_mode & JS_MODE_STRICT)) { - s->var_object_idx = add_var(ctx, s, JS_ATOM__var_); - if (s->has_parameter_expressions) { - /* an additional variable object is needed for the - argument scope */ - s->arg_var_object_idx = add_var(ctx, s, JS_ATOM__arg_var_); - } - } - /* eval can potentially use 'arguments' so we must define it */ - has_this_binding = s->has_this_binding; - if (has_this_binding) { - if (s->this_var_idx < 0) - s->this_var_idx = add_var_this(ctx, s); - if (s->new_target_var_idx < 0) - s->new_target_var_idx = add_var(ctx, s, JS_ATOM_new_target); - if (s->is_derived_class_constructor && s->this_active_func_var_idx < 0) - s->this_active_func_var_idx = add_var(ctx, s, JS_ATOM_this_active_func); - if (s->has_home_object && s->home_object_var_idx < 0) - s->home_object_var_idx = add_var(ctx, s, JS_ATOM_home_object); - } - has_arguments_binding = s->has_arguments_binding; - if (has_arguments_binding) { - add_arguments_var(ctx, s); - /* also add an arguments binding in the argument scope to - raise an error if a direct eval in the argument scope tries - to redefine it */ - if (s->has_parameter_expressions && !(s->js_mode & JS_MODE_STRICT)) - add_arguments_arg(ctx, s); - } - if (s->is_func_expr && s->func_name != JS_ATOM_NULL) - add_func_var(ctx, s, s->func_name); - /* eval can use all the variables of the enclosing functions, so - they must be all put in the closure. The closure variables are - ordered by scope. It works only because no closure are created - before. */ - assert(s->is_eval || s->closure_var_count == 0); - /* XXX: inefficient, but eval performance is less critical */ - fd = s; - for(;;) { - scope_level = fd->parent_scope_level; - fd = fd->parent; - if (!fd) - break; - /* add 'this' if it was not previously added */ - if (!has_this_binding && fd->has_this_binding) { - if (fd->this_var_idx < 0) - fd->this_var_idx = add_var_this(ctx, fd); - if (fd->new_target_var_idx < 0) - fd->new_target_var_idx = add_var(ctx, fd, JS_ATOM_new_target); - if (fd->is_derived_class_constructor && fd->this_active_func_var_idx < 0) - fd->this_active_func_var_idx = add_var(ctx, fd, JS_ATOM_this_active_func); - if (fd->has_home_object && fd->home_object_var_idx < 0) - fd->home_object_var_idx = add_var(ctx, fd, JS_ATOM_home_object); - has_this_binding = TRUE; - } - /* add 'arguments' if it was not previously added */ - if (!has_arguments_binding && fd->has_arguments_binding) { - add_arguments_var(ctx, fd); - has_arguments_binding = TRUE; - } - /* add function name */ - if (fd->is_func_expr && fd->func_name != JS_ATOM_NULL) - add_func_var(ctx, fd, fd->func_name); - /* add lexical variables */ - scope_idx = fd->scopes[scope_level].first; - while (scope_idx >= 0) { - vd = &fd->vars[scope_idx]; - vd->is_captured = 1; - get_closure_var(ctx, s, fd, FALSE, scope_idx, - vd->var_name, vd->is_const, vd->is_lexical, vd->var_kind); - scope_idx = vd->scope_next; - } - is_arg_scope = (scope_idx == ARG_SCOPE_END); - if (!is_arg_scope) { - /* add unscoped variables */ - for(i = 0; i < fd->arg_count; i++) { - vd = &fd->args[i]; - if (vd->var_name != JS_ATOM_NULL) { - get_closure_var(ctx, s, fd, - TRUE, i, vd->var_name, FALSE, FALSE, - JS_VAR_NORMAL); - } - } - for(i = 0; i < fd->var_count; i++) { - vd = &fd->vars[i]; - /* do not close top level last result */ - if (vd->scope_level == 0 && - vd->var_name != JS_ATOM__ret_ && - vd->var_name != JS_ATOM_NULL) { - get_closure_var(ctx, s, fd, - FALSE, i, vd->var_name, FALSE, FALSE, - JS_VAR_NORMAL); - } - } - } else { - for(i = 0; i < fd->var_count; i++) { - vd = &fd->vars[i]; - /* do not close top level last result */ - if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) { - get_closure_var(ctx, s, fd, - FALSE, i, vd->var_name, FALSE, FALSE, - JS_VAR_NORMAL); - } - } - } - if (fd->is_eval) { - int idx; - /* add direct eval variables (we are necessarily at the - top level) */ - for (idx = 0; idx < fd->closure_var_count; idx++) { - JSClosureVar *cv = &fd->closure_var[idx]; - get_closure_var2(ctx, s, fd, - FALSE, cv->is_arg, - idx, cv->var_name, cv->is_const, - cv->is_lexical, cv->var_kind); - } - } - } -} - -static void set_closure_from_var(JSContext *ctx, JSClosureVar *cv, - JSVarDef *vd, int var_idx) -{ - cv->is_local = TRUE; - cv->is_arg = FALSE; - cv->is_const = vd->is_const; - cv->is_lexical = vd->is_lexical; - cv->var_kind = vd->var_kind; - cv->var_idx = var_idx; - cv->var_name = JS_DupAtom(ctx, vd->var_name); -} - -/* for direct eval compilation: add references to the variables of the - calling function */ -static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s, - JSFunctionBytecode *b, int scope_idx) -{ - int i, count; - JSVarDef *vd; - BOOL is_arg_scope; - count = b->arg_count + b->var_count + b->closure_var_count; - s->closure_var = NULL; - s->closure_var_count = 0; - s->closure_var_size = count; - if (count == 0) - return 0; - s->closure_var = js_malloc(ctx, sizeof(s->closure_var[0]) * count); - if (!s->closure_var) - return -1; - /* Add lexical variables in scope at the point of evaluation */ - for (i = scope_idx; i >= 0;) { - vd = &b->vardefs[b->arg_count + i]; - if (vd->scope_level > 0) { - JSClosureVar *cv = &s->closure_var[s->closure_var_count++]; - set_closure_from_var(ctx, cv, vd, i); - } - i = vd->scope_next; - } - is_arg_scope = (i == ARG_SCOPE_END); - if (!is_arg_scope) { - /* Add argument variables */ - for(i = 0; i < b->arg_count; i++) { - JSClosureVar *cv = &s->closure_var[s->closure_var_count++]; - vd = &b->vardefs[i]; - cv->is_local = TRUE; - cv->is_arg = TRUE; - cv->is_const = FALSE; - cv->is_lexical = FALSE; - cv->var_kind = JS_VAR_NORMAL; - cv->var_idx = i; - cv->var_name = JS_DupAtom(ctx, vd->var_name); - } - /* Add local non lexical variables */ - for(i = 0; i < b->var_count; i++) { - vd = &b->vardefs[b->arg_count + i]; - if (vd->scope_level == 0 && vd->var_name != JS_ATOM__ret_) { - JSClosureVar *cv = &s->closure_var[s->closure_var_count++]; - set_closure_from_var(ctx, cv, vd, i); - } - } - } else { - /* only add pseudo variables */ - for(i = 0; i < b->var_count; i++) { - vd = &b->vardefs[b->arg_count + i]; - if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) { - JSClosureVar *cv = &s->closure_var[s->closure_var_count++]; - set_closure_from_var(ctx, cv, vd, i); - } - } - } - for(i = 0; i < b->closure_var_count; i++) { - JSClosureVar *cv0 = &b->closure_var[i]; - JSClosureVar *cv = &s->closure_var[s->closure_var_count++]; - cv->is_local = FALSE; - cv->is_arg = cv0->is_arg; - cv->is_const = cv0->is_const; - cv->is_lexical = cv0->is_lexical; - cv->var_kind = cv0->var_kind; - cv->var_idx = i; - cv->var_name = JS_DupAtom(ctx, cv0->var_name); - } - return 0; -} - -typedef struct CodeContext { - const uint8_t *bc_buf; /* code buffer */ - int bc_len; /* length of the code buffer */ - int pos; /* position past the matched code pattern */ - int line_num; /* last visited OP_line_num parameter or -1 */ - int op; - int idx; - int label; - int val; - JSAtom atom; -} CodeContext; - -#define M2(op1, op2) ((op1) | ((op2) << 8)) -#define M3(op1, op2, op3) ((op1) | ((op2) << 8) | ((op3) << 16)) -#define M4(op1, op2, op3, op4) ((op1) | ((op2) << 8) | ((op3) << 16) | ((uint32_t)(op4) << 24)) - -static BOOL code_match(CodeContext *s, int pos, ...) -{ - const uint8_t *tab = s->bc_buf; - int op, len, op1, line_num, pos_next; - va_list ap; - BOOL ret = FALSE; - line_num = -1; - va_start(ap, pos); - for(;;) { - op1 = va_arg(ap, int); - if (op1 == -1) { - s->pos = pos; - s->line_num = line_num; - ret = TRUE; - break; - } - for (;;) { - if (pos >= s->bc_len) - goto done; - op = tab[pos]; - len = opcode_info[op].size; - pos_next = pos + len; - if (pos_next > s->bc_len) - goto done; - if (op == OP_line_num) { - line_num = get_u32(tab + pos + 1); - pos = pos_next; - } else { - break; - } - } - if (op != op1) { - if (op1 == (uint8_t)op1 || !op) - break; - if (op != (uint8_t)op1 - && op != (uint8_t)(op1 >> 8) - && op != (uint8_t)(op1 >> 16) - && op != (uint8_t)(op1 >> 24)) { - break; - } - s->op = op; - } - pos++; - switch(opcode_info[op].fmt) { - case OP_FMT_loc8: - case OP_FMT_u8: - { - int idx = tab[pos]; - int arg = va_arg(ap, int); - if (arg == -1) { - s->idx = idx; - } else { - if (arg != idx) - goto done; - } - break; - } - case OP_FMT_u16: - case OP_FMT_npop: - case OP_FMT_loc: - case OP_FMT_arg: - case OP_FMT_var_ref: - { - int idx = get_u16(tab + pos); - int arg = va_arg(ap, int); - if (arg == -1) { - s->idx = idx; - } else { - if (arg != idx) - goto done; - } - break; - } - case OP_FMT_i32: - case OP_FMT_u32: - case OP_FMT_label: - case OP_FMT_const: - { - s->label = get_u32(tab + pos); - break; - } - case OP_FMT_label_u16: - { - s->label = get_u32(tab + pos); - s->val = get_u16(tab + pos + 4); - break; - } - case OP_FMT_atom: - { - s->atom = get_u32(tab + pos); - break; - } - case OP_FMT_atom_u8: - { - s->atom = get_u32(tab + pos); - s->val = get_u8(tab + pos + 4); - break; - } - case OP_FMT_atom_u16: - { - s->atom = get_u32(tab + pos); - s->val = get_u16(tab + pos + 4); - break; - } - case OP_FMT_atom_label_u8: - { - s->atom = get_u32(tab + pos); - s->label = get_u32(tab + pos + 4); - s->val = get_u8(tab + pos + 8); - break; - } - default: - break; - } - pos = pos_next; - } - done: - va_end(ap); - return ret; -} - -static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, DynBuf *bc) -{ - int i, idx, label_next = -1; - /* add the hoisted functions in arguments and local variables */ - for(i = 0; i < s->arg_count; i++) { - JSVarDef *vd = &s->args[i]; - if (vd->func_pool_idx >= 0) { - dbuf_putc(bc, OP_fclosure); - dbuf_put_u32(bc, vd->func_pool_idx); - dbuf_putc(bc, OP_put_arg); - dbuf_put_u16(bc, i); - } - } - for(i = 0; i < s->var_count; i++) { - JSVarDef *vd = &s->vars[i]; - if (vd->scope_level == 0 && vd->func_pool_idx >= 0) { - dbuf_putc(bc, OP_fclosure); - dbuf_put_u32(bc, vd->func_pool_idx); - dbuf_putc(bc, OP_put_loc); - dbuf_put_u16(bc, i); - } - } - /* the module global variables must be initialized before - evaluating the module so that the exported functions are - visible if there are cyclic module references */ - if (s->module) { - label_next = new_label_fd(s, -1); - /* if 'this' is true, initialize the global variables and return */ - dbuf_putc(bc, OP_push_this); - dbuf_putc(bc, OP_if_false); - dbuf_put_u32(bc, label_next); - update_label(s, label_next, 1); - s->jump_size++; - } - /* add the global variables (only happens if s->is_global_var is - true) */ - for(i = 0; i < s->global_var_count; i++) { - JSGlobalVar *hf = &s->global_vars[i]; - int has_closure = 0; - BOOL force_init = hf->force_init; - /* we are in an eval, so the closure contains all the - enclosing variables */ - /* If the outer function has a variable environment, - create a property for the variable there */ - for(idx = 0; idx < s->closure_var_count; idx++) { - JSClosureVar *cv = &s->closure_var[idx]; - if (cv->var_name == hf->var_name) { - has_closure = 2; - force_init = FALSE; - break; - } - if (cv->var_name == JS_ATOM__var_ || - cv->var_name == JS_ATOM__arg_var_) { - dbuf_putc(bc, OP_get_var_ref); - dbuf_put_u16(bc, idx); - has_closure = 1; - force_init = TRUE; - break; - } - } - if (!has_closure) { - int flags; - flags = 0; - if (s->eval_type != JS_EVAL_TYPE_GLOBAL) - flags |= JS_PROP_CONFIGURABLE; - if (hf->cpool_idx >= 0 && !hf->is_lexical) { - /* global function definitions need a specific handling */ - dbuf_putc(bc, OP_fclosure); - dbuf_put_u32(bc, hf->cpool_idx); - dbuf_putc(bc, OP_define_func); - dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name)); - dbuf_putc(bc, flags); - goto done_global_var; - } else { - if (hf->is_lexical) { - flags |= DEFINE_GLOBAL_LEX_VAR; - if (!hf->is_const) - flags |= JS_PROP_WRITABLE; - } - dbuf_putc(bc, OP_define_var); - dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name)); - dbuf_putc(bc, flags); - } - } - if (hf->cpool_idx >= 0 || force_init) { - if (hf->cpool_idx >= 0) { - dbuf_putc(bc, OP_fclosure); - dbuf_put_u32(bc, hf->cpool_idx); - if (hf->var_name == JS_ATOM__default_) { - /* set default export function name */ - dbuf_putc(bc, OP_set_name); - dbuf_put_u32(bc, JS_DupAtom(ctx, JS_ATOM_default)); - } - } else { - dbuf_putc(bc, OP_undefined); - } - if (has_closure == 2) { - dbuf_putc(bc, OP_put_var_ref); - dbuf_put_u16(bc, idx); - } else if (has_closure == 1) { - dbuf_putc(bc, OP_define_field); - dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name)); - dbuf_putc(bc, OP_drop); - } else { - /* XXX: Check if variable is writable and enumerable */ - dbuf_putc(bc, OP_put_var); - dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name)); - } - } - done_global_var: - JS_FreeAtom(ctx, hf->var_name); - } - if (s->module) { - dbuf_putc(bc, OP_return_undef); - dbuf_putc(bc, OP_label); - dbuf_put_u32(bc, label_next); - s->label_slots[label_next].pos2 = bc->size; - } - js_free(ctx, s->global_vars); - s->global_vars = NULL; - s->global_var_count = 0; - s->global_var_size = 0; -} - -static int skip_dead_code(JSFunctionDef *s, const uint8_t *bc_buf, int bc_len, - int pos, int *linep) -{ - int op, len, label; - for (; pos < bc_len; pos += len) { - op = bc_buf[pos]; - len = opcode_info[op].size; - if (op == OP_line_num) { - *linep = get_u32(bc_buf + pos + 1); - } else - if (op == OP_label) { - label = get_u32(bc_buf + pos + 1); - if (update_label(s, label, 0) > 0) - break; -#if 0 - if (s->label_slots[label].first_reloc) { - printf("line %d: unreferenced label %d:%d has relocations\n", - *linep, label, s->label_slots[label].pos2); - } -#endif - assert(s->label_slots[label].first_reloc == NULL); - } else { - /* XXX: output a warning for unreachable code? */ - JSAtom atom; - switch(opcode_info[op].fmt) { - case OP_FMT_label: - case OP_FMT_label_u16: - label = get_u32(bc_buf + pos + 1); - update_label(s, label, -1); - break; - case OP_FMT_atom_label_u8: - case OP_FMT_atom_label_u16: - label = get_u32(bc_buf + pos + 5); - update_label(s, label, -1); - /* fall thru */ - case OP_FMT_atom: - case OP_FMT_atom_u8: - case OP_FMT_atom_u16: - atom = get_u32(bc_buf + pos + 1); - JS_FreeAtom(s->ctx, atom); - break; - default: - break; - } - } - } - return pos; -} - -static int get_label_pos(JSFunctionDef *s, int label) -{ - int i, pos; - for (i = 0; i < 20; i++) { - pos = s->label_slots[label].pos; - for (;;) { - switch (s->byte_code.buf[pos]) { - case OP_line_num: - case OP_label: - pos += 5; - continue; - case OP_goto: - label = get_u32(s->byte_code.buf + pos + 1); - break; - default: - return pos; - } - break; - } - } - return pos; -} - -/* convert global variable accesses to local variables or closure - variables when necessary */ -static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) -{ - int pos, pos_next, bc_len, op, len, i, idx, line_num; - uint8_t *bc_buf; - JSAtom var_name; - DynBuf bc_out; - CodeContext cc; - int scope; - cc.bc_buf = bc_buf = s->byte_code.buf; - cc.bc_len = bc_len = s->byte_code.size; - js_dbuf_init(ctx, &bc_out); - /* first pass for runtime checks (must be done before the - variables are created) */ - for(i = 0; i < s->global_var_count; i++) { - JSGlobalVar *hf = &s->global_vars[i]; - int flags; - /* check if global variable (XXX: simplify) */ - for(idx = 0; idx < s->closure_var_count; idx++) { - JSClosureVar *cv = &s->closure_var[idx]; - if (cv->var_name == hf->var_name) { - if (s->eval_type == JS_EVAL_TYPE_DIRECT && - cv->is_lexical) { - /* Check if a lexical variable is - redefined as 'var'. XXX: Could abort - compilation here, but for consistency - with the other checks, we delay the - error generation. */ - dbuf_putc(&bc_out, OP_throw_error); - dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name)); - dbuf_putc(&bc_out, JS_THROW_VAR_REDECL); - } - goto next; - } - if (cv->var_name == JS_ATOM__var_ || - cv->var_name == JS_ATOM__arg_var_) - goto next; - } - dbuf_putc(&bc_out, OP_check_define_var); - dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name)); - flags = 0; - if (hf->is_lexical) - flags |= DEFINE_GLOBAL_LEX_VAR; - if (hf->cpool_idx >= 0) - flags |= DEFINE_GLOBAL_FUNC_VAR; - dbuf_putc(&bc_out, flags); - next: ; - } - line_num = 0; /* avoid warning */ - for (pos = 0; pos < bc_len; pos = pos_next) { - op = bc_buf[pos]; - len = opcode_info[op].size; - pos_next = pos + len; - switch(op) { - case OP_line_num: - line_num = get_u32(bc_buf + pos + 1); - s->line_number_size++; - goto no_change; - case OP_eval: /* convert scope index to adjusted variable index */ - { - int call_argc = get_u16(bc_buf + pos + 1); - scope = get_u16(bc_buf + pos + 1 + 2); - mark_eval_captured_variables(ctx, s, scope); - dbuf_putc(&bc_out, op); - dbuf_put_u16(&bc_out, call_argc); - dbuf_put_u16(&bc_out, s->scopes[scope].first + 1); - } - break; - case OP_apply_eval: /* convert scope index to adjusted variable index */ - scope = get_u16(bc_buf + pos + 1); - mark_eval_captured_variables(ctx, s, scope); - dbuf_putc(&bc_out, op); - dbuf_put_u16(&bc_out, s->scopes[scope].first + 1); - break; - case OP_scope_get_var_undef: - case OP_scope_get_var: - case OP_scope_put_var: - case OP_scope_delete_var: - case OP_scope_get_ref: - case OP_scope_put_var_init: - var_name = get_u32(bc_buf + pos + 1); - scope = get_u16(bc_buf + pos + 5); - pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out, - NULL, NULL, pos_next); - JS_FreeAtom(ctx, var_name); - break; - case OP_scope_make_ref: - { - int label; - LabelSlot *ls; - var_name = get_u32(bc_buf + pos + 1); - label = get_u32(bc_buf + pos + 5); - scope = get_u16(bc_buf + pos + 9); - ls = &s->label_slots[label]; - ls->ref_count--; /* always remove label reference */ - pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out, - bc_buf, ls, pos_next); - JS_FreeAtom(ctx, var_name); - } - break; - case OP_scope_get_private_field: - case OP_scope_get_private_field2: - case OP_scope_put_private_field: - { - int ret; - var_name = get_u32(bc_buf + pos + 1); - scope = get_u16(bc_buf + pos + 5); - ret = resolve_scope_private_field(ctx, s, var_name, scope, op, &bc_out); - if (ret < 0) - goto fail; - JS_FreeAtom(ctx, var_name); - } - break; - case OP_gosub: - s->jump_size++; - if (OPTIMIZE) { - /* remove calls to empty finalizers */ - int label; - LabelSlot *ls; - label = get_u32(bc_buf + pos + 1); - assert(label >= 0 && label < s->label_count); - ls = &s->label_slots[label]; - if (code_match(&cc, ls->pos, OP_ret, -1)) { - ls->ref_count--; - break; - } - } - goto no_change; - case OP_drop: - if (0) { - /* remove drops before return_undef */ - /* do not perform this optimization in pass2 because - it breaks patterns recognised in resolve_labels */ - int pos1 = pos_next; - int line1 = line_num; - while (code_match(&cc, pos1, OP_drop, -1)) { - if (cc.line_num >= 0) line1 = cc.line_num; - pos1 = cc.pos; - } - if (code_match(&cc, pos1, OP_return_undef, -1)) { - pos_next = pos1; - if (line1 != -1 && line1 != line_num) { - line_num = line1; - s->line_number_size++; - dbuf_putc(&bc_out, OP_line_num); - dbuf_put_u32(&bc_out, line_num); - } - break; - } - } - goto no_change; - case OP_insert3: - if (OPTIMIZE) { - /* Transformation: insert3 put_array_el|put_ref_value drop -> put_array_el|put_ref_value */ - if (code_match(&cc, pos_next, M2(OP_put_array_el, OP_put_ref_value), OP_drop, -1)) { - dbuf_putc(&bc_out, cc.op); - pos_next = cc.pos; - if (cc.line_num != -1 && cc.line_num != line_num) { - line_num = cc.line_num; - s->line_number_size++; - dbuf_putc(&bc_out, OP_line_num); - dbuf_put_u32(&bc_out, line_num); - } - break; - } - } - goto no_change; - case OP_goto: - s->jump_size++; - /* fall thru */ - case OP_tail_call: - case OP_tail_call_method: - case OP_return: - case OP_return_undef: - case OP_throw: - case OP_throw_error: - case OP_ret: - if (OPTIMIZE) { - /* remove dead code */ - int line = -1; - dbuf_put(&bc_out, bc_buf + pos, len); - pos = skip_dead_code(s, bc_buf, bc_len, pos + len, &line); - pos_next = pos; - if (pos < bc_len && line >= 0 && line_num != line) { - line_num = line; - s->line_number_size++; - dbuf_putc(&bc_out, OP_line_num); - dbuf_put_u32(&bc_out, line_num); - } - break; - } - goto no_change; - case OP_label: - { - int label; - LabelSlot *ls; - label = get_u32(bc_buf + pos + 1); - assert(label >= 0 && label < s->label_count); - ls = &s->label_slots[label]; - ls->pos2 = bc_out.size + opcode_info[op].size; - } - goto no_change; - case OP_enter_scope: - { - int scope_idx, scope = get_u16(bc_buf + pos + 1); - if (scope == s->body_scope) { - instantiate_hoisted_definitions(ctx, s, &bc_out); - } - for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) { - JSVarDef *vd = &s->vars[scope_idx]; - if (vd->scope_level == scope) { - if (scope_idx != s->arguments_arg_idx) { - if (vd->var_kind == JS_VAR_FUNCTION_DECL || - vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) { - /* Initialize lexical variable upon entering scope */ - dbuf_putc(&bc_out, OP_fclosure); - dbuf_put_u32(&bc_out, vd->func_pool_idx); - dbuf_putc(&bc_out, OP_put_loc); - dbuf_put_u16(&bc_out, scope_idx); - } else { - /* XXX: should check if variable can be used - before initialization */ - dbuf_putc(&bc_out, OP_set_loc_uninitialized); - dbuf_put_u16(&bc_out, scope_idx); - } - } - scope_idx = vd->scope_next; - } else { - break; - } - } - } - break; - case OP_leave_scope: - { - int scope_idx, scope = get_u16(bc_buf + pos + 1); - for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) { - JSVarDef *vd = &s->vars[scope_idx]; - if (vd->scope_level == scope) { - if (vd->is_captured) { - dbuf_putc(&bc_out, OP_close_loc); - dbuf_put_u16(&bc_out, scope_idx); - } - scope_idx = vd->scope_next; - } else { - break; - } - } - } - break; - case OP_set_name: - { - /* remove dummy set_name opcodes */ - JSAtom name = get_u32(bc_buf + pos + 1); - if (name == JS_ATOM_NULL) - break; - } - goto no_change; - case OP_if_false: - case OP_if_true: - case OP_catch: - s->jump_size++; - goto no_change; - case OP_dup: - if (OPTIMIZE) { - /* Transformation: dup if_false(l1) drop, l1: if_false(l2) -> if_false(l2) */ - /* Transformation: dup if_true(l1) drop, l1: if_true(l2) -> if_true(l2) */ - if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), OP_drop, -1)) { - int lab0, lab1, op1, pos1, line1, pos2; - lab0 = lab1 = cc.label; - assert(lab1 >= 0 && lab1 < s->label_count); - op1 = cc.op; - pos1 = cc.pos; - line1 = cc.line_num; - while (code_match(&cc, (pos2 = get_label_pos(s, lab1)), OP_dup, op1, OP_drop, -1)) { - lab1 = cc.label; - } - if (code_match(&cc, pos2, op1, -1)) { - s->jump_size++; - update_label(s, lab0, -1); - update_label(s, cc.label, +1); - dbuf_putc(&bc_out, op1); - dbuf_put_u32(&bc_out, cc.label); - pos_next = pos1; - if (line1 != -1 && line1 != line_num) { - line_num = line1; - s->line_number_size++; - dbuf_putc(&bc_out, OP_line_num); - dbuf_put_u32(&bc_out, line_num); - } - break; - } - } - } - goto no_change; - case OP_nop: - /* remove erased code */ - break; - case OP_set_class_name: - /* only used during parsing */ - break; - default: - no_change: - dbuf_put(&bc_out, bc_buf + pos, len); - break; - } - } - /* set the new byte code */ - dbuf_free(&s->byte_code); - s->byte_code = bc_out; - if (dbuf_error(&s->byte_code)) { - JS_ThrowOutOfMemory(ctx); - return -1; - } - return 0; - fail: - /* continue the copy to keep the atom refcounts consistent */ - /* XXX: find a better solution ? */ - for (; pos < bc_len; pos = pos_next) { - op = bc_buf[pos]; - len = opcode_info[op].size; - pos_next = pos + len; - dbuf_put(&bc_out, bc_buf + pos, len); - } - dbuf_free(&s->byte_code); - s->byte_code = bc_out; - return -1; -} - -/* the pc2line table gives a line number for each PC value */ -static void add_pc2line_info(JSFunctionDef *s, uint32_t pc, int line_num) -{ - if (s->line_number_slots != NULL - && s->line_number_count < s->line_number_size - && pc >= s->line_number_last_pc - && line_num != s->line_number_last) { - s->line_number_slots[s->line_number_count].pc = pc; - s->line_number_slots[s->line_number_count].line_num = line_num; - s->line_number_count++; - s->line_number_last_pc = pc; - s->line_number_last = line_num; - } -} - -static void compute_pc2line_info(JSFunctionDef *s) -{ - if (!(s->js_mode & JS_MODE_STRIP) && s->line_number_slots) { - int last_line_num = s->line_num; - uint32_t last_pc = 0; - int i; - js_dbuf_init(s->ctx, &s->pc2line); - for (i = 0; i < s->line_number_count; i++) { - uint32_t pc = s->line_number_slots[i].pc; - int line_num = s->line_number_slots[i].line_num; - int diff_pc, diff_line; - - if (line_num < 0) - continue; - - diff_pc = pc - last_pc; - diff_line = line_num - last_line_num; - if (diff_line == 0 || diff_pc < 0) - continue; - - if (diff_line >= PC2LINE_BASE && - diff_line < PC2LINE_BASE + PC2LINE_RANGE && - diff_pc <= PC2LINE_DIFF_PC_MAX) { - dbuf_putc(&s->pc2line, (diff_line - PC2LINE_BASE) + - diff_pc * PC2LINE_RANGE + PC2LINE_OP_FIRST); - } else { - /* longer encoding */ - dbuf_putc(&s->pc2line, 0); - dbuf_put_leb128(&s->pc2line, diff_pc); - dbuf_put_sleb128(&s->pc2line, diff_line); - } - last_pc = pc; - last_line_num = line_num; - } - } -} - -static RelocEntry *add_reloc(JSContext *ctx, LabelSlot *ls, uint32_t addr, int size) -{ - RelocEntry *re; - re = js_malloc(ctx, sizeof(*re)); - if (!re) - return NULL; - re->addr = addr; - re->size = size; - re->next = ls->first_reloc; - ls->first_reloc = re; - return re; -} - -static BOOL code_has_label(CodeContext *s, int pos, int label) -{ - while (pos < s->bc_len) { - int op = s->bc_buf[pos]; - if (op == OP_line_num) { - pos += 5; - continue; - } - if (op == OP_label) { - int lab = get_u32(s->bc_buf + pos + 1); - if (lab == label) - return TRUE; - pos += 5; - continue; - } - if (op == OP_goto) { - int lab = get_u32(s->bc_buf + pos + 1); - if (lab == label) - return TRUE; - } - break; - } - return FALSE; -} - -/* return the target label, following the OP_goto jumps - the first opcode at destination is stored in *pop - */ -static int find_jump_target(JSFunctionDef *s, int label, int *pop, int *pline) -{ - int i, pos, op; - update_label(s, label, -1); - for (i = 0; i < 10; i++) { - assert(label >= 0 && label < s->label_count); - pos = s->label_slots[label].pos2; - for (;;) { - switch(op = s->byte_code.buf[pos]) { - case OP_line_num: - if (pline) - *pline = get_u32(s->byte_code.buf + pos + 1); - /* fall thru */ - case OP_label: - pos += opcode_info[op].size; - continue; - case OP_goto: - label = get_u32(s->byte_code.buf + pos + 1); - break; - case OP_drop: - /* ignore drop opcodes if followed by OP_return_undef */ - while (s->byte_code.buf[++pos] == OP_drop) - continue; - if (s->byte_code.buf[pos] == OP_return_undef) - op = OP_return_undef; - /* fall thru */ - default: - goto done; - } - break; - } - } - /* cycle detected, could issue a warning */ - done: - *pop = op; - update_label(s, label, +1); - return label; -} - -static void push_short_int(DynBuf *bc_out, int val) -{ -#if SHORT_OPCODES - if (val >= -1 && val <= 7) { - dbuf_putc(bc_out, OP_push_0 + val); - return; - } - if (val == (int8_t)val) { - dbuf_putc(bc_out, OP_push_i8); - dbuf_putc(bc_out, val); - return; - } - if (val == (int16_t)val) { - dbuf_putc(bc_out, OP_push_i16); - dbuf_put_u16(bc_out, val); - return; - } -#endif - dbuf_putc(bc_out, OP_push_i32); - dbuf_put_u32(bc_out, val); -} - -static void put_short_code(DynBuf *bc_out, int op, int idx) -{ -#if SHORT_OPCODES - if (idx < 4) { - switch (op) { - case OP_get_loc: - dbuf_putc(bc_out, OP_get_loc0 + idx); - return; - case OP_put_loc: - dbuf_putc(bc_out, OP_put_loc0 + idx); - return; - case OP_set_loc: - dbuf_putc(bc_out, OP_set_loc0 + idx); - return; - case OP_get_arg: - dbuf_putc(bc_out, OP_get_arg0 + idx); - return; - case OP_put_arg: - dbuf_putc(bc_out, OP_put_arg0 + idx); - return; - case OP_set_arg: - dbuf_putc(bc_out, OP_set_arg0 + idx); - return; - case OP_get_var_ref: - dbuf_putc(bc_out, OP_get_var_ref0 + idx); - return; - case OP_put_var_ref: - dbuf_putc(bc_out, OP_put_var_ref0 + idx); - return; - case OP_set_var_ref: - dbuf_putc(bc_out, OP_set_var_ref0 + idx); - return; - case OP_call: - dbuf_putc(bc_out, OP_call0 + idx); - return; - } - } - if (idx < 256) { - switch (op) { - case OP_get_loc: - dbuf_putc(bc_out, OP_get_loc8); - dbuf_putc(bc_out, idx); - return; - case OP_put_loc: - dbuf_putc(bc_out, OP_put_loc8); - dbuf_putc(bc_out, idx); - return; - case OP_set_loc: - dbuf_putc(bc_out, OP_set_loc8); - dbuf_putc(bc_out, idx); - return; - } - } -#endif - dbuf_putc(bc_out, op); - dbuf_put_u16(bc_out, idx); -} - -/* peephole optimizations and resolve goto/labels */ -static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) -{ - int pos, pos_next, bc_len, op, op1, len, i, line_num; - const uint8_t *bc_buf; - DynBuf bc_out; - LabelSlot *label_slots, *ls; - RelocEntry *re, *re_next; - CodeContext cc; - int label; -#if SHORT_OPCODES - JumpSlot *jp; -#endif - label_slots = s->label_slots; - line_num = s->line_num; - cc.bc_buf = bc_buf = s->byte_code.buf; - cc.bc_len = bc_len = s->byte_code.size; - js_dbuf_init(ctx, &bc_out); -#if SHORT_OPCODES - if (s->jump_size) { - s->jump_slots = js_mallocz(s->ctx, sizeof(*s->jump_slots) * s->jump_size); - if (s->jump_slots == NULL) - return -1; - } -#endif - /* XXX: Should skip this phase if not generating SHORT_OPCODES */ - if (s->line_number_size && !(s->js_mode & JS_MODE_STRIP)) { - s->line_number_slots = js_mallocz(s->ctx, sizeof(*s->line_number_slots) * s->line_number_size); - if (s->line_number_slots == NULL) - return -1; - s->line_number_last = s->line_num; - s->line_number_last_pc = 0; - } - /* initialize the 'home_object' variable if needed */ - if (s->home_object_var_idx >= 0) { - dbuf_putc(&bc_out, OP_special_object); - dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_HOME_OBJECT); - put_short_code(&bc_out, OP_put_loc, s->home_object_var_idx); - } - /* initialize the 'this.active_func' variable if needed */ - if (s->this_active_func_var_idx >= 0) { - dbuf_putc(&bc_out, OP_special_object); - dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC); - put_short_code(&bc_out, OP_put_loc, s->this_active_func_var_idx); - } - /* initialize the 'new.target' variable if needed */ - if (s->new_target_var_idx >= 0) { - dbuf_putc(&bc_out, OP_special_object); - dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_NEW_TARGET); - put_short_code(&bc_out, OP_put_loc, s->new_target_var_idx); - } - /* initialize the 'this' variable if needed. In a derived class - constructor, this is initially uninitialized. */ - if (s->this_var_idx >= 0) { - if (s->is_derived_class_constructor) { - dbuf_putc(&bc_out, OP_set_loc_uninitialized); - dbuf_put_u16(&bc_out, s->this_var_idx); - } else { - dbuf_putc(&bc_out, OP_push_this); - put_short_code(&bc_out, OP_put_loc, s->this_var_idx); - } - } - /* initialize the 'arguments' variable if needed */ - if (s->arguments_var_idx >= 0) { - if ((s->js_mode & JS_MODE_STRICT) || !s->has_simple_parameter_list) { - dbuf_putc(&bc_out, OP_special_object); - dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_ARGUMENTS); - } else { - dbuf_putc(&bc_out, OP_special_object); - dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS); - } - if (s->arguments_arg_idx >= 0) - put_short_code(&bc_out, OP_set_loc, s->arguments_arg_idx); - put_short_code(&bc_out, OP_put_loc, s->arguments_var_idx); - } - /* initialize a reference to the current function if needed */ - if (s->func_var_idx >= 0) { - dbuf_putc(&bc_out, OP_special_object); - dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC); - put_short_code(&bc_out, OP_put_loc, s->func_var_idx); - } - /* initialize the variable environment object if needed */ - if (s->var_object_idx >= 0) { - dbuf_putc(&bc_out, OP_special_object); - dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT); - put_short_code(&bc_out, OP_put_loc, s->var_object_idx); - } - if (s->arg_var_object_idx >= 0) { - dbuf_putc(&bc_out, OP_special_object); - dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT); - put_short_code(&bc_out, OP_put_loc, s->arg_var_object_idx); - } - for (pos = 0; pos < bc_len; pos = pos_next) { - int val; - op = bc_buf[pos]; - len = opcode_info[op].size; - pos_next = pos + len; - switch(op) { - case OP_line_num: - /* line number info (for debug). We put it in a separate - compressed table to reduce memory usage and get better - performance */ - line_num = get_u32(bc_buf + pos + 1); - break; - case OP_label: - { - label = get_u32(bc_buf + pos + 1); - assert(label >= 0 && label < s->label_count); - ls = &label_slots[label]; - assert(ls->addr == -1); - ls->addr = bc_out.size; - /* resolve the relocation entries */ - for(re = ls->first_reloc; re != NULL; re = re_next) { - int diff = ls->addr - re->addr; - re_next = re->next; - switch (re->size) { - case 4: - put_u32(bc_out.buf + re->addr, diff); - break; - case 2: - assert(diff == (int16_t)diff); - put_u16(bc_out.buf + re->addr, diff); - break; - case 1: - assert(diff == (int8_t)diff); - put_u8(bc_out.buf + re->addr, diff); - break; - } - js_free(ctx, re); - } - ls->first_reloc = NULL; - } - break; - case OP_call: - case OP_call_method: - { - /* detect and transform tail calls */ - int argc; - argc = get_u16(bc_buf + pos + 1); - if (code_match(&cc, pos_next, OP_return, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - put_short_code(&bc_out, op + 1, argc); - pos_next = skip_dead_code(s, bc_buf, bc_len, cc.pos, &line_num); - break; - } - add_pc2line_info(s, bc_out.size, line_num); - put_short_code(&bc_out, op, argc); - break; - } - goto no_change; - case OP_return: - case OP_return_undef: - case OP_return_async: - case OP_throw: - case OP_throw_error: - pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num); - goto no_change; - case OP_goto: - label = get_u32(bc_buf + pos + 1); - has_goto: - if (OPTIMIZE) { - int line1 = -1; - /* Use custom matcher because multiple labels can follow */ - label = find_jump_target(s, label, &op1, &line1); - if (code_has_label(&cc, pos_next, label)) { - /* jump to next instruction: remove jump */ - update_label(s, label, -1); - break; - } - if (op1 == OP_return || op1 == OP_return_undef || op1 == OP_throw) { - /* jump to return/throw: remove jump, append return/throw */ - /* updating the line number obfuscates assembly listing */ - //if (line1 >= 0) line_num = line1; - update_label(s, label, -1); - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, op1); - pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num); - break; - } - /* XXX: should duplicate single instructions followed by goto or return */ - /* For example, can match one of these followed by return: - push_i32 / push_const / push_atom_value / get_var / - undefined / null / push_false / push_true / get_ref_value / - get_loc / get_arg / get_var_ref - */ - } - goto has_label; - case OP_gosub: - label = get_u32(bc_buf + pos + 1); - if (0 && OPTIMIZE) { - label = find_jump_target(s, label, &op1, NULL); - if (op1 == OP_ret) { - update_label(s, label, -1); - /* empty finally clause: remove gosub */ - break; - } - } - goto has_label; - case OP_catch: - label = get_u32(bc_buf + pos + 1); - goto has_label; - case OP_if_true: - case OP_if_false: - label = get_u32(bc_buf + pos + 1); - if (OPTIMIZE) { - label = find_jump_target(s, label, &op1, NULL); - /* transform if_false/if_true(l1) label(l1) -> drop label(l1) */ - if (code_has_label(&cc, pos_next, label)) { - update_label(s, label, -1); - dbuf_putc(&bc_out, OP_drop); - break; - } - /* transform if_false(l1) goto(l2) label(l1) -> if_false(l2) label(l1) */ - if (code_match(&cc, pos_next, OP_goto, -1)) { - int pos1 = cc.pos; - int line1 = cc.line_num; - if (code_has_label(&cc, pos1, label)) { - if (line1 >= 0) line_num = line1; - pos_next = pos1; - update_label(s, label, -1); - label = cc.label; - op ^= OP_if_true ^ OP_if_false; - } - } - } - has_label: - add_pc2line_info(s, bc_out.size, line_num); - if (op == OP_goto) { - pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num); - } - assert(label >= 0 && label < s->label_count); - ls = &label_slots[label]; -#if SHORT_OPCODES - jp = &s->jump_slots[s->jump_count++]; - jp->op = op; - jp->size = 4; - jp->pos = bc_out.size + 1; - jp->label = label; - if (ls->addr == -1) { - int diff = ls->pos2 - pos - 1; - if (diff < 128 && (op == OP_if_false || op == OP_if_true || op == OP_goto)) { - jp->size = 1; - jp->op = OP_if_false8 + (op - OP_if_false); - dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false)); - dbuf_putc(&bc_out, 0); - if (!add_reloc(ctx, ls, bc_out.size - 1, 1)) - goto fail; - break; - } - if (diff < 32768 && op == OP_goto) { - jp->size = 2; - jp->op = OP_goto16; - dbuf_putc(&bc_out, OP_goto16); - dbuf_put_u16(&bc_out, 0); - if (!add_reloc(ctx, ls, bc_out.size - 2, 2)) - goto fail; - break; - } - } else { - int diff = ls->addr - bc_out.size - 1; - if (diff == (int8_t)diff && (op == OP_if_false || op == OP_if_true || op == OP_goto)) { - jp->size = 1; - jp->op = OP_if_false8 + (op - OP_if_false); - dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false)); - dbuf_putc(&bc_out, diff); - break; - } - if (diff == (int16_t)diff && op == OP_goto) { - jp->size = 2; - jp->op = OP_goto16; - dbuf_putc(&bc_out, OP_goto16); - dbuf_put_u16(&bc_out, diff); - break; - } - } -#endif - dbuf_putc(&bc_out, op); - dbuf_put_u32(&bc_out, ls->addr - bc_out.size); - if (ls->addr == -1) { - /* unresolved yet: create a new relocation entry */ - if (!add_reloc(ctx, ls, bc_out.size - 4, 4)) - goto fail; - } - break; - 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; - int is_with; - atom = get_u32(bc_buf + pos + 1); - label = get_u32(bc_buf + pos + 5); - is_with = bc_buf[pos + 9]; - if (OPTIMIZE) { - label = find_jump_target(s, label, &op1, NULL); - } - assert(label >= 0 && label < s->label_count); - ls = &label_slots[label]; - add_pc2line_info(s, bc_out.size, line_num); -#if SHORT_OPCODES - jp = &s->jump_slots[s->jump_count++]; - jp->op = op; - jp->size = 4; - jp->pos = bc_out.size + 5; - jp->label = label; -#endif - dbuf_putc(&bc_out, op); - dbuf_put_u32(&bc_out, atom); - dbuf_put_u32(&bc_out, ls->addr - bc_out.size); - if (ls->addr == -1) { - /* unresolved yet: create a new relocation entry */ - if (!add_reloc(ctx, ls, bc_out.size - 4, 4)) - goto fail; - } - dbuf_putc(&bc_out, is_with); - } - break; - case OP_drop: - if (OPTIMIZE) { - /* remove useless drops before return */ - if (code_match(&cc, pos_next, OP_return_undef, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - break; - } - } - goto no_change; - case OP_null: -#if SHORT_OPCODES - if (OPTIMIZE) { - /* transform null strict_eq into is_null */ - if (code_match(&cc, pos_next, OP_strict_eq, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, OP_is_null); - pos_next = cc.pos; - break; - } - /* transform null strict_neq if_false/if_true -> is_null if_true/if_false */ - if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, OP_is_null); - pos_next = cc.pos; - label = cc.label; - op = cc.op ^ OP_if_false ^ OP_if_true; - goto has_label; - } - } -#endif - /* fall thru */ - case OP_push_false: - case OP_push_true: - if (OPTIMIZE) { - val = (op == OP_push_true); - if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) { - has_constant_test: - if (cc.line_num >= 0) line_num = cc.line_num; - if (val == cc.op - OP_if_false) { - /* transform null if_false(l1) -> goto l1 */ - /* transform false if_false(l1) -> goto l1 */ - /* transform true if_true(l1) -> goto l1 */ - pos_next = cc.pos; - op = OP_goto; - label = cc.label; - goto has_goto; - } else { - /* transform null if_true(l1) -> nop */ - /* transform false if_true(l1) -> nop */ - /* transform true if_false(l1) -> nop */ - pos_next = cc.pos; - update_label(s, cc.label, -1); - break; - } - } - } - goto no_change; - case OP_push_i32: - if (OPTIMIZE) { - /* transform i32(val) neg -> i32(-val) */ - val = get_i32(bc_buf + pos + 1); - if ((val != INT32_MIN && val != 0) - && code_match(&cc, pos_next, OP_neg, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - if (code_match(&cc, cc.pos, OP_drop, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - } else { - add_pc2line_info(s, bc_out.size, line_num); - push_short_int(&bc_out, -val); - } - pos_next = cc.pos; - break; - } - /* remove push/drop pairs generated by the parser */ - if (code_match(&cc, pos_next, OP_drop, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - pos_next = cc.pos; - break; - } - /* Optimize constant tests: `if (0)`, `if (1)`, `if (!0)`... */ - if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) { - val = (val != 0); - goto has_constant_test; - } - add_pc2line_info(s, bc_out.size, line_num); - push_short_int(&bc_out, val); - break; - } - goto no_change; -#if SHORT_OPCODES - case OP_push_const: - case OP_fclosure: - if (OPTIMIZE) { - int idx = get_u32(bc_buf + pos + 1); - if (idx < 256) { - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, OP_push_const8 + op - OP_push_const); - dbuf_putc(&bc_out, idx); - break; - } - } - goto no_change; - case OP_get_field: - if (OPTIMIZE) { - JSAtom atom = get_u32(bc_buf + pos + 1); - if (atom == JS_ATOM_length) { - JS_FreeAtom(ctx, atom); - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, OP_get_length); - break; - } - } - goto no_change; -#endif - case OP_push_atom_value: - if (OPTIMIZE) { - JSAtom atom = get_u32(bc_buf + pos + 1); - /* remove push/drop pairs generated by the parser */ - if (code_match(&cc, pos_next, OP_drop, -1)) { - JS_FreeAtom(ctx, atom); - if (cc.line_num >= 0) line_num = cc.line_num; - pos_next = cc.pos; - break; - } -#if SHORT_OPCODES - if (atom == JS_ATOM_empty_string) { - JS_FreeAtom(ctx, atom); - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, OP_push_empty_string); - break; - } -#endif - } - goto no_change; - case OP_to_propkey: - case OP_to_propkey2: - if (OPTIMIZE) { - /* remove redundant to_propkey/to_propkey2 opcodes when storing simple data */ - if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_put_array_el, -1) - || code_match(&cc, pos_next, M3(OP_push_i32, OP_push_const, OP_push_atom_value), OP_put_array_el, -1) - || code_match(&cc, pos_next, M4(OP_undefined, OP_null, OP_push_true, OP_push_false), OP_put_array_el, -1)) { - break; - } - } - goto no_change; - case OP_undefined: - if (OPTIMIZE) { - /* remove push/drop pairs generated by the parser */ - if (code_match(&cc, pos_next, OP_drop, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - pos_next = cc.pos; - break; - } - /* transform undefined return -> return_undefined */ - if (code_match(&cc, pos_next, OP_return, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, OP_return_undef); - pos_next = cc.pos; - break; - } - /* transform undefined if_true(l1)/if_false(l1) -> nop/goto(l1) */ - if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) { - val = 0; - goto has_constant_test; - } -#if SHORT_OPCODES - /* transform undefined strict_eq -> is_undefined */ - if (code_match(&cc, pos_next, OP_strict_eq, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, OP_is_undefined); - pos_next = cc.pos; - break; - } - /* transform undefined strict_neq if_false/if_true -> is_undefined if_true/if_false */ - if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, OP_is_undefined); - pos_next = cc.pos; - label = cc.label; - op = cc.op ^ OP_if_false ^ OP_if_true; - goto has_label; - } -#endif - } - goto no_change; - case OP_insert2: - if (OPTIMIZE) { - /* Transformation: - insert2 put_field(a) drop -> put_field(a) - insert2 put_var_strict(a) drop -> put_var_strict(a) - */ - if (code_match(&cc, pos_next, M2(OP_put_field, OP_put_var_strict), OP_drop, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, cc.op); - dbuf_put_u32(&bc_out, cc.atom); - pos_next = cc.pos; - break; - } - } - goto no_change; - case OP_dup: - if (OPTIMIZE) { - /* Transformation: dup put_x(n) drop -> put_x(n) */ - int op1, line2 = -1; - /* Transformation: dup put_x(n) -> set_x(n) */ - if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - op1 = cc.op + 1; /* put_x -> set_x */ - pos_next = cc.pos; - if (code_match(&cc, cc.pos, OP_drop, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - op1 -= 1; /* set_x drop -> put_x */ - pos_next = cc.pos; - if (code_match(&cc, cc.pos, op1 - 1, cc.idx, -1)) { - line2 = cc.line_num; /* delay line number update */ - op1 += 1; /* put_x(n) get_x(n) -> set_x(n) */ - pos_next = cc.pos; - } - } - add_pc2line_info(s, bc_out.size, line_num); - put_short_code(&bc_out, op1, cc.idx); - if (line2 >= 0) line_num = line2; - break; - } - } - goto no_change; - case OP_get_loc: - if (OPTIMIZE) { - /* transformation: - get_loc(n) post_dec put_loc(n) drop -> dec_loc(n) - get_loc(n) post_inc put_loc(n) drop -> inc_loc(n) - get_loc(n) dec dup put_loc(n) drop -> dec_loc(n) - get_loc(n) inc dup put_loc(n) drop -> inc_loc(n) - */ - int idx; - idx = get_u16(bc_buf + pos + 1); - if (idx >= 256) - goto no_change; - if (code_match(&cc, pos_next, M2(OP_post_dec, OP_post_inc), OP_put_loc, idx, OP_drop, -1) || - code_match(&cc, pos_next, M2(OP_dec, OP_inc), OP_dup, OP_put_loc, idx, OP_drop, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, (cc.op == OP_inc || cc.op == OP_post_inc) ? OP_inc_loc : OP_dec_loc); - dbuf_putc(&bc_out, idx); - pos_next = cc.pos; - break; - } - /* transformation: - get_loc(n) push_atom_value(x) add dup put_loc(n) drop -> push_atom_value(x) add_loc(n) - */ - if (code_match(&cc, pos_next, OP_push_atom_value, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); -#if SHORT_OPCODES - if (cc.atom == JS_ATOM_empty_string) { - JS_FreeAtom(ctx, cc.atom); - dbuf_putc(&bc_out, OP_push_empty_string); - } else -#endif - { - dbuf_putc(&bc_out, OP_push_atom_value); - dbuf_put_u32(&bc_out, cc.atom); - } - dbuf_putc(&bc_out, OP_add_loc); - dbuf_putc(&bc_out, idx); - pos_next = cc.pos; - break; - } - /* transformation: - get_loc(n) push_i32(x) add dup put_loc(n) drop -> push_i32(x) add_loc(n) - */ - if (code_match(&cc, pos_next, OP_push_i32, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - push_short_int(&bc_out, cc.label); - dbuf_putc(&bc_out, OP_add_loc); - dbuf_putc(&bc_out, idx); - pos_next = cc.pos; - break; - } - /* transformation: XXX: also do these: - get_loc(n) get_loc(x) add dup put_loc(n) drop -> get_loc(x) add_loc(n) - get_loc(n) get_arg(x) add dup put_loc(n) drop -> get_arg(x) add_loc(n) - get_loc(n) get_var_ref(x) add dup put_loc(n) drop -> get_var_ref(x) add_loc(n) - */ - if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - put_short_code(&bc_out, cc.op, cc.idx); - dbuf_putc(&bc_out, OP_add_loc); - dbuf_putc(&bc_out, idx); - pos_next = cc.pos; - break; - } - add_pc2line_info(s, bc_out.size, line_num); - put_short_code(&bc_out, op, idx); - break; - } - goto no_change; -#if SHORT_OPCODES - case OP_get_arg: - case OP_get_var_ref: - if (OPTIMIZE) { - int idx; - idx = get_u16(bc_buf + pos + 1); - add_pc2line_info(s, bc_out.size, line_num); - put_short_code(&bc_out, op, idx); - break; - } - goto no_change; -#endif - case OP_put_loc: - case OP_put_arg: - case OP_put_var_ref: - if (OPTIMIZE) { - /* transformation: put_x(n) get_x(n) -> set_x(n) */ - int idx; - idx = get_u16(bc_buf + pos + 1); - if (code_match(&cc, pos_next, op - 1, idx, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - put_short_code(&bc_out, op + 1, idx); - pos_next = cc.pos; - break; - } - add_pc2line_info(s, bc_out.size, line_num); - put_short_code(&bc_out, op, idx); - break; - } - goto no_change; - case OP_post_inc: - case OP_post_dec: - if (OPTIMIZE) { - /* transformation: - post_inc put_x drop -> inc put_x - post_inc perm3 put_field drop -> inc put_field - post_inc perm3 put_var_strict drop -> inc put_var_strict - post_inc perm4 put_array_el drop -> inc put_array_el - */ - int op1, idx; - if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, OP_drop, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - op1 = cc.op; - idx = cc.idx; - pos_next = cc.pos; - if (code_match(&cc, cc.pos, op1 - 1, idx, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - op1 += 1; /* put_x(n) get_x(n) -> set_x(n) */ - pos_next = cc.pos; - } - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec)); - put_short_code(&bc_out, op1, idx); - break; - } - if (code_match(&cc, pos_next, OP_perm3, M2(OP_put_field, OP_put_var_strict), OP_drop, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec)); - dbuf_putc(&bc_out, cc.op); - dbuf_put_u32(&bc_out, cc.atom); - pos_next = cc.pos; - break; - } - if (code_match(&cc, pos_next, OP_perm4, OP_put_array_el, OP_drop, -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec)); - dbuf_putc(&bc_out, OP_put_array_el); - pos_next = cc.pos; - break; - } - } - goto no_change; -#if SHORT_OPCODES - case OP_typeof: - if (OPTIMIZE) { - /* simplify typeof tests */ - if (code_match(&cc, pos_next, OP_push_atom_value, M4(OP_strict_eq, OP_strict_neq, OP_eq, OP_neq), -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - int op1 = (cc.op == OP_strict_eq || cc.op == OP_eq) ? OP_strict_eq : OP_strict_neq; - int op2 = -1; - switch (cc.atom) { - case JS_ATOM_undefined: - op2 = OP_typeof_is_undefined; - break; - case JS_ATOM_function: - op2 = OP_typeof_is_function; - break; - } - if (op2 >= 0) { - /* transform typeof(s) == "" into is_ */ - if (op1 == OP_strict_eq) { - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, op2); - JS_FreeAtom(ctx, cc.atom); - pos_next = cc.pos; - break; - } - if (op1 == OP_strict_neq && code_match(&cc, cc.pos, OP_if_false, -1)) { - /* transform typeof(s) != "" if_false into is_ if_true */ - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, op2); - JS_FreeAtom(ctx, cc.atom); - pos_next = cc.pos; - label = cc.label; - op = OP_if_true; - goto has_label; - } - } - } - } - goto no_change; -#endif - default: - no_change: - add_pc2line_info(s, bc_out.size, line_num); - dbuf_put(&bc_out, bc_buf + pos, len); - break; - } - } - /* check that there were no missing labels */ - for(i = 0; i < s->label_count; i++) { - assert(label_slots[i].first_reloc == NULL); - } -#if SHORT_OPCODES - if (OPTIMIZE) { - /* more jump optimizations */ - int patch_offsets = 0; - for (i = 0, jp = s->jump_slots; i < s->jump_count; i++, jp++) { - LabelSlot *ls; - JumpSlot *jp1; - int j, pos, diff, delta; - delta = 3; - switch (op = jp->op) { - case OP_goto16: - delta = 1; - /* fall thru */ - case OP_if_false: - case OP_if_true: - case OP_goto: - pos = jp->pos; - diff = s->label_slots[jp->label].addr - pos; - if (diff >= -128 && diff <= 127 + delta) { - //put_u8(bc_out.buf + pos, diff); - jp->size = 1; - if (op == OP_goto16) { - bc_out.buf[pos - 1] = jp->op = OP_goto8; - } else { - bc_out.buf[pos - 1] = jp->op = OP_if_false8 + (op - OP_if_false); - } - goto shrink; - } else - if (diff == (int16_t)diff && op == OP_goto) { - //put_u16(bc_out.buf + pos, diff); - jp->size = 2; - delta = 2; - bc_out.buf[pos - 1] = jp->op = OP_goto16; - shrink: - /* XXX: should reduce complexity, using 2 finger copy scheme */ - memmove(bc_out.buf + pos + jp->size, bc_out.buf + pos + jp->size + delta, - bc_out.size - pos - jp->size - delta); - bc_out.size -= delta; - patch_offsets++; - for (j = 0, ls = s->label_slots; j < s->label_count; j++, ls++) { - if (ls->addr > pos) - ls->addr -= delta; - } - for (j = i + 1, jp1 = jp + 1; j < s->jump_count; j++, jp1++) { - if (jp1->pos > pos) - jp1->pos -= delta; - } - for (j = 0; j < s->line_number_count; j++) { - if (s->line_number_slots[j].pc > pos) - s->line_number_slots[j].pc -= delta; - } - continue; - } - break; - } - } - if (patch_offsets) { - JumpSlot *jp1; - int j; - for (j = 0, jp1 = s->jump_slots; j < s->jump_count; j++, jp1++) { - int diff1 = s->label_slots[jp1->label].addr - jp1->pos; - switch (jp1->size) { - case 1: - put_u8(bc_out.buf + jp1->pos, diff1); - break; - case 2: - put_u16(bc_out.buf + jp1->pos, diff1); - break; - case 4: - put_u32(bc_out.buf + jp1->pos, diff1); - break; - } - } - } - } - js_free(ctx, s->jump_slots); - s->jump_slots = NULL; -#endif - js_free(ctx, s->label_slots); - s->label_slots = NULL; - /* XXX: should delay until copying to runtime bytecode function */ - compute_pc2line_info(s); - js_free(ctx, s->line_number_slots); - s->line_number_slots = NULL; - /* set the new byte code */ - dbuf_free(&s->byte_code); - s->byte_code = bc_out; - s->use_short_opcodes = TRUE; - if (dbuf_error(&s->byte_code)) { - JS_ThrowOutOfMemory(ctx); - return -1; - } - return 0; - fail: - /* XXX: not safe */ - dbuf_free(&bc_out); - return -1; -} - -/* compute the maximum stack size needed by the function */ -typedef struct StackSizeState { - int bc_len; - int stack_len_max; - uint16_t *stack_level_tab; - int *pc_stack; - int pc_stack_len; - int pc_stack_size; -} StackSizeState; - -/* 'op' is only used for error indication */ -static __exception int ss_check(JSContext *ctx, StackSizeState *s, - int pos, int op, int stack_len) -{ - if ((unsigned)pos >= s->bc_len) { - JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos); - return -1; - } - if (stack_len > s->stack_len_max) { - s->stack_len_max = stack_len; - if (s->stack_len_max > JS_STACK_SIZE_MAX) { - JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos); - return -1; - } - } - if (s->stack_level_tab[pos] != 0xffff) { - /* already explored: check that the stack size is consistent */ - if (s->stack_level_tab[pos] != stack_len) { - JS_ThrowInternalError(ctx, "unconsistent stack size: %d %d (pc=%d)", - s->stack_level_tab[pos], stack_len, pos); - return -1; - } else { - return 0; - } - } - /* mark as explored and store the stack size */ - s->stack_level_tab[pos] = stack_len; - /* queue the new PC to explore */ - if (js_resize_array(ctx, (void **)&s->pc_stack, sizeof(s->pc_stack[0]), - &s->pc_stack_size, s->pc_stack_len + 1)) - return -1; - s->pc_stack[s->pc_stack_len++] = pos; - return 0; -} - -static __exception int compute_stack_size(JSContext *ctx, - JSFunctionDef *fd, - int *pstack_size) -{ - StackSizeState s_s, *s = &s_s; - int i, diff, n_pop, pos_next, stack_len, pos, op; - const JSOpCode *oi; - const uint8_t *bc_buf; - bc_buf = fd->byte_code.buf; - s->bc_len = fd->byte_code.size; - /* bc_len > 0 */ - s->stack_level_tab = js_malloc(ctx, sizeof(s->stack_level_tab[0]) * - s->bc_len); - if (!s->stack_level_tab) - return -1; - for(i = 0; i < s->bc_len; i++) - s->stack_level_tab[i] = 0xffff; - s->stack_len_max = 0; - s->pc_stack = NULL; - s->pc_stack_len = 0; - s->pc_stack_size = 0; - /* breadth-first graph exploration */ - if (ss_check(ctx, s, 0, OP_invalid, 0)) - goto fail; - while (s->pc_stack_len > 0) { - pos = s->pc_stack[--s->pc_stack_len]; - stack_len = s->stack_level_tab[pos]; - op = bc_buf[pos]; - if (op == 0 || op >= OP_COUNT) { - JS_ThrowInternalError(ctx, "invalid opcode (op=%d, pc=%d)", op, pos); - goto fail; - } - oi = &short_opcode_info(op); - pos_next = pos + oi->size; - if (pos_next > s->bc_len) { - JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos); - goto fail; - } - n_pop = oi->n_pop; - /* call pops a variable number of arguments */ - if (oi->fmt == OP_FMT_npop || oi->fmt == OP_FMT_npop_u16) { - n_pop += get_u16(bc_buf + pos + 1); - } else { -#if SHORT_OPCODES - if (oi->fmt == OP_FMT_npopx) { - n_pop += op - OP_call0; - } -#endif - } - if (stack_len < n_pop) { - JS_ThrowInternalError(ctx, "stack underflow (op=%d, pc=%d)", op, pos); - goto fail; - } - stack_len += oi->n_push - n_pop; - if (stack_len > s->stack_len_max) { - s->stack_len_max = stack_len; - if (s->stack_len_max > JS_STACK_SIZE_MAX) { - JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos); - goto fail; - } - } - switch(op) { - case OP_tail_call: - case OP_tail_call_method: - case OP_return: - case OP_return_undef: - case OP_return_async: - case OP_throw: - case OP_throw_error: - case OP_ret: - goto done_insn; - case OP_goto: - diff = get_u32(bc_buf + pos + 1); - pos_next = pos + 1 + diff; - break; -#if SHORT_OPCODES - case OP_goto16: - diff = (int16_t)get_u16(bc_buf + pos + 1); - pos_next = pos + 1 + diff; - break; - case OP_goto8: - diff = (int8_t)bc_buf[pos + 1]; - pos_next = pos + 1 + diff; - break; - case OP_if_true8: - case OP_if_false8: - diff = (int8_t)bc_buf[pos + 1]; - if (ss_check(ctx, s, pos + 1 + diff, op, stack_len)) - goto fail; - break; -#endif - case OP_if_true: - case OP_if_false: - case OP_catch: - diff = get_u32(bc_buf + pos + 1); - if (ss_check(ctx, s, pos + 1 + diff, op, stack_len)) - goto fail; - break; - case OP_gosub: - diff = get_u32(bc_buf + pos + 1); - if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1)) - goto fail; - break; - case OP_with_get_var: - case OP_with_delete_var: - diff = get_u32(bc_buf + pos + 5); - if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1)) - goto fail; - break; - case OP_with_make_ref: - case OP_with_get_ref: - case OP_with_get_ref_undef: - diff = get_u32(bc_buf + pos + 5); - if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2)) - goto fail; - break; - case OP_with_put_var: - diff = get_u32(bc_buf + pos + 5); - if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1)) - goto fail; - break; - default: - break; - } - if (ss_check(ctx, s, pos_next, op, stack_len)) - goto fail; - done_insn: ; - } - js_free(ctx, s->stack_level_tab); - js_free(ctx, s->pc_stack); - *pstack_size = s->stack_len_max; - return 0; - fail: - js_free(ctx, s->stack_level_tab); - js_free(ctx, s->pc_stack); - *pstack_size = 0; - return -1; -} - -static int add_module_variables(JSContext *ctx, JSFunctionDef *fd) -{ - int i, idx; - JSModuleDef *m = fd->module; - JSExportEntry *me; - JSGlobalVar *hf; - /* The imported global variables were added as closure variables - in js_parse_import(). We add here the module global - variables. */ - for(i = 0; i < fd->global_var_count; i++) { - hf = &fd->global_vars[i]; - if (add_closure_var(ctx, fd, TRUE, FALSE, i, hf->var_name, hf->is_const, - hf->is_lexical, FALSE) < 0) - return -1; - } - /* resolve the variable names of the local exports */ - for(i = 0; i < m->export_entries_count; i++) { - me = &m->export_entries[i]; - if (me->export_type == JS_EXPORT_TYPE_LOCAL) { - idx = find_closure_var(ctx, fd, me->local_name); - if (idx < 0) { - JS_ThrowSyntaxErrorAtom(ctx, "exported variable '%s' does not exist", - me->local_name); - return -1; - } - me->u.local.var_idx = idx; - } - } - return 0; -} - -/* create a function object from a function definition. The function - definition is freed. All the child functions are also created. It - must be done this way to resolve all the variables. */ -static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd) -{ - JSValue func_obj; - JSFunctionBytecode *b; - struct list_head *el, *el1; - int stack_size, scope, idx; - int function_size, byte_code_offset, cpool_offset; - int closure_var_offset, vardefs_offset; - /* recompute scope linkage */ - for (scope = 0; scope < fd->scope_count; scope++) { - fd->scopes[scope].first = -1; - } - if (fd->has_parameter_expressions) { - /* special end of variable list marker for the argument scope */ - fd->scopes[ARG_SCOPE_INDEX].first = ARG_SCOPE_END; - } - for (idx = 0; idx < fd->var_count; idx++) { - JSVarDef *vd = &fd->vars[idx]; - vd->scope_next = fd->scopes[vd->scope_level].first; - fd->scopes[vd->scope_level].first = idx; - } - for (scope = 2; scope < fd->scope_count; scope++) { - JSVarScope *sd = &fd->scopes[scope]; - if (sd->first < 0) - sd->first = fd->scopes[sd->parent].first; - } - for (idx = 0; idx < fd->var_count; idx++) { - JSVarDef *vd = &fd->vars[idx]; - if (vd->scope_next < 0 && vd->scope_level > 1) { - scope = fd->scopes[vd->scope_level].parent; - vd->scope_next = fd->scopes[scope].first; - } - } - /* if the function contains an eval call, the closure variables - are used to compile the eval and they must be ordered by scope, - so it is necessary to create the closure variables before any - other variable lookup is done. */ - if (fd->has_eval_call) - add_eval_variables(ctx, fd); - /* add the module global variables in the closure */ - if (fd->module) { - if (add_module_variables(ctx, fd)) - goto fail; - } - /* first create all the child functions */ - list_for_each_safe(el, el1, &fd->child_list) { - JSFunctionDef *fd1; - int cpool_idx; - fd1 = list_entry(el, JSFunctionDef, link); - cpool_idx = fd1->parent_cpool_idx; - func_obj = js_create_function(ctx, fd1); - if (JS_IsException(func_obj)) - goto fail; - /* save it in the constant pool */ - assert(cpool_idx >= 0); - fd->cpool[cpool_idx] = func_obj; - } -#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 4) - if (!(fd->js_mode & JS_MODE_STRIP)) { - printf("pass 1\n"); - dump_byte_code(ctx, 1, fd->byte_code.buf, fd->byte_code.size, - fd->args, fd->arg_count, fd->vars, fd->var_count, - fd->closure_var, fd->closure_var_count, - fd->cpool, fd->cpool_count, fd->source, fd->line_num, - fd->label_slots, NULL); - printf("\n"); - } -#endif - if (resolve_variables(ctx, fd)) - goto fail; -#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 2) - if (!(fd->js_mode & JS_MODE_STRIP)) { - printf("pass 2\n"); - dump_byte_code(ctx, 2, fd->byte_code.buf, fd->byte_code.size, - fd->args, fd->arg_count, fd->vars, fd->var_count, - fd->closure_var, fd->closure_var_count, - fd->cpool, fd->cpool_count, fd->source, fd->line_num, - fd->label_slots, NULL); - printf("\n"); - } -#endif - if (resolve_labels(ctx, fd)) - goto fail; - if (compute_stack_size(ctx, fd, &stack_size) < 0) - goto fail; - if (fd->js_mode & JS_MODE_STRIP) { - function_size = offsetof(JSFunctionBytecode, debug); - } else { - function_size = sizeof(*b); - } - cpool_offset = function_size; - function_size += fd->cpool_count * sizeof(*fd->cpool); - vardefs_offset = function_size; - if (!(fd->js_mode & JS_MODE_STRIP) || fd->has_eval_call) { - function_size += (fd->arg_count + fd->var_count) * sizeof(*b->vardefs); - } - closure_var_offset = function_size; - function_size += fd->closure_var_count * sizeof(*fd->closure_var); - byte_code_offset = function_size; - function_size += fd->byte_code.size; - b = js_mallocz(ctx, function_size); - if (!b) - goto fail; - b->header.ref_count = 1; - b->byte_code_buf = (void *)((uint8_t*)b + byte_code_offset); - b->byte_code_len = fd->byte_code.size; - memcpy(b->byte_code_buf, fd->byte_code.buf, fd->byte_code.size); - js_free(ctx, fd->byte_code.buf); - fd->byte_code.buf = NULL; - b->func_name = fd->func_name; - if (fd->arg_count + fd->var_count > 0) { - if ((fd->js_mode & JS_MODE_STRIP) && !fd->has_eval_call) { - /* Strip variable definitions not needed at runtime */ - int i; - for(i = 0; i < fd->var_count; i++) { - JS_FreeAtom(ctx, fd->vars[i].var_name); - } - for(i = 0; i < fd->arg_count; i++) { - JS_FreeAtom(ctx, fd->args[i].var_name); - } - for(i = 0; i < fd->closure_var_count; i++) { - JS_FreeAtom(ctx, fd->closure_var[i].var_name); - fd->closure_var[i].var_name = JS_ATOM_NULL; - } - } else { - b->vardefs = (void *)((uint8_t*)b + vardefs_offset); - if (fd->arg_count) { - memcpy(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0])); - } - if (fd->var_count) { - memcpy(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0])); - } - } - b->var_count = fd->var_count; - b->arg_count = fd->arg_count; - b->defined_arg_count = fd->defined_arg_count; - js_free(ctx, fd->args); - js_free(ctx, fd->vars); - } - b->cpool_count = fd->cpool_count; - if (b->cpool_count) { - b->cpool = (void *)((uint8_t*)b + cpool_offset); - memcpy(b->cpool, fd->cpool, b->cpool_count * sizeof(*b->cpool)); - } - js_free(ctx, fd->cpool); - fd->cpool = NULL; - b->stack_size = stack_size; - if (fd->js_mode & JS_MODE_STRIP) { - JS_FreeAtom(ctx, fd->filename); - dbuf_free(&fd->pc2line); // probably useless - } else { - /* XXX: source and pc2line info should be packed at the end of the - JSFunctionBytecode structure, avoiding allocation overhead - */ - b->has_debug = 1; - b->debug.filename = fd->filename; - b->debug.line_num = fd->line_num; - //DynBuf pc2line; - //compute_pc2line_info(fd, &pc2line); - //js_free(ctx, fd->line_number_slots) - b->debug.pc2line_buf = js_realloc(ctx, fd->pc2line.buf, fd->pc2line.size); - if (!b->debug.pc2line_buf) - b->debug.pc2line_buf = fd->pc2line.buf; - b->debug.pc2line_len = fd->pc2line.size; - b->debug.source = fd->source; - b->debug.source_len = fd->source_len; - } - if (fd->scopes != fd->def_scope_array) - js_free(ctx, fd->scopes); - b->closure_var_count = fd->closure_var_count; - if (b->closure_var_count) { - b->closure_var = (void *)((uint8_t*)b + closure_var_offset); - memcpy(b->closure_var, fd->closure_var, b->closure_var_count * sizeof(*b->closure_var)); - } - js_free(ctx, fd->closure_var); - fd->closure_var = NULL; - b->has_prototype = fd->has_prototype; - b->has_simple_parameter_list = fd->has_simple_parameter_list; - b->js_mode = fd->js_mode; - b->is_derived_class_constructor = fd->is_derived_class_constructor; - b->func_kind = fd->func_kind; - b->need_home_object = (fd->home_object_var_idx >= 0 || - fd->need_home_object); - b->new_target_allowed = fd->new_target_allowed; - b->super_call_allowed = fd->super_call_allowed; - b->super_allowed = fd->super_allowed; - b->arguments_allowed = fd->arguments_allowed; - b->backtrace_barrier = fd->backtrace_barrier; - b->realm = JS_DupContext(ctx); - add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE); -#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 1) - if (!(fd->js_mode & JS_MODE_STRIP)) { - js_dump_function_bytecode(ctx, b); - } -#endif - if (fd->parent) { - /* remove from parent list */ - list_del(&fd->link); - } - js_free(ctx, fd); - return JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b); - fail: - js_free_function_def(ctx, fd); - return JS_EXCEPTION; -} - -static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj, - JSValueConst this_obj, - JSVarRef **var_refs, JSStackFrame *sf) -{ - JSValue ret_val; - uint32_t tag; - tag = JS_VALUE_GET_TAG(fun_obj); - if (tag == JS_TAG_FUNCTION_BYTECODE) { - fun_obj = js_closure(ctx, fun_obj, var_refs, sf); - ret_val = JS_CallFree(ctx, fun_obj, this_obj, 0, NULL); - } else if (tag == JS_TAG_MODULE) { - JSModuleDef *m; - m = JS_VALUE_GET_PTR(fun_obj); - /* the module refcount should be >= 2 */ - JS_FreeValue(ctx, fun_obj); - if (js_create_module_function(ctx, m) < 0) - goto fail; - if (js_link_module(ctx, m) < 0) - goto fail; - ret_val = js_evaluate_module(ctx, m); - if (JS_IsException(ret_val)) { - fail: - js_free_modules(ctx, JS_FREE_MODULE_NOT_EVALUATED); - return JS_EXCEPTION; - } - } else { - JS_FreeValue(ctx, fun_obj); - ret_val = JS_ThrowTypeError(ctx, "bytecode function expected"); - } - return ret_val; -} - -JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj) -{ - return JS_EvalFunctionInternal(ctx, fun_obj, ctx->global_obj, NULL, NULL); -} - -static void skip_shebang(JSParseState *s) -{ - const uint8_t *p = s->buf_ptr; - int c; - if (p[0] == '#' && p[1] == '!') { - p += 2; - while (p < s->buf_end) { - if (*p == '\n' || *p == '\r') { - break; - } else if (*p >= 0x80) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); - if (c == CP_LS || c == CP_PS) { - break; - } else if (c == -1) { - p++; /* skip invalid UTF-8 */ - } - } else { - p++; - } - } - s->buf_ptr = p; - } -} - -/* 'input' must be zero terminated i.e. input[input_len] = '\0'. */ -static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, - const char *input, size_t input_len, - const char *filename, int flags, int scope_idx) -{ - JSParseState s1, *s = &s1; - int err, js_mode, eval_type; - JSValue fun_obj, ret_val; - JSStackFrame *sf; - JSVarRef **var_refs; - JSFunctionBytecode *b; - JSFunctionDef *fd; - JSModuleDef *m; - js_parse_init(ctx, s, input, input_len, filename); - skip_shebang(s); - eval_type = flags & JS_EVAL_TYPE_MASK; - m = NULL; - if (eval_type == JS_EVAL_TYPE_DIRECT) { - JSObject *p; - sf = ctx->rt->current_stack_frame; - assert(sf != NULL); - assert(JS_VALUE_GET_TAG(sf->cur_func) == JS_TAG_OBJECT); - p = JS_VALUE_GET_OBJ(sf->cur_func); - assert(js_class_has_bytecode(p->class_id)); - b = p->u.func.function_bytecode; - var_refs = p->u.func.var_refs; - js_mode = b->js_mode; - } else { - sf = NULL; - b = NULL; - var_refs = NULL; - js_mode = 0; - if (flags & JS_EVAL_FLAG_STRICT) - js_mode |= JS_MODE_STRICT; - if (flags & JS_EVAL_FLAG_STRIP) - js_mode |= JS_MODE_STRIP; - if (eval_type == JS_EVAL_TYPE_MODULE) { - JSAtom module_name = JS_NewAtom(ctx, filename); - if (module_name == JS_ATOM_NULL) - return JS_EXCEPTION; - m = js_new_module_def(ctx, module_name); - if (!m) - return JS_EXCEPTION; - js_mode |= JS_MODE_STRICT; - } - } - fd = js_new_function_def(ctx, NULL, TRUE, FALSE, filename, 1); - if (!fd) - goto fail1; - s->cur_func = fd; - fd->eval_type = eval_type; - fd->has_this_binding = (eval_type != JS_EVAL_TYPE_DIRECT); - fd->backtrace_barrier = ((flags & JS_EVAL_FLAG_BACKTRACE_BARRIER) != 0); - if (eval_type == JS_EVAL_TYPE_DIRECT) { - fd->new_target_allowed = b->new_target_allowed; - fd->super_call_allowed = b->super_call_allowed; - fd->super_allowed = b->super_allowed; - fd->arguments_allowed = b->arguments_allowed; - } else { - fd->new_target_allowed = FALSE; - fd->super_call_allowed = FALSE; - fd->super_allowed = FALSE; - fd->arguments_allowed = TRUE; - } - fd->js_mode = js_mode; - fd->func_name = JS_DupAtom(ctx, JS_ATOM__eval_); - if (b) { - if (add_closure_variables(ctx, fd, b, scope_idx)) - goto fail; - } - fd->module = m; - s->is_module = (m != NULL); - s->allow_html_comments = !s->is_module; - push_scope(s); /* body scope */ - fd->body_scope = fd->scope_level; - err = js_parse_program(s); - if (err) { - fail: - free_token(s, &s->token); - js_free_function_def(ctx, fd); - goto fail1; - } - /* create the function object and all the enclosed functions */ - fun_obj = js_create_function(ctx, fd); - if (JS_IsException(fun_obj)) - goto fail1; - /* Could add a flag to avoid resolution if necessary */ - if (m) { - m->func_obj = fun_obj; - if (js_resolve_module(ctx, m) < 0) - goto fail1; - fun_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); - } - if (flags & JS_EVAL_FLAG_COMPILE_ONLY) { - ret_val = fun_obj; - } else { - ret_val = JS_EvalFunctionInternal(ctx, fun_obj, this_obj, var_refs, sf); - } - return ret_val; - fail1: - /* XXX: should free all the unresolved dependencies */ - if (m) - js_free_module_def(ctx, m); - return JS_EXCEPTION; -} - -/* the indirection is needed to make 'eval' optional */ -static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, - const char *input, size_t input_len, - const char *filename, int flags, int scope_idx) -{ - if (UNLIKELY(!ctx->eval_internal)) { - return JS_ThrowTypeError(ctx, "eval is not supported"); - } - return ctx->eval_internal(ctx, this_obj, input, input_len, filename, - flags, scope_idx); -} - -JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj, - JSValueConst val, int flags, int scope_idx) -{ - JSValue ret; - const char *str; - size_t len; - if (!JS_IsString(val)) - return JS_DupValue(ctx, val); - str = JS_ToCStringLen(ctx, &len, val); - if (!str) - return JS_EXCEPTION; - ret = JS_EvalInternal(ctx, this_obj, str, len, "", flags, scope_idx); - JS_FreeCString(ctx, str); - return ret; - -} - -JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj, - const char *input, size_t input_len, - const char *filename, int eval_flags) -{ - int eval_type = eval_flags & JS_EVAL_TYPE_MASK; - JSValue ret; - unassert(eval_type == JS_EVAL_TYPE_GLOBAL || - eval_type == JS_EVAL_TYPE_MODULE); - ret = JS_EvalInternal(ctx, this_obj, input, input_len, filename, - eval_flags, -1); - return ret; -} - -JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len, - const char *filename, int eval_flags) -{ - return JS_EvalThis(ctx, ctx->global_obj, input, input_len, filename, - eval_flags); -} - -int JS_ResolveModule(JSContext *ctx, JSValueConst obj) -{ - if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) { - JSModuleDef *m = JS_VALUE_GET_PTR(obj); - if (js_resolve_module(ctx, m) < 0) { - js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED); - return -1; - } - } - return 0; -} - -/*******************************************************************/ -/* runtime functions & objects */ - -static JSValue js_boolean_constructor(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv); -static JSValue js_number_constructor(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv); - -int check_function(JSContext *ctx, JSValueConst obj) -{ - if (LIKELY(JS_IsFunction(ctx, obj))) - return 0; - JS_ThrowTypeError(ctx, "not a function"); - return -1; -} - -int check_exception_free(JSContext *ctx, JSValue obj) -{ - JS_FreeValue(ctx, obj); - return JS_IsException(obj); -} - -static JSAtom find_atom(JSContext *ctx, const char *name) -{ - JSAtom atom; - int len; - if (*name == '[') { - name++; - len = strlen(name) - 1; - /* We assume 8 bit non null strings, which is the case for these - symbols */ - for(atom = JS_ATOM_Symbol_toPrimitive; atom < JS_ATOM_END; atom++) { - JSAtomStruct *p = ctx->rt->atom_array[atom]; - JSString *str = p; - if (str->len == len && !memcmp(str->u.str8, name, len)) - return JS_DupAtom(ctx, atom); - } - abort(); - } else { - atom = JS_NewAtom(ctx, name); - } - return atom; -} - -static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p, - JSAtom atom, void *opaque) -{ - const JSCFunctionListEntry *e = opaque; - JSValue val; - switch(e->def_type) { - case JS_DEF_CFUNC: - val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic, - e->name, e->u.func.length, e->u.func.cproto, e->magic); - break; - case JS_DEF_PROP_STRING: - val = JS_NewAtomString(ctx, e->u.str); - break; - case JS_DEF_OBJECT: - val = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len); - break; - default: - abort(); - } - return val; -} - -static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj, - JSAtom atom, - const JSCFunctionListEntry *e) -{ - JSValue val; - int prop_flags = e->prop_flags; - switch(e->def_type) { - case JS_DEF_ALIAS: /* using autoinit for aliases is not safe */ - { - JSAtom atom1 = find_atom(ctx, e->u.alias.name); - switch (e->u.alias.base) { - case -1: - val = JS_GetProperty(ctx, obj, atom1); - break; - case 0: - val = JS_GetProperty(ctx, ctx->global_obj, atom1); - break; - case 1: - val = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], atom1); - break; - default: - abort(); - } - JS_FreeAtom(ctx, atom1); - if (atom == JS_ATOM_Symbol_toPrimitive) { - /* Symbol.toPrimitive functions are not writable */ - prop_flags = JS_PROP_CONFIGURABLE; - } else if (atom == JS_ATOM_Symbol_hasInstance) { - /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */ - prop_flags = 0; - } - } - break; - case JS_DEF_CFUNC: - if (atom == JS_ATOM_Symbol_toPrimitive) { - /* Symbol.toPrimitive functions are not writable */ - prop_flags = JS_PROP_CONFIGURABLE; - } else if (atom == JS_ATOM_Symbol_hasInstance) { - /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */ - prop_flags = 0; - } - JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP, - (void *)e, prop_flags); - return 0; - case JS_DEF_CGETSET: /* XXX: use autoinit again ? */ - case JS_DEF_CGETSET_MAGIC: - { - JSValue getter, setter; - char buf[64]; - getter = JS_UNDEFINED; - if (e->u.getset.get.generic) { - snprintf(buf, sizeof(buf), "get %s", e->name); - getter = JS_NewCFunction2(ctx, e->u.getset.get.generic, - buf, 0, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_getter_magic : JS_CFUNC_getter, - e->magic); - } - setter = JS_UNDEFINED; - if (e->u.getset.set.generic) { - snprintf(buf, sizeof(buf), "set %s", e->name); - setter = JS_NewCFunction2(ctx, e->u.getset.set.generic, - buf, 1, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_setter_magic : JS_CFUNC_setter, - e->magic); - } - JS_DefinePropertyGetSet(ctx, obj, atom, getter, setter, prop_flags); - return 0; - } - break; - case JS_DEF_PROP_INT32: - val = JS_NewInt32(ctx, e->u.i32); - break; - case JS_DEF_PROP_INT64: - val = JS_NewInt64(ctx, e->u.i64); - break; - case JS_DEF_PROP_DOUBLE: - val = __JS_NewFloat64(ctx, e->u.f64); - break; - case JS_DEF_PROP_UNDEFINED: - val = JS_UNDEFINED; - break; - case JS_DEF_PROP_STRING: - case JS_DEF_OBJECT: - JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP, - (void *)e, prop_flags); - return 0; - default: - abort(); - } - JS_DefinePropertyValue(ctx, obj, atom, val, prop_flags); - return 0; -} - -void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj, - const JSCFunctionListEntry *tab, int len) -{ - int i; - for (i = 0; i < len; i++) { - const JSCFunctionListEntry *e = &tab[i]; - JSAtom atom = find_atom(ctx, e->name); - JS_InstantiateFunctionListItem(ctx, obj, atom, e); - JS_FreeAtom(ctx, atom); - } -} - -int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m, - const JSCFunctionListEntry *tab, int len) -{ - int i; - for(i = 0; i < len; i++) { - if (JS_AddModuleExport(ctx, m, tab[i].name)) - return -1; - } - return 0; -} - -int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m, - const JSCFunctionListEntry *tab, int len) -{ - int i; - JSValue val; - for(i = 0; i < len; i++) { - const JSCFunctionListEntry *e = &tab[i]; - switch(e->def_type) { - case JS_DEF_CFUNC: - val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic, - e->name, e->u.func.length, e->u.func.cproto, e->magic); - break; - case JS_DEF_PROP_STRING: - val = JS_NewString(ctx, e->u.str); - break; - case JS_DEF_PROP_INT32: - val = JS_NewInt32(ctx, e->u.i32); - break; - case JS_DEF_PROP_INT64: - val = JS_NewInt64(ctx, e->u.i64); - break; - case JS_DEF_PROP_DOUBLE: - val = __JS_NewFloat64(ctx, e->u.f64); - break; - case JS_DEF_OBJECT: - val = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len); - break; - default: - abort(); - } - if (JS_SetModuleExport(ctx, m, e->name, val)) - return -1; - } - return 0; -} - -/* Note: 'func_obj' is not necessarily a constructor */ -void JS_SetConstructor2(JSContext *ctx, - JSValueConst func_obj, - JSValueConst proto, - int proto_flags, int ctor_flags) -{ - JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype, - JS_DupValue(ctx, proto), proto_flags); - JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor, - JS_DupValue(ctx, func_obj), - ctor_flags); - set_cycle_flag(ctx, func_obj); - set_cycle_flag(ctx, proto); -} - -void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, - JSValueConst proto) -{ - JS_SetConstructor2(ctx, func_obj, proto, - 0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); -} - -void JS_NewGlobalCConstructor2(JSContext *ctx, - JSValue func_obj, - const char *name, - JSValueConst proto) -{ - JS_DefinePropertyValueStr(ctx, ctx->global_obj, name, - JS_DupValue(ctx, func_obj), - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - JS_SetConstructor(ctx, func_obj, proto); - JS_FreeValue(ctx, func_obj); -} - -JSValueConst JS_NewGlobalCConstructor(JSContext *ctx, const char *name, - JSCFunction *func, int length, - JSValueConst proto) -{ - JSValue func_obj; - func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor_or_func, 0); - JS_NewGlobalCConstructor2(ctx, func_obj, name, proto); - return func_obj; -} - -JSValueConst JS_NewGlobalCConstructorOnly(JSContext *ctx, const char *name, - JSCFunction *func, int length, - JSValueConst proto) -{ - JSValue func_obj; - func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor, 0); - JS_NewGlobalCConstructor2(ctx, func_obj, name, proto); - return func_obj; -} - -static JSValue js_global_eval(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_EvalObject(ctx, ctx->global_obj, argv[0], JS_EVAL_TYPE_INDIRECT, -1); -} - -static JSValue js_global_isNaN(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - double d; - - /* XXX: does this work for bigfloat? */ - if (UNLIKELY(JS_ToFloat64(ctx, &d, argv[0]))) - return JS_EXCEPTION; - return JS_NewBool(ctx, isnan(d)); -} - -static JSValue js_global_isFinite(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - BOOL res; - double d; - if (UNLIKELY(JS_ToFloat64(ctx, &d, argv[0]))) - return JS_EXCEPTION; - res = isfinite(d); - return JS_NewBool(ctx, res); -} - -/* Object class */ - -/* Function class */ - -static JSValue js_function_proto(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_UNDEFINED; -} - -int js_get_length32(JSContext *ctx, uint32_t *pres, JSValueConst obj) -{ - JSValue len_val; - len_val = JS_GetProperty(ctx, obj, JS_ATOM_length); - if (JS_IsException(len_val)) { - *pres = 0; - return -1; - } - return JS_ToUint32Free(ctx, pres, len_val); -} - -int js_get_length64(JSContext *ctx, int64_t *pres, JSValueConst obj) -{ - JSValue len_val; - len_val = JS_GetProperty(ctx, obj, JS_ATOM_length); - if (JS_IsException(len_val)) { - *pres = 0; - return -1; - } - return JS_ToLengthFree(ctx, pres, len_val); -} - -void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len) -{ - uint32_t i; - for(i = 0; i < len; i++) { - JS_FreeValue(ctx, tab[i]); - } - js_free(ctx, tab); -} - -/* XXX: should use ValueArray */ -JSValue *build_arg_list(JSContext *ctx, uint32_t *plen, - JSValueConst array_arg) -{ - uint32_t len, i; - JSValue *tab, ret; - JSObject *p; - if (JS_VALUE_GET_TAG(array_arg) != JS_TAG_OBJECT) { - JS_ThrowTypeError(ctx, "not a object"); - return NULL; - } - if (js_get_length32(ctx, &len, array_arg)) - return NULL; - if (len > JS_MAX_LOCAL_VARS) { - JS_ThrowInternalError(ctx, "too many arguments"); - return NULL; - } - /* avoid allocating 0 bytes */ - tab = js_mallocz(ctx, sizeof(tab[0]) * max_uint32(1, len)); - if (!tab) - return NULL; - p = JS_VALUE_GET_OBJ(array_arg); - if ((p->class_id == JS_CLASS_ARRAY || p->class_id == JS_CLASS_ARGUMENTS) && - p->fast_array && - len == p->u.array.count) { - for(i = 0; i < len; i++) { - tab[i] = JS_DupValue(ctx, p->u.array.u.values[i]); - } - } else { - for(i = 0; i < len; i++) { - ret = JS_GetPropertyUint32(ctx, array_arg, i); - if (JS_IsException(ret)) { - free_arg_list(ctx, tab, i); - return NULL; - } - tab[i] = ret; - } - } - *plen = len; - return tab; -} - -/* magic value: 0 = normal apply, 1 = apply for constructor, 2 = - Reflect.apply */ -JSValue js_function_apply(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSValueConst this_arg, array_arg; - uint32_t len; - JSValue *tab, ret; - if (check_function(ctx, this_val)) - return JS_EXCEPTION; - this_arg = argv[0]; - array_arg = argv[1]; - if ((JS_VALUE_GET_TAG(array_arg) == JS_TAG_UNDEFINED || - JS_VALUE_GET_TAG(array_arg) == JS_TAG_NULL) && magic != 2) { - return JS_Call(ctx, this_val, this_arg, 0, NULL); - } - tab = build_arg_list(ctx, &len, array_arg); - if (!tab) - return JS_EXCEPTION; - if (magic & 1) { - ret = JS_CallConstructor2(ctx, this_val, this_arg, len, (JSValueConst *)tab); - } else { - ret = JS_Call(ctx, this_val, this_arg, len, (JSValueConst *)tab); - } - free_arg_list(ctx, tab, len); - return ret; -} - -static JSValue js_function_call(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - if (argc <= 0) { - return JS_Call(ctx, this_val, JS_UNDEFINED, 0, NULL); - } else { - return JS_Call(ctx, this_val, argv[0], argc - 1, argv + 1); - } -} - -static JSValue js_function_bind(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSBoundFunction *bf; - JSValue func_obj, name1, len_val; - JSObject *p; - int arg_count, i, ret; - if (check_function(ctx, this_val)) - return JS_EXCEPTION; - func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto, - JS_CLASS_BOUND_FUNCTION); - if (JS_IsException(func_obj)) - return JS_EXCEPTION; - p = JS_VALUE_GET_OBJ(func_obj); - p->is_constructor = JS_IsConstructor(ctx, this_val); - arg_count = max_int(0, argc - 1); - bf = js_malloc(ctx, sizeof(*bf) + arg_count * sizeof(JSValue)); - if (!bf) - goto exception; - bf->func_obj = JS_DupValue(ctx, this_val); - bf->this_val = JS_DupValue(ctx, argv[0]); - bf->argc = arg_count; - for(i = 0; i < arg_count; i++) { - bf->argv[i] = JS_DupValue(ctx, argv[i + 1]); - } - p->u.bound_function = bf; - /* XXX: the spec could be simpler by only using GetOwnProperty */ - ret = JS_GetOwnProperty(ctx, NULL, this_val, JS_ATOM_length); - if (ret < 0) - goto exception; - if (!ret) { - len_val = JS_NewInt32(ctx, 0); - } else { - len_val = JS_GetProperty(ctx, this_val, JS_ATOM_length); - if (JS_IsException(len_val)) - goto exception; - if (JS_VALUE_GET_TAG(len_val) == JS_TAG_INT) { - /* most common case */ - int len1 = JS_VALUE_GET_INT(len_val); - if (len1 <= arg_count) - len1 = 0; - else - len1 -= arg_count; - len_val = JS_NewInt32(ctx, len1); - } else if (JS_VALUE_GET_NORM_TAG(len_val) == JS_TAG_FLOAT64) { - double d = JS_VALUE_GET_FLOAT64(len_val); - if (isnan(d)) { - d = 0.0; - } else { - d = trunc(d); - if (d <= (double)arg_count) - d = 0.0; - else - d -= (double)arg_count; /* also converts -0 to +0 */ - } - len_val = JS_NewFloat64(ctx, d); - } else { - JS_FreeValue(ctx, len_val); - len_val = JS_NewInt32(ctx, 0); - } - } - JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length, - len_val, JS_PROP_CONFIGURABLE); - name1 = JS_GetProperty(ctx, this_val, JS_ATOM_name); - if (JS_IsException(name1)) - goto exception; - if (!JS_IsString(name1)) { - JS_FreeValue(ctx, name1); - name1 = JS_AtomToString(ctx, JS_ATOM_empty_string); - } - name1 = JS_ConcatString3(ctx, "bound ", name1, ""); - if (JS_IsException(name1)) - goto exception; - JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name1, - JS_PROP_CONFIGURABLE); - return func_obj; - exception: - JS_FreeValue(ctx, func_obj); - return JS_EXCEPTION; -} - -static JSValue js_function_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSObject *p; - JSFunctionKindEnum func_kind = JS_FUNC_NORMAL; - if (check_function(ctx, this_val)) - return JS_EXCEPTION; - p = JS_VALUE_GET_OBJ(this_val); - if (js_class_has_bytecode(p->class_id)) { - JSFunctionBytecode *b = p->u.func.function_bytecode; - if (b->has_debug && b->debug.source) { - return JS_NewStringLen(ctx, b->debug.source, b->debug.source_len); - } - func_kind = b->func_kind; - } - { - JSValue name; - const char *pref, *suff; - switch(func_kind) { - default: - case JS_FUNC_NORMAL: - pref = "function "; - break; - case JS_FUNC_GENERATOR: - pref = "function *"; - break; - case JS_FUNC_ASYNC: - pref = "async function "; - break; - case JS_FUNC_ASYNC_GENERATOR: - pref = "async function *"; - break; - } - suff = "() {\n [native code]\n}"; - name = JS_GetProperty(ctx, this_val, JS_ATOM_name); - if (JS_IsUndefined(name)) - name = JS_AtomToString(ctx, JS_ATOM_empty_string); - return JS_ConcatString3(ctx, pref, name, suff); - } -} - -static JSValue js_function_hasInstance(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int ret; - ret = JS_OrdinaryIsInstanceOf(ctx, argv[0], this_val); - if (ret < 0) - return JS_EXCEPTION; - else - return JS_NewBool(ctx, ret); -} - -static const JSCFunctionListEntry js_function_proto_funcs[] = { - JS_CFUNC_DEF("call", 1, js_function_call ), - JS_CFUNC_MAGIC_DEF("apply", 2, js_function_apply, 0 ), - JS_CFUNC_DEF("bind", 1, js_function_bind ), - JS_CFUNC_DEF("toString", 0, js_function_toString ), - JS_CFUNC_DEF("[Symbol.hasInstance]", 1, js_function_hasInstance ), - JS_CGETSET_DEF("fileName", js_function_proto_fileName, NULL ), - JS_CGETSET_DEF("lineNumber", js_function_proto_lineNumber, NULL ), -}; - -/* Error class */ - -static JSValue iterator_to_array(JSContext *ctx, JSValueConst items) -{ - JSValue iter, next_method = JS_UNDEFINED; - JSValue v, r = JS_UNDEFINED; - int64_t k; - BOOL done; - - iter = JS_GetIterator(ctx, items, FALSE); - if (JS_IsException(iter)) - goto exception; - next_method = JS_GetProperty(ctx, iter, JS_ATOM_next); - if (JS_IsException(next_method)) - goto exception; - r = JS_NewArray(ctx); - if (JS_IsException(r)) - goto exception; - for (k = 0;; k++) { - v = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done); - if (JS_IsException(v)) - goto exception_close; - if (done) - break; - if (JS_DefinePropertyValueInt64(ctx, r, k, v, - JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception_close; - } - done: - JS_FreeValue(ctx, next_method); - JS_FreeValue(ctx, iter); - return r; - exception_close: - JS_IteratorClose(ctx, iter, TRUE); - exception: - JS_FreeValue(ctx, r); - r = JS_EXCEPTION; - goto done; -} - -static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv, int magic) -{ - JSValue obj, msg, proto; - JSValueConst message; - - if (JS_IsUndefined(new_target)) - new_target = JS_GetActiveFunction(ctx); - proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype); - if (JS_IsException(proto)) - return proto; - if (!JS_IsObject(proto)) { - JSContext *realm; - JSValueConst proto1; - - JS_FreeValue(ctx, proto); - realm = JS_GetFunctionRealm(ctx, new_target); - if (!realm) - return JS_EXCEPTION; - if (magic < 0) { - proto1 = realm->class_proto[JS_CLASS_ERROR]; - } else { - proto1 = realm->native_error_proto[magic]; - } - proto = JS_DupValue(ctx, proto1); - } - obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_ERROR); - JS_FreeValue(ctx, proto); - if (JS_IsException(obj)) - return obj; - if (magic == JS_AGGREGATE_ERROR) { - message = argv[1]; - } else { - message = argv[0]; - } - - if (!JS_IsUndefined(message)) { - msg = JS_ToString(ctx, message); - if (UNLIKELY(JS_IsException(msg))) - goto exception; - JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, msg, - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - } - - if (magic == JS_AGGREGATE_ERROR) { - JSValue error_list = iterator_to_array(ctx, argv[0]); - if (JS_IsException(error_list)) - goto exception; - JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, error_list, - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - } - - /* skip the Error() function in the backtrace */ - build_backtrace(ctx, obj, NULL, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL); - return obj; - exception: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - -static JSValue js_error_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue name, msg; - - if (!JS_IsObject(this_val)) - return JS_ThrowTypeErrorNotAnObject(ctx); - name = JS_GetProperty(ctx, this_val, JS_ATOM_name); - if (JS_IsUndefined(name)) - name = JS_AtomToString(ctx, JS_ATOM_Error); - else - name = JS_ToStringFree(ctx, name); - if (JS_IsException(name)) - return JS_EXCEPTION; - - msg = JS_GetProperty(ctx, this_val, JS_ATOM_message); - if (JS_IsUndefined(msg)) - msg = JS_AtomToString(ctx, JS_ATOM_empty_string); - else - msg = JS_ToStringFree(ctx, msg); - if (JS_IsException(msg)) { - JS_FreeValue(ctx, name); - return JS_EXCEPTION; - } - if (!JS_IsEmptyString(name) && !JS_IsEmptyString(msg)) - name = JS_ConcatString3(ctx, "", name, ": "); - return JS_ConcatString(ctx, name, msg); -} - -static const JSCFunctionListEntry js_error_proto_funcs[] = { - JS_CFUNC_DEF("toString", 0, js_error_toString ), - JS_PROP_STRING_DEF("name", "Error", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ), - JS_PROP_STRING_DEF("message", "", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ), -}; - -/* Number */ - -static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) -{ - JSValue val, obj; - if (argc == 0) { - val = JS_NewInt32(ctx, 0); - } else { - val = JS_ToNumeric(ctx, argv[0]); - if (JS_IsException(val)) - return val; - switch(JS_VALUE_GET_TAG(val)) { -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_INT: - case JS_TAG_BIG_FLOAT: - { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - double d; - bf_get_float64(&p->num, &d, BF_RNDN); - JS_FreeValue(ctx, val); - val = __JS_NewFloat64(ctx, d); - } - break; - case JS_TAG_BIG_DECIMAL: - val = JS_ToStringFree(ctx, val); - if (JS_IsException(val)) - return val; - val = JS_ToNumberFree(ctx, val); - if (JS_IsException(val)) - return val; - break; -#endif - default: - break; - } - } - if (!JS_IsUndefined(new_target)) { - obj = js_create_from_ctor(ctx, new_target, JS_CLASS_NUMBER); - if (!JS_IsException(obj)) - JS_SetObjectData(ctx, obj, val); - return obj; - } else { - return val; - } -} - -#if 0 -static JSValue js_number___toInteger(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[0])); -} - -static JSValue js_number___toLength(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int64_t v; - if (JS_ToLengthFree(ctx, &v, JS_DupValue(ctx, argv[0]))) - return JS_EXCEPTION; - return JS_NewInt64(ctx, v); -} -#endif - -static JSValue js_number_isNaN(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - if (!JS_IsNumber(argv[0])) - return JS_FALSE; - return js_global_isNaN(ctx, this_val, argc, argv); -} - -static JSValue js_number_isFinite(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - if (!JS_IsNumber(argv[0])) - return JS_FALSE; - return js_global_isFinite(ctx, this_val, argc, argv); -} - -static JSValue js_number_isInteger(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int ret; - ret = JS_NumberIsInteger(ctx, argv[0]); - if (ret < 0) - return JS_EXCEPTION; - else - return JS_NewBool(ctx, ret); -} - -static JSValue js_number_isSafeInteger(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - double d; - if (!JS_IsNumber(argv[0])) - return JS_FALSE; - if (UNLIKELY(JS_ToFloat64(ctx, &d, argv[0]))) - return JS_EXCEPTION; - return JS_NewBool(ctx, is_safe_integer(d)); -} - -static const JSCFunctionListEntry js_number_funcs[] = { - /* global ParseInt and parseFloat should be defined already or delayed */ - JS_ALIAS_BASE_DEF("parseInt", "parseInt", 0 ), - JS_ALIAS_BASE_DEF("parseFloat", "parseFloat", 0 ), - JS_CFUNC_DEF("isNaN", 1, js_number_isNaN ), - JS_CFUNC_DEF("isFinite", 1, js_number_isFinite ), - JS_CFUNC_DEF("isInteger", 1, js_number_isInteger ), - JS_CFUNC_DEF("isSafeInteger", 1, js_number_isSafeInteger ), - JS_PROP_DOUBLE_DEF("MAX_VALUE", 1.7976931348623157e+308, 0 ), - JS_PROP_DOUBLE_DEF("MIN_VALUE", 5e-324, 0 ), - JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ), - JS_PROP_DOUBLE_DEF("NEGATIVE_INFINITY", -INFINITY, 0 ), - JS_PROP_DOUBLE_DEF("POSITIVE_INFINITY", INFINITY, 0 ), - JS_PROP_DOUBLE_DEF("EPSILON", 2.220446049250313e-16, 0 ), /* ES6 */ - JS_PROP_DOUBLE_DEF("MAX_SAFE_INTEGER", 9007199254740991.0, 0 ), /* ES6 */ - JS_PROP_DOUBLE_DEF("MIN_SAFE_INTEGER", -9007199254740991.0, 0 ), /* ES6 */ - //JS_CFUNC_DEF("__toInteger", 1, js_number___toInteger ), - //JS_CFUNC_DEF("__toLength", 1, js_number___toLength ), -}; - -static JSValue js_thisNumberValue(JSContext *ctx, JSValueConst this_val) -{ - if (JS_IsNumber(this_val)) - return JS_DupValue(ctx, this_val); - - if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(this_val); - if (p->class_id == JS_CLASS_NUMBER) { - if (JS_IsNumber(p->u.object_data)) - return JS_DupValue(ctx, p->u.object_data); - } - } - return JS_ThrowTypeError(ctx, "not a number"); -} - -static JSValue js_number_valueOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return js_thisNumberValue(ctx, this_val); -} - -int js_get_radix(JSContext *ctx, JSValueConst val) -{ - int radix; - if (JS_ToInt32Sat(ctx, &radix, val)) - return -1; - if (radix < 2 || radix > 36) { - JS_ThrowRangeError(ctx, "radix must be between 2 and 36"); - return -1; - } - return radix; -} - -static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSValue val; - int base; - double d; - val = js_thisNumberValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (magic || JS_IsUndefined(argv[0])) { - base = 10; - } else { - base = js_get_radix(ctx, argv[0]); - if (base < 0) - goto fail; - } - if (JS_ToFloat64Free(ctx, &d, val)) - return JS_EXCEPTION; - return js_dtoa(ctx, d, base, 0, JS_DTOA_VAR_FORMAT); - fail: - JS_FreeValue(ctx, val); - return JS_EXCEPTION; -} - -static JSValue js_number_toFixed(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val; - int f; - double d; - val = js_thisNumberValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (JS_ToFloat64Free(ctx, &d, val)) - return JS_EXCEPTION; - if (JS_ToInt32Sat(ctx, &f, argv[0])) - return JS_EXCEPTION; - if (f < 0 || f > 100) - return JS_ThrowRangeError(ctx, "invalid number of digits"); - if (fabs(d) >= 1e21) { - return JS_ToStringFree(ctx, __JS_NewFloat64(ctx, d)); - } else { - return js_dtoa(ctx, d, 10, f, JS_DTOA_FRAC_FORMAT); - } -} - -static JSValue js_number_toExponential(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val; - int f, flags; - double d; - val = js_thisNumberValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (JS_ToFloat64Free(ctx, &d, val)) - return JS_EXCEPTION; - if (JS_ToInt32Sat(ctx, &f, argv[0])) - return JS_EXCEPTION; - if (!isfinite(d)) { - return JS_ToStringFree(ctx, __JS_NewFloat64(ctx, d)); - } - if (JS_IsUndefined(argv[0])) { - flags = 0; - f = 0; - } else { - if (f < 0 || f > 100) - return JS_ThrowRangeError(ctx, "invalid number of digits"); - f++; - flags = JS_DTOA_FIXED_FORMAT; - } - return js_dtoa(ctx, d, 10, f, flags | JS_DTOA_FORCE_EXP); -} - -static JSValue js_number_toPrecision(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val; - int p; - double d; - val = js_thisNumberValue(ctx, this_val); - if (JS_IsException(val)) - return val; - if (JS_ToFloat64Free(ctx, &d, val)) - return JS_EXCEPTION; - if (JS_IsUndefined(argv[0])) - goto to_string; - if (JS_ToInt32Sat(ctx, &p, argv[0])) - return JS_EXCEPTION; - if (!isfinite(d)) { - to_string: - return JS_ToStringFree(ctx, __JS_NewFloat64(ctx, d)); - } - if (p < 1 || p > 100) - return JS_ThrowRangeError(ctx, "invalid number of digits"); - return js_dtoa(ctx, d, 10, p, JS_DTOA_FIXED_FORMAT); -} - -static const JSCFunctionListEntry js_number_proto_funcs[] = { - JS_CFUNC_DEF("toExponential", 1, js_number_toExponential ), - JS_CFUNC_DEF("toFixed", 1, js_number_toFixed ), - JS_CFUNC_DEF("toPrecision", 1, js_number_toPrecision ), - JS_CFUNC_MAGIC_DEF("toString", 1, js_number_toString, 0 ), - JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_number_toString, 1 ), - JS_CFUNC_DEF("valueOf", 0, js_number_valueOf ), -}; - -static JSValue js_parseInt(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *str, *p; - int radix, flags; - JSValue ret; - str = JS_ToCString(ctx, argv[0]); - if (!str) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &radix, argv[1])) { - JS_FreeCString(ctx, str); - return JS_EXCEPTION; - } - if (radix != 0 && (radix < 2 || radix > 36)) { - ret = JS_NAN; - } else { - p = str; - p += skip_spaces(p); - flags = ATOD_INT_ONLY | ATOD_ACCEPT_PREFIX_AFTER_SIGN; - ret = js_atof(ctx, p, NULL, radix, flags); - } - JS_FreeCString(ctx, str); - return ret; -} - -static JSValue js_parseFloat(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *str, *p; - JSValue ret; - str = JS_ToCString(ctx, argv[0]); - if (!str) - return JS_EXCEPTION; - p = str; - p += skip_spaces(p); - ret = js_atof(ctx, p, NULL, 10, 0); - JS_FreeCString(ctx, str); - return ret; -} - -/* Boolean */ -static JSValue js_boolean_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) -{ - JSValue val, obj; - val = JS_NewBool(ctx, JS_ToBool(ctx, argv[0])); - if (!JS_IsUndefined(new_target)) { - obj = js_create_from_ctor(ctx, new_target, JS_CLASS_BOOLEAN); - if (!JS_IsException(obj)) - JS_SetObjectData(ctx, obj, val); - return obj; - } else { - return val; - } -} - -static JSValue js_thisBooleanValue(JSContext *ctx, JSValueConst this_val) -{ - if (JS_VALUE_GET_TAG(this_val) == JS_TAG_BOOL) - return JS_DupValue(ctx, this_val); - if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(this_val); - if (p->class_id == JS_CLASS_BOOLEAN) { - if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_BOOL) - return p->u.object_data; - } - } - return JS_ThrowTypeError(ctx, "not a boolean"); -} - -static JSValue js_boolean_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val = js_thisBooleanValue(ctx, this_val); - if (JS_IsException(val)) - return val; - return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ? - JS_ATOM_true : JS_ATOM_false); -} - -static JSValue js_boolean_valueOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return js_thisBooleanValue(ctx, this_val); -} - -static const JSCFunctionListEntry js_boolean_proto_funcs[] = { - JS_CFUNC_DEF("toString", 0, js_boolean_toString ), - JS_CFUNC_DEF("valueOf", 0, js_boolean_valueOf ), -}; - -/* Symbol */ - -static JSValue js_symbol_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) -{ - JSValue str; - JSString *p; - if (!JS_IsUndefined(new_target)) - return JS_ThrowTypeError(ctx, "not a constructor"); - if (argc == 0 || JS_IsUndefined(argv[0])) { - p = NULL; - } else { - str = JS_ToString(ctx, argv[0]); - if (JS_IsException(str)) - return JS_EXCEPTION; - p = JS_VALUE_GET_STRING(str); - } - return JS_NewSymbol(ctx, p, JS_ATOM_TYPE_SYMBOL); -} - -static JSValue js_thisSymbolValue(JSContext *ctx, JSValueConst this_val) -{ - if (JS_VALUE_GET_TAG(this_val) == JS_TAG_SYMBOL) - return JS_DupValue(ctx, this_val); - if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(this_val); - if (p->class_id == JS_CLASS_SYMBOL) { - if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_SYMBOL) - return JS_DupValue(ctx, p->u.object_data); - } - } - return JS_ThrowTypeError(ctx, "not a symbol"); -} - -static JSValue js_symbol_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val, ret; - val = js_thisSymbolValue(ctx, this_val); - if (JS_IsException(val)) - return val; - /* XXX: use JS_ToStringInternal() with a flags */ - ret = js_string_constructor(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val); - JS_FreeValue(ctx, val); - return ret; -} - -static JSValue js_symbol_valueOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return js_thisSymbolValue(ctx, this_val); -} - -static JSValue js_symbol_get_description(JSContext *ctx, JSValueConst this_val) -{ - JSValue val, ret; - JSAtomStruct *p; - - val = js_thisSymbolValue(ctx, this_val); - if (JS_IsException(val)) - return val; - p = JS_VALUE_GET_PTR(val); - if (p->len == 0 && p->is_wide_char != 0) { - ret = JS_UNDEFINED; - } else { - ret = JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p)); - } - JS_FreeValue(ctx, val); - return ret; -} - -static const JSCFunctionListEntry js_symbol_proto_funcs[] = { - JS_CFUNC_DEF("toString", 0, js_symbol_toString ), - JS_CFUNC_DEF("valueOf", 0, js_symbol_valueOf ), - // XXX: should have writable: false - JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_symbol_valueOf ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Symbol", JS_PROP_CONFIGURABLE ), - JS_CGETSET_DEF("description", js_symbol_get_description, NULL ), -}; - -static JSValue js_symbol_for(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue str; - str = JS_ToString(ctx, argv[0]); - if (JS_IsException(str)) - return JS_EXCEPTION; - return JS_NewSymbol(ctx, JS_VALUE_GET_STRING(str), JS_ATOM_TYPE_GLOBAL_SYMBOL); -} - -static JSValue js_symbol_keyFor(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSAtomStruct *p; - if (!JS_IsSymbol(argv[0])) - return JS_ThrowTypeError(ctx, "not a symbol"); - p = JS_VALUE_GET_PTR(argv[0]); - if (p->atom_type != JS_ATOM_TYPE_GLOBAL_SYMBOL) - return JS_UNDEFINED; - return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p)); -} - -static const JSCFunctionListEntry js_symbol_funcs[] = { - JS_CFUNC_DEF("for", 1, js_symbol_for ), - JS_CFUNC_DEF("keyFor", 1, js_symbol_keyFor ), -}; - -/* AsyncFromSyncIteratorPrototype */ - -static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx, - JSValueConst sync_iter) -{ - JSValue async_iter, next_method; - JSAsyncFromSyncIteratorData *s; - next_method = JS_GetProperty(ctx, sync_iter, JS_ATOM_next); - if (JS_IsException(next_method)) - return JS_EXCEPTION; - async_iter = JS_NewObjectClass(ctx, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR); - if (JS_IsException(async_iter)) { - JS_FreeValue(ctx, next_method); - return async_iter; - } - s = js_mallocz(ctx, sizeof(*s)); - if (!s) { - JS_FreeValue(ctx, async_iter); - JS_FreeValue(ctx, next_method); - return JS_EXCEPTION; - } - s->sync_iter = JS_DupValue(ctx, sync_iter); - s->next_method = next_method; - JS_SetOpaque(async_iter, s); - return async_iter; -} - -/* global object */ - -static const JSCFunctionListEntry js_global_funcs[] = { - JS_CFUNC_DEF("parseInt", 2, js_parseInt ), - JS_CFUNC_DEF("parseFloat", 1, js_parseFloat ), - JS_CFUNC_DEF("isNaN", 1, js_global_isNaN ), - JS_CFUNC_DEF("isFinite", 1, js_global_isFinite ), - JS_CFUNC_MAGIC_DEF("decodeURI", 1, js_global_decodeURI, 0 ), - JS_CFUNC_MAGIC_DEF("decodeURIComponent", 1, js_global_decodeURI, 1 ), - JS_CFUNC_MAGIC_DEF("encodeURI", 1, js_global_encodeURI, 0 ), - JS_CFUNC_MAGIC_DEF("encodeURIComponent", 1, js_global_encodeURI, 1 ), - JS_CFUNC_DEF("escape", 1, js_global_escape ), - JS_CFUNC_DEF("unescape", 1, js_global_unescape ), - JS_PROP_DOUBLE_DEF("Infinity", 1.0 / 0.0, 0 ), - JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ), - JS_PROP_UNDEFINED_DEF("undefined", 0 ), - /* for the 'Date' implementation */ - JS_CFUNC_DEF("__date_clock", 0, js___date_clock ), - //JS_CFUNC_DEF("__date_now", 0, js___date_now ), - //JS_CFUNC_DEF("__date_getTimezoneOffset", 1, js___date_getTimezoneOffset ), - //JS_CFUNC_DEF("__date_create", 3, js___date_create ), -}; - -/* eval */ - -void JS_AddIntrinsicEval(JSContext *ctx) -{ - ctx->eval_internal = __JS_EvalInternal; -} - -#ifdef CONFIG_BIGNUM - -/* Operators */ - -static void js_operator_set_finalizer(JSRuntime *rt, JSValue val) -{ - JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET); - int i, j; - JSBinaryOperatorDefEntry *ent; - if (opset) { - for(i = 0; i < JS_OVOP_COUNT; i++) { - if (opset->self_ops[i]) - JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i])); - } - for(j = 0; j < opset->left.count; j++) { - ent = &opset->left.tab[j]; - for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) { - if (ent->ops[i]) - JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i])); - } - } - js_free_rt(rt, opset->left.tab); - for(j = 0; j < opset->right.count; j++) { - ent = &opset->right.tab[j]; - for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) { - if (ent->ops[i]) - JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i])); - } - } - js_free_rt(rt, opset->right.tab); - js_free_rt(rt, opset); - } -} - -static void js_operator_set_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET); - int i, j; - JSBinaryOperatorDefEntry *ent; - if (opset) { - for(i = 0; i < JS_OVOP_COUNT; i++) { - if (opset->self_ops[i]) - JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i]), - mark_func); - } - for(j = 0; j < opset->left.count; j++) { - ent = &opset->left.tab[j]; - for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) { - if (ent->ops[i]) - JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]), - mark_func); - } - } - for(j = 0; j < opset->right.count; j++) { - ent = &opset->right.tab[j]; - for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) { - if (ent->ops[i]) - JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]), - mark_func); - } - } - } -} - -/* create an OperatorSet object */ -static JSValue js_operators_create_internal(JSContext *ctx, - int argc, JSValueConst *argv, - BOOL is_primitive) -{ - JSValue opset_obj, prop, obj; - JSOperatorSetData *opset, *opset1; - JSBinaryOperatorDef *def; - JSValueConst arg; - int i, j; - JSBinaryOperatorDefEntry *new_tab; - JSBinaryOperatorDefEntry *ent; - uint32_t op_count; - if (ctx->rt->operator_count == UINT32_MAX) { - return JS_ThrowTypeError(ctx, "too many operators"); - } - opset_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_OPERATOR_SET); - if (JS_IsException(opset_obj)) - goto fail; - opset = js_mallocz(ctx, sizeof(*opset)); - if (!opset) - goto fail; - JS_SetOpaque(opset_obj, opset); - if (argc >= 1) { - arg = argv[0]; - /* self operators */ - for(i = 0; i < JS_OVOP_COUNT; i++) { - prop = JS_GetPropertyStr(ctx, arg, js_overloadable_operator_names[i]); - if (JS_IsException(prop)) - goto fail; - if (!JS_IsUndefined(prop)) { - if (check_function(ctx, prop)) { - JS_FreeValue(ctx, prop); - goto fail; - } - opset->self_ops[i] = JS_VALUE_GET_OBJ(prop); - } - } - } - /* left & right operators */ - for(j = 1; j < argc; j++) { - arg = argv[j]; - prop = JS_GetPropertyStr(ctx, arg, "left"); - if (JS_IsException(prop)) - goto fail; - def = &opset->right; - if (JS_IsUndefined(prop)) { - prop = JS_GetPropertyStr(ctx, arg, "right"); - if (JS_IsException(prop)) - goto fail; - if (JS_IsUndefined(prop)) { - JS_ThrowTypeError(ctx, "left or right property must be present"); - goto fail; - } - def = &opset->left; - } - /* get the operator set */ - obj = JS_GetProperty(ctx, prop, JS_ATOM_prototype); - JS_FreeValue(ctx, prop); - if (JS_IsException(obj)) - goto fail; - prop = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet); - JS_FreeValue(ctx, obj); - if (JS_IsException(prop)) - goto fail; - opset1 = JS_GetOpaque2(ctx, prop, JS_CLASS_OPERATOR_SET); - if (!opset1) { - JS_FreeValue(ctx, prop); - goto fail; - } - op_count = opset1->operator_counter; - JS_FreeValue(ctx, prop); - /* we assume there are few entries */ - new_tab = js_realloc(ctx, def->tab, - (def->count + 1) * sizeof(def->tab[0])); - if (!new_tab) - goto fail; - def->tab = new_tab; - def->count++; - ent = def->tab + def->count - 1; - bzero(ent, sizeof(def->tab[0])); - ent->operator_index = op_count; - for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) { - prop = JS_GetPropertyStr(ctx, arg, - js_overloadable_operator_names[i]); - if (JS_IsException(prop)) - goto fail; - if (!JS_IsUndefined(prop)) { - if (check_function(ctx, prop)) { - JS_FreeValue(ctx, prop); - goto fail; - } - ent->ops[i] = JS_VALUE_GET_OBJ(prop); - } - } - } - opset->is_primitive = is_primitive; - opset->operator_counter = ctx->rt->operator_count++; - return opset_obj; - fail: - JS_FreeValue(ctx, opset_obj); - return JS_EXCEPTION; -} - -static JSValue js_operators_create(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return js_operators_create_internal(ctx, argc, argv, FALSE); -} - -static JSValue js_operators_updateBigIntOperators(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue opset_obj, prop; - JSOperatorSetData *opset; - const JSOverloadableOperatorEnum ops[2] = { JS_OVOP_DIV, JS_OVOP_POW }; - JSOverloadableOperatorEnum op; - int i; - opset_obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_BIG_INT], - JS_ATOM_Symbol_operatorSet); - if (JS_IsException(opset_obj)) - goto fail; - opset = JS_GetOpaque2(ctx, opset_obj, JS_CLASS_OPERATOR_SET); - if (!opset) - goto fail; - for(i = 0; i < countof(ops); i++) { - op = ops[i]; - prop = JS_GetPropertyStr(ctx, argv[0], - js_overloadable_operator_names[op]); - if (JS_IsException(prop)) - goto fail; - if (!JS_IsUndefined(prop)) { - if (!JS_IsNull(prop) && check_function(ctx, prop)) { - JS_FreeValue(ctx, prop); - goto fail; - } - if (opset->self_ops[op]) - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[op])); - if (JS_IsNull(prop)) { - opset->self_ops[op] = NULL; - } else { - opset->self_ops[op] = JS_VALUE_GET_PTR(prop); - } - } - } - JS_FreeValue(ctx, opset_obj); - return JS_UNDEFINED; - fail: - JS_FreeValue(ctx, opset_obj); - return JS_EXCEPTION; -} - -static int js_operators_set_default(JSContext *ctx, JSValueConst obj) -{ - JSValue opset_obj; - if (!JS_IsObject(obj)) /* in case the prototype is not defined */ - return 0; - opset_obj = js_operators_create_internal(ctx, 0, NULL, TRUE); - if (JS_IsException(opset_obj)) - return -1; - /* cannot be modified by the user */ - JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_operatorSet, - opset_obj, 0); - return 0; -} - -static JSValue js_dummy_operators_ctor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) -{ - return js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT); -} - -static JSValue js_global_operators(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue func_obj, proto, opset_obj; - func_obj = JS_UNDEFINED; - proto = JS_NewObject(ctx); - if (JS_IsException(proto)) - return JS_EXCEPTION; - opset_obj = js_operators_create_internal(ctx, argc, argv, FALSE); - if (JS_IsException(opset_obj)) - goto fail; - JS_DefinePropertyValue(ctx, proto, JS_ATOM_Symbol_operatorSet, - opset_obj, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - func_obj = JS_NewCFunction2(ctx, js_dummy_operators_ctor, "Operators", - 0, JS_CFUNC_constructor, 0); - if (JS_IsException(func_obj)) - goto fail; - JS_SetConstructor2(ctx, func_obj, proto, - 0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - JS_FreeValue(ctx, proto); - return func_obj; - fail: - JS_FreeValue(ctx, proto); - JS_FreeValue(ctx, func_obj); - return JS_EXCEPTION; -} - -static const JSCFunctionListEntry js_operators_funcs[] = { - JS_CFUNC_DEF("create", 1, js_operators_create ), - JS_CFUNC_DEF("updateBigIntOperators", 2, js_operators_updateBigIntOperators ), -}; - -/* must be called after all overloadable base types are initialized */ -void JS_AddIntrinsicOperators(JSContext *ctx) -{ - JSValue obj; - ctx->allow_operator_overloading = TRUE; - obj = JS_NewCFunction(ctx, js_global_operators, "Operators", 1); - JS_SetPropertyFunctionList(ctx, obj, - js_operators_funcs, - countof(js_operators_funcs)); - JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_Operators, - obj, - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - /* add default operatorSets */ - js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BOOLEAN]); - js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_NUMBER]); - js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_STRING]); - js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_INT]); - js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT]); - js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL]); -} - -#endif /* CONFIG_BIGNUM */ - -static const char * const native_error_name[JS_NATIVE_ERROR_COUNT] = { - "EvalError", "RangeError", "ReferenceError", - "SyntaxError", "TypeError", "URIError", - "InternalError", "AggregateError", -}; - -/* Minimum amount of objects to be able to compile code and display - error messages. No JSAtom should be allocated by this function. */ -static void JS_AddIntrinsicBasicObjects(JSContext *ctx) -{ - JSValue proto; - int i; - ctx->class_proto[JS_CLASS_OBJECT] = JS_NewObjectProto(ctx, JS_NULL); - ctx->function_proto = JS_NewCFunction3(ctx, js_function_proto, "", 0, - JS_CFUNC_generic, 0, - ctx->class_proto[JS_CLASS_OBJECT]); - ctx->class_proto[JS_CLASS_BYTECODE_FUNCTION] = JS_DupValue(ctx, ctx->function_proto); - ctx->class_proto[JS_CLASS_ERROR] = JS_NewObject(ctx); -#if 0 - /* these are auto-initialized from js_error_proto_funcs, - but delaying might be a problem */ - JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ERROR], JS_ATOM_name, - JS_AtomToString(ctx, JS_ATOM_Error), - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ERROR], JS_ATOM_message, - JS_AtomToString(ctx, JS_ATOM_empty_string), - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); -#endif - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ERROR], - js_error_proto_funcs, - countof(js_error_proto_funcs)); - for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) { - proto = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ERROR]); - JS_DefinePropertyValue(ctx, proto, JS_ATOM_name, - JS_NewAtomString(ctx, native_error_name[i]), - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - JS_DefinePropertyValue(ctx, proto, JS_ATOM_message, - JS_AtomToString(ctx, JS_ATOM_empty_string), - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - ctx->native_error_proto[i] = proto; - } - /* the array prototype is an array */ - ctx->class_proto[JS_CLASS_ARRAY] = - JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], - JS_CLASS_ARRAY); - ctx->array_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_ARRAY]), - JS_PROP_INITIAL_HASH_SIZE, 1); - add_shape_property(ctx, &ctx->array_shape, NULL, - JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_LENGTH); - /* XXX: could test it on first context creation to ensure that no - new atoms are created in JS_AddIntrinsicBasicObjects(). It is - necessary to avoid useless renumbering of atoms after - JS_EvalBinary() if it is done just after - JS_AddIntrinsicBasicObjects(). */ - // assert(ctx->rt->atom_count == JS_ATOM_END); -} - -void JS_AddIntrinsicBaseObjects(JSContext *ctx) -{ - int i; - JSValue obj1; - JSValueConst obj, number_obj; - ctx->throw_type_error = JS_NewCFunction(ctx, js_throw_type_error, NULL, 0); - /* add caller and arguments properties to throw a TypeError */ - obj1 = JS_NewCFunction(ctx, js_function_proto_caller, NULL, 0); - JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_caller, JS_UNDEFINED, - obj1, ctx->throw_type_error, - JS_PROP_HAS_GET | JS_PROP_HAS_SET | - JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE); - JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_arguments, JS_UNDEFINED, - obj1, ctx->throw_type_error, - JS_PROP_HAS_GET | JS_PROP_HAS_SET | - JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE); - JS_FreeValue(ctx, obj1); - JS_FreeValue(ctx, js_object_seal(ctx, JS_UNDEFINED, 1, (JSValueConst *)&ctx->throw_type_error, 1)); - ctx->global_obj = JS_NewObject(ctx); - ctx->global_var_obj = JS_NewObjectProto(ctx, JS_NULL); - JS_AddIntrinsicObject(ctx); - /* Function */ - JS_SetPropertyFunctionList(ctx, ctx->function_proto, js_function_proto_funcs, countof(js_function_proto_funcs)); - ctx->function_ctor = JS_NewCFunctionMagic(ctx, js_function_constructor, - "Function", 1, JS_CFUNC_constructor_or_func_magic, - JS_FUNC_NORMAL); - JS_NewGlobalCConstructor2(ctx, JS_DupValue(ctx, ctx->function_ctor), "Function", - ctx->function_proto); - /* Error */ - obj1 = JS_NewCFunctionMagic(ctx, js_error_constructor, - "Error", 1, JS_CFUNC_constructor_or_func_magic, -1); - JS_NewGlobalCConstructor2(ctx, obj1, - "Error", ctx->class_proto[JS_CLASS_ERROR]); - for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) { - JSValue func_obj; - int n_args; - n_args = 1 + (i == JS_AGGREGATE_ERROR); - func_obj = JS_NewCFunction3(ctx, (JSCFunction *)js_error_constructor, - native_error_name[i], n_args, - JS_CFUNC_constructor_or_func_magic, i, obj1); - JS_NewGlobalCConstructor2(ctx, func_obj, native_error_name[i], - ctx->native_error_proto[i]); - } - JS_AddIteratorProto(ctx); - JS_AddIntrinsicArray(ctx); - /* XXX: create auto_initializer */ - { - /* initialize Array.prototype[Symbol.unscopables] */ - char const unscopables[] = "copyWithin" "\0" "entries" "\0" "fill" "\0" "find" "\0" - "findIndex" "\0" "flat" "\0" "flatMap" "\0" "includes" "\0" "keys" "\0" "values" "\0"; - const char *p = unscopables; - obj1 = JS_NewObjectProto(ctx, JS_NULL); - for(p = unscopables; *p; p += strlen(p) + 1) { - JS_DefinePropertyValueStr(ctx, obj1, p, JS_TRUE, JS_PROP_C_W_E); - } - JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ARRAY], - JS_ATOM_Symbol_unscopables, obj1, - JS_PROP_CONFIGURABLE); - } - /* needed to initialize arguments[Symbol.iterator] */ - JS_AddArrayIteratorProto(ctx); - /* parseFloat and parseInteger must be defined before Number - because of the Number.parseFloat and Number.parseInteger - aliases */ - JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_global_funcs, - countof(js_global_funcs)); - /* Number */ - ctx->class_proto[JS_CLASS_NUMBER] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], - JS_CLASS_NUMBER); - JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_NUMBER], JS_NewInt32(ctx, 0)); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_NUMBER], - js_number_proto_funcs, - countof(js_number_proto_funcs)); - number_obj = JS_NewGlobalCConstructor(ctx, "Number", js_number_constructor, 1, - ctx->class_proto[JS_CLASS_NUMBER]); - JS_SetPropertyFunctionList(ctx, number_obj, js_number_funcs, countof(js_number_funcs)); - /* Boolean */ - ctx->class_proto[JS_CLASS_BOOLEAN] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], - JS_CLASS_BOOLEAN); - JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], JS_NewBool(ctx, FALSE)); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], js_boolean_proto_funcs, - countof(js_boolean_proto_funcs)); - JS_NewGlobalCConstructor(ctx, "Boolean", js_boolean_constructor, 1, - ctx->class_proto[JS_CLASS_BOOLEAN]); - JS_AddIntrinsicString(ctx); - JS_AddIntrinsicMath(ctx); - /* ES6 Reflect: create as autoinit object */ - JS_AddIntrinsicReflect(ctx); - /* ES6 Symbol */ - ctx->class_proto[JS_CLASS_SYMBOL] = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_SYMBOL], js_symbol_proto_funcs, - countof(js_symbol_proto_funcs)); - obj = JS_NewGlobalCConstructor(ctx, "Symbol", js_symbol_constructor, 0, - ctx->class_proto[JS_CLASS_SYMBOL]); - JS_SetPropertyFunctionList(ctx, obj, js_symbol_funcs, - countof(js_symbol_funcs)); - for(i = JS_ATOM_Symbol_toPrimitive; i < JS_ATOM_END; i++) { - char buf[ATOM_GET_STR_BUF_SIZE]; - const char *str, *p; - str = JS_AtomGetStr(ctx, buf, sizeof(buf), i); - /* skip "Symbol." */ - p = strchr(str, '.'); - if (p) - str = p + 1; - JS_DefinePropertyValueStr(ctx, obj, str, JS_AtomToValue(ctx, i), 0); - } - /* ES6 Generator */ - JS_AddIntrinsicGenerator(ctx); - /* global properties */ - ctx->eval_obj = JS_NewCFunction(ctx, js_global_eval, "eval", 1); - JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_eval, - JS_DupValue(ctx, ctx->eval_obj), - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_globalThis, - JS_DupValue(ctx, ctx->global_obj), - JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE); -} diff --git a/third_party/quickjs/quickjs.h b/third_party/quickjs/quickjs.h deleted file mode 100644 index 91f51deef..000000000 --- a/third_party/quickjs/quickjs.h +++ /dev/null @@ -1,1012 +0,0 @@ -#ifndef COSMOPOLITAN_THIRD_PARTY_QUICKJS_QUICKJS_H_ -#define COSMOPOLITAN_THIRD_PARTY_QUICKJS_QUICKJS_H_ -#include "libc/intrin/likely.h" -#include "libc/math.h" -#include "libc/stdio/stdio.h" -COSMOPOLITAN_C_START_ - -#if (defined(__GNUC__) || defined(__clang__)) && !defined(__STRICT_ANSI__) -#define __js_printf_like(f, a) __attribute__((__format__(__printf__, f, a))) -#else -#define __js_printf_like(a, b) -#endif - -#define JS_BOOL int - -typedef struct JSRuntime JSRuntime; -typedef struct JSContext JSContext; -typedef struct JSObject JSObject; -typedef struct JSClass JSClass; -typedef uint32_t JSClassID; -typedef uint32_t JSAtom; - -#if INTPTR_MAX >= INT64_MAX -#define JS_PTR64 -#define JS_PTR64_DEF(a) a -#else -#define JS_PTR64_DEF(a) -#endif - -#ifndef JS_PTR64 -#define JS_NAN_BOXING -#endif - -enum { - /* all tags with a reference count are negative */ - JS_TAG_FIRST = -11, /* first negative tag */ - JS_TAG_BIG_DECIMAL = -11, - JS_TAG_BIG_INT = -10, - JS_TAG_BIG_FLOAT = -9, - JS_TAG_SYMBOL = -8, - JS_TAG_STRING = -7, - JS_TAG_MODULE = -3, /* used internally */ - JS_TAG_FUNCTION_BYTECODE = -2, /* used internally */ - JS_TAG_OBJECT = -1, - - JS_TAG_INT = 0, - JS_TAG_BOOL = 1, - JS_TAG_NULL = 2, - JS_TAG_UNDEFINED = 3, - JS_TAG_UNINITIALIZED = 4, - JS_TAG_CATCH_OFFSET = 5, - JS_TAG_EXCEPTION = 6, - JS_TAG_FLOAT64 = 7, - /* any larger tag is FLOAT64 if JS_NAN_BOXING */ -}; - -typedef struct JSRefCountHeader { - int ref_count; -} JSRefCountHeader; - -#define JS_FLOAT64_NAN NAN - -#ifdef CONFIG_CHECK_JSVALUE -/* JSValue consistency : it is not possible to run the code in this - mode, but it is useful to detect simple reference counting - errors. It would be interesting to modify a static C analyzer to - handle specific annotations (clang has such annotations but only - for objective C) */ -typedef struct __JSValue *JSValue; -typedef const struct __JSValue *JSValueConst; - -#define JS_VALUE_GET_TAG(v) (int)((uintptr_t)(v) & 0xf) -/* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ -#define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v) -#define JS_VALUE_GET_INT(v) (int)((intptr_t)(v) >> 4) -#define JS_VALUE_GET_BOOL(v) JS_VALUE_GET_INT(v) -#define JS_VALUE_GET_FLOAT64(v) (double)JS_VALUE_GET_INT(v) -#define JS_VALUE_GET_PTR(v) (void *)((intptr_t)(v) & ~0xf) - -#define JS_MKVAL(tag, val) (JSValue)(intptr_t)(((val) << 4) | (tag)) -#define JS_MKPTR(tag, p) (JSValue)((intptr_t)(p) | (tag)) - -#define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64) - -#define JS_NAN JS_MKVAL(JS_TAG_FLOAT64, 1) - -static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) -{ - return JS_MKVAL(JS_TAG_FLOAT64, (int)d); -} - -static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) -{ - return 0; -} - -#elif defined(JS_NAN_BOXING) - -typedef uint64_t JSValue; - -#define JSValueConst JSValue - -#define JS_VALUE_GET_TAG(v) (int)((v) >> 32) -#define JS_VALUE_GET_INT(v) (int)(v) -#define JS_VALUE_GET_BOOL(v) (int)(v) -#define JS_VALUE_GET_PTR(v) (void *)(intptr_t)(v) - -#define JS_MKVAL(tag, val) (((uint64_t)(tag) << 32) | (uint32_t)(val)) -#define JS_MKPTR(tag, ptr) (((uint64_t)(tag) << 32) | (uintptr_t)(ptr)) - -#define JS_FLOAT64_TAG_ADDEND (0x7ff80000 - JS_TAG_FIRST + 1) /* quiet NaN encoding */ - -static inline double JS_VALUE_GET_FLOAT64(JSValue v) -{ - union { - JSValue v; - double d; - } u; - u.v = v; - u.v += (uint64_t)JS_FLOAT64_TAG_ADDEND << 32; - return u.d; -} - -#define JS_NAN (0x7ff8000000000000 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32)) - -static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) -{ - union { - double d; - uint64_t u64; - } u; - JSValue v; - u.d = d; - /* normalize NaN */ - if (UNLIKELY((u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000)) - v = JS_NAN; - else - v = u.u64 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32); - return v; -} - -#define JS_TAG_IS_FLOAT64(tag) ((unsigned)((tag) - JS_TAG_FIRST) >= (JS_TAG_FLOAT64 - JS_TAG_FIRST)) - -/* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ -static inline int JS_VALUE_GET_NORM_TAG(JSValue v) -{ - uint32_t tag; - tag = JS_VALUE_GET_TAG(v); - if (JS_TAG_IS_FLOAT64(tag)) - return JS_TAG_FLOAT64; - else - return tag; -} - -static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) -{ - uint32_t tag; - tag = JS_VALUE_GET_TAG(v); - return tag == (JS_NAN >> 32); -} - -#else /* !JS_NAN_BOXING */ - -typedef union JSValueUnion { - int32_t int32; - double float64; - void *ptr; -} JSValueUnion; - -typedef struct JSValue { - JSValueUnion u; - int64_t tag; -} JSValue; - -#define JSValueConst JSValue - -#define JS_VALUE_GET_TAG(v) ((int32_t)(v).tag) -/* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ -#define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v) -#define JS_VALUE_GET_INT(v) ((v).u.int32) -#define JS_VALUE_GET_BOOL(v) ((v).u.int32) -#define JS_VALUE_GET_FLOAT64(v) ((v).u.float64) -#define JS_VALUE_GET_PTR(v) ((v).u.ptr) - -#define JS_MKVAL(tag, val) (JSValue){ (JSValueUnion){ .int32 = val }, tag } -#define JS_MKPTR(tag, p) (JSValue){ (JSValueUnion){ .ptr = p }, tag } - -#define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64) - -#define JS_NAN (JSValue){ .u.float64 = JS_FLOAT64_NAN, JS_TAG_FLOAT64 } - -static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) -{ - JSValue v; - v.tag = JS_TAG_FLOAT64; - v.u.float64 = d; - return v; -} - -static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) -{ - union { - double d; - uint64_t u64; - } u; - if (v.tag != JS_TAG_FLOAT64) - return 0; - u.d = v.u.float64; - return (u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000; -} - -#endif /* !JS_NAN_BOXING */ - -#define JS_VALUE_IS_BOTH_INT(v1, v2) ((JS_VALUE_GET_TAG(v1) | JS_VALUE_GET_TAG(v2)) == 0) -#define JS_VALUE_IS_BOTH_FLOAT(v1, v2) (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v1)) && JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v2))) - -#define JS_VALUE_GET_OBJ(v) ((JSObject *)JS_VALUE_GET_PTR(v)) -#define JS_VALUE_GET_STRING(v) ((JSString *)JS_VALUE_GET_PTR(v)) -#define JS_VALUE_HAS_REF_COUNT(v) ((unsigned)JS_VALUE_GET_TAG(v) >= (unsigned)JS_TAG_FIRST) - -/* special values */ -#define JS_NULL JS_MKVAL(JS_TAG_NULL, 0) -#define JS_UNDEFINED JS_MKVAL(JS_TAG_UNDEFINED, 0) -#define JS_FALSE JS_MKVAL(JS_TAG_BOOL, 0) -#define JS_TRUE JS_MKVAL(JS_TAG_BOOL, 1) -#define JS_EXCEPTION JS_MKVAL(JS_TAG_EXCEPTION, 0) -#define JS_UNINITIALIZED JS_MKVAL(JS_TAG_UNINITIALIZED, 0) - -/* flags for object properties */ -#define JS_PROP_CONFIGURABLE (1 << 0) -#define JS_PROP_WRITABLE (1 << 1) -#define JS_PROP_ENUMERABLE (1 << 2) -#define JS_PROP_C_W_E (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE | JS_PROP_ENUMERABLE) -#define JS_PROP_LENGTH (1 << 3) /* used internally in Arrays */ -#define JS_PROP_TMASK (3 << 4) /* mask for NORMAL, GETSET, VARREF, AUTOINIT */ -#define JS_PROP_NORMAL (0 << 4) -#define JS_PROP_GETSET (1 << 4) -#define JS_PROP_VARREF (2 << 4) /* used internally */ -#define JS_PROP_AUTOINIT (3 << 4) /* used internally */ - -/* flags for JS_DefineProperty */ -#define JS_PROP_HAS_SHIFT 8 -#define JS_PROP_HAS_CONFIGURABLE (1 << 8) -#define JS_PROP_HAS_WRITABLE (1 << 9) -#define JS_PROP_HAS_ENUMERABLE (1 << 10) -#define JS_PROP_HAS_GET (1 << 11) -#define JS_PROP_HAS_SET (1 << 12) -#define JS_PROP_HAS_VALUE (1 << 13) - -/* throw an exception if false would be returned - (JS_DefineProperty/JS_SetProperty) */ -#define JS_PROP_THROW (1 << 14) -/* throw an exception if false would be returned in strict mode - (JS_SetProperty) */ -#define JS_PROP_THROW_STRICT (1 << 15) - -#define JS_PROP_NO_ADD (1 << 16) /* internal use */ -#define JS_PROP_NO_EXOTIC (1 << 17) /* internal use */ - -#define JS_DEFAULT_STACK_SIZE (256 * 1024) - -/* JS_Eval() flags */ -#define JS_EVAL_TYPE_GLOBAL (0 << 0) /* global code (default) */ -#define JS_EVAL_TYPE_MODULE (1 << 0) /* module code */ -#define JS_EVAL_TYPE_DIRECT (2 << 0) /* direct call (internal use) */ -#define JS_EVAL_TYPE_INDIRECT (3 << 0) /* indirect call (internal use) */ -#define JS_EVAL_TYPE_MASK (3 << 0) - -#define JS_EVAL_FLAG_STRICT (1 << 3) /* force 'strict' mode */ -#define JS_EVAL_FLAG_STRIP (1 << 4) /* force 'strip' mode */ -/* compile but do not run. The result is an object with a - JS_TAG_FUNCTION_BYTECODE or JS_TAG_MODULE tag. It can be executed - with JS_EvalFunction(). */ -#define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5) -/* don't include the stack frames before this eval in the Error() backtraces */ -#define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6) - -typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); -typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); -typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data); - -typedef struct JSMallocState { - size_t malloc_count; - size_t malloc_size; - size_t malloc_limit; - void *opaque; /* user opaque */ -} JSMallocState; - -typedef struct JSMallocFunctions { - void *(*js_malloc)(JSMallocState *s, size_t size); - void (*js_free)(JSMallocState *s, void *ptr); - void *(*js_realloc)(JSMallocState *s, void *ptr, size_t size); - size_t (*js_malloc_usable_size)(const void *ptr); -} JSMallocFunctions; - -typedef struct JSGCObjectHeader JSGCObjectHeader; - -JSRuntime *JS_NewRuntime(void); -/* info lifetime must exceed that of rt */ -void JS_SetRuntimeInfo(JSRuntime *rt, const char *info); -void JS_SetMemoryLimit(JSRuntime *rt, size_t limit); -void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold); -/* use 0 to disable maximum stack size check */ -void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size); -/* should be called when changing thread to update the stack top value - used to check stack overflow. */ -void JS_UpdateStackTop(JSRuntime *rt); -JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque); -void JS_FreeRuntime(JSRuntime *rt); -void *JS_GetRuntimeOpaque(JSRuntime *rt); -void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque); -typedef void JS_MarkFunc(JSRuntime *rt, JSGCObjectHeader *gp); -void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); -void JS_RunGC(JSRuntime *rt); -JS_BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj); - -JSContext *JS_NewContext(JSRuntime *rt); -void JS_FreeContext(JSContext *s); -JSContext *JS_DupContext(JSContext *ctx); -void *JS_GetContextOpaque(JSContext *ctx); -void JS_SetContextOpaque(JSContext *ctx, void *opaque); -JSRuntime *JS_GetRuntime(JSContext *ctx); -void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj); -JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id); - -/* the following functions are used to select the intrinsic object to - save memory */ -JSContext *JS_NewContextRaw(JSRuntime *rt); -void JS_AddIntrinsicBaseObjects(JSContext *ctx); -void JS_AddIntrinsicDate(JSContext *ctx); -void JS_AddIntrinsicEval(JSContext *ctx); -void JS_AddIntrinsicStringNormalize(JSContext *ctx); -void JS_AddIntrinsicRegExpCompiler(JSContext *ctx); -void JS_AddIntrinsicRegExp(JSContext *ctx); -void JS_AddIntrinsicJSON(JSContext *ctx); -void JS_AddIntrinsicProxy(JSContext *ctx); -void JS_AddIntrinsicMapSet(JSContext *ctx); -void JS_AddIntrinsicTypedArrays(JSContext *ctx); -void JS_AddIntrinsicPromise(JSContext *ctx); -void JS_AddIntrinsicBigInt(JSContext *ctx); -void JS_AddIntrinsicBigFloat(JSContext *ctx); -void JS_AddIntrinsicBigDecimal(JSContext *ctx); -/* enable operator overloading */ -void JS_AddIntrinsicOperators(JSContext *ctx); -/* enable "use math" */ -void JS_EnableBignumExt(JSContext *ctx, JS_BOOL enable); - -JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv); - -void *js_malloc_rt(JSRuntime *rt, size_t size); -void js_free_rt(JSRuntime *rt, void *ptr); -void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size); -size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr); -void *js_mallocz_rt(JSRuntime *rt, size_t size); - -void *js_malloc(JSContext *ctx, size_t size); -void js_free(JSContext *ctx, void *ptr); -void *js_realloc(JSContext *ctx, void *ptr, size_t size); -size_t js_malloc_usable_size(JSContext *ctx, const void *ptr); -void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack); -void *js_mallocz(JSContext *ctx, size_t size); -char *js_strdup(JSContext *ctx, const char *str); -char *js_strndup(JSContext *ctx, const char *s, size_t n); - -typedef struct JSMemoryUsage { - int64_t malloc_size, malloc_limit, memory_used_size; - int64_t malloc_count; - int64_t memory_used_count; - int64_t atom_count, atom_size; - int64_t str_count, str_size; - int64_t obj_count, obj_size; - int64_t prop_count, prop_size; - int64_t shape_count, shape_size; - int64_t js_func_count, js_func_size, js_func_code_size; - int64_t js_func_pc2line_count, js_func_pc2line_size; - int64_t c_func_count, array_count; - int64_t fast_array_count, fast_array_elements; - int64_t binary_object_count, binary_object_size; -} JSMemoryUsage; - -void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s); -void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt); - -/* atom support */ -#define JS_ATOM_NULL 0 - -JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len); -JSAtom JS_NewAtom(JSContext *ctx, const char *str); -JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n); -JSAtom JS_DupAtom(JSContext *ctx, JSAtom v); -void JS_FreeAtom(JSContext *ctx, JSAtom v); -void JS_FreeAtomRT(JSRuntime *rt, JSAtom v); -JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom); -JSValue JS_AtomToString(JSContext *ctx, JSAtom atom); -const char *JS_AtomToCString(JSContext *ctx, JSAtom atom); -JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val); - -/* object class support */ - -typedef struct JSPropertyEnum { - JS_BOOL is_enumerable; - JSAtom atom; -} JSPropertyEnum; - -typedef struct JSPropertyDescriptor { - int flags; - JSValue value; - JSValue getter; - JSValue setter; -} JSPropertyDescriptor; - -typedef struct JSClassExoticMethods { - /* Return -1 if exception (can only happen in case of Proxy object), - FALSE if the property does not exists, TRUE if it exists. If 1 is - returned, the property descriptor 'desc' is filled if != NULL. */ - int (*get_own_property)(JSContext *ctx, JSPropertyDescriptor *desc, - JSValueConst obj, JSAtom prop); - /* '*ptab' should hold the '*plen' property keys. Return 0 if OK, - -1 if exception. The 'is_enumerable' field is ignored. - */ - int (*get_own_property_names)(JSContext *ctx, JSPropertyEnum **ptab, - uint32_t *plen, - JSValueConst obj); - /* return < 0 if exception, or TRUE/FALSE */ - int (*delete_property)(JSContext *ctx, JSValueConst obj, JSAtom prop); - /* return < 0 if exception or TRUE/FALSE */ - int (*define_own_property)(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValueConst val, - JSValueConst getter, JSValueConst setter, - int flags); - /* The following methods can be emulated with the previous ones, - so they are usually not needed */ - /* return < 0 if exception or TRUE/FALSE */ - int (*has_property)(JSContext *ctx, JSValueConst obj, JSAtom atom); - JSValue (*get_property)(JSContext *ctx, JSValueConst obj, JSAtom atom, - JSValueConst receiver); - /* return < 0 if exception or TRUE/FALSE */ - int (*set_property)(JSContext *ctx, JSValueConst obj, JSAtom atom, - JSValueConst value, JSValueConst receiver, int flags); -} JSClassExoticMethods; - -typedef void JSClassFinalizer(JSRuntime *rt, JSValue val); -typedef void JSClassGCMark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func); -#define JS_CALL_FLAG_CONSTRUCTOR (1 << 0) -typedef JSValue JSClassCall(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_val, int argc, JSValueConst *argv, - int flags); - -typedef struct JSClassDef { - const char *class_name; - JSClassFinalizer *finalizer; - JSClassGCMark *gc_mark; - /* if call != NULL, the object is a function. If (flags & - JS_CALL_FLAG_CONSTRUCTOR) != 0, the function is called as a - constructor. In this case, 'this_val' is new.target. A - constructor call only happens if the object constructor bit is - set (see JS_SetConstructorBit()). */ - JSClassCall *call; - /* XXX: suppress this indirection ? It is here only to save memory - because only a few classes need these methods */ - JSClassExoticMethods *exotic; -} JSClassDef; - -JSClassID JS_NewClassID(JSClassID *pclass_id); -int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def); -int JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id); - -/* value handling */ - -forceinline JSValue JS_NewBool(JSContext *ctx, JS_BOOL val) -{ - return JS_MKVAL(JS_TAG_BOOL, (val != 0)); -} - -forceinline JSValue JS_NewInt32(JSContext *ctx, int32_t val) -{ - return JS_MKVAL(JS_TAG_INT, val); -} - -forceinline JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val) -{ - return JS_MKVAL(JS_TAG_CATCH_OFFSET, val); -} - -forceinline JSValue JS_NewInt64(JSContext *ctx, int64_t val) -{ - JSValue v; - if (val == (int32_t)val) { - v = JS_NewInt32(ctx, val); - } else { - v = __JS_NewFloat64(ctx, val); - } - return v; -} - -forceinline JSValue JS_NewUint32(JSContext *ctx, uint32_t val) -{ - JSValue v; - if (val <= 0x7fffffff) { - v = JS_NewInt32(ctx, val); - } else { - v = __JS_NewFloat64(ctx, val); - } - return v; -} - -JSValue JS_NewBigInt64(JSContext *ctx, int64_t v); -JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v); - -forceinline JSValue JS_NewFloat64(JSContext *ctx, double d) -{ - JSValue v; - int32_t val; - union { - double d; - uint64_t u; - } u, t; - u.d = d; - val = (int32_t)d; - t.d = val; - /* -0 cannot be represented as integer, so we compare the bit - representation */ - if (u.u == t.u) { - v = JS_MKVAL(JS_TAG_INT, val); - } else { - v = __JS_NewFloat64(ctx, d); - } - return v; -} - -static inline JS_BOOL JS_IsNumber(JSValueConst v) -{ - int tag = JS_VALUE_GET_TAG(v); - return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag); -} - -static inline JS_BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v) -{ - int tag = JS_VALUE_GET_TAG(v); - return tag == JS_TAG_BIG_INT; -} - -static inline JS_BOOL JS_IsBigFloat(JSValueConst v) -{ - int tag = JS_VALUE_GET_TAG(v); - return tag == JS_TAG_BIG_FLOAT; -} - -static inline JS_BOOL JS_IsBigDecimal(JSValueConst v) -{ - int tag = JS_VALUE_GET_TAG(v); - return tag == JS_TAG_BIG_DECIMAL; -} - -static inline JS_BOOL JS_IsBool(JSValueConst v) -{ - return JS_VALUE_GET_TAG(v) == JS_TAG_BOOL; -} - -static inline JS_BOOL JS_IsNull(JSValueConst v) -{ - return JS_VALUE_GET_TAG(v) == JS_TAG_NULL; -} - -static inline JS_BOOL JS_IsUndefined(JSValueConst v) -{ - return JS_VALUE_GET_TAG(v) == JS_TAG_UNDEFINED; -} - -static inline JS_BOOL JS_IsException(JSValueConst v) -{ - return UNLIKELY(JS_VALUE_GET_TAG(v) == JS_TAG_EXCEPTION); -} - -static inline JS_BOOL JS_IsUninitialized(JSValueConst v) -{ - return UNLIKELY(JS_VALUE_GET_TAG(v) == JS_TAG_UNINITIALIZED); -} - -static inline JS_BOOL JS_IsString(JSValueConst v) -{ - return JS_VALUE_GET_TAG(v) == JS_TAG_STRING; -} - -static inline JS_BOOL JS_IsSymbol(JSValueConst v) -{ - return JS_VALUE_GET_TAG(v) == JS_TAG_SYMBOL; -} - -static inline JS_BOOL JS_IsObject(JSValueConst v) -{ - return JS_VALUE_GET_TAG(v) == JS_TAG_OBJECT; -} - -JSValue JS_Throw(JSContext *ctx, JSValue obj); -JSValue JS_GetException(JSContext *ctx); -JS_BOOL JS_IsError(JSContext *ctx, JSValueConst val); -void JS_ResetUncatchableError(JSContext *ctx); -JSValue JS_NewError(JSContext *ctx); -JSValue __js_printf_like(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...); -JSValue __js_printf_like(2, 3) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...); -JSValue __js_printf_like(2, 3) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...); -JSValue __js_printf_like(2, 3) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...); -JSValue __js_printf_like(2, 3) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...); -JSValue JS_ThrowOutOfMemory(JSContext *ctx); - -void __JS_FreeValue(JSContext *ctx, JSValue v); -static inline void JS_FreeValue(JSContext *ctx, JSValue v) -{ - if (JS_VALUE_HAS_REF_COUNT(v)) { - JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); - if (--p->ref_count <= 0) { - __JS_FreeValue(ctx, v); - } - } -} -void __JS_FreeValueRT(JSRuntime *rt, JSValue v); -static inline void JS_FreeValueRT(JSRuntime *rt, JSValue v) -{ - if (JS_VALUE_HAS_REF_COUNT(v)) { - JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); - if (--p->ref_count <= 0) { - __JS_FreeValueRT(rt, v); - } - } -} - -static inline JSValue JS_DupValue(JSContext *ctx, JSValueConst v) -{ - if (JS_VALUE_HAS_REF_COUNT(v)) { - JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); - p->ref_count++; - } - return (JSValue)v; -} - -static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v) -{ - if (JS_VALUE_HAS_REF_COUNT(v)) { - JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); - p->ref_count++; - } - return (JSValue)v; -} - -int JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION */ -int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val); -static inline int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val) -{ - return JS_ToInt32(ctx, (int32_t*)pres, val); -} -int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val); -int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val); -int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val); -/* return an exception if 'val' is a Number */ -int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val); -/* same as JS_ToInt64() but allow BigInt */ -int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val); - -JSValue JS_NewStringLen(JSContext *ctx, const char *str1, size_t len1); -JSValue JS_NewString(JSContext *ctx, const char *str); -JSValue JS_NewAtomString(JSContext *ctx, const char *str); -JSValue JS_ToString(JSContext *ctx, JSValueConst val); -JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val); -const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, JS_BOOL cesu8); -static inline const char *JS_ToCStringLen(JSContext *ctx, size_t *plen, JSValueConst val1) -{ - return JS_ToCStringLen2(ctx, plen, val1, 0); -} -static inline const char *JS_ToCString(JSContext *ctx, JSValueConst val1) -{ - return JS_ToCStringLen2(ctx, NULL, val1, 0); -} -void JS_FreeCString(JSContext *ctx, const char *ptr); - -JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto, JSClassID class_id); -JSValue JS_NewObjectClass(JSContext *ctx, int class_id); -JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto); -JSValue JS_NewObject(JSContext *ctx); - -JS_BOOL JS_IsFunction(JSContext* ctx, JSValueConst val); -JS_BOOL JS_IsConstructor(JSContext* ctx, JSValueConst val); -JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, JS_BOOL val); -JS_BOOL JS_IsArrayBuffer(JSContext *ctx, JSValueConst val); - -JSValue JS_NewArray(JSContext *ctx); -int JS_IsArray(JSContext *ctx, JSValueConst val); - -JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, - JSAtom prop, JSValueConst receiver, - JS_BOOL throw_ref_error); -forceinline JSValue JS_GetProperty(JSContext *ctx, JSValueConst this_obj, - JSAtom prop) -{ - return JS_GetPropertyInternal(ctx, this_obj, prop, this_obj, 0); -} -JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj, - const char *prop); -JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj, - uint32_t idx); - -int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValue val, - int flags); -static inline int JS_SetProperty(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValue val) -{ - return JS_SetPropertyInternal(ctx, this_obj, prop, val, JS_PROP_THROW); -} -int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj, - uint32_t idx, JSValue val); -int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj, - int64_t idx, JSValue val); -int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj, - const char *prop, JSValue val); -int JS_HasProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop); -int JS_IsExtensible(JSContext *ctx, JSValueConst obj); -int JS_PreventExtensions(JSContext *ctx, JSValueConst obj); -int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags); -int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val); -JSValue JS_GetPrototype(JSContext *ctx, JSValueConst val); - -#define JS_GPN_STRING_MASK (1 << 0) -#define JS_GPN_SYMBOL_MASK (1 << 1) -#define JS_GPN_PRIVATE_MASK (1 << 2) -/* only include the enumerable properties */ -#define JS_GPN_ENUM_ONLY (1 << 4) -/* set theJSPropertyEnum.is_enumerable field */ -#define JS_GPN_SET_ENUM (1 << 5) - -int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, - uint32_t *plen, JSValueConst obj, int flags); -int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc, - JSValueConst obj, JSAtom prop); - -JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, - int argc, JSValueConst *argv); -JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom, - int argc, JSValueConst *argv); -JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj, - int argc, JSValueConst *argv); -JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj, - JSValueConst new_target, - int argc, JSValueConst *argv); -JS_BOOL JS_DetectModule(const char *input, size_t input_len); -/* 'input' must be zero terminated i.e. input[input_len] = '\0'. */ -JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len, - const char *filename, int eval_flags); -/* same as JS_Eval() but with an explicit 'this_obj' parameter */ -JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj, - const char *input, size_t input_len, - const char *filename, int eval_flags); -JSValue JS_GetGlobalObject(JSContext *ctx); -int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj); -int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValueConst val, - JSValueConst getter, JSValueConst setter, int flags); -int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValue val, int flags); -int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj, - uint32_t idx, JSValue val, int flags); -int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj, - const char *prop, JSValue val, int flags); -int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValue getter, JSValue setter, - int flags); -void JS_SetOpaque(JSValue obj, void *opaque); -void *JS_GetOpaque(JSValueConst obj, JSClassID class_id); -void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id); - -/* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */ -JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, - const char *filename); -#define JS_PARSE_JSON_EXT (1 << 0) /* allow extended JSON */ -JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len, - const char *filename, int flags); -JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj, - JSValueConst replacer, JSValueConst space0); - -typedef void JSFreeArrayBufferDataFunc(JSRuntime *rt, void *opaque, void *ptr); -JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len, - JSFreeArrayBufferDataFunc *free_func, void *opaque, - JS_BOOL is_shared); -JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len); -void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj); -uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj); -JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj, - size_t *pbyte_offset, - size_t *pbyte_length, - size_t *pbytes_per_element); -typedef struct { - void *(*sab_alloc)(void *opaque, size_t size); - void (*sab_free)(void *opaque, void *ptr); - void (*sab_dup)(void *opaque, void *ptr); - void *sab_opaque; -} JSSharedArrayBufferFunctions; -void JS_SetSharedArrayBufferFunctions(JSRuntime *rt, - const JSSharedArrayBufferFunctions *sf); - -JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs); - -/* is_handled = TRUE means that the rejection is handled */ -typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise, - JSValueConst reason, - JS_BOOL is_handled, void *opaque); -void JS_SetHostPromiseRejectionTracker(JSRuntime *rt, JSHostPromiseRejectionTracker *cb, void *opaque); - -/* return != 0 if the JS code needs to be interrupted */ -typedef int JSInterruptHandler(JSRuntime *rt, void *opaque); -void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque); -/* if can_block is TRUE, Atomics.wait() can be used */ -void JS_SetCanBlock(JSRuntime *rt, JS_BOOL can_block); -/* set the [IsHTMLDDA] internal slot */ -void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj); - -typedef struct JSModuleDef JSModuleDef; - -/* return the module specifier (allocated with js_malloc()) or NULL if - exception */ -typedef char *JSModuleNormalizeFunc(JSContext *ctx, - const char *module_base_name, - const char *module_name, void *opaque); -typedef JSModuleDef *JSModuleLoaderFunc(JSContext *ctx, - const char *module_name, void *opaque); - -/* module_normalize = NULL is allowed and invokes the default module - filename normalizer */ -void JS_SetModuleLoaderFunc(JSRuntime *rt, - JSModuleNormalizeFunc *module_normalize, - JSModuleLoaderFunc *module_loader, void *opaque); -/* return the import.meta object of a module */ -JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m); -JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m); - -/* JS Job support */ - -typedef JSValue JSJobFunc(JSContext *ctx, int argc, JSValueConst *argv); -int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, int argc, JSValueConst *argv); - -JS_BOOL JS_IsJobPending(JSRuntime *rt); -int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx); - -/* Object Writer/Reader (currently only used to handle precompiled code) */ -#define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */ -#define JS_WRITE_OBJ_BSWAP (1 << 1) /* byte swapped output */ -#define JS_WRITE_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */ -#define JS_WRITE_OBJ_REFERENCE (1 << 3) /* allow object references to - encode arbitrary object - graph */ -uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj, - int flags); -uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj, - int flags, uint8_t ***psab_tab, size_t *psab_tab_len); - -#define JS_READ_OBJ_BYTECODE (1 << 0) /* allow function/module */ -#define JS_READ_OBJ_ROM_DATA (1 << 1) /* avoid duplicating 'buf' data */ -#define JS_READ_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */ -#define JS_READ_OBJ_REFERENCE (1 << 3) /* allow object references */ -JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, - int flags); -/* instantiate and evaluate a bytecode function. Only used when - reading a script or module with JS_ReadObject() */ -JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj); -/* load the dependencies of the module 'obj'. Useful when JS_ReadObject() - returns a module. */ -int JS_ResolveModule(JSContext *ctx, JSValueConst obj); - -/* only exported for os.Worker() */ -JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels); -/* only exported for os.Worker() */ -JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename, - const char *filename); - -/* C function definition */ -typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */ - JS_CFUNC_generic, - JS_CFUNC_generic_magic, - JS_CFUNC_constructor, - JS_CFUNC_constructor_magic, - JS_CFUNC_constructor_or_func, - JS_CFUNC_constructor_or_func_magic, - JS_CFUNC_f_f, - JS_CFUNC_f_f_f, - JS_CFUNC_getter, - JS_CFUNC_setter, - JS_CFUNC_getter_magic, - JS_CFUNC_setter_magic, - JS_CFUNC_iterator_next, -} JSCFunctionEnum; - -typedef union JSCFunctionType { - JSCFunction *generic; - JSValue (*generic_magic)(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); - JSCFunction *constructor; - JSValue (*constructor_magic)(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv, int magic); - JSCFunction *constructor_or_func; - double (*f_f)(double); - double (*f_f_f)(double, double); - JSValue (*getter)(JSContext *ctx, JSValueConst this_val); - JSValue (*setter)(JSContext *ctx, JSValueConst this_val, JSValueConst val); - JSValue (*getter_magic)(JSContext *ctx, JSValueConst this_val, int magic); - JSValue (*setter_magic)(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic); - JSValue (*iterator_next)(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int *pdone, int magic); -} JSCFunctionType; - -JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func, - const char *name, - int length, JSCFunctionEnum cproto, int magic); -JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, - int length, int magic, int data_len, - JSValueConst *data); - -static inline JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func, const char *name, - int length) -{ - return JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_generic, 0); -} - -static inline JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *func, - const char *name, - int length, JSCFunctionEnum cproto, int magic) -{ - return JS_NewCFunction2(ctx, (JSCFunction *)func, name, length, cproto, magic); -} -void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, - JSValueConst proto); - -/* C property definition */ - -typedef struct JSCFunctionListEntry { - const char *name; - uint8_t prop_flags; - uint8_t def_type; - int16_t magic; - union { - struct { - uint8_t length; /* XXX: should move outside union */ - uint8_t cproto; /* XXX: should move outside union */ - JSCFunctionType cfunc; - } func; - struct { - JSCFunctionType get; - JSCFunctionType set; - } getset; - struct { - const char *name; - int base; - } alias; - struct { - const struct JSCFunctionListEntry *tab; - int len; - } prop_list; - const char *str; - int32_t i32; - int64_t i64; - double f64; - } u; -} JSCFunctionListEntry; - -#define JS_DEF_CFUNC 0 -#define JS_DEF_CGETSET 1 -#define JS_DEF_CGETSET_MAGIC 2 -#define JS_DEF_PROP_STRING 3 -#define JS_DEF_PROP_INT32 4 -#define JS_DEF_PROP_INT64 5 -#define JS_DEF_PROP_DOUBLE 6 -#define JS_DEF_PROP_UNDEFINED 7 -#define JS_DEF_OBJECT 8 -#define JS_DEF_ALIAS 9 - -/* Note: c++ does not like nested designators */ -#define JS_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } } -#define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } } } -#define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_ ## cproto, { .cproto = func1 } } } } -#define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } } } -#define JS_CGETSET_DEF(name, fgetter, fsetter) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET, 0, .u = { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } } -#define JS_CGETSET_MAGIC_DEF(name, fgetter, fsetter, magic) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET_MAGIC, magic, .u = { .getset = { .get = { .getter_magic = fgetter }, .set = { .setter_magic = fsetter } } } } -#define JS_PROP_STRING_DEF(name, cstr, prop_flags) { name, prop_flags, JS_DEF_PROP_STRING, 0, .u = { .str = cstr } } -#define JS_PROP_INT32_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT32, 0, .u = { .i32 = val } } -#define JS_PROP_INT64_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT64, 0, .u = { .i64 = val } } -#define JS_PROP_DOUBLE_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, .u = { .f64 = val } } -#define JS_PROP_UNDEFINED_DEF(name, prop_flags) { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, .u = { .i32 = 0 } } -#define JS_OBJECT_DEF(name, tab, len, prop_flags) { name, prop_flags, JS_DEF_OBJECT, 0, .u = { .prop_list = { tab, len } } } -#define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, -1 } } } -#define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, base } } } - -void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj, - const JSCFunctionListEntry *tab, - int len); - -/* C module definition */ - -typedef int JSModuleInitFunc(JSContext *ctx, JSModuleDef *m); - -JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str, - JSModuleInitFunc *func); -/* can only be called before the module is instantiated */ -int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *name_str); -int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m, - const JSCFunctionListEntry *tab, int len); -/* can only be called after the module is instantiated */ -int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name, - JSValue val); -int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m, - const JSCFunctionListEntry *tab, int len); - -/* clang-format on */ -COSMOPOLITAN_C_END_ -#endif /* COSMOPOLITAN_THIRD_PARTY_QUICKJS_QUICKJS_H_ */ diff --git a/third_party/quickjs/readme.txt b/third_party/quickjs/readme.txt deleted file mode 100644 index 789521d53..000000000 --- a/third_party/quickjs/readme.txt +++ /dev/null @@ -1 +0,0 @@ -The main documentation is in doc/quickjs.pdf or doc/quickjs.html. diff --git a/third_party/quickjs/reflect.c b/third_party/quickjs/reflect.c deleted file mode 100644 index bca54c9c9..000000000 --- a/third_party/quickjs/reflect.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "third_party/quickjs/internal.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -static JSValue js_reflect_apply(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return js_function_apply(ctx, argv[0], max_int(0, argc - 1), argv + 1, 2); -} - -static JSValue js_reflect_construct(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst func, array_arg, new_target; - JSValue *tab, ret; - uint32_t len; - func = argv[0]; - array_arg = argv[1]; - if (argc > 2) { - new_target = argv[2]; - if (!JS_IsConstructor(ctx, new_target)) - return JS_ThrowTypeError(ctx, "not a constructor"); - } else { - new_target = func; - } - tab = build_arg_list(ctx, &len, array_arg); - if (!tab) - return JS_EXCEPTION; - ret = JS_CallConstructor2(ctx, func, new_target, len, (JSValueConst *)tab); - free_arg_list(ctx, tab, len); - return ret; -} - -static JSValue js_reflect_deleteProperty(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst obj; - JSAtom atom; - int ret; - obj = argv[0]; - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - return JS_ThrowTypeErrorNotAnObject(ctx); - atom = JS_ValueToAtom(ctx, argv[1]); - if (UNLIKELY(atom == JS_ATOM_NULL)) - return JS_EXCEPTION; - ret = JS_DeleteProperty(ctx, obj, atom, 0); - JS_FreeAtom(ctx, atom); - if (ret < 0) - return JS_EXCEPTION; - else - return JS_NewBool(ctx, ret); -} - -static JSValue js_reflect_get(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst obj, prop, receiver; - JSAtom atom; - JSValue ret; - obj = argv[0]; - prop = argv[1]; - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - return JS_ThrowTypeErrorNotAnObject(ctx); - if (argc > 2) - receiver = argv[2]; - else - receiver = obj; - atom = JS_ValueToAtom(ctx, prop); - if (UNLIKELY(atom == JS_ATOM_NULL)) - return JS_EXCEPTION; - ret = JS_GetPropertyInternal(ctx, obj, atom, receiver, FALSE); - JS_FreeAtom(ctx, atom); - return ret; -} - -static JSValue js_reflect_has(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst obj, prop; - JSAtom atom; - int ret; - obj = argv[0]; - prop = argv[1]; - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - return JS_ThrowTypeErrorNotAnObject(ctx); - atom = JS_ValueToAtom(ctx, prop); - if (UNLIKELY(atom == JS_ATOM_NULL)) - return JS_EXCEPTION; - ret = JS_HasProperty(ctx, obj, atom); - JS_FreeAtom(ctx, atom); - if (ret < 0) - return JS_EXCEPTION; - else - return JS_NewBool(ctx, ret); -} - -static JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst obj, prop, val, receiver; - int ret; - JSAtom atom; - obj = argv[0]; - prop = argv[1]; - val = argv[2]; - if (argc > 3) - receiver = argv[3]; - else - receiver = obj; - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - return JS_ThrowTypeErrorNotAnObject(ctx); - atom = JS_ValueToAtom(ctx, prop); - if (UNLIKELY(atom == JS_ATOM_NULL)) - return JS_EXCEPTION; - ret = JS_SetPropertyGeneric(ctx, obj, atom, - JS_DupValue(ctx, val), receiver, 0); - JS_FreeAtom(ctx, atom); - if (ret < 0) - return JS_EXCEPTION; - else - return JS_NewBool(ctx, ret); -} - -static JSValue js_reflect_setPrototypeOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int ret; - ret = JS_SetPrototypeInternal(ctx, argv[0], argv[1], FALSE); - if (ret < 0) - return JS_EXCEPTION; - else - return JS_NewBool(ctx, ret); -} - -static JSValue js_reflect_ownKeys(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT) - return JS_ThrowTypeErrorNotAnObject(ctx); - return JS_GetOwnPropertyNames2(ctx, argv[0], - JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK, - JS_ITERATOR_KIND_KEY); -} - -static const JSCFunctionListEntry js_reflect_funcs[] = { - JS_CFUNC_DEF("apply", 3, js_reflect_apply ), - JS_CFUNC_DEF("construct", 2, js_reflect_construct ), - JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 1 ), - JS_CFUNC_DEF("deleteProperty", 2, js_reflect_deleteProperty ), - JS_CFUNC_DEF("get", 2, js_reflect_get ), - JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 1 ), - JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 1 ), - JS_CFUNC_DEF("has", 2, js_reflect_has ), - JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 1 ), - JS_CFUNC_DEF("ownKeys", 1, js_reflect_ownKeys ), - JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 1 ), - JS_CFUNC_DEF("set", 3, js_reflect_set ), - JS_CFUNC_DEF("setPrototypeOf", 2, js_reflect_setPrototypeOf ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Reflect", JS_PROP_CONFIGURABLE ), -}; - -static const JSCFunctionListEntry js_reflect_obj[] = { - JS_OBJECT_DEF("Reflect", js_reflect_funcs, countof(js_reflect_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ), -}; - -void JS_AddIntrinsicReflect(JSContext *ctx) { - JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_reflect_obj, countof(js_reflect_obj)); -} diff --git a/third_party/quickjs/regexp.c b/third_party/quickjs/regexp.c deleted file mode 100644 index 0862de38a..000000000 --- a/third_party/quickjs/regexp.c +++ /dev/null @@ -1,1409 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/str/str.h" -#include "third_party/quickjs/internal.h" -#include "third_party/quickjs/libregexp.h" -#include "third_party/quickjs/quickjs.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -void js_regexp_finalizer(JSRuntime *rt, JSValue val) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JSRegExp *re = &p->u.regexp; - JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->bytecode)); - JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->pattern)); -} - -/* create a string containing the RegExp bytecode */ -JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern, - JSValueConst flags) -{ - const char *str; - int re_flags, mask; - uint8_t *re_bytecode_buf; - size_t i, len; - int re_bytecode_len; - JSValue ret; - char error_msg[64]; - re_flags = 0; - if (!JS_IsUndefined(flags)) { - str = JS_ToCStringLen(ctx, &len, flags); - if (!str) - return JS_EXCEPTION; - /* XXX: re_flags = LRE_FLAG_OCTAL unless strict mode? */ - for (i = 0; i < len; i++) { - switch(str[i]) { - case 'g': - mask = LRE_FLAG_GLOBAL; - break; - case 'i': - mask = LRE_FLAG_IGNORECASE; - break; - case 'm': - mask = LRE_FLAG_MULTILINE; - break; - case 's': - mask = LRE_FLAG_DOTALL; - break; - case 'u': - mask = LRE_FLAG_UTF16; - break; - case 'y': - mask = LRE_FLAG_STICKY; - break; - default: - goto bad_flags; - } - if ((re_flags & mask) != 0) { - bad_flags: - JS_FreeCString(ctx, str); - return JS_ThrowSyntaxError(ctx, "invalid regular expression flags"); - } - re_flags |= mask; - } - JS_FreeCString(ctx, str); - } - str = JS_ToCStringLen2(ctx, &len, pattern, !(re_flags & LRE_FLAG_UTF16)); - if (!str) - return JS_EXCEPTION; - re_bytecode_buf = lre_compile(&re_bytecode_len, error_msg, - sizeof(error_msg), str, len, re_flags, ctx); - JS_FreeCString(ctx, str); - if (!re_bytecode_buf) { - JS_ThrowSyntaxError(ctx, "%s", error_msg); - return JS_EXCEPTION; - } - ret = js_new_string8(ctx, re_bytecode_buf, re_bytecode_len); - js_free(ctx, re_bytecode_buf); - return ret; -} - -/* create a RegExp object from a string containing the RegExp bytecode - and the source pattern */ -JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor, - JSValue pattern, JSValue bc) -{ - JSValue obj; - JSObject *p; - JSRegExp *re; - /* sanity check */ - if (JS_VALUE_GET_TAG(bc) != JS_TAG_STRING || - JS_VALUE_GET_TAG(pattern) != JS_TAG_STRING) { - JS_ThrowTypeError(ctx, "string expected"); - fail: - JS_FreeValue(ctx, bc); - JS_FreeValue(ctx, pattern); - return JS_EXCEPTION; - } - obj = js_create_from_ctor(ctx, ctor, JS_CLASS_REGEXP); - if (JS_IsException(obj)) - goto fail; - p = JS_VALUE_GET_OBJ(obj); - re = &p->u.regexp; - re->pattern = JS_VALUE_GET_STRING(pattern); - re->bytecode = JS_VALUE_GET_STRING(bc); - JS_DefinePropertyValue(ctx, obj, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0), - JS_PROP_WRITABLE); - return obj; -} - -JSRegExp *js_get_regexp(JSContext *ctx, JSValueConst obj, BOOL throw_error) -{ - if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(obj); - if (p->class_id == JS_CLASS_REGEXP) - return &p->u.regexp; - } - if (throw_error) { - JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP); - } - return NULL; -} - -/* return < 0 if exception or TRUE/FALSE */ -int js_is_regexp(JSContext *ctx, JSValueConst obj) -{ - JSValue m; - - if (!JS_IsObject(obj)) - return FALSE; - m = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_match); - if (JS_IsException(m)) - return -1; - if (!JS_IsUndefined(m)) - return JS_ToBoolFree(ctx, m); - return js_get_regexp(ctx, obj, FALSE) != NULL; -} - -JSValue js_regexp_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) -{ - JSValue pattern, flags, bc, val; - JSValueConst pat, flags1; - JSRegExp *re; - int pat_is_regexp; - pat = argv[0]; - flags1 = argv[1]; - pat_is_regexp = js_is_regexp(ctx, pat); - if (pat_is_regexp < 0) - return JS_EXCEPTION; - if (JS_IsUndefined(new_target)) { - /* called as a function */ - new_target = JS_GetActiveFunction(ctx); - if (pat_is_regexp && JS_IsUndefined(flags1)) { - JSValue ctor; - BOOL res; - ctor = JS_GetProperty(ctx, pat, JS_ATOM_constructor); - if (JS_IsException(ctor)) - return ctor; - res = js_same_value(ctx, ctor, new_target); - JS_FreeValue(ctx, ctor); - if (res) - return JS_DupValue(ctx, pat); - } - } - re = js_get_regexp(ctx, pat, FALSE); - if (re) { - pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern)); - if (JS_IsUndefined(flags1)) { - bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode)); - goto no_compilation; - } else { - flags = JS_ToString(ctx, flags1); - if (JS_IsException(flags)) - goto fail; - } - } else { - flags = JS_UNDEFINED; - if (pat_is_regexp) { - pattern = JS_GetProperty(ctx, pat, JS_ATOM_source); - if (JS_IsException(pattern)) - goto fail; - if (JS_IsUndefined(flags1)) { - flags = JS_GetProperty(ctx, pat, JS_ATOM_flags); - if (JS_IsException(flags)) - goto fail; - } else { - flags = JS_DupValue(ctx, flags1); - } - } else { - pattern = JS_DupValue(ctx, pat); - flags = JS_DupValue(ctx, flags1); - } - if (JS_IsUndefined(pattern)) { - pattern = JS_AtomToString(ctx, JS_ATOM_empty_string); - } else { - val = pattern; - pattern = JS_ToString(ctx, val); - JS_FreeValue(ctx, val); - if (JS_IsException(pattern)) - goto fail; - } - } - bc = js_compile_regexp(ctx, pattern, flags); - if (JS_IsException(bc)) - goto fail; - JS_FreeValue(ctx, flags); - no_compilation: - return js_regexp_constructor_internal(ctx, new_target, pattern, bc); - fail: - JS_FreeValue(ctx, pattern); - JS_FreeValue(ctx, flags); - return JS_EXCEPTION; -} - -JSValue js_regexp_compile(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSRegExp *re1, *re; - JSValueConst pattern1, flags1; - JSValue bc, pattern; - re = js_get_regexp(ctx, this_val, TRUE); - if (!re) - return JS_EXCEPTION; - pattern1 = argv[0]; - flags1 = argv[1]; - re1 = js_get_regexp(ctx, pattern1, FALSE); - if (re1) { - if (!JS_IsUndefined(flags1)) - return JS_ThrowTypeError(ctx, "flags must be undefined"); - pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->pattern)); - bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->bytecode)); - } else { - bc = JS_UNDEFINED; - if (JS_IsUndefined(pattern1)) - pattern = JS_AtomToString(ctx, JS_ATOM_empty_string); - else - pattern = JS_ToString(ctx, pattern1); - if (JS_IsException(pattern)) - goto fail; - bc = js_compile_regexp(ctx, pattern, flags1); - if (JS_IsException(bc)) - goto fail; - } - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern)); - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode)); - re->pattern = JS_VALUE_GET_STRING(pattern); - re->bytecode = JS_VALUE_GET_STRING(bc); - if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex, - JS_NewInt32(ctx, 0)) < 0) - return JS_EXCEPTION; - return JS_DupValue(ctx, this_val); - fail: - JS_FreeValue(ctx, pattern); - JS_FreeValue(ctx, bc); - return JS_EXCEPTION; -} - -#if 0 -static JSValue js_regexp_get___source(JSContext *ctx, JSValueConst this_val) -{ - JSRegExp *re = js_get_regexp(ctx, this_val, TRUE); - if (!re) - return JS_EXCEPTION; - return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern)); -} -static JSValue js_regexp_get___flags(JSContext *ctx, JSValueConst this_val) -{ - JSRegExp *re = js_get_regexp(ctx, this_val, TRUE); - int flags; - if (!re) - return JS_EXCEPTION; - flags = lre_get_flags(re->bytecode->u.str8); - return JS_NewInt32(ctx, flags); -} -#endif - -JSValue js_regexp_get_source(JSContext *ctx, JSValueConst this_val) -{ - JSRegExp *re; - JSString *p; - StringBuffer b_s, *b = &b_s; - int i, n, c, c2, bra; - if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT) - return JS_ThrowTypeErrorNotAnObject(ctx); - if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP])) - goto empty_regex; - re = js_get_regexp(ctx, this_val, TRUE); - if (!re) - return JS_EXCEPTION; - p = re->pattern; - if (p->len == 0) { - empty_regex: - return JS_NewString(ctx, "(?:)"); - } - string_buffer_init2(ctx, b, p->len, p->is_wide_char); - /* Escape '/' and newline sequences as needed */ - bra = 0; - for (i = 0, n = p->len; i < n;) { - c2 = -1; - switch (c = string_get(p, i++)) { - case '\\': - if (i < n) - c2 = string_get(p, i++); - break; - case ']': - bra = 0; - break; - case '[': - if (!bra) { - if (i < n && string_get(p, i) == ']') - c2 = string_get(p, i++); - bra = 1; - } - break; - case '\n': - c = '\\'; - c2 = 'n'; - break; - case '\r': - c = '\\'; - c2 = 'r'; - break; - case '/': - if (!bra) { - c = '\\'; - c2 = '/'; - } - break; - } - string_buffer_putc16(b, c); - if (c2 >= 0) - string_buffer_putc16(b, c2); - } - return string_buffer_end(b); -} - -JSValue js_regexp_get_flag(JSContext *ctx, JSValueConst this_val, int mask) -{ - JSRegExp *re; - int flags; - if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT) - return JS_ThrowTypeErrorNotAnObject(ctx); - re = js_get_regexp(ctx, this_val, FALSE); - if (!re) { - if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP])) - return JS_UNDEFINED; - else - return JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP); - } - flags = lre_get_flags(re->bytecode->u.str8); - return JS_NewBool(ctx, (flags & mask) != 0); -} - -JSValue js_regexp_get_flags(JSContext *ctx, JSValueConst this_val) -{ - char str[8], *p = str; - int res; - if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT) - return JS_ThrowTypeErrorNotAnObject(ctx); - res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, JS_ATOM_global)); - if (res < 0) - goto exception; - if (res) - *p++ = 'g'; - res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "ignoreCase")); - if (res < 0) - goto exception; - if (res) - *p++ = 'i'; - res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "multiline")); - if (res < 0) - goto exception; - if (res) - *p++ = 'm'; - res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "dotAll")); - if (res < 0) - goto exception; - if (res) - *p++ = 's'; - res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, JS_ATOM_unicode)); - if (res < 0) - goto exception; - if (res) - *p++ = 'u'; - res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "sticky")); - if (res < 0) - goto exception; - if (res) - *p++ = 'y'; - return JS_NewStringLen(ctx, str, p - str); -exception: - return JS_EXCEPTION; -} - -JSValue js_regexp_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue pattern, flags; - StringBuffer b_s, *b = &b_s; - if (!JS_IsObject(this_val)) - return JS_ThrowTypeErrorNotAnObject(ctx); - string_buffer_init(ctx, b, 0); - string_buffer_putc8(b, '/'); - pattern = JS_GetProperty(ctx, this_val, JS_ATOM_source); - if (string_buffer_concat_value_free(b, pattern)) - goto fail; - string_buffer_putc8(b, '/'); - flags = JS_GetProperty(ctx, this_val, JS_ATOM_flags); - if (string_buffer_concat_value_free(b, flags)) - goto fail; - return string_buffer_end(b); -fail: - string_buffer_free(b); - return JS_EXCEPTION; -} - -void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data; - if (it) { - JS_FreeValueRT(rt, it->iterating_regexp); - JS_FreeValueRT(rt, it->iterated_string); - js_free_rt(rt, it); - } -} - -void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data; - if (it) { - JS_MarkValue(rt, it->iterating_regexp, mark_func); - JS_MarkValue(rt, it->iterated_string, mark_func); - } -} - -JSValue js_regexp_string_iterator_next(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, - BOOL *pdone, int magic) -{ - JSRegExpStringIteratorData *it; - JSValueConst R, S; - JSValue matchStr = JS_UNDEFINED, match = JS_UNDEFINED; - JSString *sp; - it = JS_GetOpaque2(ctx, this_val, JS_CLASS_REGEXP_STRING_ITERATOR); - if (!it) - goto exception; - if (it->done) { - *pdone = TRUE; - return JS_UNDEFINED; - } - R = it->iterating_regexp; - S = it->iterated_string; - match = JS_RegExpExec(ctx, R, S); - if (JS_IsException(match)) - goto exception; - if (JS_IsNull(match)) { - it->done = TRUE; - *pdone = TRUE; - return JS_UNDEFINED; - } else if (it->global) { - matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, match, 0)); - if (JS_IsException(matchStr)) - goto exception; - if (JS_IsEmptyString(matchStr)) { - int64_t thisIndex, nextIndex; - if (JS_ToLengthFree(ctx, &thisIndex, - JS_GetProperty(ctx, R, JS_ATOM_lastIndex)) < 0) - goto exception; - sp = JS_VALUE_GET_STRING(S); - nextIndex = string_advance_index(sp, thisIndex, it->unicode); - if (JS_SetProperty(ctx, R, JS_ATOM_lastIndex, - JS_NewInt64(ctx, nextIndex)) < 0) - goto exception; - } - JS_FreeValue(ctx, matchStr); - } else { - it->done = TRUE; - } - *pdone = FALSE; - return match; - exception: - JS_FreeValue(ctx, match); - JS_FreeValue(ctx, matchStr); - *pdone = FALSE; - return JS_EXCEPTION; -} - -JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // [Symbol.matchAll](str) - JSValueConst R = this_val; - JSValue S, C, flags, matcher, iter; - JSValueConst args[2]; - JSString *strp; - int64_t lastIndex; - JSRegExpStringIteratorData *it; - if (!JS_IsObject(R)) - return JS_ThrowTypeErrorNotAnObject(ctx); - C = JS_UNDEFINED; - flags = JS_UNDEFINED; - matcher = JS_UNDEFINED; - iter = JS_UNDEFINED; - S = JS_ToString(ctx, argv[0]); - if (JS_IsException(S)) - goto exception; - C = JS_SpeciesConstructor(ctx, R, ctx->regexp_ctor); - if (JS_IsException(C)) - goto exception; - flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, R, JS_ATOM_flags)); - if (JS_IsException(flags)) - goto exception; - args[0] = R; - args[1] = flags; - matcher = JS_CallConstructor(ctx, C, 2, args); - if (JS_IsException(matcher)) - goto exception; - if (JS_ToLengthFree(ctx, &lastIndex, - JS_GetProperty(ctx, R, JS_ATOM_lastIndex))) - goto exception; - if (JS_SetProperty(ctx, matcher, JS_ATOM_lastIndex, - JS_NewInt64(ctx, lastIndex)) < 0) - goto exception; - iter = JS_NewObjectClass(ctx, JS_CLASS_REGEXP_STRING_ITERATOR); - if (JS_IsException(iter)) - goto exception; - it = js_malloc(ctx, sizeof(*it)); - if (!it) - goto exception; - it->iterating_regexp = matcher; - it->iterated_string = S; - strp = JS_VALUE_GET_STRING(flags); - it->global = string_indexof_char(strp, 'g', 0) >= 0; - it->unicode = string_indexof_char(strp, 'u', 0) >= 0; - it->done = FALSE; - JS_SetOpaque(iter, it); - JS_FreeValue(ctx, C); - JS_FreeValue(ctx, flags); - return iter; - exception: - JS_FreeValue(ctx, S); - JS_FreeValue(ctx, C); - JS_FreeValue(ctx, flags); - JS_FreeValue(ctx, matcher); - JS_FreeValue(ctx, iter); - return JS_EXCEPTION; -} - -JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) -{ - JSRegExp *re = js_get_regexp(ctx, this_val, TRUE); - JSString *str; - JSValue str_val, obj, val, groups = JS_UNDEFINED; - uint8_t *re_bytecode; - int ret; - uint8_t **capture, *str_buf; - int capture_count, shift, i, re_flags; - int64_t last_index; - const char *group_name_ptr; - if (!re) - return JS_EXCEPTION; - str_val = JS_ToString(ctx, argv[0]); - if (JS_IsException(str_val)) - return str_val; - val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex); - if (JS_IsException(val) || - JS_ToLengthFree(ctx, &last_index, val)) { - JS_FreeValue(ctx, str_val); - return JS_EXCEPTION; - } - re_bytecode = re->bytecode->u.str8; - re_flags = lre_get_flags(re_bytecode); - if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) { - last_index = 0; - } - str = JS_VALUE_GET_STRING(str_val); - capture_count = lre_get_capture_count(re_bytecode); - capture = NULL; - if (capture_count > 0) { - capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2); - if (!capture) { - JS_FreeValue(ctx, str_val); - return JS_EXCEPTION; - } - } - shift = str->is_wide_char; - str_buf = str->u.str8; - if (last_index > str->len) { - ret = 2; - } else { - ret = lre_exec(capture, re_bytecode, - str_buf, last_index, str->len, - shift, ctx); - } - obj = JS_NULL; - if (ret != 1) { - if (ret >= 0) { - if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) { - if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex, - JS_NewInt32(ctx, 0)) < 0) - goto fail; - } - } else { - JS_ThrowInternalError(ctx, "out of memory in regexp execution"); - goto fail; - } - JS_FreeValue(ctx, str_val); - } else { - int prop_flags; - if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) { - if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex, - JS_NewInt32(ctx, (capture[1] - str_buf) >> shift)) < 0) - goto fail; - } - obj = JS_NewArray(ctx); - if (JS_IsException(obj)) - goto fail; - prop_flags = JS_PROP_C_W_E | JS_PROP_THROW; - group_name_ptr = lre_get_groupnames(re_bytecode); - if (group_name_ptr) { - groups = JS_NewObjectProto(ctx, JS_NULL); - if (JS_IsException(groups)) - goto fail; - } - for(i = 0; i < capture_count; i++) { - int start, end; - JSValue val; - if (capture[2 * i] == NULL || - capture[2 * i + 1] == NULL) { - val = JS_UNDEFINED; - } else { - start = (capture[2 * i] - str_buf) >> shift; - end = (capture[2 * i + 1] - str_buf) >> shift; - val = js_sub_string(ctx, str, start, end); - if (JS_IsException(val)) - goto fail; - } - if (group_name_ptr && i > 0) { - if (*group_name_ptr) { - if (JS_DefinePropertyValueStr(ctx, groups, group_name_ptr, - JS_DupValue(ctx, val), - prop_flags) < 0) { - JS_FreeValue(ctx, val); - goto fail; - } - } - group_name_ptr += strlen(group_name_ptr) + 1; - } - if (JS_DefinePropertyValueUint32(ctx, obj, i, val, prop_flags) < 0) - goto fail; - } - if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_groups, - groups, prop_flags) < 0) - goto fail; - if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_index, - JS_NewInt32(ctx, (capture[0] - str_buf) >> shift), prop_flags) < 0) - goto fail; - if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_input, str_val, prop_flags) < 0) - goto fail1; - } - js_free(ctx, capture); - return obj; -fail: - JS_FreeValue(ctx, groups); - JS_FreeValue(ctx, str_val); -fail1: - JS_FreeValue(ctx, obj); - js_free(ctx, capture); - return JS_EXCEPTION; -} - -JSValue JS_RegExpExec(JSContext *ctx, JSValueConst r, JSValueConst s) -{ - JSValue method, ret; - method = JS_GetProperty(ctx, r, JS_ATOM_exec); - if (JS_IsException(method)) - return method; - if (JS_IsFunction(ctx, method)) { - ret = JS_CallFree(ctx, method, r, 1, &s); - if (JS_IsException(ret)) - return ret; - if (!JS_IsObject(ret) && !JS_IsNull(ret)) { - JS_FreeValue(ctx, ret); - return JS_ThrowTypeError(ctx, "RegExp exec method must return an object or null"); - } - return ret; - } - JS_FreeValue(ctx, method); - return js_regexp_exec(ctx, r, 1, &s); -} - -BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size) -{ - JSContext *ctx = opaque; - return js_check_stack_overflow(ctx->rt, alloca_size); -} - -void *lre_realloc(void *opaque, void *ptr, size_t size) -{ - JSContext *ctx = opaque; - /* No JS exception is raised here */ - return js_realloc_rt(ctx->rt, ptr, size); -} - -/* delete portions of a string that match a given regex */ -static JSValue JS_RegExpDelete(JSContext *ctx, JSValueConst this_val, JSValueConst arg) -{ - JSRegExp *re = js_get_regexp(ctx, this_val, TRUE); - JSString *str; - JSValue str_val, val; - uint8_t *re_bytecode; - int ret; - uint8_t **capture, *str_buf; - int capture_count, shift, re_flags; - int next_src_pos, start, end; - int64_t last_index; - StringBuffer b_s, *b = &b_s; - if (!re) - return JS_EXCEPTION; - string_buffer_init(ctx, b, 0); - capture = NULL; - str_val = JS_ToString(ctx, arg); - if (JS_IsException(str_val)) - goto fail; - str = JS_VALUE_GET_STRING(str_val); - re_bytecode = re->bytecode->u.str8; - re_flags = lre_get_flags(re_bytecode); - if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) { - last_index = 0; - } else { - val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex); - if (JS_IsException(val) || JS_ToLengthFree(ctx, &last_index, val)) - goto fail; - } - capture_count = lre_get_capture_count(re_bytecode); - if (capture_count > 0) { - capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2); - if (!capture) - goto fail; - } - shift = str->is_wide_char; - str_buf = str->u.str8; - next_src_pos = 0; - for (;;) { - if (last_index > str->len) - break; - ret = lre_exec(capture, re_bytecode, - str_buf, last_index, str->len, shift, ctx); - if (ret != 1) { - if (ret >= 0) { - if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) { - if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex, - JS_NewInt32(ctx, 0)) < 0) - goto fail; - } - } else { - JS_ThrowInternalError(ctx, "out of memory in regexp execution"); - goto fail; - } - break; - } - start = (capture[0] - str_buf) >> shift; - end = (capture[1] - str_buf) >> shift; - last_index = end; - if (next_src_pos < start) { - if (string_buffer_concat(b, str, next_src_pos, start)) - goto fail; - } - next_src_pos = end; - if (!(re_flags & LRE_FLAG_GLOBAL)) { - if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex, - JS_NewInt32(ctx, end)) < 0) - goto fail; - break; - } - if (end == start) { - if (!(re_flags & LRE_FLAG_UTF16) || (unsigned)end >= str->len || !str->is_wide_char) { - end++; - } else { - string_getc(str, &end); - } - } - last_index = end; - } - if (string_buffer_concat(b, str, next_src_pos, str->len)) - goto fail; - JS_FreeValue(ctx, str_val); - js_free(ctx, capture); - return string_buffer_end(b); -fail: - JS_FreeValue(ctx, str_val); - js_free(ctx, capture); - string_buffer_free(b); - return JS_EXCEPTION; -} - -#if 0 -static JSValue js_regexp___RegExpExec(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_RegExpExec(ctx, argv[0], argv[1]); -} -static JSValue js_regexp___RegExpDelete(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_RegExpDelete(ctx, argv[0], argv[1]); -} -#endif - -static JSValue js_regexp_test(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val; - BOOL ret; - val = JS_RegExpExec(ctx, this_val, argv[0]); - if (JS_IsException(val)) - return JS_EXCEPTION; - ret = !JS_IsNull(val); - JS_FreeValue(ctx, val); - return JS_NewBool(ctx, ret); -} - -static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // [Symbol.match](str) - JSValueConst rx = this_val; - JSValue A, S, result, matchStr; - int global, n, fullUnicode, isEmpty; - JSString *p; - if (!JS_IsObject(rx)) - return JS_ThrowTypeErrorNotAnObject(ctx); - A = JS_UNDEFINED; - result = JS_UNDEFINED; - matchStr = JS_UNDEFINED; - S = JS_ToString(ctx, argv[0]); - if (JS_IsException(S)) - goto exception; - global = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_global)); - if (global < 0) - goto exception; - if (!global) { - A = JS_RegExpExec(ctx, rx, S); - } else { - fullUnicode = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_unicode)); - if (fullUnicode < 0) - goto exception; - if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) - goto exception; - A = JS_NewArray(ctx); - if (JS_IsException(A)) - goto exception; - n = 0; - for(;;) { - JS_FreeValue(ctx, result); - result = JS_RegExpExec(ctx, rx, S); - if (JS_IsException(result)) - goto exception; - if (JS_IsNull(result)) - break; - matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0)); - if (JS_IsException(matchStr)) - goto exception; - isEmpty = JS_IsEmptyString(matchStr); - if (JS_SetPropertyInt64(ctx, A, n++, matchStr) < 0) - goto exception; - if (isEmpty) { - int64_t thisIndex, nextIndex; - if (JS_ToLengthFree(ctx, &thisIndex, - JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0) - goto exception; - p = JS_VALUE_GET_STRING(S); - nextIndex = string_advance_index(p, thisIndex, fullUnicode); - if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0) - goto exception; - } - } - if (n == 0) { - JS_FreeValue(ctx, A); - A = JS_NULL; - } - } - JS_FreeValue(ctx, result); - JS_FreeValue(ctx, S); - return A; -exception: - JS_FreeValue(ctx, A); - JS_FreeValue(ctx, result); - JS_FreeValue(ctx, S); - return JS_EXCEPTION; -} - -typedef struct ValueBuffer { - JSContext *ctx; - JSValue *arr; - JSValue def[4]; - int len; - int size; - int error_status; -} ValueBuffer; - -static int value_buffer_init(JSContext *ctx, ValueBuffer *b) -{ - b->ctx = ctx; - b->len = 0; - b->size = 4; - b->error_status = 0; - b->arr = b->def; - return 0; -} - -static void value_buffer_free(ValueBuffer *b) -{ - while (b->len > 0) - JS_FreeValue(b->ctx, b->arr[--b->len]); - if (b->arr != b->def) - js_free(b->ctx, b->arr); - b->arr = b->def; - b->size = 4; -} - -static int value_buffer_append(ValueBuffer *b, JSValue val) -{ - if (b->error_status) - return -1; - if (b->len >= b->size) { - int new_size = (b->len + (b->len >> 1) + 31) & ~16; - size_t slack; - JSValue *new_arr; - if (b->arr == b->def) { - new_arr = js_realloc2(b->ctx, NULL, sizeof(*b->arr) * new_size, &slack); - if (new_arr) - memcpy(new_arr, b->def, sizeof b->def); - } else { - new_arr = js_realloc2(b->ctx, b->arr, sizeof(*b->arr) * new_size, &slack); - } - if (!new_arr) { - value_buffer_free(b); - JS_FreeValue(b->ctx, val); - b->error_status = -1; - return -1; - } - new_size += slack / sizeof(*new_arr); - b->arr = new_arr; - b->size = new_size; - } - b->arr[b->len++] = val; - return 0; -} - -static int js_is_standard_regexp(JSContext *ctx, JSValueConst rx) -{ - JSValue val; - int res; - val = JS_GetProperty(ctx, rx, JS_ATOM_constructor); - if (JS_IsException(val)) - return -1; - // rx.constructor === RegExp - res = js_same_value(ctx, val, ctx->regexp_ctor); - JS_FreeValue(ctx, val); - if (res) { - val = JS_GetProperty(ctx, rx, JS_ATOM_exec); - if (JS_IsException(val)) - return -1; - // rx.exec === RE_exec - res = JS_IsCFunction(ctx, val, js_regexp_exec, 0); - JS_FreeValue(ctx, val); - } - return res; -} - -static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // [Symbol.replace](str, rep) - JSValueConst rx = this_val, rep = argv[1]; - JSValueConst args[6]; - JSValue str, rep_val, matched, tab, rep_str, namedCaptures, res; - JSString *sp, *rp; - StringBuffer b_s, *b = &b_s; - ValueBuffer v_b, *results = &v_b; - int nextSourcePosition, n, j, functionalReplace, is_global, fullUnicode; - uint32_t nCaptures; - int64_t position; - if (!JS_IsObject(rx)) - return JS_ThrowTypeErrorNotAnObject(ctx); - string_buffer_init(ctx, b, 0); - value_buffer_init(ctx, results); - rep_val = JS_UNDEFINED; - matched = JS_UNDEFINED; - tab = JS_UNDEFINED; - rep_str = JS_UNDEFINED; - namedCaptures = JS_UNDEFINED; - str = JS_ToString(ctx, argv[0]); - if (JS_IsException(str)) - goto exception; - sp = JS_VALUE_GET_STRING(str); - rp = NULL; - functionalReplace = JS_IsFunction(ctx, rep); - if (!functionalReplace) { - rep_val = JS_ToString(ctx, rep); - if (JS_IsException(rep_val)) - goto exception; - rp = JS_VALUE_GET_STRING(rep_val); - } - fullUnicode = 0; - is_global = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_global)); - if (is_global < 0) - goto exception; - if (is_global) { - fullUnicode = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_unicode)); - if (fullUnicode < 0) - goto exception; - if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) - goto exception; - } - if (rp && rp->len == 0 && is_global && js_is_standard_regexp(ctx, rx)) { - /* use faster version for simple cases */ - res = JS_RegExpDelete(ctx, rx, str); - goto done; - } - for(;;) { - JSValue result; - result = JS_RegExpExec(ctx, rx, str); - if (JS_IsException(result)) - goto exception; - if (JS_IsNull(result)) - break; - if (value_buffer_append(results, result) < 0) - goto exception; - if (!is_global) - break; - JS_FreeValue(ctx, matched); - matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0)); - if (JS_IsException(matched)) - goto exception; - if (JS_IsEmptyString(matched)) { - /* always advance of at least one char */ - int64_t thisIndex, nextIndex; - if (JS_ToLengthFree(ctx, &thisIndex, JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0) - goto exception; - nextIndex = string_advance_index(sp, thisIndex, fullUnicode); - if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0) - goto exception; - } - } - nextSourcePosition = 0; - for(j = 0; j < results->len; j++) { - JSValueConst result; - result = results->arr[j]; - if (js_get_length32(ctx, &nCaptures, result) < 0) - goto exception; - JS_FreeValue(ctx, matched); - matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0)); - if (JS_IsException(matched)) - goto exception; - if (JS_ToLengthFree(ctx, &position, JS_GetProperty(ctx, result, JS_ATOM_index))) - goto exception; - if (position > sp->len) - position = sp->len; - else if (position < 0) - position = 0; - /* ignore substition if going backward (can happen - with custom regexp object) */ - JS_FreeValue(ctx, tab); - tab = JS_NewArray(ctx); - if (JS_IsException(tab)) - goto exception; - if (JS_DefinePropertyValueInt64(ctx, tab, 0, JS_DupValue(ctx, matched), - JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - for(n = 1; n < nCaptures; n++) { - JSValue capN; - capN = JS_GetPropertyInt64(ctx, result, n); - if (JS_IsException(capN)) - goto exception; - if (!JS_IsUndefined(capN)) { - capN = JS_ToStringFree(ctx, capN); - if (JS_IsException(capN)) - goto exception; - } - if (JS_DefinePropertyValueInt64(ctx, tab, n, capN, - JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - } - JS_FreeValue(ctx, namedCaptures); - namedCaptures = JS_GetProperty(ctx, result, JS_ATOM_groups); - if (JS_IsException(namedCaptures)) - goto exception; - if (functionalReplace) { - if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_NewInt32(ctx, position), JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, str), JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - if (!JS_IsUndefined(namedCaptures)) { - if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, namedCaptures), JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - } - args[0] = JS_UNDEFINED; - args[1] = tab; - JS_FreeValue(ctx, rep_str); - rep_str = JS_ToStringFree(ctx, js_function_apply(ctx, rep, 2, args, 0)); - } else { - JSValue namedCaptures1; - if (!JS_IsUndefined(namedCaptures)) { - namedCaptures1 = JS_ToObject(ctx, namedCaptures); - if (JS_IsException(namedCaptures1)) - goto exception; - } else { - namedCaptures1 = JS_UNDEFINED; - } - args[0] = matched; - args[1] = str; - args[2] = JS_NewInt32(ctx, position); - args[3] = tab; - args[4] = namedCaptures1; - args[5] = rep_val; - JS_FreeValue(ctx, rep_str); - rep_str = js_string___GetSubstitution(ctx, JS_UNDEFINED, 6, args); - JS_FreeValue(ctx, namedCaptures1); - } - if (JS_IsException(rep_str)) - goto exception; - if (position >= nextSourcePosition) { - string_buffer_concat(b, sp, nextSourcePosition, position); - string_buffer_concat_value(b, rep_str); - nextSourcePosition = position + JS_VALUE_GET_STRING(matched)->len; - } - } - string_buffer_concat(b, sp, nextSourcePosition, sp->len); - res = string_buffer_end(b); - goto done1; -exception: - res = JS_EXCEPTION; -done: - string_buffer_free(b); -done1: - value_buffer_free(results); - JS_FreeValue(ctx, rep_val); - JS_FreeValue(ctx, matched); - JS_FreeValue(ctx, tab); - JS_FreeValue(ctx, rep_str); - JS_FreeValue(ctx, namedCaptures); - JS_FreeValue(ctx, str); - return res; -} - -static JSValue js_regexp_Symbol_search(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst rx = this_val; - JSValue str, previousLastIndex, currentLastIndex, result, index; - if (!JS_IsObject(rx)) - return JS_ThrowTypeErrorNotAnObject(ctx); - result = JS_UNDEFINED; - currentLastIndex = JS_UNDEFINED; - previousLastIndex = JS_UNDEFINED; - str = JS_ToString(ctx, argv[0]); - if (JS_IsException(str)) - goto exception; - previousLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex); - if (JS_IsException(previousLastIndex)) - goto exception; - if (!js_same_value(ctx, previousLastIndex, JS_NewInt32(ctx, 0))) { - if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) { - goto exception; - } - } - result = JS_RegExpExec(ctx, rx, str); - if (JS_IsException(result)) - goto exception; - currentLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex); - if (JS_IsException(currentLastIndex)) - goto exception; - if (js_same_value(ctx, currentLastIndex, previousLastIndex)) { - JS_FreeValue(ctx, previousLastIndex); - } else { - if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, previousLastIndex) < 0) { - previousLastIndex = JS_UNDEFINED; - goto exception; - } - } - JS_FreeValue(ctx, str); - JS_FreeValue(ctx, currentLastIndex); - if (JS_IsNull(result)) { - return JS_NewInt32(ctx, -1); - } else { - index = JS_GetProperty(ctx, result, JS_ATOM_index); - JS_FreeValue(ctx, result); - return index; - } -exception: - JS_FreeValue(ctx, result); - JS_FreeValue(ctx, str); - JS_FreeValue(ctx, currentLastIndex); - JS_FreeValue(ctx, previousLastIndex); - return JS_EXCEPTION; -} - -static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // [Symbol.split](str, limit) - JSValueConst rx = this_val; - JSValueConst args[2]; - JSValue str, ctor, splitter, A, flags, z, sub; - JSString *strp; - uint32_t lim, size, p, q; - int unicodeMatching; - int64_t lengthA, e, numberOfCaptures, i; - if (!JS_IsObject(rx)) - return JS_ThrowTypeErrorNotAnObject(ctx); - ctor = JS_UNDEFINED; - splitter = JS_UNDEFINED; - A = JS_UNDEFINED; - flags = JS_UNDEFINED; - z = JS_UNDEFINED; - str = JS_ToString(ctx, argv[0]); - if (JS_IsException(str)) - goto exception; - ctor = JS_SpeciesConstructor(ctx, rx, ctx->regexp_ctor); - if (JS_IsException(ctor)) - goto exception; - flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_flags)); - if (JS_IsException(flags)) - goto exception; - strp = JS_VALUE_GET_STRING(flags); - unicodeMatching = string_indexof_char(strp, 'u', 0) >= 0; - if (string_indexof_char(strp, 'y', 0) < 0) { - flags = JS_ConcatString3(ctx, "", flags, "y"); - if (JS_IsException(flags)) - goto exception; - } - args[0] = rx; - args[1] = flags; - splitter = JS_CallConstructor(ctx, ctor, 2, args); - if (JS_IsException(splitter)) - goto exception; - A = JS_NewArray(ctx); - if (JS_IsException(A)) - goto exception; - lengthA = 0; - if (JS_IsUndefined(argv[1])) { - lim = 0xffffffff; - } else { - if (JS_ToUint32(ctx, &lim, argv[1]) < 0) - goto exception; - if (lim == 0) - goto done; - } - strp = JS_VALUE_GET_STRING(str); - p = q = 0; - size = strp->len; - if (size == 0) { - z = JS_RegExpExec(ctx, splitter, str); - if (JS_IsException(z)) - goto exception; - if (JS_IsNull(z)) - goto add_tail; - goto done; - } - while (q < size) { - if (JS_SetProperty(ctx, splitter, JS_ATOM_lastIndex, JS_NewInt32(ctx, q)) < 0) - goto exception; - JS_FreeValue(ctx, z); - z = JS_RegExpExec(ctx, splitter, str); - if (JS_IsException(z)) - goto exception; - if (JS_IsNull(z)) { - q = string_advance_index(strp, q, unicodeMatching); - } else { - if (JS_ToLengthFree(ctx, &e, JS_GetProperty(ctx, splitter, JS_ATOM_lastIndex))) - goto exception; - if (e > size) - e = size; - if (e == p) { - q = string_advance_index(strp, q, unicodeMatching); - } else { - sub = js_sub_string(ctx, strp, p, q); - if (JS_IsException(sub)) - goto exception; - if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, - JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - if (lengthA == lim) - goto done; - p = e; - if (js_get_length64(ctx, &numberOfCaptures, z)) - goto exception; - for(i = 1; i < numberOfCaptures; i++) { - sub = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, z, i)); - if (JS_IsException(sub)) - goto exception; - if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - if (lengthA == lim) - goto done; - } - q = p; - } - } - } -add_tail: - if (p > size) - p = size; - sub = js_sub_string(ctx, strp, p, size); - if (JS_IsException(sub)) - goto exception; - if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - goto done; -exception: - JS_FreeValue(ctx, A); - A = JS_EXCEPTION; -done: - JS_FreeValue(ctx, str); - JS_FreeValue(ctx, ctor); - JS_FreeValue(ctx, splitter); - JS_FreeValue(ctx, flags); - JS_FreeValue(ctx, z); - return A; -} - -static const JSCFunctionListEntry js_regexp_funcs[] = { - JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ), - //JS_CFUNC_DEF("__RegExpExec", 2, js_regexp___RegExpExec ), - //JS_CFUNC_DEF("__RegExpDelete", 2, js_regexp___RegExpDelete ), -}; - -static const JSCFunctionListEntry js_regexp_proto_funcs[] = { - JS_CGETSET_DEF("flags", js_regexp_get_flags, NULL ), - JS_CGETSET_DEF("source", js_regexp_get_source, NULL ), - JS_CGETSET_MAGIC_DEF("global", js_regexp_get_flag, NULL, 1 ), - JS_CGETSET_MAGIC_DEF("ignoreCase", js_regexp_get_flag, NULL, 2 ), - JS_CGETSET_MAGIC_DEF("multiline", js_regexp_get_flag, NULL, 4 ), - JS_CGETSET_MAGIC_DEF("dotAll", js_regexp_get_flag, NULL, 8 ), - JS_CGETSET_MAGIC_DEF("unicode", js_regexp_get_flag, NULL, 16 ), - JS_CGETSET_MAGIC_DEF("sticky", js_regexp_get_flag, NULL, 32 ), - JS_CFUNC_DEF("exec", 1, js_regexp_exec ), - JS_CFUNC_DEF("compile", 2, js_regexp_compile ), - JS_CFUNC_DEF("test", 1, js_regexp_test ), - JS_CFUNC_DEF("toString", 0, js_regexp_toString ), - JS_CFUNC_DEF("[Symbol.replace]", 2, js_regexp_Symbol_replace ), - JS_CFUNC_DEF("[Symbol.match]", 1, js_regexp_Symbol_match ), - JS_CFUNC_DEF("[Symbol.matchAll]", 1, js_regexp_Symbol_matchAll ), - JS_CFUNC_DEF("[Symbol.search]", 1, js_regexp_Symbol_search ), - JS_CFUNC_DEF("[Symbol.split]", 2, js_regexp_Symbol_split ), - //JS_CGETSET_DEF("__source", js_regexp_get___source, NULL ), - //JS_CGETSET_DEF("__flags", js_regexp_get___flags, NULL ), -}; - -static const JSCFunctionListEntry js_regexp_string_iterator_proto_funcs[] = { - JS_ITERATOR_NEXT_DEF("next", 0, js_regexp_string_iterator_next, 0 ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "RegExp String Iterator", JS_PROP_CONFIGURABLE ), -}; - -void JS_AddIntrinsicRegExpCompiler(JSContext *ctx) -{ - ctx->compile_regexp = js_compile_regexp; -} - -void JS_AddIntrinsicRegExp(JSContext *ctx) -{ - JSValueConst obj; - JS_AddIntrinsicRegExpCompiler(ctx); - ctx->class_proto[JS_CLASS_REGEXP] = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_REGEXP], js_regexp_proto_funcs, - countof(js_regexp_proto_funcs)); - obj = JS_NewGlobalCConstructor(ctx, "RegExp", js_regexp_constructor, 2, - ctx->class_proto[JS_CLASS_REGEXP]); - ctx->regexp_ctor = JS_DupValue(ctx, obj); - JS_SetPropertyFunctionList(ctx, obj, js_regexp_funcs, countof(js_regexp_funcs)); - ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR] = - JS_NewObjectProto(ctx, ctx->iterator_proto); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR], - js_regexp_string_iterator_proto_funcs, - countof(js_regexp_string_iterator_proto_funcs)); -} diff --git a/third_party/quickjs/repl.js b/third_party/quickjs/repl.js deleted file mode 100644 index df710f3de..000000000 --- a/third_party/quickjs/repl.js +++ /dev/null @@ -1,1573 +0,0 @@ -/* - * QuickJS Read Eval Print Loop - * - * 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. - */ -"use strip"; - -import * as std from "std"; -import * as os from "os"; - -(function(g) { - /* add 'os' and 'std' bindings */ - g.os = os; - g.std = std; - - /* close global objects */ - var Object = g.Object; - var String = g.String; - var Array = g.Array; - var Date = g.Date; - var Math = g.Math; - var isFinite = g.isFinite; - var parseFloat = g.parseFloat; - - /* XXX: use preprocessor ? */ - var config_numcalc = (typeof os.open === "undefined"); - var has_jscalc = (typeof Fraction === "function"); - var has_bignum = (typeof BigFloat === "function"); - - var colors = { - none: "\x1b[0m", - black: "\x1b[30m", - red: "\x1b[31m", - green: "\x1b[32m", - yellow: "\x1b[33m", - blue: "\x1b[34m", - magenta: "\x1b[35m", - cyan: "\x1b[36m", - white: "\x1b[37m", - gray: "\x1b[30;1m", - grey: "\x1b[30;1m", - bright_red: "\x1b[31;1m", - bright_green: "\x1b[32;1m", - bright_yellow: "\x1b[33;1m", - bright_blue: "\x1b[34;1m", - bright_magenta: "\x1b[35;1m", - bright_cyan: "\x1b[36;1m", - bright_white: "\x1b[37;1m", - }; - - var styles; - if (config_numcalc) { - styles = { - 'default': 'black', - 'comment': 'white', - 'string': 'green', - 'regex': 'cyan', - 'number': 'green', - 'keyword': 'blue', - 'function': 'gray', - 'type': 'bright_magenta', - 'identifier': 'yellow', - 'error': 'bright_red', - 'result': 'black', - 'error_msg': 'bright_red', - }; - } else { - styles = { - 'default': 'bright_green', - 'comment': 'white', - 'string': 'bright_cyan', - 'regex': 'cyan', - 'number': 'green', - 'keyword': 'bright_white', - 'function': 'bright_yellow', - 'type': 'bright_magenta', - 'identifier': 'bright_green', - 'error': 'red', - 'result': 'bright_white', - 'error_msg': 'bright_red', - }; - } - - var history = []; - var clip_board = ""; - var prec; - var expBits; - var log2_10; - - var pstate = ""; - var prompt = ""; - var plen = 0; - var ps1; - if (config_numcalc) - ps1 = ">: "; - else - ps1 = "qjs >: "; - var ps2 = " ... "; - var utf8 = true; - var show_time = false; - var show_colors = true; - var eval_time = 0; - - var mexpr = ""; - var level = 0; - var cmd = ""; - var cursor_pos = 0; - var last_cmd = ""; - var last_cursor_pos = 0; - var history_index; - var this_fun, last_fun; - var quote_flag = false; - - var utf8_state = 0; - var utf8_val = 0; - - var term_fd; - var term_read_buf; - var term_width; - /* current X position of the cursor in the terminal */ - var term_cursor_x = 0; - - function termInit() { - var tab; - term_fd = std.in.fileno(); - - /* get the terminal size */ - term_width = 80; - if (os.isatty(term_fd)) { - if (os.ttyGetWinSize) { - tab = os.ttyGetWinSize(term_fd); - if (tab) - term_width = tab[0]; - } - if (os.ttySetRaw) { - /* set the TTY to raw mode */ - os.ttySetRaw(term_fd); - } - } - - /* install a Ctrl-C signal handler */ - os.signal(os.SIGINT, sigint_handler); - - /* install a handler to read stdin */ - term_read_buf = new Uint8Array(64); - os.setReadHandler(term_fd, term_read_handler); - } - - function sigint_handler() { - /* send Ctrl-C to readline */ - handle_byte(3); - } - - function term_read_handler() { - var l, i; - l = os.read(term_fd, term_read_buf.buffer, 0, term_read_buf.length); - for(i = 0; i < l; i++) - handle_byte(term_read_buf[i]); - } - - function handle_byte(c) { - if (!utf8) { - handle_char(c); - } else if (utf8_state !== 0 && (c >= 0x80 && c < 0xc0)) { - utf8_val = (utf8_val << 6) | (c & 0x3F); - utf8_state--; - if (utf8_state === 0) { - handle_char(utf8_val); - } - } else if (c >= 0xc0 && c < 0xf8) { - utf8_state = 1 + (c >= 0xe0) + (c >= 0xf0); - utf8_val = c & ((1 << (6 - utf8_state)) - 1); - } else { - utf8_state = 0; - handle_char(c); - } - } - - function is_alpha(c) { - return typeof c === "string" && - ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')); - } - - function is_digit(c) { - return typeof c === "string" && (c >= '0' && c <= '9'); - } - - function is_word(c) { - return typeof c === "string" && - (is_alpha(c) || is_digit(c) || c == '_' || c == '$'); - } - - function ucs_length(str) { - var len, c, i, str_len = str.length; - len = 0; - /* we never count the trailing surrogate to have the - following property: ucs_length(str) = - ucs_length(str.substring(0, a)) + ucs_length(str.substring(a, - str.length)) for 0 <= a <= str.length */ - for(i = 0; i < str_len; i++) { - c = str.charCodeAt(i); - if (c < 0xdc00 || c >= 0xe000) - len++; - } - return len; - } - - function is_trailing_surrogate(c) { - var d; - if (typeof c !== "string") - return false; - d = c.codePointAt(0); /* can be NaN if empty string */ - return d >= 0xdc00 && d < 0xe000; - } - - function is_balanced(a, b) { - switch (a + b) { - case "()": - case "[]": - case "{}": - return true; - } - return false; - } - - function print_color_text(str, start, style_names) { - var i, j; - for (j = start; j < str.length;) { - var style = style_names[i = j]; - while (++j < str.length && style_names[j] == style) - continue; - std.puts(colors[styles[style] || 'default']); - std.puts(str.substring(i, j)); - std.puts(colors['none']); - } - } - - function print_csi(n, code) { - std.puts("\x1b[" + ((n != 1) ? n : "") + code); - } - - /* XXX: handle double-width characters */ - function move_cursor(delta) { - var i, l; - if (delta > 0) { - while (delta != 0) { - if (term_cursor_x == (term_width - 1)) { - std.puts("\n"); /* translated to CRLF */ - term_cursor_x = 0; - delta--; - } else { - l = Math.min(term_width - 1 - term_cursor_x, delta); - print_csi(l, "C"); /* right */ - delta -= l; - term_cursor_x += l; - } - } - } else { - delta = -delta; - while (delta != 0) { - if (term_cursor_x == 0) { - print_csi(1, "A"); /* up */ - print_csi(term_width - 1, "C"); /* right */ - delta--; - term_cursor_x = term_width - 1; - } else { - l = Math.min(delta, term_cursor_x); - print_csi(l, "D"); /* left */ - delta -= l; - term_cursor_x -= l; - } - } - } - } - - function update() { - var i, cmd_len; - /* cursor_pos is the position in 16 bit characters inside the - UTF-16 string 'cmd' */ - if (cmd != last_cmd) { - if (!show_colors && last_cmd.substring(0, last_cursor_pos) == cmd.substring(0, last_cursor_pos)) { - /* optimize common case */ - std.puts(cmd.substring(last_cursor_pos)); - } else { - /* goto the start of the line */ - move_cursor(-ucs_length(last_cmd.substring(0, last_cursor_pos))); - if (show_colors) { - var str = mexpr ? mexpr + '\n' + cmd : cmd; - var start = str.length - cmd.length; - var colorstate = colorize_js(str); - print_color_text(str, start, colorstate[2]); - } else { - std.puts(cmd); - } - } - term_cursor_x = (term_cursor_x + ucs_length(cmd)) % term_width; - if (term_cursor_x == 0) { - /* show the cursor on the next line */ - std.puts(" \x08"); - } - /* remove the trailing characters */ - std.puts("\x1b[J"); - last_cmd = cmd; - last_cursor_pos = cmd.length; - } - if (cursor_pos > last_cursor_pos) { - move_cursor(ucs_length(cmd.substring(last_cursor_pos, cursor_pos))); - } else if (cursor_pos < last_cursor_pos) { - move_cursor(-ucs_length(cmd.substring(cursor_pos, last_cursor_pos))); - } - last_cursor_pos = cursor_pos; - std.out.flush(); - } - - /* editing commands */ - function insert(str) { - if (str) { - cmd = cmd.substring(0, cursor_pos) + str + cmd.substring(cursor_pos); - cursor_pos += str.length; - } - } - - function quoted_insert() { - quote_flag = true; - } - - function abort() { - cmd = ""; - cursor_pos = 0; - return -2; - } - - function alert() { - } - - function beginning_of_line() { - cursor_pos = 0; - } - - function end_of_line() { - cursor_pos = cmd.length; - } - - function forward_char() { - if (cursor_pos < cmd.length) { - cursor_pos++; - while (is_trailing_surrogate(cmd.charAt(cursor_pos))) - cursor_pos++; - } - } - - function backward_char() { - if (cursor_pos > 0) { - cursor_pos--; - while (is_trailing_surrogate(cmd.charAt(cursor_pos))) - cursor_pos--; - } - } - - function skip_word_forward(pos) { - while (pos < cmd.length && !is_word(cmd.charAt(pos))) - pos++; - while (pos < cmd.length && is_word(cmd.charAt(pos))) - pos++; - return pos; - } - - function skip_word_backward(pos) { - while (pos > 0 && !is_word(cmd.charAt(pos - 1))) - pos--; - while (pos > 0 && is_word(cmd.charAt(pos - 1))) - pos--; - return pos; - } - - function forward_word() { - cursor_pos = skip_word_forward(cursor_pos); - } - - function backward_word() { - cursor_pos = skip_word_backward(cursor_pos); - } - - function accept_line() { - std.puts("\n"); - history_add(cmd); - return -1; - } - - function history_add(str) { - if (str) { - history.push(str); - } - history_index = history.length; - } - - function previous_history() { - if (history_index > 0) { - if (history_index == history.length) { - history.push(cmd); - } - history_index--; - cmd = history[history_index]; - cursor_pos = cmd.length; - } - } - - function next_history() { - if (history_index < history.length - 1) { - history_index++; - cmd = history[history_index]; - cursor_pos = cmd.length; - } - } - - function history_search(dir) { - var pos = cursor_pos; - for (var i = 1; i <= history.length; i++) { - var index = (history.length + i * dir + history_index) % history.length; - if (history[index].substring(0, pos) == cmd.substring(0, pos)) { - history_index = index; - cmd = history[index]; - return; - } - } - } - - function history_search_backward() { - return history_search(-1); - } - - function history_search_forward() { - return history_search(1); - } - - function delete_char_dir(dir) { - var start, end; - - start = cursor_pos; - if (dir < 0) { - start--; - while (is_trailing_surrogate(cmd.charAt(start))) - start--; - } - end = start + 1; - while (is_trailing_surrogate(cmd.charAt(end))) - end++; - - if (start >= 0 && start < cmd.length) { - if (last_fun === kill_region) { - kill_region(start, end, dir); - } else { - cmd = cmd.substring(0, start) + cmd.substring(end); - cursor_pos = start; - } - } - } - - function delete_char() { - delete_char_dir(1); - } - - function control_d() { - if (cmd.length == 0) { - std.puts("\n"); - return -3; /* exit read eval print loop */ - } else { - delete_char_dir(1); - } - } - - function backward_delete_char() { - delete_char_dir(-1); - } - - function transpose_chars() { - var pos = cursor_pos; - if (cmd.length > 1 && pos > 0) { - if (pos == cmd.length) - pos--; - cmd = cmd.substring(0, pos - 1) + cmd.substring(pos, pos + 1) + - cmd.substring(pos - 1, pos) + cmd.substring(pos + 1); - cursor_pos = pos + 1; - } - } - - function transpose_words() { - var p1 = skip_word_backward(cursor_pos); - var p2 = skip_word_forward(p1); - var p4 = skip_word_forward(cursor_pos); - var p3 = skip_word_backward(p4); - - if (p1 < p2 && p2 <= cursor_pos && cursor_pos <= p3 && p3 < p4) { - cmd = cmd.substring(0, p1) + cmd.substring(p3, p4) + - cmd.substring(p2, p3) + cmd.substring(p1, p2); - cursor_pos = p4; - } - } - - function upcase_word() { - var end = skip_word_forward(cursor_pos); - cmd = cmd.substring(0, cursor_pos) + - cmd.substring(cursor_pos, end).toUpperCase() + - cmd.substring(end); - } - - function downcase_word() { - var end = skip_word_forward(cursor_pos); - cmd = cmd.substring(0, cursor_pos) + - cmd.substring(cursor_pos, end).toLowerCase() + - cmd.substring(end); - } - - function kill_region(start, end, dir) { - var s = cmd.substring(start, end); - if (last_fun !== kill_region) - clip_board = s; - else if (dir < 0) - clip_board = s + clip_board; - else - clip_board = clip_board + s; - - cmd = cmd.substring(0, start) + cmd.substring(end); - if (cursor_pos > end) - cursor_pos -= end - start; - else if (cursor_pos > start) - cursor_pos = start; - this_fun = kill_region; - } - - function clear_screen() { - std.puts("\e[H\e[2J"); - return -1; - } - - function kill_line() { - kill_region(cursor_pos, cmd.length, 1); - } - - function backward_kill_line() { - kill_region(0, cursor_pos, -1); - } - - function kill_word() { - kill_region(cursor_pos, skip_word_forward(cursor_pos), 1); - } - - function backward_kill_word() { - kill_region(skip_word_backward(cursor_pos), cursor_pos, -1); - } - - function yank() { - insert(clip_board); - } - - function control_c() { - if (last_fun === control_c) { - std.puts("\n"); - std.exit(0); - } else { - std.puts("\n(Press Ctrl-C again to quit)\n"); - readline_print_prompt(); - } - } - - function reset() { - cmd = ""; - cursor_pos = 0; - } - - function get_context_word(line, pos) { - var s = ""; - while (pos > 0 && is_word(line[pos - 1])) { - pos--; - s = line[pos] + s; - } - return s; - } - function get_context_object(line, pos) { - var obj, base, c; - if (pos <= 0 || " ~!%^&*(-+={[|:;,<>?/".indexOf(line[pos - 1]) >= 0) - return g; - if (pos >= 2 && line[pos - 1] === ".") { - pos--; - obj = {}; - switch (c = line[pos - 1]) { - case '\'': - case '\"': - return "a"; - case ']': - return []; - case '}': - return {}; - case '/': - return / /; - default: - if (is_word(c)) { - base = get_context_word(line, pos); - if (["true", "false", "null", "this"].includes(base) || !isNaN(+base)) - return eval(base); - obj = get_context_object(line, pos - base.length); - if (obj === null || obj === void 0) - return obj; - if (obj === g && obj[base] === void 0) - return eval(base); - else - return obj[base]; - } - return {}; - } - } - return void 0; - } - - function get_completions(line, pos) { - var s, obj, ctx_obj, r, i, j, paren; - - s = get_context_word(line, pos); - ctx_obj = get_context_object(line, pos - s.length); - r = []; - /* enumerate properties from object and its prototype chain, - add non-numeric regular properties with s as e prefix - */ - for (i = 0, obj = ctx_obj; i < 10 && obj !== null && obj !== void 0; i++) { - var props = Object.getOwnPropertyNames(obj); - /* add non-numeric regular properties */ - for (j = 0; j < props.length; j++) { - var prop = props[j]; - if (typeof prop == "string" && ""+(+prop) != prop && prop.startsWith(s)) - r.push(prop); - } - obj = Object.getPrototypeOf(obj); - } - if (r.length > 1) { - /* sort list with internal names last and remove duplicates */ - function symcmp(a, b) { - if (a[0] != b[0]) { - if (a[0] == '_') - return 1; - if (b[0] == '_') - return -1; - } - if (a < b) - return -1; - if (a > b) - return +1; - return 0; - } - r.sort(symcmp); - for(i = j = 1; i < r.length; i++) { - if (r[i] != r[i - 1]) - r[j++] = r[i]; - } - r.length = j; - } - /* 'tab' = list of completions, 'pos' = cursor position inside - the completions */ - return { tab: r, pos: s.length, ctx: ctx_obj }; - } - - function completion() { - var tab, res, s, i, j, len, t, max_width, col, n_cols, row, n_rows; - res = get_completions(cmd, cursor_pos); - tab = res.tab; - if (tab.length === 0) - return; - s = tab[0]; - len = s.length; - /* add the chars which are identical in all the completions */ - for(i = 1; i < tab.length; i++) { - t = tab[i]; - for(j = 0; j < len; j++) { - if (t[j] !== s[j]) { - len = j; - break; - } - } - } - for(i = res.pos; i < len; i++) { - insert(s[i]); - } - if (last_fun === completion && tab.length == 1) { - /* append parentheses to function names */ - var m = res.ctx[tab[0]]; - if (typeof m == "function") { - insert('('); - if (m.length == 0) - insert(')'); - } else if (typeof m == "object") { - insert('.'); - } - } - /* show the possible completions */ - if (last_fun === completion && tab.length >= 2) { - max_width = 0; - for(i = 0; i < tab.length; i++) - max_width = Math.max(max_width, tab[i].length); - max_width += 2; - n_cols = Math.max(1, Math.floor((term_width + 1) / max_width)); - n_rows = Math.ceil(tab.length / n_cols); - std.puts("\n"); - /* display the sorted list column-wise */ - for (row = 0; row < n_rows; row++) { - for (col = 0; col < n_cols; col++) { - i = col * n_rows + row; - if (i >= tab.length) - break; - s = tab[i]; - if (col != n_cols - 1) - s = s.padEnd(max_width); - std.puts(s); - } - std.puts("\n"); - } - /* show a new prompt */ - readline_print_prompt(); - } - } - - var commands = { /* command table */ - "\x01": beginning_of_line, /* ^A - bol */ - "\x02": backward_char, /* ^B - backward-char */ - "\x03": control_c, /* ^C - abort */ - "\x04": control_d, /* ^D - delete-char or exit */ - "\x05": end_of_line, /* ^E - eol */ - "\x06": forward_char, /* ^F - forward-char */ - "\x07": abort, /* ^G - bell */ - "\x08": backward_delete_char, /* ^H - backspace */ - "\x09": completion, /* ^I - history-search-backward */ - "\x0a": accept_line, /* ^J - newline */ - "\x0b": kill_line, /* ^K - delete to end of line */ - "\x0c": clear_screen, /* ^L - clear screen */ - "\x0d": accept_line, /* ^M - enter */ - "\x0e": next_history, /* ^N - down */ - "\x10": previous_history, /* ^P - up */ - "\x11": quoted_insert, /* ^Q - quoted-insert */ - "\x12": alert, /* ^R - reverse-search */ - "\x13": alert, /* ^S - search */ - "\x14": transpose_chars, /* ^T - transpose */ - "\x15": backward_kill_line, /* ^U - clear backwards */ - "\x18": reset, /* ^X - cancel */ - "\x19": yank, /* ^Y - yank */ - "\x1bOA": previous_history, /* ^[OA - up */ - "\x1bOB": next_history, /* ^[OB - down */ - "\x1bOC": forward_char, /* ^[OC - right */ - "\x1bOD": backward_char, /* ^[OD - left */ - "\x1bOF": forward_word, /* ^[OF - ctrl-right */ - "\x1bOH": backward_word, /* ^[OH - ctrl-left */ - "\x1b[1;5C": forward_word, /* ^[[1;5C - ctrl-right */ - "\x1b[1;5D": backward_word, /* ^[[1;5D - ctrl-left */ - "\x1b[1~": beginning_of_line, /* ^[[1~ - bol */ - "\x1b[3~": delete_char, /* ^[[3~ - delete */ - "\x1b[4~": end_of_line, /* ^[[4~ - eol */ - "\x1b[5~": history_search_backward,/* ^[[5~ - page up */ - "\x1b[6~": history_search_forward, /* ^[[5~ - page down */ - "\x1b[A": previous_history, /* ^[[A - up */ - "\x1b[B": next_history, /* ^[[B - down */ - "\x1b[C": forward_char, /* ^[[C - right */ - "\x1b[D": backward_char, /* ^[[D - left */ - "\x1b[F": end_of_line, /* ^[[F - end */ - "\x1b[H": beginning_of_line, /* ^[[H - home */ - "\x1b\x7f": backward_kill_word, /* M-C-? - backward_kill_word */ - "\x1bb": backward_word, /* M-b - backward_word */ - "\x1bd": kill_word, /* M-d - kill_word */ - "\x1bf": forward_word, /* M-f - backward_word */ - "\x1bk": backward_kill_line, /* M-k - backward_kill_line */ - "\x1bl": downcase_word, /* M-l - downcase_word */ - "\x1bt": transpose_words, /* M-t - transpose_words */ - "\x1bu": upcase_word, /* M-u - upcase_word */ - "\x7f": backward_delete_char, /* ^? - delete */ - }; - - function dupstr(str, count) { - var res = ""; - while (count-- > 0) - res += str; - return res; - } - - var readline_keys; - var readline_state; - var readline_cb; - - function readline_print_prompt() - { - std.puts(prompt); - term_cursor_x = ucs_length(prompt) % term_width; - last_cmd = ""; - last_cursor_pos = 0; - } - - function readline_start(defstr, cb) { - cmd = defstr || ""; - cursor_pos = cmd.length; - history_index = history.length; - readline_cb = cb; - - prompt = pstate; - - if (mexpr) { - prompt += dupstr(" ", plen - prompt.length); - prompt += ps2; - } else { - if (show_time) { - var t = Math.round(eval_time) + " "; - eval_time = 0; - t = dupstr("0", 5 - t.length) + t; - prompt += t.substring(0, t.length - 4) + "." + t.substring(t.length - 4); - } - plen = prompt.length; - prompt += ps1; - } - readline_print_prompt(); - update(); - readline_state = 0; - } - - function handle_char(c1) { - var c; - c = String.fromCodePoint(c1); - switch(readline_state) { - case 0: - if (c == '\x1b') { /* '^[' - ESC */ - readline_keys = c; - readline_state = 1; - } else { - handle_key(c); - } - break; - case 1: /* '^[ */ - readline_keys += c; - if (c == '[') { - readline_state = 2; - } else if (c == 'O') { - readline_state = 3; - } else { - handle_key(readline_keys); - readline_state = 0; - } - break; - case 2: /* '^[[' - CSI */ - readline_keys += c; - if (!(c == ';' || (c >= '0' && c <= '9'))) { - handle_key(readline_keys); - readline_state = 0; - } - break; - case 3: /* '^[O' - ESC2 */ - readline_keys += c; - handle_key(readline_keys); - readline_state = 0; - break; - } - } - - function handle_key(keys) { - var fun; - - if (quote_flag) { - if (ucs_length(keys) === 1) - insert(keys); - quote_flag = false; - } else if (fun = commands[keys]) { - this_fun = fun; - switch (fun(keys)) { - case -1: - readline_cb(cmd); - return; - case -2: - readline_cb(null); - return; - case -3: - /* uninstall a Ctrl-C signal handler */ - os.signal(os.SIGINT, null); - /* uninstall the stdin read handler */ - os.setReadHandler(term_fd, null); - return; - } - last_fun = this_fun; - } else if (ucs_length(keys) === 1 && keys >= ' ') { - insert(keys); - last_fun = insert; - } else { - alert(); /* beep! */ - } - - cursor_pos = (cursor_pos < 0) ? 0 : - (cursor_pos > cmd.length) ? cmd.length : cursor_pos; - update(); - } - - var hex_mode = false; - var eval_mode = "std"; - - function number_to_string(a, radix) { - var s; - if (!isFinite(a)) { - /* NaN, Infinite */ - return a.toString(); - } else { - if (a == 0) { - if (1 / a < 0) - s = "-0"; - else - s = "0"; - } else { - if (radix == 16 && a === Math.floor(a)) { - var s; - if (a < 0) { - a = -a; - s = "-"; - } else { - s = ""; - } - s += "0x" + a.toString(16); - } else { - s = a.toString(); - } - } - return s; - } - } - - function bigfloat_to_string(a, radix) { - var s; - if (!BigFloat.isFinite(a)) { - /* NaN, Infinite */ - if (eval_mode !== "math") { - return "BigFloat(" + a.toString() + ")"; - } else { - return a.toString(); - } - } else { - if (a == 0) { - if (1 / a < 0) - s = "-0"; - else - s = "0"; - } else { - if (radix == 16) { - var s; - if (a < 0) { - a = -a; - s = "-"; - } else { - s = ""; - } - s += "0x" + a.toString(16); - } else { - s = a.toString(); - } - } - if (typeof a === "bigfloat" && eval_mode !== "math") { - s += "l"; - } else if (eval_mode !== "std" && s.indexOf(".") < 0 && - ((radix == 16 && s.indexOf("p") < 0) || - (radix == 10 && s.indexOf("e") < 0))) { - /* add a decimal point so that the floating point type - is visible */ - s += ".0"; - } - return s; - } - } - - function bigint_to_string(a, radix) { - var s; - if (radix == 16) { - var s; - if (a < 0) { - a = -a; - s = "-"; - } else { - s = ""; - } - s += "0x" + a.toString(16); - } else { - s = a.toString(); - } - if (eval_mode === "std") - s += "n"; - return s; - } - - function print(a) { - var stack = []; - - function print_rec(a) { - var n, i, keys, key, type, s; - - type = typeof(a); - if (type === "object") { - if (a === null) { - std.puts(a); - } else if (stack.indexOf(a) >= 0) { - std.puts("[circular]"); - } else if (has_jscalc && (a instanceof Fraction || - a instanceof Complex || - a instanceof Mod || - a instanceof Polynomial || - a instanceof PolyMod || - a instanceof RationalFunction || - a instanceof Series)) { - std.puts(a.toString()); - } else { - stack.push(a); - if (Array.isArray(a)) { - n = a.length; - std.puts("[ "); - for(i = 0; i < n; i++) { - if (i !== 0) - std.puts(", "); - if (i in a) { - print_rec(a[i]); - } else { - std.puts(""); - } - if (i > 20) { - std.puts("..."); - break; - } - } - std.puts(" ]"); - } else if (Object.__getClass(a) === "RegExp") { - std.puts(a.toString()); - } else { - keys = Object.keys(a); - n = keys.length; - std.puts("{ "); - for(i = 0; i < n; i++) { - if (i !== 0) - std.puts(", "); - key = keys[i]; - std.puts(key, ": "); - print_rec(a[key]); - } - std.puts(" }"); - } - stack.pop(a); - } - } else if (type === "string") { - s = a.__quote(); - if (s.length > 79) - s = s.substring(0, 75) + "...\""; - std.puts(s); - } else if (type === "number") { - std.puts(number_to_string(a, hex_mode ? 16 : 10)); - } else if (type === "bigint") { - std.puts(bigint_to_string(a, hex_mode ? 16 : 10)); - } else if (type === "bigfloat") { - std.puts(bigfloat_to_string(a, hex_mode ? 16 : 10)); - } else if (type === "bigdecimal") { - std.puts(a.toString() + "m"); - } else if (type === "symbol") { - std.puts(String(a)); - } else if (type === "function") { - std.puts("function " + a.name + "()"); - } else { - std.puts(a); - } - } - print_rec(a); - } - - function extract_directive(a) { - var pos; - if (a[0] !== '\\') - return ""; - for (pos = 1; pos < a.length; pos++) { - if (!is_alpha(a[pos])) - break; - } - return a.substring(1, pos); - } - - /* return true if the string after cmd can be evaluted as JS */ - function handle_directive(cmd, expr) { - var param, prec1, expBits1; - - if (cmd === "h" || cmd === "?" || cmd == "help") { - help(); - } else if (cmd === "load") { - var filename = expr.substring(cmd.length + 1).trim(); - if (filename.lastIndexOf(".") <= filename.lastIndexOf("/")) - filename += ".js"; - std.loadScript(filename); - return false; - } else if (cmd === "x") { - hex_mode = true; - } else if (cmd === "d") { - hex_mode = false; - } else if (cmd === "t") { - show_time = !show_time; - } else if (has_bignum && cmd === "p") { - param = expr.substring(cmd.length + 1).trim().split(" "); - if (param.length === 1 && param[0] === "") { - std.puts("BigFloat precision=" + prec + " bits (~" + - Math.floor(prec / log2_10) + - " digits), exponent size=" + expBits + " bits\n"); - } else if (param[0] === "f16") { - prec = 11; - expBits = 5; - } else if (param[0] === "f32") { - prec = 24; - expBits = 8; - } else if (param[0] === "f64") { - prec = 53; - expBits = 11; - } else if (param[0] === "f128") { - prec = 113; - expBits = 15; - } else { - prec1 = parseInt(param[0]); - if (param.length >= 2) - expBits1 = parseInt(param[1]); - else - expBits1 = BigFloatEnv.expBitsMax; - if (Number.isNaN(prec1) || - prec1 < BigFloatEnv.precMin || - prec1 > BigFloatEnv.precMax) { - std.puts("Invalid precision\n"); - return false; - } - if (Number.isNaN(expBits1) || - expBits1 < BigFloatEnv.expBitsMin || - expBits1 > BigFloatEnv.expBitsMax) { - std.puts("Invalid exponent bits\n"); - return false; - } - prec = prec1; - expBits = expBits1; - } - return false; - } else if (has_bignum && cmd === "digits") { - param = expr.substring(cmd.length + 1).trim(); - prec1 = Math.ceil(parseFloat(param) * log2_10); - if (prec1 < BigFloatEnv.precMin || - prec1 > BigFloatEnv.precMax) { - std.puts("Invalid precision\n"); - return false; - } - prec = prec1; - expBits = BigFloatEnv.expBitsMax; - return false; - } else if (has_bignum && cmd === "mode") { - param = expr.substring(cmd.length + 1).trim(); - if (param === "") { - std.puts("Running mode=" + eval_mode + "\n"); - } else if (param === "std" || param === "math") { - eval_mode = param; - } else { - std.puts("Invalid mode\n"); - } - return false; - } else if (cmd === "clear") { - std.puts("\x1b[H\x1b[J"); - } else if (cmd === "q") { - std.exit(0); - } else if (has_jscalc && cmd === "a") { - algebraicMode = true; - } else if (has_jscalc && cmd === "n") { - algebraicMode = false; - } else { - std.puts("Unknown directive: " + cmd + "\n"); - return false; - } - return true; - } - - if (config_numcalc) { - /* called by the GUI */ - g.execCmd = function (cmd) { - switch(cmd) { - case "dec": - hex_mode = false; - break; - case "hex": - hex_mode = true; - break; - case "num": - algebraicMode = false; - break; - case "alg": - algebraicMode = true; - break; - } - } - } - - function help() { - function sel(n) { - return n ? "*": " "; - } - std.puts("\\h this help\n" + - "\\x " + sel(hex_mode) + "hexadecimal number display\n" + - "\\d " + sel(!hex_mode) + "decimal number display\n" + - "\\t " + sel(show_time) + "toggle timing display\n" + - "\\clear clear the terminal\n"); - if (has_jscalc) { - std.puts("\\a " + sel(algebraicMode) + "algebraic mode\n" + - "\\n " + sel(!algebraicMode) + "numeric mode\n"); - } - if (has_bignum) { - std.puts("\\p [m [e]] set the BigFloat precision to 'm' bits\n" + - "\\digits n set the BigFloat precision to 'ceil(n*log2(10))' bits\n"); - if (!has_jscalc) { - std.puts("\\mode [std|math] change the running mode (current = " + eval_mode + ")\n"); - } - } - if (!config_numcalc) { - std.puts("\\q exit\n"); - } - } - - function eval_and_print(expr) { - var result; - - try { - if (eval_mode === "math") - expr = '"use math"; void 0;' + expr; - var now = (new Date).getTime(); - /* eval as a script */ - result = std.evalScript(expr, { backtrace_barrier: true }); - eval_time = (new Date).getTime() - now; - std.puts(colors[styles.result]); - print(result); - std.puts("\n"); - std.puts(colors.none); - /* set the last result */ - g._ = result; - } catch (error) { - std.puts(colors[styles.error_msg]); - if (error instanceof Error) { - console.log(error); - if (error.stack) { - std.puts(error.stack); - } - } else { - std.puts("Throw: "); - console.log(error); - } - std.puts(colors.none); - } - } - - function cmd_start() { - if (!config_numcalc) { - if (has_jscalc) - std.puts('QJSCalc - Type "\\h" for help\n'); - else - std.puts('QuickJS - Type "\\h" for help\n'); - } - if (has_bignum) { - log2_10 = Math.log(10) / Math.log(2); - prec = 113; - expBits = 15; - if (has_jscalc) { - eval_mode = "math"; - /* XXX: numeric mode should always be the default ? */ - g.algebraicMode = config_numcalc; - } - } - - cmd_readline_start(); - } - - function cmd_readline_start() { - readline_start(dupstr(" ", level), readline_handle_cmd); - } - - function readline_handle_cmd(expr) { - handle_cmd(expr); - cmd_readline_start(); - } - - function handle_cmd(expr) { - var colorstate, cmd; - - if (expr === null) { - expr = ""; - return; - } - if (expr === "?") { - help(); - return; - } - cmd = extract_directive(expr); - if (cmd.length > 0) { - if (!handle_directive(cmd, expr)) - return; - expr = expr.substring(cmd.length + 1); - } - if (expr === "") - return; - - if (mexpr) - expr = mexpr + '\n' + expr; - colorstate = colorize_js(expr); - pstate = colorstate[0]; - level = colorstate[1]; - if (pstate) { - mexpr = expr; - return; - } - mexpr = ""; - - if (has_bignum) { - BigFloatEnv.setPrec(eval_and_print.bind(null, expr), - prec, expBits); - } else { - eval_and_print(expr); - } - level = 0; - - /* run the garbage collector after each command */ - std.gc(); - } - - function colorize_js(str) { - var i, c, start, n = str.length; - var style, state = "", level = 0; - var primary, can_regex = 1; - var r = []; - - function push_state(c) { state += c; } - function last_state(c) { return state.substring(state.length - 1); } - function pop_state(c) { - var c = last_state(); - state = state.substring(0, state.length - 1); - return c; - } - - function parse_block_comment() { - style = 'comment'; - push_state('/'); - for (i++; i < n - 1; i++) { - if (str[i] == '*' && str[i + 1] == '/') { - i += 2; - pop_state('/'); - break; - } - } - } - - function parse_line_comment() { - style = 'comment'; - for (i++; i < n; i++) { - if (str[i] == '\n') { - break; - } - } - } - - function parse_string(delim) { - style = 'string'; - push_state(delim); - while (i < n) { - c = str[i++]; - if (c == '\n') { - style = 'error'; - continue; - } - if (c == '\\') { - if (i >= n) - break; - i++; - } else - if (c == delim) { - pop_state(); - break; - } - } - } - - function parse_regex() { - style = 'regex'; - push_state('/'); - while (i < n) { - c = str[i++]; - if (c == '\n') { - style = 'error'; - continue; - } - if (c == '\\') { - if (i < n) { - i++; - } - continue; - } - if (last_state() == '[') { - if (c == ']') { - pop_state() - } - // ECMA 5: ignore '/' inside char classes - continue; - } - if (c == '[') { - push_state('['); - if (str[i] == '[' || str[i] == ']') - i++; - continue; - } - if (c == '/') { - pop_state(); - while (i < n && is_word(str[i])) - i++; - break; - } - } - } - - function parse_number() { - style = 'number'; - while (i < n && (is_word(str[i]) || (str[i] == '.' && (i == n - 1 || str[i + 1] != '.')))) { - i++; - } - } - - var js_keywords = "|" + - "break|case|catch|continue|debugger|default|delete|do|" + - "else|finally|for|function|if|in|instanceof|new|" + - "return|switch|this|throw|try|typeof|while|with|" + - "class|const|enum|import|export|extends|super|" + - "implements|interface|let|package|private|protected|" + - "public|static|yield|" + - "undefined|null|true|false|Infinity|NaN|" + - "eval|arguments|" + - "await|"; - - var js_no_regex = "|this|super|undefined|null|true|false|Infinity|NaN|arguments|"; - var js_types = "|void|var|"; - - function parse_identifier() { - can_regex = 1; - - while (i < n && is_word(str[i])) - i++; - - var w = '|' + str.substring(start, i) + '|'; - - if (js_keywords.indexOf(w) >= 0) { - style = 'keyword'; - if (js_no_regex.indexOf(w) >= 0) - can_regex = 0; - return; - } - - var i1 = i; - while (i1 < n && str[i1] == ' ') - i1++; - - if (i1 < n && str[i1] == '(') { - style = 'function'; - return; - } - - if (js_types.indexOf(w) >= 0) { - style = 'type'; - return; - } - - style = 'identifier'; - can_regex = 0; - } - - function set_style(from, to) { - while (r.length < from) - r.push('default'); - while (r.length < to) - r.push(style); - } - - for (i = 0; i < n;) { - style = null; - start = i; - switch (c = str[i++]) { - case ' ': - case '\t': - case '\r': - case '\n': - continue; - case '+': - case '-': - if (i < n && str[i] == c) { - i++; - continue; - } - can_regex = 1; - continue; - case '/': - if (i < n && str[i] == '*') { // block comment - parse_block_comment(); - break; - } - if (i < n && str[i] == '/') { // line comment - parse_line_comment(); - break; - } - if (can_regex) { - parse_regex(); - can_regex = 0; - break; - } - can_regex = 1; - continue; - case '\'': - case '\"': - case '`': - parse_string(c); - can_regex = 0; - break; - case '(': - case '[': - case '{': - can_regex = 1; - level++; - push_state(c); - continue; - case ')': - case ']': - case '}': - can_regex = 0; - if (level > 0 && is_balanced(last_state(), c)) { - level--; - pop_state(); - continue; - } - style = 'error'; - break; - default: - if (is_digit(c)) { - parse_number(); - can_regex = 0; - break; - } - if (is_word(c) || c == '$') { - parse_identifier(); - break; - } - can_regex = 1; - continue; - } - if (style) - set_style(start, i); - } - set_style(n, n); - return [ state, level, r ]; - } - - termInit(); - - cmd_start(); - -})(globalThis); diff --git a/third_party/quickjs/run-test262.c b/third_party/quickjs/run-test262.c deleted file mode 100644 index 86d3e7ef1..000000000 --- a/third_party/quickjs/run-test262.c +++ /dev/null @@ -1,2116 +0,0 @@ -/* - * ECMA Test 262 Runner for QuickJS - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/calls/calls.h" -#include "libc/calls/struct/stat.h" -#include "libc/calls/weirdtypes.h" -#include "libc/fmt/conv.h" -#include "libc/log/log.h" -#include "libc/mem/alg.h" -#include "libc/mem/mem.h" -#include "libc/runtime/runtime.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/clock.h" -#include "libc/stdio/ftw.h" -#include "third_party/quickjs/cutils.h" -#include "third_party/quickjs/list.h" -#include "third_party/quickjs/quickjs-libc.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - - -/* enable test262 thread support to test SharedArrayBuffer and Atomics */ -/* #define CONFIG_AGENT */ - -#define CMD_NAME "run-test262" - -typedef struct namelist_t { - char **array; - int count; - int size; - unsigned int sorted : 1; -} namelist_t; - -namelist_t test_list; -namelist_t exclude_list; -namelist_t exclude_dir_list; - -FILE *outfile; -enum test_mode_t { - TEST_DEFAULT_NOSTRICT, /* run tests as nostrict unless test is flagged as strictonly */ - TEST_DEFAULT_STRICT, /* run tests as strict unless test is flagged as nostrict */ - TEST_NOSTRICT, /* run tests as nostrict, skip strictonly tests */ - TEST_STRICT, /* run tests as strict, skip nostrict tests */ - TEST_ALL, /* run tests in both strict and nostrict, unless restricted by spec */ -} test_mode = TEST_DEFAULT_NOSTRICT; -int skip_async; -int skip_module; -int new_style; -int dump_memory; -int stats_count; -JSMemoryUsage stats_all, stats_avg, stats_min, stats_max; -char *stats_min_filename; -char *stats_max_filename; -int verbose; -char *harness_dir; -char *harness_exclude; -char *harness_features; -char *harness_skip_features; -char *error_filename; -char *error_file; -FILE *error_out; -char *report_filename; -int update_errors; -int test_count, test_failed, test_index, test_skipped, test_excluded; -int new_errors, changed_errors, fixed_errors; -int async_done; - -void warning(const char *, ...) __attribute__((__format__(__printf__, 1, 2))); -void fatal(int, const char *, ...) __attribute__((__format__(__printf__, 2, 3))); - -void warning(const char *fmt, ...) -{ - va_list ap; - - fflush(stdout); - fprintf(stderr, "%s: ", CMD_NAME); - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fputc('\n', stderr); -} - -void fatal(int errcode, const char *fmt, ...) -{ - va_list ap; - - fflush(stdout); - fprintf(stderr, "%s: ", CMD_NAME); - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fputc('\n', stderr); - - exit(errcode); -} - -void perror_exit(int errcode, const char *s) -{ - fflush(stdout); - fprintf(stderr, "%s: ", CMD_NAME); - perror(s); - exit(errcode); -} - -char *strdup_len(const char *str, int len) -{ - char *p = malloc(len + 1); - memcpy(p, str, len); - p[len] = '\0'; - return p; -} - -static inline int str_equal(const char *a, const char *b) { - return !strcmp(a, b); -} - -char *str_append(char **pp, const char *sep, const char *str) { - char *res, *p; - size_t len = 0; - p = *pp; - if (p) { - len = strlen(p) + strlen(sep); - } - res = malloc(len + strlen(str) + 1); - if (p) { - strcpy(res, p); - strcat(res, sep); - } - strcpy(res + len, str); - free(p); - return *pp = res; -} - -char *str_strip(char *p) -{ - size_t len = strlen(p); - while (len > 0 && isspace((unsigned char)p[len - 1])) - p[--len] = '\0'; - while (isspace((unsigned char)*p)) - p++; - return p; -} - -int has_prefix(const char *str, const char *prefix) -{ - return !strncmp(str, prefix, strlen(prefix)); -} - -char *skip_prefix(const char *str, const char *prefix) -{ - int i; - for (i = 0;; i++) { - if (prefix[i] == '\0') { /* skip the prefix */ - str += i; - break; - } - if (str[i] != prefix[i]) - break; - } - return (char *)str; -} - -char *get_basename(const char *filename) -{ - char *p; - - p = strrchr(filename, '/'); - if (!p) - return NULL; - return strdup_len(filename, p - filename); -} - -char *compose_path(const char *path, const char *name) -{ - int path_len, name_len; - char *d, *q; - - if (!path || path[0] == '\0' || *name == '/') { - d = strdup(name); - } else { - path_len = strlen(path); - name_len = strlen(name); - d = malloc(path_len + 1 + name_len + 1); - if (d) { - q = d; - memcpy(q, path, path_len); - q += path_len; - if (path[path_len - 1] != '/') - *q++ = '/'; - memcpy(q, name, name_len + 1); - } - } - return d; -} - -int namelist_cmp(const char *a, const char *b) -{ - /* compare strings in modified lexicographical order */ - for (;;) { - int ca = (unsigned char)*a++; - int cb = (unsigned char)*b++; - if (isdigit(ca) && isdigit(cb)) { - int na = ca - '0'; - int nb = cb - '0'; - while (isdigit(ca = (unsigned char)*a++)) - na = na * 10 + ca - '0'; - while (isdigit(cb = (unsigned char)*b++)) - nb = nb * 10 + cb - '0'; - if (na < nb) - return -1; - if (na > nb) - return +1; - } - if (ca < cb) - return -1; - if (ca > cb) - return +1; - if (ca == '\0') - return 0; - } -} - -int namelist_cmp_indirect(const void *a, const void *b) -{ - return namelist_cmp(*(const char **)a, *(const char **)b); -} - -void namelist_sort(namelist_t *lp) -{ - int i, count; - if (lp->count > 1) { - qsort(lp->array, lp->count, sizeof(*lp->array), namelist_cmp_indirect); - /* remove duplicates */ - for (count = i = 1; i < lp->count; i++) { - if (namelist_cmp(lp->array[count - 1], lp->array[i]) == 0) { - free(lp->array[i]); - } else { - lp->array[count++] = lp->array[i]; - } - } - lp->count = count; - } - lp->sorted = 1; -} - -int namelist_find(namelist_t *lp, const char *name) -{ - int a, b, m, cmp; - - if (!lp->sorted) { - namelist_sort(lp); - } - for (a = 0, b = lp->count; a < b;) { - m = a + (b - a) / 2; - cmp = namelist_cmp(lp->array[m], name); - if (cmp < 0) - a = m + 1; - else if (cmp > 0) - b = m; - else - return m; - } - return -1; -} - -void namelist_add(namelist_t *lp, const char *base, const char *name) -{ - char *s; - - s = compose_path(base, name); - if (!s) - goto fail; - if (lp->count == lp->size) { - size_t newsize = lp->size + (lp->size >> 1) + 4; - char **a = realloc(lp->array, sizeof(lp->array[0]) * newsize); - if (!a) - goto fail; - lp->array = a; - lp->size = newsize; - } - lp->array[lp->count] = s; - lp->count++; - return; -fail: - fatal(1, "allocation failure\n"); -} - -void namelist_load(namelist_t *lp, const char *filename) -{ - char buf[1024]; - char *base_name; - FILE *f; - - f = fopen(filename, "rb"); - if (!f) { - perror_exit(1, filename); - } - base_name = get_basename(filename); - - while (fgets(buf, sizeof(buf), f) != NULL) { - char *p = str_strip(buf); - if (*p == '#' || *p == ';' || *p == '\0') - continue; /* line comment */ - - namelist_add(lp, base_name, p); - } - free(base_name); - fclose(f); -} - -void namelist_add_from_error_file(namelist_t *lp, const char *file) -{ - const char *p, *p0; - char *pp; - - for (p = file; (p = strstr(p, ".js:")) != NULL; p++) { - for (p0 = p; p0 > file && p0[-1] != '\n'; p0--) - continue; - pp = strdup_len(p0, p + 3 - p0); - namelist_add(lp, NULL, pp); - free(pp); - } -} - -void namelist_free(namelist_t *lp) -{ - while (lp->count > 0) { - free(lp->array[--lp->count]); - } - free(lp->array); - lp->array = NULL; - lp->size = 0; -} - -static int add_test_file(const char *filename, const struct stat *ptr, int flag) -{ - namelist_t *lp = &test_list; - if (has_suffix(filename, ".js") && !has_suffix(filename, "_FIXTURE.js")) - namelist_add(lp, NULL, filename); - return 0; -} - -/* find js files from the directory tree and sort the list */ -static void enumerate_tests(const char *path) -{ - namelist_t *lp = &test_list; - int start = lp->count; - ftw(path, add_test_file, 100); - qsort(lp->array + start, lp->count - start, sizeof(*lp->array), - namelist_cmp_indirect); -} - -static JSValue js_print(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int i; - const char *str; - - if (outfile) { - for (i = 0; i < argc; i++) { - if (i != 0) - fputc(' ', outfile); - str = JS_ToCString(ctx, argv[i]); - if (!str) - return JS_EXCEPTION; - if (!strcmp(str, "Test262:AsyncTestComplete")) { - async_done++; - } else if (strstart(str, "Test262:AsyncTestFailure", NULL)) { - async_done = 2; /* force an error */ - } - fputs(str, outfile); - JS_FreeCString(ctx, str); - } - fputc('\n', outfile); - } - return JS_UNDEFINED; -} - -static JSValue js_detachArrayBuffer(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv) -{ - JS_DetachArrayBuffer(ctx, argv[0]); - return JS_UNDEFINED; -} - -static JSValue js_evalScript(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv) -{ - const char *str; - size_t len; - JSValue ret; - str = JS_ToCStringLen(ctx, &len, argv[0]); - if (!str) - return JS_EXCEPTION; - ret = JS_Eval(ctx, str, len, "", JS_EVAL_TYPE_GLOBAL); - JS_FreeCString(ctx, str); - return ret; -} - -static JSValue add_helpers1(JSContext *ctx); - -static int64_t get_clock_ms(void) -{ - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (uint64_t)ts.tv_sec * 1000 + (ts.tv_nsec / 1000000); -} - -#ifdef CONFIG_AGENT - -typedef struct { - struct list_head link; - pthread_t tid; - char *script; - JSValue broadcast_func; - BOOL broadcast_pending; - JSValue broadcast_sab; /* in the main context */ - uint8_t *broadcast_sab_buf; - size_t broadcast_sab_size; - int32_t broadcast_val; -} Test262Agent; - -typedef struct { - struct list_head link; - char *str; -} AgentReport; - -static void add_helpers(JSContext *ctx); - -static pthread_mutex_t agent_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t agent_cond = PTHREAD_COND_INITIALIZER; -/* list of Test262Agent.link */ -static struct list_head agent_list = LIST_HEAD_INIT(agent_list); - -static pthread_mutex_t report_mutex = PTHREAD_MUTEX_INITIALIZER; -/* list of AgentReport.link */ -static struct list_head report_list = LIST_HEAD_INIT(report_list); - -static void *agent_start(void *arg) -{ - Test262Agent *agent = arg; - JSRuntime *rt; - JSContext *ctx; - JSValue ret_val; - int ret; - - rt = JS_NewRuntime(); - if (rt == NULL) { - fatal(1, "JS_NewRuntime failure"); - } - ctx = JS_NewContext(rt); - if (ctx == NULL) { - JS_FreeRuntime(rt); - fatal(1, "JS_NewContext failure"); - } - JS_SetContextOpaque(ctx, agent); - JS_SetRuntimeInfo(rt, "agent"); - JS_SetCanBlock(rt, TRUE); - - add_helpers(ctx); - ret_val = JS_Eval(ctx, agent->script, strlen(agent->script), - "", JS_EVAL_TYPE_GLOBAL); - free(agent->script); - agent->script = NULL; - if (JS_IsException(ret_val)) - js_std_dump_error(ctx); - JS_FreeValue(ctx, ret_val); - - for(;;) { - JSContext *ctx1; - ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); - if (ret < 0) { - js_std_dump_error(ctx); - break; - } else if (ret == 0) { - if (JS_IsUndefined(agent->broadcast_func)) { - break; - } else { - JSValue args[2]; - - pthread_mutex_lock(&agent_mutex); - while (!agent->broadcast_pending) { - pthread_cond_wait(&agent_cond, &agent_mutex); - } - - agent->broadcast_pending = FALSE; - pthread_cond_signal(&agent_cond); - - pthread_mutex_unlock(&agent_mutex); - - args[0] = JS_NewArrayBuffer(ctx, agent->broadcast_sab_buf, - agent->broadcast_sab_size, - NULL, NULL, TRUE); - args[1] = JS_NewInt32(ctx, agent->broadcast_val); - ret_val = JS_Call(ctx, agent->broadcast_func, JS_UNDEFINED, - 2, (JSValueConst *)args); - JS_FreeValue(ctx, args[0]); - JS_FreeValue(ctx, args[1]); - if (JS_IsException(ret_val)) - js_std_dump_error(ctx); - JS_FreeValue(ctx, ret_val); - JS_FreeValue(ctx, agent->broadcast_func); - agent->broadcast_func = JS_UNDEFINED; - } - } - } - JS_FreeValue(ctx, agent->broadcast_func); - - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - return NULL; -} - -static JSValue js_agent_start(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv) -{ - const char *script; - Test262Agent *agent; - - if (JS_GetContextOpaque(ctx) != NULL) - return JS_ThrowTypeError(ctx, "cannot be called inside an agent"); - - script = JS_ToCString(ctx, argv[0]); - if (!script) - return JS_EXCEPTION; - agent = malloc(sizeof(*agent)); - bzero(agent, sizeof(*agent)); - agent->broadcast_func = JS_UNDEFINED; - agent->broadcast_sab = JS_UNDEFINED; - agent->script = strdup(script); - JS_FreeCString(ctx, script); - list_add_tail(&agent->link, &agent_list); - pthread_create(&agent->tid, NULL, agent_start, agent); - return JS_UNDEFINED; -} - -static void js_agent_free(JSContext *ctx) -{ - struct list_head *el, *el1; - Test262Agent *agent; - - list_for_each_safe(el, el1, &agent_list) { - agent = list_entry(el, Test262Agent, link); - pthread_join(agent->tid, NULL); - JS_FreeValue(ctx, agent->broadcast_sab); - list_del(&agent->link); - free(agent); - } -} - -static JSValue js_agent_leaving(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv) -{ - Test262Agent *agent = JS_GetContextOpaque(ctx); - if (!agent) - return JS_ThrowTypeError(ctx, "must be called inside an agent"); - /* nothing to do */ - return JS_UNDEFINED; -} - -static BOOL is_broadcast_pending(void) -{ - struct list_head *el; - Test262Agent *agent; - list_for_each(el, &agent_list) { - agent = list_entry(el, Test262Agent, link); - if (agent->broadcast_pending) - return TRUE; - } - return FALSE; -} - -static JSValue js_agent_broadcast(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv) -{ - JSValueConst sab = argv[0]; - struct list_head *el; - Test262Agent *agent; - uint8_t *buf; - size_t buf_size; - int32_t val; - - if (JS_GetContextOpaque(ctx) != NULL) - return JS_ThrowTypeError(ctx, "cannot be called inside an agent"); - - buf = JS_GetArrayBuffer(ctx, &buf_size, sab); - if (!buf) - return JS_EXCEPTION; - if (JS_ToInt32(ctx, &val, argv[1])) - return JS_EXCEPTION; - - /* broadcast the values and wait until all agents have started - calling their callbacks */ - pthread_mutex_lock(&agent_mutex); - list_for_each(el, &agent_list) { - agent = list_entry(el, Test262Agent, link); - agent->broadcast_pending = TRUE; - /* the shared array buffer is used by the thread, so increment - its refcount */ - agent->broadcast_sab = JS_DupValue(ctx, sab); - agent->broadcast_sab_buf = buf; - agent->broadcast_sab_size = buf_size; - agent->broadcast_val = val; - } - pthread_cond_broadcast(&agent_cond); - - while (is_broadcast_pending()) { - pthread_cond_wait(&agent_cond, &agent_mutex); - } - pthread_mutex_unlock(&agent_mutex); - return JS_UNDEFINED; -} - -static JSValue js_agent_receiveBroadcast(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv) -{ - Test262Agent *agent = JS_GetContextOpaque(ctx); - if (!agent) - return JS_ThrowTypeError(ctx, "must be called inside an agent"); - if (!JS_IsFunction(ctx, argv[0])) - return JS_ThrowTypeError(ctx, "expecting function"); - JS_FreeValue(ctx, agent->broadcast_func); - agent->broadcast_func = JS_DupValue(ctx, argv[0]); - return JS_UNDEFINED; -} - -static JSValue js_agent_sleep(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv) -{ - uint32_t duration; - if (JS_ToUint32(ctx, &duration, argv[0])) - return JS_EXCEPTION; - usleep(duration * 1000); - return JS_UNDEFINED; -} - -static JSValue js_agent_monotonicNow(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv) -{ - return JS_NewInt64(ctx, get_clock_ms()); -} - -static JSValue js_agent_getReport(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv) -{ - AgentReport *rep; - JSValue ret; - - pthread_mutex_lock(&report_mutex); - if (list_empty(&report_list)) { - rep = NULL; - } else { - rep = list_entry(report_list.next, AgentReport, link); - list_del(&rep->link); - } - pthread_mutex_unlock(&report_mutex); - if (rep) { - ret = JS_NewString(ctx, rep->str); - free(rep->str); - free(rep); - } else { - ret = JS_NULL; - } - return ret; -} - -static JSValue js_agent_report(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv) -{ - const char *str; - AgentReport *rep; - - str = JS_ToCString(ctx, argv[0]); - if (!str) - return JS_EXCEPTION; - rep = malloc(sizeof(*rep)); - rep->str = strdup(str); - JS_FreeCString(ctx, str); - - pthread_mutex_lock(&report_mutex); - list_add_tail(&rep->link, &report_list); - pthread_mutex_unlock(&report_mutex); - return JS_UNDEFINED; -} - -static const JSCFunctionListEntry js_agent_funcs[] = { - /* only in main */ - JS_CFUNC_DEF("start", 1, js_agent_start ), - JS_CFUNC_DEF("getReport", 0, js_agent_getReport ), - JS_CFUNC_DEF("broadcast", 2, js_agent_broadcast ), - /* only in agent */ - JS_CFUNC_DEF("report", 1, js_agent_report ), - JS_CFUNC_DEF("leaving", 0, js_agent_leaving ), - JS_CFUNC_DEF("receiveBroadcast", 1, js_agent_receiveBroadcast ), - /* in both */ - JS_CFUNC_DEF("sleep", 1, js_agent_sleep ), - JS_CFUNC_DEF("monotonicNow", 0, js_agent_monotonicNow ), -}; - -static JSValue js_new_agent(JSContext *ctx) -{ - JSValue agent; - agent = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, agent, js_agent_funcs, - countof(js_agent_funcs)); - return agent; -} -#endif - -static JSValue js_createRealm(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv) -{ - JSContext *ctx1; - JSValue ret; - - ctx1 = JS_NewContext(JS_GetRuntime(ctx)); - if (!ctx1) - return JS_ThrowOutOfMemory(ctx); - ret = add_helpers1(ctx1); - /* ctx1 has a refcount so it stays alive */ - JS_FreeContext(ctx1); - return ret; -} - -static JSValue js_IsHTMLDDA(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv) -{ - return JS_NULL; -} - -static JSValue add_helpers1(JSContext *ctx) -{ - JSValue global_obj; - JSValue obj262, obj; - - global_obj = JS_GetGlobalObject(ctx); - - JS_SetPropertyStr(ctx, global_obj, "print", - JS_NewCFunction(ctx, js_print, "print", 1)); - - /* $262 special object used by the tests */ - obj262 = JS_NewObject(ctx); - JS_SetPropertyStr(ctx, obj262, "detachArrayBuffer", - JS_NewCFunction(ctx, js_detachArrayBuffer, - "detachArrayBuffer", 1)); - JS_SetPropertyStr(ctx, obj262, "evalScript", - JS_NewCFunction(ctx, js_evalScript, - "evalScript", 1)); - JS_SetPropertyStr(ctx, obj262, "codePointRange", - JS_NewCFunction(ctx, js_string_codePointRange, - "codePointRange", 2)); -#ifdef CONFIG_AGENT - JS_SetPropertyStr(ctx, obj262, "agent", js_new_agent(ctx)); -#endif - - JS_SetPropertyStr(ctx, obj262, "global", - JS_DupValue(ctx, global_obj)); - JS_SetPropertyStr(ctx, obj262, "createRealm", - JS_NewCFunction(ctx, js_createRealm, - "createRealm", 0)); - obj = JS_NewCFunction(ctx, js_IsHTMLDDA, "IsHTMLDDA", 0); - JS_SetIsHTMLDDA(ctx, obj); - JS_SetPropertyStr(ctx, obj262, "IsHTMLDDA", obj); - - JS_SetPropertyStr(ctx, global_obj, "$262", JS_DupValue(ctx, obj262)); - - JS_FreeValue(ctx, global_obj); - return obj262; -} - -static void add_helpers(JSContext *ctx) -{ - JS_FreeValue(ctx, add_helpers1(ctx)); -} - -static char *load_file(const char *filename, size_t *lenp) -{ - char *buf; - size_t buf_len; - buf = (char *)js_load_file(NULL, &buf_len, filename); - if (!buf) - perror_exit(1, filename); - if (lenp) - *lenp = buf_len; - return buf; -} - -static JSModuleDef *js_module_loader_test(JSContext *ctx, - const char *module_name, void *opaque) -{ - size_t buf_len; - uint8_t *buf; - JSModuleDef *m; - JSValue func_val; - - buf = js_load_file(ctx, &buf_len, module_name); - if (!buf) { - JS_ThrowReferenceError(ctx, "could not load module filename '%s'", - module_name); - return NULL; - } - - /* compile the module */ - func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, - JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); - js_free(ctx, buf); - if (JS_IsException(func_val)) - return NULL; - /* the module is already referenced, so we must free it */ - m = JS_VALUE_GET_PTR(func_val); - JS_FreeValue(ctx, func_val); - return m; -} - -int is_line_sep(char c) -{ - return (c == '\0' || c == '\n' || c == '\r'); -} - -char *find_line(const char *str, const char *line) -{ - if (str) { - const char *p; - int len = strlen(line); - for (p = str; (p = strstr(p, line)) != NULL; p += len + 1) { - if ((p == str || is_line_sep(p[-1])) && is_line_sep(p[len])) - return (char *)p; - } - } - return NULL; -} - -int is_word_sep(char c) -{ - return (c == '\0' || isspace((unsigned char)c) || c == ','); -} - -char *find_word(const char *str, const char *word) -{ - const char *p; - int len = strlen(word); - if (str && len) { - for (p = str; (p = strstr(p, word)) != NULL; p += len) { - if ((p == str || is_word_sep(p[-1])) && is_word_sep(p[len])) - return (char *)p; - } - } - return NULL; -} - -/* handle exclude directories */ -void update_exclude_dirs(void) -{ - namelist_t *lp = &test_list; - namelist_t *ep = &exclude_list; - namelist_t *dp = &exclude_dir_list; - char *name; - int i, j, count; - - /* split directpries from exclude_list */ - for (count = i = 0; i < ep->count; i++) { - name = ep->array[i]; - if (has_suffix(name, "/")) { - namelist_add(dp, NULL, name); - free(name); - } else { - ep->array[count++] = name; - } - } - ep->count = count; - - namelist_sort(dp); - - /* filter out excluded directories */ - for (count = i = 0; i < lp->count; i++) { - name = lp->array[i]; - for (j = 0; j < dp->count; j++) { - if (has_prefix(name, dp->array[j])) { - test_excluded++; - free(name); - name = NULL; - break; - } - } - if (name) { - lp->array[count++] = name; - } - } - lp->count = count; -} - -void load_config(const char *filename) -{ - char buf[1024]; - FILE *f; - char *base_name; - enum { - SECTION_NONE = 0, - SECTION_CONFIG, - SECTION_EXCLUDE, - SECTION_FEATURES, - SECTION_TESTS, - } section = SECTION_NONE; - int lineno = 0; - - f = fopen(filename, "rb"); - if (!f) { - perror_exit(1, filename); - } - /* base_name = get_basename(filename); */ - base_name = strdup(""); - - while (fgets(buf, sizeof(buf), f) != NULL) { - char *p, *q; - lineno++; - p = str_strip(buf); - if (*p == '#' || *p == ';' || *p == '\0') - continue; /* line comment */ - - if (*p == "[]"[0]) { - /* new section */ - p++; - p[strcspn(p, "]")] = '\0'; - if (str_equal(p, "config")) - section = SECTION_CONFIG; - else if (str_equal(p, "exclude")) - section = SECTION_EXCLUDE; - else if (str_equal(p, "features")) - section = SECTION_FEATURES; - else if (str_equal(p, "tests")) - section = SECTION_TESTS; - else - section = SECTION_NONE; - continue; - } - q = strchr(p, '='); - if (q) { - /* setting: name=value */ - *q++ = '\0'; - q = str_strip(q); - } - switch (section) { - case SECTION_CONFIG: - if (!q) { - printf("%s:%d: syntax error\n", filename, lineno); - continue; - } - if (str_equal(p, "style")) { - new_style = str_equal(q, "new"); - continue; - } - if (str_equal(p, "testdir")) { - char *testdir = compose_path(base_name, q); - enumerate_tests(testdir); - free(testdir); - continue; - } - if (str_equal(p, "harnessdir")) { - harness_dir = compose_path(base_name, q); - continue; - } - if (str_equal(p, "harnessexclude")) { - str_append(&harness_exclude, " ", q); - continue; - } - if (str_equal(p, "features")) { - str_append(&harness_features, " ", q); - continue; - } - if (str_equal(p, "skip-features")) { - str_append(&harness_skip_features, " ", q); - continue; - } - if (str_equal(p, "mode")) { - if (str_equal(q, "default") || str_equal(q, "default-nostrict")) - test_mode = TEST_DEFAULT_NOSTRICT; - else if (str_equal(q, "default-strict")) - test_mode = TEST_DEFAULT_STRICT; - else if (str_equal(q, "nostrict")) - test_mode = TEST_NOSTRICT; - else if (str_equal(q, "strict")) - test_mode = TEST_STRICT; - else if (str_equal(q, "all") || str_equal(q, "both")) - test_mode = TEST_ALL; - else - fatal(2, "unknown test mode: %s", q); - continue; - } - if (str_equal(p, "strict")) { - if (str_equal(q, "skip") || str_equal(q, "no")) - test_mode = TEST_NOSTRICT; - continue; - } - if (str_equal(p, "nostrict")) { - if (str_equal(q, "skip") || str_equal(q, "no")) - test_mode = TEST_STRICT; - continue; - } - if (str_equal(p, "async")) { - skip_async = !str_equal(q, "yes"); - continue; - } - if (str_equal(p, "module")) { - skip_module = !str_equal(q, "yes"); - continue; - } - if (str_equal(p, "verbose")) { - verbose = str_equal(q, "yes"); - continue; - } - if (str_equal(p, "errorfile")) { - error_filename = compose_path(base_name, q); - continue; - } - if (str_equal(p, "excludefile")) { - char *path = compose_path(base_name, q); - namelist_load(&exclude_list, path); - free(path); - continue; - } - if (str_equal(p, "reportfile")) { - report_filename = compose_path(base_name, q); - continue; - } - case SECTION_EXCLUDE: - namelist_add(&exclude_list, base_name, p); - break; - case SECTION_FEATURES: - if (!q || str_equal(q, "yes")) - str_append(&harness_features, " ", p); - else - str_append(&harness_skip_features, " ", p); - break; - case SECTION_TESTS: - namelist_add(&test_list, base_name, p); - break; - default: - /* ignore settings in other sections */ - break; - } - } - fclose(f); - free(base_name); -} - -char *find_error(const char *filename, int *pline, int is_strict) -{ - if (error_file) { - size_t len = strlen(filename); - const char *p, *q, *r; - int line; - - for (p = error_file; (p = strstr(p, filename)) != NULL; p += len) { - if ((p == error_file || p[-1] == '\n' || p[-1] == '(') && p[len] == ':') { - q = p + len; - line = 1; - if (*q == ':') { - line = strtol(q + 1, (char**)&q, 10); - if (*q == ':') - q++; - } - while (*q == ' ') { - q++; - } - /* check strict mode indicator */ - if (!strstart(q, "strict mode: ", &q) != !is_strict) - continue; - r = q = skip_prefix(q, "unexpected error: "); - r += strcspn(r, "\n"); - while (r[0] == '\n' && r[1] && strncmp(r + 1, filename, 8)) { - r++; - r += strcspn(r, "\n"); - } - if (pline) - *pline = line; - return strdup_len(q, r - q); - } - } - } - return NULL; -} - -int skip_comments(const char *str, int line, int *pline) -{ - const char *p; - int c; - - p = str; - while ((c = (unsigned char)*p++) != '\0') { - if (isspace(c)) { - if (c == '\n') - line++; - continue; - } - if (c == '/' && *p == '/') { - while (*++p && *p != '\n') - continue; - continue; - } - if (c == '/' && *p == '*') { - for (p += 1; *p; p++) { - if (*p == '\n') { - line++; - continue; - } - if (*p == '*' && p[1] == '/') { - p += 2; - break; - } - } - continue; - } - break; - } - if (pline) - *pline = line; - - return p - str; -} - -int longest_match(const char *str, const char *find, int pos, int *ppos, int line, int *pline) -{ - int len, maxlen; - - maxlen = 0; - - if (*find) { - const char *p; - for (p = str + pos; *p; p++) { - if (*p == *find) { - for (len = 1; p[len] && p[len] == find[len]; len++) - continue; - if (len > maxlen) { - maxlen = len; - if (ppos) - *ppos = p - str; - if (pline) - *pline = line; - if (!find[len]) - break; - } - } - if (*p == '\n') - line++; - } - } - return maxlen; -} - -static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len, - const char *filename, int is_test, int is_negative, - const char *error_type, FILE *outfile, int eval_flags, - int is_async) -{ - JSValue res_val, exception_val; - int ret, error_line, pos, pos_line; - BOOL is_error, has_error_line; - const char *error_name; - - pos = skip_comments(buf, 1, &pos_line); - error_line = pos_line; - has_error_line = FALSE; - exception_val = JS_UNDEFINED; - error_name = NULL; - - async_done = 0; /* counter of "Test262:AsyncTestComplete" messages */ - - res_val = JS_Eval(ctx, buf, buf_len, filename, eval_flags); - - if (is_async && !JS_IsException(res_val)) { - JS_FreeValue(ctx, res_val); - for(;;) { - JSContext *ctx1; - ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); - if (ret < 0) { - res_val = JS_EXCEPTION; - break; - } else if (ret == 0) { - /* test if the test called $DONE() once */ - if (async_done != 1) { - res_val = JS_ThrowTypeError(ctx, "$DONE() not called"); - } else { - res_val = JS_UNDEFINED; - } - break; - } - } - } - - if (JS_IsException(res_val)) { - exception_val = JS_GetException(ctx); - is_error = JS_IsError(ctx, exception_val); - /* XXX: should get the filename and line number */ - if (outfile) { - if (!is_error) - fprintf(outfile, "%sThrow: ", (eval_flags & JS_EVAL_FLAG_STRICT) ? - "strict mode: " : ""); - js_print(ctx, JS_NULL, 1, &exception_val); - } - if (is_error) { - JSValue name, stack; - const char *stack_str; - - name = JS_GetPropertyStr(ctx, exception_val, "name"); - error_name = JS_ToCString(ctx, name); - stack = JS_GetPropertyStr(ctx, exception_val, "stack"); - if (!JS_IsUndefined(stack)) { - stack_str = JS_ToCString(ctx, stack); - if (stack_str) { - const char *p; - int len; - - if (outfile) - fprintf(outfile, "%s", stack_str); - - len = strlen(filename); - p = strstr(stack_str, filename); - if (p != NULL && p[len] == ':') { - error_line = atoi(p + len + 1); - has_error_line = TRUE; - } - JS_FreeCString(ctx, stack_str); - } - } - JS_FreeValue(ctx, stack); - JS_FreeValue(ctx, name); - } - if (is_negative) { - ret = 0; - if (error_type) { - char *error_class; - const char *msg; - - msg = JS_ToCString(ctx, exception_val); - error_class = strdup_len(msg, strcspn(msg, ":")); - if (!str_equal(error_class, error_type)) - ret = -1; - free(error_class); - JS_FreeCString(ctx, msg); - } - } else { - ret = -1; - } - } else { - if (is_negative) - ret = -1; - else - ret = 0; - } - - if (verbose && is_test) { - JSValue msg_val = JS_UNDEFINED; - const char *msg = NULL; - int s_line; - char *s = find_error(filename, &s_line, eval_flags & JS_EVAL_FLAG_STRICT); - const char *strict_mode = (eval_flags & JS_EVAL_FLAG_STRICT) ? "strict mode: " : ""; - - if (!JS_IsUndefined(exception_val)) { - msg_val = JS_ToString(ctx, exception_val); - msg = JS_ToCString(ctx, msg_val); - } - if (is_negative) { // expect error - if (ret == 0) { - if (msg && s && - (str_equal(s, "expected error") || - strstart(s, "unexpected error type:", NULL) || - str_equal(s, msg))) { // did not have error yet - if (!has_error_line) { - longest_match(buf, msg, pos, &pos, pos_line, &error_line); - } - printf("%s:%d: %sOK, now has error %s\n", - filename, error_line, strict_mode, msg); - fixed_errors++; - } - } else { - if (!s) { // not yet reported - if (msg) { - fprintf(error_out, "%s:%d: %sunexpected error type: %s\n", - filename, error_line, strict_mode, msg); - } else { - fprintf(error_out, "%s:%d: %sexpected error\n", - filename, error_line, strict_mode); - } - new_errors++; - } - } - } else { // should not have error - if (msg) { - if (!s || !str_equal(s, msg)) { - if (!has_error_line) { - char *p = skip_prefix(msg, "Test262 Error: "); - if (strstr(p, "Test case returned non-true value!")) { - longest_match(buf, "runTestCase", pos, &pos, pos_line, &error_line); - } else { - longest_match(buf, p, pos, &pos, pos_line, &error_line); - } - } - fprintf(error_out, "%s:%d: %s%s%s\n", filename, error_line, strict_mode, - error_file ? "unexpected error: " : "", msg); - - if (s && (!str_equal(s, msg) || error_line != s_line)) { - printf("%s:%d: %sprevious error: %s\n", filename, s_line, strict_mode, s); - changed_errors++; - } else { - new_errors++; - } - } - } else { - if (s) { - printf("%s:%d: %sOK, fixed error: %s\n", filename, s_line, strict_mode, s); - fixed_errors++; - } - } - } - JS_FreeValue(ctx, msg_val); - JS_FreeCString(ctx, msg); - free(s); - } - JS_FreeCString(ctx, error_name); - JS_FreeValue(ctx, exception_val); - JS_FreeValue(ctx, res_val); - return ret; -} - -static int eval_file(JSContext *ctx, const char *base, const char *p, - int eval_flags) -{ - char *buf; - size_t buf_len; - char *filename = compose_path(base, p); - - buf = load_file(filename, &buf_len); - if (!buf) { - warning("cannot load %s", filename); - goto fail; - } - if (eval_buf(ctx, buf, buf_len, filename, FALSE, FALSE, NULL, stderr, - eval_flags, FALSE)) { - warning("error evaluating %s", filename); - goto fail; - } - free(buf); - free(filename); - return 0; - -fail: - free(buf); - free(filename); - return 1; -} - -char *extract_desc(const char *buf, char style) -{ - const char *p, *desc_start; - char *desc; - int len; - - p = buf; - while (*p != '\0') { - if (p[0] == '/' && p[1] == '*' && p[2] == style && p[3] != '/') { - p += 3; - desc_start = p; - while (*p != '\0' && (p[0] != '*' || p[1] != '/')) - p++; - if (*p == '\0') { - warning("Expecting end of desc comment"); - return NULL; - } - len = p - desc_start; - desc = malloc(len + 1); - memcpy(desc, desc_start, len); - desc[len] = '\0'; - return desc; - } else { - p++; - } - } - return NULL; -} - -static char *find_tag(char *desc, const char *tag, int *state) -{ - char *p; - p = strstr(desc, tag); - if (p) { - p += strlen(tag); - *state = 0; - } - return p; -} - -static char *get_option(char **pp, int *state) -{ - char *p, *p0, *option = NULL; - if (*pp) { - for (p = *pp;; p++) { - switch (*p) { - case '[': - *state += 1; - continue; - case ']': - *state -= 1; - if (*state > 0) - continue; - p = NULL; - break; - case ' ': - case '\t': - case '\r': - case ',': - case '-': - continue; - case '\n': - if (*state > 0 || p[1] == ' ') - continue; - p = NULL; - break; - case '\0': - p = NULL; - break; - default: - p0 = p; - p += strcspn(p0, " \t\r\n,]"); - option = strdup_len(p0, p - p0); - break; - } - break; - } - *pp = p; - } - return option; -} - -void update_stats(JSRuntime *rt, const char *filename) { - JSMemoryUsage stats; - JS_ComputeMemoryUsage(rt, &stats); - if (stats_count++ == 0) { - stats_avg = stats_all = stats_min = stats_max = stats; - stats_min_filename = strdup(filename); - stats_max_filename = strdup(filename); - } else { - if (stats_max.malloc_size < stats.malloc_size) { - stats_max = stats; - free(stats_max_filename); - stats_max_filename = strdup(filename); - } - if (stats_min.malloc_size > stats.malloc_size) { - stats_min = stats; - free(stats_min_filename); - stats_min_filename = strdup(filename); - } - -#define update(f) stats_avg.f = (stats_all.f += stats.f) / stats_count - update(malloc_count); - update(malloc_size); - update(memory_used_count); - update(memory_used_size); - update(atom_count); - update(atom_size); - update(str_count); - update(str_size); - update(obj_count); - update(obj_size); - update(prop_count); - update(prop_size); - update(shape_count); - update(shape_size); - update(js_func_count); - update(js_func_size); - update(js_func_code_size); - update(js_func_pc2line_count); - update(js_func_pc2line_size); - update(c_func_count); - update(array_count); - update(fast_array_count); - update(fast_array_elements); - } -#undef update -} - -int run_test_buf(const char *filename, char *harness, namelist_t *ip, - char *buf, size_t buf_len, const char* error_type, - int eval_flags, BOOL is_negative, BOOL is_async, - BOOL can_block) -{ - JSRuntime *rt; - JSContext *ctx; - int i, ret; - - rt = JS_NewRuntime(); - if (rt == NULL) { - fatal(1, "JS_NewRuntime failure"); - } - ctx = JS_NewContext(rt); - if (ctx == NULL) { - JS_FreeRuntime(rt); - fatal(1, "JS_NewContext failure"); - } - JS_SetRuntimeInfo(rt, filename); - - JS_SetCanBlock(rt, can_block); - - /* loader for ES6 modules */ - JS_SetModuleLoaderFunc(rt, NULL, js_module_loader_test, NULL); - - add_helpers(ctx); - - for (i = 0; i < ip->count; i++) { - if (eval_file(ctx, harness, ip->array[i], - JS_EVAL_TYPE_GLOBAL | JS_EVAL_FLAG_STRIP)) { - fatal(1, "error including %s for %s", ip->array[i], filename); - } - } - - ret = eval_buf(ctx, buf, buf_len, filename, TRUE, is_negative, - error_type, outfile, eval_flags, is_async); - ret = (ret != 0); - - if (dump_memory) { - update_stats(rt, filename); - } -#ifdef CONFIG_AGENT - js_agent_free(ctx); -#endif - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - - test_count++; - if (ret) { - test_failed++; - if (outfile) { - /* do not output a failure number to minimize diff */ - fprintf(outfile, " FAILED\n"); - } - } - return ret; -} - -int run_test(const char *filename, int index) -{ - char harnessbuf[1024]; - char *harness; - char *buf; - size_t buf_len; - char *desc, *p; - char *error_type; - int ret, eval_flags, use_strict, use_nostrict; - BOOL is_negative, is_nostrict, is_onlystrict, is_async, is_module, skip; - BOOL can_block; - namelist_t include_list = { 0 }, *ip = &include_list; - - is_nostrict = is_onlystrict = is_negative = is_async = is_module = skip = FALSE; - can_block = TRUE; - error_type = NULL; - buf = load_file(filename, &buf_len); - - harness = harness_dir; - - if (new_style) { - if (!harness) { - p = strstr(filename, "test/"); - if (p) { - snprintf(harnessbuf, sizeof(harnessbuf), "%.*s%s", - (int)(p - filename), filename, "harness"); - } - harness = harnessbuf; - } - namelist_add(ip, NULL, "sta.js"); - namelist_add(ip, NULL, "assert.js"); - /* extract the YAML frontmatter */ - desc = extract_desc(buf, '-'); - if (desc) { - char *ifile, *option; - int state; - p = find_tag(desc, "includes:", &state); - if (p) { - while ((ifile = get_option(&p, &state)) != NULL) { - // skip unsupported harness files - if (find_word(harness_exclude, ifile)) { - skip |= 1; - } else { - namelist_add(ip, NULL, ifile); - } - free(ifile); - } - } - p = find_tag(desc, "flags:", &state); - if (p) { - while ((option = get_option(&p, &state)) != NULL) { - if (str_equal(option, "noStrict") || - str_equal(option, "raw")) { - is_nostrict = TRUE; - skip |= (test_mode == TEST_STRICT); - } - else if (str_equal(option, "onlyStrict")) { - is_onlystrict = TRUE; - skip |= (test_mode == TEST_NOSTRICT); - } - else if (str_equal(option, "async")) { - is_async = TRUE; - skip |= skip_async; - } - else if (str_equal(option, "module")) { - is_module = TRUE; - skip |= skip_module; - } - else if (str_equal(option, "CanBlockIsFalse")) { - can_block = FALSE; - } - free(option); - } - } - p = find_tag(desc, "negative:", &state); - if (p) { - /* XXX: should extract the phase */ - char *q = find_tag(p, "type:", &state); - if (q) { - while (isspace(*q)) - q++; - error_type = strdup_len(q, strcspn(q, " \n")); - } - is_negative = TRUE; - } - p = find_tag(desc, "features:", &state); - if (p) { - while ((option = get_option(&p, &state)) != NULL) { - if (find_word(harness_features, option)) { - /* feature is enabled */ - } else if (find_word(harness_skip_features, option)) { - /* skip disabled feature */ - skip |= 1; - } else { - /* feature is not listed: skip and warn */ - printf("%s:%d: unknown feature: %s\n", filename, 1, option); - skip |= 1; - } - free(option); - } - } - free(desc); - } - if (is_async) - namelist_add(ip, NULL, "doneprintHandle.js"); - } else { - char *ifile; - - if (!harness) { - p = strstr(filename, "test/"); - if (p) { - snprintf(harnessbuf, sizeof(harnessbuf), "%.*s%s", - (int)(p - filename), filename, "test/harness"); - } else { - strcpy(harnessbuf, ""); /* XXX */ - } - harness = harnessbuf; - } - - namelist_add(ip, NULL, "sta.js"); - - /* include extra harness files */ - for (p = buf; (p = strstr(p, "$INCLUDE(\"")) != NULL; p++) { - p += 10; - ifile = strdup_len(p, strcspn(p, "\"")); - // skip unsupported harness files - if (find_word(harness_exclude, ifile)) { - skip |= 1; - } else { - namelist_add(ip, NULL, ifile); - } - free(ifile); - } - - /* locate the old style configuration comment */ - desc = extract_desc(buf, '*'); - if (desc) { - if (strstr(desc, "@noStrict")) { - is_nostrict = TRUE; - skip |= (test_mode == TEST_STRICT); - } - if (strstr(desc, "@onlyStrict")) { - is_onlystrict = TRUE; - skip |= (test_mode == TEST_NOSTRICT); - } - if (strstr(desc, "@negative")) { - /* XXX: should extract the regex to check error type */ - is_negative = TRUE; - } - free(desc); - } - } - - if (outfile && index >= 0) { - fprintf(outfile, "%d: %s%s%s%s%s%s%s\n", index, filename, - is_nostrict ? " @noStrict" : "", - is_onlystrict ? " @onlyStrict" : "", - is_async ? " async" : "", - is_module ? " module" : "", - is_negative ? " @negative" : "", - skip ? " SKIPPED" : ""); - fflush(outfile); - } - - use_strict = use_nostrict = 0; - /* XXX: should remove 'test_mode' or simplify it just to force - strict or non strict mode for single file tests */ - switch (test_mode) { - case TEST_DEFAULT_NOSTRICT: - if (is_onlystrict) - use_strict = 1; - else - use_nostrict = 1; - break; - case TEST_DEFAULT_STRICT: - if (is_nostrict) - use_nostrict = 1; - else - use_strict = 1; - break; - case TEST_NOSTRICT: - if (!is_onlystrict) - use_nostrict = 1; - break; - case TEST_STRICT: - if (!is_nostrict) - use_strict = 1; - break; - case TEST_ALL: - if (is_module) { - use_nostrict = 1; - } else { - if (!is_nostrict) - use_strict = 1; - if (!is_onlystrict) - use_nostrict = 1; - } - break; - } - - if (skip || use_strict + use_nostrict == 0) { - test_skipped++; - ret = -2; - } else { - clock_t clocks; - - if (is_module) { - eval_flags = JS_EVAL_TYPE_MODULE; - } else { - eval_flags = JS_EVAL_TYPE_GLOBAL; - } - clocks = clock(); - ret = 0; - if (use_nostrict) { - ret = run_test_buf(filename, harness, ip, buf, buf_len, - error_type, eval_flags, is_negative, is_async, - can_block); - } - if (use_strict) { - ret |= run_test_buf(filename, harness, ip, buf, buf_len, - error_type, eval_flags | JS_EVAL_FLAG_STRICT, - is_negative, is_async, can_block); - } - clocks = clock() - clocks; - if (outfile && index >= 0 && clocks >= CLOCKS_PER_SEC / 10) { - /* output timings for tests that take more than 100 ms */ - fprintf(outfile, " time: %d ms\n", (int)(clocks * 1000LL / CLOCKS_PER_SEC)); - } - } - namelist_free(&include_list); - free(error_type); - free(buf); - - return ret; -} - -/* run a test when called by test262-harness+eshost */ -int run_test262_harness_test(const char *filename, BOOL is_module) -{ - JSRuntime *rt; - JSContext *ctx; - char *buf; - size_t buf_len; - int eval_flags, ret_code, ret; - JSValue res_val; - BOOL can_block; - - outfile = stdout; /* for js_print */ - - rt = JS_NewRuntime(); - if (rt == NULL) { - fatal(1, "JS_NewRuntime failure"); - } - ctx = JS_NewContext(rt); - if (ctx == NULL) { - JS_FreeRuntime(rt); - fatal(1, "JS_NewContext failure"); - } - JS_SetRuntimeInfo(rt, filename); - - can_block = TRUE; - JS_SetCanBlock(rt, can_block); - - /* loader for ES6 modules */ - JS_SetModuleLoaderFunc(rt, NULL, js_module_loader_test, NULL); - - add_helpers(ctx); - - buf = load_file(filename, &buf_len); - - if (is_module) { - eval_flags = JS_EVAL_TYPE_MODULE; - } else { - eval_flags = JS_EVAL_TYPE_GLOBAL; - } - res_val = JS_Eval(ctx, buf, buf_len, filename, eval_flags); - ret_code = 0; - if (JS_IsException(res_val)) { - js_std_dump_error(ctx); - ret_code = 1; - } else { - JS_FreeValue(ctx, res_val); - for(;;) { - JSContext *ctx1; - ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); - if (ret < 0) { - js_std_dump_error(ctx1); - ret_code = 1; - } else if (ret == 0) { - break; - } - } - } - free(buf); -#ifdef CONFIG_AGENT - js_agent_free(ctx); -#endif - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - return ret_code; -} - -clock_t last_clock; - -void show_progress(int force) { - clock_t t = clock(); - if (force || !last_clock || (t - last_clock) > CLOCKS_PER_SEC / 20) { - last_clock = t; - /* output progress indicator: erase end of line and return to col 0 */ - fprintf(stderr, "%d/%d/%d\033[K\r", - test_failed, test_count, test_skipped); - fflush(stderr); - } -} - -static int slow_test_threshold; - -void run_test_dir_list(namelist_t *lp, int start_index, int stop_index) -{ - int i; - - namelist_sort(lp); - for (i = 0; i < lp->count; i++) { - const char *p = lp->array[i]; - if (namelist_find(&exclude_list, p) >= 0) { - test_excluded++; - } else if (test_index < start_index) { - test_skipped++; - } else if (stop_index >= 0 && test_index > stop_index) { - test_skipped++; - } else { - int ti; - if (slow_test_threshold != 0) { - ti = get_clock_ms(); - } else { - ti = 0; - } - run_test(p, test_index); - if (slow_test_threshold != 0) { - ti = get_clock_ms() - ti; - if (ti >= slow_test_threshold) - fprintf(stderr, "\n%s (%d ms)\n", p, ti); - } - show_progress(FALSE); - } - test_index++; - } - show_progress(TRUE); -} - -void help(void) -{ - printf("run-test262 version " CONFIG_VERSION "\n" - "usage: run-test262 [options] {-f file ... | [dir_list] [index range]}\n" - "-h help\n" - "-a run tests in strict and nostrict modes\n" - "-m print memory usage summary\n" - "-n use new style harness\n" - "-N run test prepared by test262-harness+eshost\n" - "-s run tests in strict mode, skip @nostrict tests\n" - "-E only run tests from the error file\n" - "-u update error file\n" - "-v verbose: output error messages\n" - "-T duration display tests taking more than 'duration' ms\n" - "-c file read configuration from 'file'\n" - "-d dir run all test files in directory tree 'dir'\n" - "-e file load the known errors from 'file'\n" - "-f file execute single test from 'file'\n" - "-r file set the report file name (default=none)\n" - "-x file exclude tests listed in 'file'\n"); - exit(1); -} - -char *get_opt_arg(const char *option, char *arg) -{ - if (!arg) { - fatal(2, "missing argument for option %s", option); - } - return arg; -} - -int main(int argc, char **argv) -{ - int optind, start_index, stop_index; - BOOL is_dir_list; - BOOL only_check_errors = FALSE; - const char *filename; - BOOL is_test262_harness = FALSE; - BOOL is_module = FALSE; - - ShowCrashReports(); - -#if !defined(_WIN32) - /* Date tests assume California local time */ - setenv("TZ", "America/Los_Angeles", 1); -#endif - - /* cannot use getopt because we want to pass the command line to - the script */ - optind = 1; - is_dir_list = TRUE; - while (optind < argc) { - char *arg = argv[optind]; - if (*arg != '-') - break; - optind++; - if (str_equal(arg, "-h")) { - help(); - } else if (str_equal(arg, "-m")) { - dump_memory++; - } else if (str_equal(arg, "-n")) { - new_style++; - } else if (str_equal(arg, "-s")) { - test_mode = TEST_STRICT; - } else if (str_equal(arg, "-a")) { - test_mode = TEST_ALL; - } else if (str_equal(arg, "-u")) { - update_errors++; - } else if (str_equal(arg, "-v")) { - verbose++; - } else if (str_equal(arg, "-c")) { - load_config(get_opt_arg(arg, argv[optind++])); - } else if (str_equal(arg, "-d")) { - enumerate_tests(get_opt_arg(arg, argv[optind++])); - } else if (str_equal(arg, "-e")) { - error_filename = get_opt_arg(arg, argv[optind++]); - } else if (str_equal(arg, "-x")) { - namelist_load(&exclude_list, get_opt_arg(arg, argv[optind++])); - } else if (str_equal(arg, "-f")) { - is_dir_list = FALSE; - } else if (str_equal(arg, "-r")) { - report_filename = get_opt_arg(arg, argv[optind++]); - } else if (str_equal(arg, "-E")) { - only_check_errors = TRUE; - } else if (str_equal(arg, "-T")) { - slow_test_threshold = atoi(get_opt_arg(arg, argv[optind++])); - } else if (str_equal(arg, "-N")) { - is_test262_harness = TRUE; - } else if (str_equal(arg, "--module")) { - is_module = TRUE; - } else { - fatal(1, "unknown option: %s", arg); - break; - } - } - - if (optind >= argc && !test_list.count) - help(); - - if (is_test262_harness) { - return run_test262_harness_test(argv[optind], is_module); - } - - error_out = stdout; - if (error_filename) { - error_file = load_file(error_filename, NULL); - if (only_check_errors && error_file) { - namelist_free(&test_list); - namelist_add_from_error_file(&test_list, error_file); - } - if (update_errors) { - free(error_file); - error_file = NULL; - error_out = fopen(error_filename, "w"); - if (!error_out) { - perror_exit(1, error_filename); - } - } - } - - update_exclude_dirs(); - - if (is_dir_list) { - if (optind < argc && !isdigit(argv[optind][0])) { - filename = argv[optind++]; - namelist_load(&test_list, filename); - } - start_index = 0; - stop_index = -1; - if (optind < argc) { - start_index = atoi(argv[optind++]); - if (optind < argc) { - stop_index = atoi(argv[optind++]); - } - } - if (!report_filename || str_equal(report_filename, "none")) { - outfile = NULL; - } else if (str_equal(report_filename, "-")) { - outfile = stdout; - } else { - outfile = fopen(report_filename, "wb"); - if (!outfile) { - perror_exit(1, report_filename); - } - } - run_test_dir_list(&test_list, start_index, stop_index); - - if (outfile && outfile != stdout) { - fclose(outfile); - outfile = NULL; - } - } else { - outfile = stdout; - while (optind < argc) { - run_test(argv[optind++], -1); - } - } - - if (dump_memory) { - if (dump_memory > 1 && stats_count > 1) { - printf("\nMininum memory statistics for %s:\n\n", stats_min_filename); - JS_DumpMemoryUsage(stdout, &stats_min, NULL); - printf("\nMaximum memory statistics for %s:\n\n", stats_max_filename); - JS_DumpMemoryUsage(stdout, &stats_max, NULL); - } - printf("\nAverage memory statistics for %d tests:\n\n", stats_count); - JS_DumpMemoryUsage(stdout, &stats_avg, NULL); - printf("\n"); - } - - if (is_dir_list) { - fprintf(stderr, "Result: %d/%d error%s", - test_failed, test_count, test_count != 1 ? "s" : ""); - if (test_excluded) - fprintf(stderr, ", %d excluded", test_excluded); - if (test_skipped) - fprintf(stderr, ", %d skipped", test_skipped); - if (error_file) { - if (new_errors) - fprintf(stderr, ", %d new", new_errors); - if (changed_errors) - fprintf(stderr, ", %d changed", changed_errors); - if (fixed_errors) - fprintf(stderr, ", %d fixed", fixed_errors); - } - fprintf(stderr, "\n"); - } - - if (error_out && error_out != stdout) { - fclose(error_out); - error_out = NULL; - } - - namelist_free(&test_list); - namelist_free(&exclude_list); - namelist_free(&exclude_dir_list); - free(harness_dir); - free(harness_features); - free(harness_exclude); - free(error_file); - - return 0; -} diff --git a/third_party/quickjs/shape.c b/third_party/quickjs/shape.c deleted file mode 100644 index 9bf23cd02..000000000 --- a/third_party/quickjs/shape.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/assert.h" -#include "libc/str/str.h" -#include "third_party/quickjs/internal.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -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; -} - -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++; -} - -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' */ -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; - bzero(prop_hash_end(sh) - hash_size, sizeof(prop_hash_end(sh)[0]) * - hash_size); - sh->prop_hash_mask = hash_size - 1; - sh->prop_size = prop_size; - sh->prop_count = 0; - sh->deleted_prop_count = 0; - /* insert in the hash table */ - sh->hash = shape_initial_hash(proto); - sh->is_hashed = TRUE; - sh->has_small_array_index = FALSE; - js_shape_hash_link(ctx->rt, sh); - return sh; -} - -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 */ -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; -} - -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)); -} - -void js_free_shape(JSRuntime *rt, JSShape *sh) -{ - if (UNLIKELY(--sh->header.ref_count <= 0)) { - js_free_shape0(rt, sh); - } -} - -int add_shape_property(JSContext *ctx, JSShape **psh, - JSObject *p, JSAtom atom, int prop_flags) -{ - JSRuntime *rt = ctx->rt; - JSShape *sh = *psh; - JSShapeProperty *pr, *prop; - uint32_t hash_mask, new_shape_hash = 0; - intptr_t h; - /* update the shape hash */ - if (sh->is_hashed) { - js_shape_hash_unlink(rt, sh); - new_shape_hash = shape_hash(shape_hash(sh->hash, atom), prop_flags); - } - if (UNLIKELY(sh->prop_count >= sh->prop_size)) { - if (resize_properties(ctx, psh, p, sh->prop_count + 1)) { - /* in case of error, reinsert in the hash table. - sh is still valid if resize_properties() failed */ - if (sh->is_hashed) - js_shape_hash_link(rt, sh); - return -1; - } - sh = *psh; - } - if (sh->is_hashed) { - sh->hash = new_shape_hash; - js_shape_hash_link(rt, sh); - } - /* Initialize the new shape property. - The object property at p->prop[sh->prop_count] is uninitialized */ - prop = get_shape_prop(sh); - pr = &prop[sh->prop_count++]; - pr->atom = JS_DupAtom(ctx, atom); - pr->flags = prop_flags; - sh->has_small_array_index |= __JS_AtomIsTaggedInt(atom); - /* add in hash table */ - hash_mask = sh->prop_hash_mask; - h = atom & hash_mask; - pr->hash_next = prop_hash_end(sh)[-h - 1]; - prop_hash_end(sh)[-h - 1] = sh->prop_count; - return 0; -} - -/* find a hashed empty shape matching the prototype. Return NULL if - not found */ -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 */ -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"); -} - -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->is_HTMLDDA = 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: - case JS_CLASS_INT8_ARRAY: - case JS_CLASS_UINT8_ARRAY: - case JS_CLASS_INT16_ARRAY: - case JS_CLASS_UINT16_ARRAY: - case JS_CLASS_INT32_ARRAY: - case JS_CLASS_UINT32_ARRAY: -#ifdef CONFIG_BIGNUM - case JS_CLASS_BIG_INT64_ARRAY: - case JS_CLASS_BIG_UINT64_ARRAY: -#endif - case JS_CLASS_FLOAT32_ARRAY: - case JS_CLASS_FLOAT64_ARRAY: - p->is_exotic = 1; - p->fast_array = 1; - p->u.array.u.ptr = NULL; - p->u.array.count = 0; - break; - case JS_CLASS_DATAVIEW: - p->u.array.u.ptr = NULL; - p->u.array.count = 0; - break; - case JS_CLASS_NUMBER: - case JS_CLASS_STRING: - case JS_CLASS_BOOLEAN: - case JS_CLASS_SYMBOL: - case JS_CLASS_DATE: -#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); -} diff --git a/third_party/quickjs/str.c b/third_party/quickjs/str.c deleted file mode 100644 index 966d1733d..000000000 --- a/third_party/quickjs/str.c +++ /dev/null @@ -1,2312 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/str/str.h" -#include "libc/assert.h" -#include "libc/fmt/conv.h" -#include "libc/runtime/fenv.h" -#include "third_party/gdtoa/gdtoa.h" -#include "third_party/quickjs/internal.h" -#include "third_party/quickjs/libregexp.h" -#include "third_party/quickjs/quickjs.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -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; -} - -/* Note: the string contents are uninitialized */ -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; -} - -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; -} - -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); -} - -/* same as JS_FreeValueRT() but faster */ -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); - } - } -} - -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); -} - -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); -} - -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); - } -} - -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 */ -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; -} - -#ifdef CONFIG_BIGNUM - -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; -} - -JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val) -{ - return js_bigint_to_string1(ctx, val, 10); -} - -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; -} - -JSValue js_bigfloat_to_string(JSContext *ctx, JSValueConst val) -{ - return js_ftoa(ctx, val, 10, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN); -} - -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; -} - -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); -} - -/* 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); - } - } - } -} - -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); -} - -JSValue JS_ToStringFree(JSContext *ctx, JSValue val) -{ - JSValue ret; - ret = JS_ToString(ctx, val); - JS_FreeValue(ctx, val); - return ret; -} - -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); -} - -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; -} - -int string_cmp(JSString *p1, JSString *p2, int x1, int x2, int len) -{ - int i, c1, c2; - for (i = 0; i < len; i++) { - if ((c1 = string_get(p1, x1 + i)) != (c2 = string_get(p2, x2 + i))) - return c1 - c2; - } - return 0; -} - -int string_indexof_char(JSString *p, int c, int from) -{ - /* assuming 0 <= from <= p->len */ - int i, len = p->len; - if (p->is_wide_char) { - for (i = from; i < len; i++) { - if (p->u.str16[i] == c) - return i; - } - } else { - if ((c & ~0xff) == 0) { - for (i = from; i < len; i++) { - if (p->u.str8[i] == (uint8_t)c) - return i; - } - } - } - return -1; -} - -int string_indexof(JSString *p1, JSString *p2, int from) -{ - /* assuming 0 <= from <= p1->len */ - int c, i, j, len1 = p1->len, len2 = p2->len; - if (len2 == 0) - return from; - for (i = from, c = string_get(p2, 0); i + len2 <= len1; i = j + 1) { - j = string_indexof_char(p1, c, i); - if (j < 0 || j + len2 > len1) - break; - if (!string_cmp(p1, p2, j + 1, 1, len2 - 1)) - return j; - } - return -1; -} - -int64_t string_advance_index(JSString *p, int64_t index, BOOL unicode) -{ - if (!unicode || index >= p->len || !p->is_wide_char) { - index++; - } else { - int index32 = (int)index; - string_getc(p, &index32); - index = index32; - } - return index; -} - -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); - } -} - -static int js_string_get_own_property(JSContext *ctx, - JSPropertyDescriptor *desc, - JSValueConst obj, JSAtom prop) -{ - JSObject *p; - JSString *p1; - uint32_t idx, ch; - - /* This is a class exotic method: obj class_id is JS_CLASS_STRING */ - if (__JS_AtomIsTaggedInt(prop)) { - p = JS_VALUE_GET_OBJ(obj); - if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) { - p1 = JS_VALUE_GET_STRING(p->u.object_data); - idx = __JS_AtomToUInt32(prop); - if (idx < p1->len) { - if (desc) { - if (p1->is_wide_char) - ch = p1->u.str16[idx]; - else - ch = p1->u.str8[idx]; - desc->flags = JS_PROP_ENUMERABLE; - desc->value = js_new_string_char(ctx, ch); - desc->getter = JS_UNDEFINED; - desc->setter = JS_UNDEFINED; - } - return TRUE; - } - } - } - return FALSE; -} - -static int js_string_define_own_property(JSContext *ctx, - JSValueConst this_obj, - JSAtom prop, JSValueConst val, - JSValueConst getter, - JSValueConst setter, int flags) -{ - uint32_t idx; - JSObject *p; - JSString *p1, *p2; - - if (__JS_AtomIsTaggedInt(prop)) { - idx = __JS_AtomToUInt32(prop); - p = JS_VALUE_GET_OBJ(this_obj); - if (JS_VALUE_GET_TAG(p->u.object_data) != JS_TAG_STRING) - goto def; - p1 = JS_VALUE_GET_STRING(p->u.object_data); - if (idx >= p1->len) - goto def; - if (!check_define_prop_flags(JS_PROP_ENUMERABLE, flags)) - goto fail; - /* check that the same value is configured */ - if (flags & JS_PROP_HAS_VALUE) { - if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING) - goto fail; - p2 = JS_VALUE_GET_STRING(val); - if (p2->len != 1) - goto fail; - if (string_get(p1, idx) != string_get(p2, 0)) { - fail: - return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable"); - } - } - return TRUE; - } else { - def: - return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter, - flags | JS_PROP_NO_EXOTIC); - } -} - -static int js_string_delete_property(JSContext *ctx, - JSValueConst obj, JSAtom prop) -{ - uint32_t idx; - - if (__JS_AtomIsTaggedInt(prop)) { - idx = __JS_AtomToUInt32(prop); - if (idx < js_string_obj_get_length(ctx, obj)) { - return FALSE; - } - } - return TRUE; -} - -JSValue js_string_constructor(JSContext *ctx, JSValueConst new_target, - int argc, JSValueConst *argv) -{ - JSValue val, obj; - if (argc == 0) { - val = JS_AtomToString(ctx, JS_ATOM_empty_string); - } else { - if (JS_IsUndefined(new_target) && JS_IsSymbol(argv[0])) { - JSAtomStruct *p = JS_VALUE_GET_PTR(argv[0]); - val = JS_ConcatString3(ctx, "Symbol(", JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p)), ")"); - } else { - val = JS_ToString(ctx, argv[0]); - } - if (JS_IsException(val)) - return val; - } - if (!JS_IsUndefined(new_target)) { - JSString *p1 = JS_VALUE_GET_STRING(val); - - obj = js_create_from_ctor(ctx, new_target, JS_CLASS_STRING); - if (!JS_IsException(obj)) { - JS_SetObjectData(ctx, obj, val); - JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0); - } - return obj; - } else { - return val; - } -} - -static JSValue js_thisStringValue(JSContext *ctx, JSValueConst this_val) -{ - if (JS_VALUE_GET_TAG(this_val) == JS_TAG_STRING) - return JS_DupValue(ctx, this_val); - - if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(this_val); - if (p->class_id == JS_CLASS_STRING) { - if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) - return JS_DupValue(ctx, p->u.object_data); - } - } - return JS_ThrowTypeError(ctx, "not a string"); -} - -static JSValue js_string_fromCharCode(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int i; - StringBuffer b_s, *b = &b_s; - string_buffer_init(ctx, b, argc); - for(i = 0; i < argc; i++) { - int32_t c; - if (JS_ToInt32(ctx, &c, argv[i]) || string_buffer_putc16(b, c & 0xffff)) { - string_buffer_free(b); - return JS_EXCEPTION; - } - } - return string_buffer_end(b); -} - -static JSValue js_string_fromCodePoint(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - double d; - int i, c; - StringBuffer b_s, *b = &b_s; - /* XXX: could pre-compute string length if all arguments are JS_TAG_INT */ - if (string_buffer_init(ctx, b, argc)) - goto fail; - for(i = 0; i < argc; i++) { - if (JS_VALUE_GET_TAG(argv[i]) == JS_TAG_INT) { - c = JS_VALUE_GET_INT(argv[i]); - if (c < 0 || c > 0x10ffff) - goto range_error; - } else { - if (JS_ToFloat64(ctx, &d, argv[i])) - goto fail; - if (d < 0 || d > 0x10ffff || (c = (int)d) != d) - goto range_error; - } - if (string_buffer_putc(b, c)) - goto fail; - } - return string_buffer_end(b); - range_error: - JS_ThrowRangeError(ctx, "invalid code point"); - fail: - string_buffer_free(b); - return JS_EXCEPTION; -} - -static JSValue js_string_raw(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // raw(temp,...a) - JSValue cooked, val, raw; - StringBuffer b_s, *b = &b_s; - int64_t i, n; - string_buffer_init(ctx, b, 0); - raw = JS_UNDEFINED; - cooked = JS_ToObject(ctx, argv[0]); - if (JS_IsException(cooked)) - goto exception; - raw = JS_ToObjectFree(ctx, JS_GetProperty(ctx, cooked, JS_ATOM_raw)); - if (JS_IsException(raw)) - goto exception; - if (js_get_length64(ctx, &n, raw) < 0) - goto exception; - for (i = 0; i < n; i++) { - val = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, raw, i)); - if (JS_IsException(val)) - goto exception; - string_buffer_concat_value_free(b, val); - if (i < n - 1 && i + 1 < argc) { - if (string_buffer_concat_value(b, argv[i + 1])) - goto exception; - } - } - JS_FreeValue(ctx, cooked); - JS_FreeValue(ctx, raw); - return string_buffer_end(b); -exception: - JS_FreeValue(ctx, cooked); - JS_FreeValue(ctx, raw); - string_buffer_free(b); - return JS_EXCEPTION; -} - -/* only used in test262 */ -JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - uint32_t start, end, i, n; - StringBuffer b_s, *b = &b_s; - if (JS_ToUint32(ctx, &start, argv[0]) || - JS_ToUint32(ctx, &end, argv[1])) - return JS_EXCEPTION; - end = min_uint32(end, 0x10ffff + 1); - if (start > end) { - start = end; - } - n = end - start; - if (end > 0x10000) { - n += end - max_uint32(start, 0x10000); - } - if (string_buffer_init2(ctx, b, n, end >= 0x100)) - return JS_EXCEPTION; - for(i = start; i < end; i++) { - string_buffer_putc(b, i); - } - return string_buffer_end(b); -} - -#if 0 -static JSValue js_string___isSpace(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int c; - if (JS_ToInt32(ctx, &c, argv[0])) - return JS_EXCEPTION; - return JS_NewBool(ctx, lre_is_space(c)); -} -#endif - -static JSValue js_string_charCodeAt(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val, ret; - JSString *p; - int idx, c; - val = JS_ToStringCheckObject(ctx, this_val); - if (JS_IsException(val)) - return val; - p = JS_VALUE_GET_STRING(val); - if (JS_ToInt32Sat(ctx, &idx, argv[0])) { - JS_FreeValue(ctx, val); - return JS_EXCEPTION; - } - if (idx < 0 || idx >= p->len) { - ret = JS_NAN; - } else { - if (p->is_wide_char) - c = p->u.str16[idx]; - else - c = p->u.str8[idx]; - ret = JS_NewInt32(ctx, c); - } - JS_FreeValue(ctx, val); - return ret; -} - -static JSValue js_string_charAt(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val, ret; - JSString *p; - int idx, c; - val = JS_ToStringCheckObject(ctx, this_val); - if (JS_IsException(val)) - return val; - p = JS_VALUE_GET_STRING(val); - if (JS_ToInt32Sat(ctx, &idx, argv[0])) { - JS_FreeValue(ctx, val); - return JS_EXCEPTION; - } - if (idx < 0 || idx >= p->len) { - ret = js_new_string8(ctx, NULL, 0); - } else { - if (p->is_wide_char) - c = p->u.str16[idx]; - else - c = p->u.str8[idx]; - ret = js_new_string_char(ctx, c); - } - JS_FreeValue(ctx, val); - return ret; -} - -static JSValue js_string_codePointAt(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val, ret; - JSString *p; - int idx, c; - val = JS_ToStringCheckObject(ctx, this_val); - if (JS_IsException(val)) - return val; - p = JS_VALUE_GET_STRING(val); - if (JS_ToInt32Sat(ctx, &idx, argv[0])) { - JS_FreeValue(ctx, val); - return JS_EXCEPTION; - } - if (idx < 0 || idx >= p->len) { - ret = JS_UNDEFINED; - } else { - c = string_getc(p, &idx); - ret = JS_NewInt32(ctx, c); - } - JS_FreeValue(ctx, val); - return ret; -} - -static JSValue js_string_concat(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue r; - int i; - /* XXX: Use more efficient method */ - /* XXX: This method is OK if r has a single refcount */ - /* XXX: should use string_buffer? */ - r = JS_ToStringCheckObject(ctx, this_val); - for (i = 0; i < argc; i++) { - if (JS_IsException(r)) - break; - r = JS_ConcatString(ctx, r, JS_DupValue(ctx, argv[i])); - } - return r; -} - -static JSValue js_string_indexOf(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int lastIndexOf) -{ - JSValue str, v; - int i, len, v_len, pos, start, stop, ret, inc; - JSString *p; - JSString *p1; - str = JS_ToStringCheckObject(ctx, this_val); - if (JS_IsException(str)) - return str; - v = JS_ToString(ctx, argv[0]); - if (JS_IsException(v)) - goto fail; - p = JS_VALUE_GET_STRING(str); - p1 = JS_VALUE_GET_STRING(v); - len = p->len; - v_len = p1->len; - if (lastIndexOf) { - pos = len - v_len; - if (argc > 1) { - double d; - if (JS_ToFloat64(ctx, &d, argv[1])) - goto fail; - if (!isnan(d)) { - if (d <= 0) - pos = 0; - else if (d < pos) - pos = d; - } - } - start = pos; - stop = 0; - inc = -1; - } else { - pos = 0; - if (argc > 1) { - if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0)) - goto fail; - } - start = pos; - stop = len - v_len; - inc = 1; - } - ret = -1; - if (len >= v_len && inc * (stop - start) >= 0) { - for (i = start;; i += inc) { - if (!string_cmp(p, p1, i, 0, v_len)) { - ret = i; - break; - } - if (i == stop) - break; - } - } - JS_FreeValue(ctx, str); - JS_FreeValue(ctx, v); - return JS_NewInt32(ctx, ret); -fail: - JS_FreeValue(ctx, str); - JS_FreeValue(ctx, v); - return JS_EXCEPTION; -} - -static JSValue js_string_includes(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSValue str, v = JS_UNDEFINED; - int i, len, v_len, pos, start, stop, ret; - JSString *p; - JSString *p1; - str = JS_ToStringCheckObject(ctx, this_val); - if (JS_IsException(str)) - return str; - ret = js_is_regexp(ctx, argv[0]); - if (ret) { - if (ret > 0) - JS_ThrowTypeError(ctx, "regex not supported"); - goto fail; - } - v = JS_ToString(ctx, argv[0]); - if (JS_IsException(v)) - goto fail; - p = JS_VALUE_GET_STRING(str); - p1 = JS_VALUE_GET_STRING(v); - len = p->len; - v_len = p1->len; - pos = (magic == 2) ? len : 0; - if (argc > 1 && !JS_IsUndefined(argv[1])) { - if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0)) - goto fail; - } - len -= v_len; - ret = 0; - if (magic == 0) { - start = pos; - stop = len; - } else { - if (magic == 1) { - if (pos > len) - goto done; - } else { - pos -= v_len; - } - start = stop = pos; - } - if (start >= 0 && start <= stop) { - for (i = start;; i++) { - if (!string_cmp(p, p1, i, 0, v_len)) { - ret = 1; - break; - } - if (i == stop) - break; - } - } - done: - JS_FreeValue(ctx, str); - JS_FreeValue(ctx, v); - return JS_NewBool(ctx, ret); -fail: - JS_FreeValue(ctx, str); - JS_FreeValue(ctx, v); - return JS_EXCEPTION; -} - -static int check_regexp_g_flag(JSContext *ctx, JSValueConst regexp) -{ - int ret; - JSValue flags; - ret = js_is_regexp(ctx, regexp); - if (ret < 0) - return -1; - if (ret) { - flags = JS_GetProperty(ctx, regexp, JS_ATOM_flags); - if (JS_IsException(flags)) - return -1; - if (JS_IsUndefined(flags) || JS_IsNull(flags)) { - JS_ThrowTypeError(ctx, "cannot convert to object"); - return -1; - } - flags = JS_ToStringFree(ctx, flags); - if (JS_IsException(flags)) - return -1; - ret = string_indexof_char(JS_VALUE_GET_STRING(flags), 'g', 0); - JS_FreeValue(ctx, flags); - if (ret < 0) { - JS_ThrowTypeError(ctx, "regexp must have the 'g' flag"); - return -1; - } - } - return 0; -} - -static JSValue js_string_match(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int atom) -{ - // match(rx), search(rx), matchAll(rx) - // atom is JS_ATOM_Symbol_match, JS_ATOM_Symbol_search, or JS_ATOM_Symbol_matchAll - JSValueConst O = this_val, regexp = argv[0], args[2]; - JSValue matcher, S, rx, result, str; - int args_len; - if (JS_IsUndefined(O) || JS_IsNull(O)) - return JS_ThrowTypeError(ctx, "cannot convert to object"); - if (!JS_IsUndefined(regexp) && !JS_IsNull(regexp)) { - matcher = JS_GetProperty(ctx, regexp, atom); - if (JS_IsException(matcher)) - return JS_EXCEPTION; - if (atom == JS_ATOM_Symbol_matchAll) { - if (check_regexp_g_flag(ctx, regexp) < 0) { - JS_FreeValue(ctx, matcher); - return JS_EXCEPTION; - } - } - if (!JS_IsUndefined(matcher) && !JS_IsNull(matcher)) { - return JS_CallFree(ctx, matcher, regexp, 1, &O); - } - } - S = JS_ToString(ctx, O); - if (JS_IsException(S)) - return JS_EXCEPTION; - args_len = 1; - args[0] = regexp; - str = JS_UNDEFINED; - if (atom == JS_ATOM_Symbol_matchAll) { - str = JS_NewString(ctx, "g"); - if (JS_IsException(str)) - goto fail; - args[args_len++] = (JSValueConst)str; - } - rx = JS_CallConstructor(ctx, ctx->regexp_ctor, args_len, args); - JS_FreeValue(ctx, str); - if (JS_IsException(rx)) { - fail: - JS_FreeValue(ctx, S); - return JS_EXCEPTION; - } - result = JS_InvokeFree(ctx, rx, atom, 1, (JSValueConst *)&S); - JS_FreeValue(ctx, S); - return result; -} - -JSValue js_string___GetSubstitution(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // GetSubstitution(matched, str, position, captures, namedCaptures, rep) - JSValueConst matched, str, captures, namedCaptures, rep; - JSValue capture, name, s; - uint32_t position, len, matched_len, captures_len; - int i, j, j0, k, k1; - int c, c1; - StringBuffer b_s, *b = &b_s; - JSString *sp, *rp; - matched = argv[0]; - str = argv[1]; - captures = argv[3]; - namedCaptures = argv[4]; - rep = argv[5]; - if (!JS_IsString(rep) || !JS_IsString(str)) - return JS_ThrowTypeError(ctx, "not a string"); - sp = JS_VALUE_GET_STRING(str); - rp = JS_VALUE_GET_STRING(rep); - string_buffer_init(ctx, b, 0); - captures_len = 0; - if (!JS_IsUndefined(captures)) { - if (js_get_length32(ctx, &captures_len, captures)) - goto exception; - } - if (js_get_length32(ctx, &matched_len, matched)) - goto exception; - if (JS_ToUint32(ctx, &position, argv[2]) < 0) - goto exception; - len = rp->len; - i = 0; - for(;;) { - j = string_indexof_char(rp, '$', i); - if (j < 0 || j + 1 >= len) - break; - string_buffer_concat(b, rp, i, j); - j0 = j++; - c = string_get(rp, j++); - if (c == '$') { - string_buffer_putc8(b, '$'); - } else if (c == '&') { - if (string_buffer_concat_value(b, matched)) - goto exception; - } else if (c == '`') { - string_buffer_concat(b, sp, 0, position); - } else if (c == '\'') { - string_buffer_concat(b, sp, position + matched_len, sp->len); - } else if (c >= '0' && c <= '9') { - k = c - '0'; - if (j < len) { - c1 = string_get(rp, j); - if (c1 >= '0' && c1 <= '9') { - /* This behavior is specified in ES6 and refined in ECMA 2019 */ - /* ECMA 2019 does not have the extra test, but - Test262 S15.5.4.11_A3_T1..3 require this behavior */ - k1 = k * 10 + c1 - '0'; - if (k1 >= 1 && k1 < captures_len) { - k = k1; - j++; - } - } - } - if (k >= 1 && k < captures_len) { - s = JS_GetPropertyInt64(ctx, captures, k); - if (JS_IsException(s)) - goto exception; - if (!JS_IsUndefined(s)) { - if (string_buffer_concat_value_free(b, s)) - goto exception; - } - } else { - goto norep; - } - } else if (c == '<' && !JS_IsUndefined(namedCaptures)) { - k = string_indexof_char(rp, '>', j); - if (k < 0) - goto norep; - name = js_sub_string(ctx, rp, j, k); - if (JS_IsException(name)) - goto exception; - capture = JS_GetPropertyValue(ctx, namedCaptures, name); - if (JS_IsException(capture)) - goto exception; - if (!JS_IsUndefined(capture)) { - if (string_buffer_concat_value_free(b, capture)) - goto exception; - } - j = k + 1; - } else { - norep: - string_buffer_concat(b, rp, j0, j); - } - i = j; - } - string_buffer_concat(b, rp, i, rp->len); - return string_buffer_end(b); -exception: - string_buffer_free(b); - return JS_EXCEPTION; -} - -static JSValue js_string_replace(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - int is_replaceAll) -{ - // replace(rx, rep) - JSValueConst O = this_val, searchValue = argv[0], replaceValue = argv[1]; - JSValueConst args[6]; - JSValue str, search_str, replaceValue_str, repl_str; - JSString *sp, *searchp; - StringBuffer b_s, *b = &b_s; - int pos, functionalReplace, endOfLastMatch; - BOOL is_first; - if (JS_IsUndefined(O) || JS_IsNull(O)) - return JS_ThrowTypeError(ctx, "cannot convert to object"); - search_str = JS_UNDEFINED; - replaceValue_str = JS_UNDEFINED; - repl_str = JS_UNDEFINED; - if (!JS_IsUndefined(searchValue) && !JS_IsNull(searchValue)) { - JSValue replacer; - if (is_replaceAll) { - if (check_regexp_g_flag(ctx, searchValue) < 0) - return JS_EXCEPTION; - } - replacer = JS_GetProperty(ctx, searchValue, JS_ATOM_Symbol_replace); - if (JS_IsException(replacer)) - return JS_EXCEPTION; - if (!JS_IsUndefined(replacer) && !JS_IsNull(replacer)) { - args[0] = O; - args[1] = replaceValue; - return JS_CallFree(ctx, replacer, searchValue, 2, args); - } - } - string_buffer_init(ctx, b, 0); - str = JS_ToString(ctx, O); - if (JS_IsException(str)) - goto exception; - search_str = JS_ToString(ctx, searchValue); - if (JS_IsException(search_str)) - goto exception; - functionalReplace = JS_IsFunction(ctx, replaceValue); - if (!functionalReplace) { - replaceValue_str = JS_ToString(ctx, replaceValue); - if (JS_IsException(replaceValue_str)) - goto exception; - } - sp = JS_VALUE_GET_STRING(str); - searchp = JS_VALUE_GET_STRING(search_str); - endOfLastMatch = 0; - is_first = TRUE; - for(;;) { - if (UNLIKELY(searchp->len == 0)) { - if (is_first) - pos = 0; - else if (endOfLastMatch >= sp->len) - pos = -1; - else - pos = endOfLastMatch + 1; - } else { - pos = string_indexof(sp, searchp, endOfLastMatch); - } - if (pos < 0) { - if (is_first) { - string_buffer_free(b); - JS_FreeValue(ctx, search_str); - JS_FreeValue(ctx, replaceValue_str); - return str; - } else { - break; - } - } - if (functionalReplace) { - args[0] = search_str; - args[1] = JS_NewInt32(ctx, pos); - args[2] = str; - repl_str = JS_ToStringFree(ctx, JS_Call(ctx, replaceValue, JS_UNDEFINED, 3, args)); - } else { - args[0] = search_str; - args[1] = str; - args[2] = JS_NewInt32(ctx, pos); - args[3] = JS_UNDEFINED; - args[4] = JS_UNDEFINED; - args[5] = replaceValue_str; - repl_str = js_string___GetSubstitution(ctx, JS_UNDEFINED, 6, args); - } - if (JS_IsException(repl_str)) - goto exception; - string_buffer_concat(b, sp, endOfLastMatch, pos); - string_buffer_concat_value_free(b, repl_str); - endOfLastMatch = pos + searchp->len; - is_first = FALSE; - if (!is_replaceAll) - break; - } - string_buffer_concat(b, sp, endOfLastMatch, sp->len); - JS_FreeValue(ctx, search_str); - JS_FreeValue(ctx, replaceValue_str); - JS_FreeValue(ctx, str); - return string_buffer_end(b); -exception: - string_buffer_free(b); - JS_FreeValue(ctx, search_str); - JS_FreeValue(ctx, replaceValue_str); - JS_FreeValue(ctx, str); - return JS_EXCEPTION; -} - -static JSValue js_string_split(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // split(sep, limit) - JSValueConst O = this_val, separator = argv[0], limit = argv[1]; - JSValueConst args[2]; - JSValue S, A, R, T; - uint32_t lim, lengthA; - int64_t p, q, s, r, e; - JSString *sp, *rp; - if (JS_IsUndefined(O) || JS_IsNull(O)) - return JS_ThrowTypeError(ctx, "cannot convert to object"); - S = JS_UNDEFINED; - A = JS_UNDEFINED; - R = JS_UNDEFINED; - if (!JS_IsUndefined(separator) && !JS_IsNull(separator)) { - JSValue splitter; - splitter = JS_GetProperty(ctx, separator, JS_ATOM_Symbol_split); - if (JS_IsException(splitter)) - return JS_EXCEPTION; - if (!JS_IsUndefined(splitter) && !JS_IsNull(splitter)) { - args[0] = O; - args[1] = limit; - return JS_CallFree(ctx, splitter, separator, 2, args); - } - } - S = JS_ToString(ctx, O); - if (JS_IsException(S)) - goto exception; - A = JS_NewArray(ctx); - if (JS_IsException(A)) - goto exception; - lengthA = 0; - if (JS_IsUndefined(limit)) { - lim = 0xffffffff; - } else { - if (JS_ToUint32(ctx, &lim, limit) < 0) - goto exception; - } - sp = JS_VALUE_GET_STRING(S); - s = sp->len; - R = JS_ToString(ctx, separator); - if (JS_IsException(R)) - goto exception; - rp = JS_VALUE_GET_STRING(R); - r = rp->len; - p = 0; - if (lim == 0) - goto done; - if (JS_IsUndefined(separator)) - goto add_tail; - if (s == 0) { - if (r != 0) - goto add_tail; - goto done; - } - q = p; - for (q = p; (q += !r) <= s - r - !r; q = p = e + r) { - e = string_indexof(sp, rp, q); - if (e < 0) - break; - T = js_sub_string(ctx, sp, p, e); - if (JS_IsException(T)) - goto exception; - if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T, 0) < 0) - goto exception; - if (lengthA == lim) - goto done; - } -add_tail: - T = js_sub_string(ctx, sp, p, s); - if (JS_IsException(T)) - goto exception; - if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T,0 ) < 0) - goto exception; -done: - JS_FreeValue(ctx, S); - JS_FreeValue(ctx, R); - return A; -exception: - JS_FreeValue(ctx, A); - JS_FreeValue(ctx, S); - JS_FreeValue(ctx, R); - return JS_EXCEPTION; -} - -static JSValue js_string_substring(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue str, ret; - int a, b, start, end; - JSString *p; - str = JS_ToStringCheckObject(ctx, this_val); - if (JS_IsException(str)) - return str; - p = JS_VALUE_GET_STRING(str); - if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, p->len, 0)) { - JS_FreeValue(ctx, str); - return JS_EXCEPTION; - } - b = p->len; - if (!JS_IsUndefined(argv[1])) { - if (JS_ToInt32Clamp(ctx, &b, argv[1], 0, p->len, 0)) { - JS_FreeValue(ctx, str); - return JS_EXCEPTION; - } - } - if (a < b) { - start = a; - end = b; - } else { - start = b; - end = a; - } - ret = js_sub_string(ctx, p, start, end); - JS_FreeValue(ctx, str); - return ret; -} - -static JSValue js_string_substr(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue str, ret; - int a, len, n; - JSString *p; - str = JS_ToStringCheckObject(ctx, this_val); - if (JS_IsException(str)) - return str; - p = JS_VALUE_GET_STRING(str); - len = p->len; - if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, len, len)) { - JS_FreeValue(ctx, str); - return JS_EXCEPTION; - } - n = len - a; - if (!JS_IsUndefined(argv[1])) { - if (JS_ToInt32Clamp(ctx, &n, argv[1], 0, len - a, 0)) { - JS_FreeValue(ctx, str); - return JS_EXCEPTION; - } - } - ret = js_sub_string(ctx, p, a, a + n); - JS_FreeValue(ctx, str); - return ret; -} - -static JSValue js_string_slice(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue str, ret; - int len, start, end; - JSString *p; - str = JS_ToStringCheckObject(ctx, this_val); - if (JS_IsException(str)) - return str; - p = JS_VALUE_GET_STRING(str); - len = p->len; - if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len)) { - JS_FreeValue(ctx, str); - return JS_EXCEPTION; - } - end = len; - if (!JS_IsUndefined(argv[1])) { - if (JS_ToInt32Clamp(ctx, &end, argv[1], 0, len, len)) { - JS_FreeValue(ctx, str); - return JS_EXCEPTION; - } - } - ret = js_sub_string(ctx, p, start, max_int(end, start)); - JS_FreeValue(ctx, str); - return ret; -} - -static JSValue js_string_pad(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int padEnd) -{ - JSValue str, v = JS_UNDEFINED; - StringBuffer b_s, *b = &b_s; - JSString *p, *p1 = NULL; - int n, len, c = ' '; - str = JS_ToStringCheckObject(ctx, this_val); - if (JS_IsException(str)) - goto fail1; - if (JS_ToInt32Sat(ctx, &n, argv[0])) - goto fail2; - p = JS_VALUE_GET_STRING(str); - len = p->len; - if (len >= n) - return str; - if (argc > 1 && !JS_IsUndefined(argv[1])) { - v = JS_ToString(ctx, argv[1]); - if (JS_IsException(v)) - goto fail2; - p1 = JS_VALUE_GET_STRING(v); - if (p1->len == 0) { - JS_FreeValue(ctx, v); - return str; - } - if (p1->len == 1) { - c = string_get(p1, 0); - p1 = NULL; - } - } - if (n > JS_STRING_LEN_MAX) { - JS_ThrowInternalError(ctx, "string too long"); - goto fail2; - } - if (string_buffer_init(ctx, b, n)) - goto fail3; - n -= len; - if (padEnd) { - if (string_buffer_concat(b, p, 0, len)) - goto fail; - } - if (p1) { - while (n > 0) { - int chunk = min_int(n, p1->len); - if (string_buffer_concat(b, p1, 0, chunk)) - goto fail; - n -= chunk; - } - } else { - if (string_buffer_fill(b, c, n)) - goto fail; - } - if (!padEnd) { - if (string_buffer_concat(b, p, 0, len)) - goto fail; - } - JS_FreeValue(ctx, v); - JS_FreeValue(ctx, str); - return string_buffer_end(b); -fail: - string_buffer_free(b); -fail3: - JS_FreeValue(ctx, v); -fail2: - JS_FreeValue(ctx, str); -fail1: - return JS_EXCEPTION; -} - -static JSValue js_string_repeat(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue str; - StringBuffer b_s, *b = &b_s; - JSString *p; - int64_t val; - int n, len; - str = JS_ToStringCheckObject(ctx, this_val); - if (JS_IsException(str)) - goto fail; - if (JS_ToInt64Sat(ctx, &val, argv[0])) - goto fail; - if (val < 0 || val > 2147483647) { - JS_ThrowRangeError(ctx, "invalid repeat count"); - goto fail; - } - n = val; - p = JS_VALUE_GET_STRING(str); - len = p->len; - if (len == 0 || n == 1) - return str; - if (val * len > JS_STRING_LEN_MAX) { - JS_ThrowInternalError(ctx, "string too long"); - goto fail; - } - if (string_buffer_init2(ctx, b, n * len, p->is_wide_char)) - goto fail; - if (len == 1) { - string_buffer_fill(b, string_get(p, 0), n); - } else { - while (n-- > 0) { - string_buffer_concat(b, p, 0, len); - } - } - JS_FreeValue(ctx, str); - return string_buffer_end(b); - -fail: - JS_FreeValue(ctx, str); - return JS_EXCEPTION; -} - -static JSValue js_string_trim(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSValue str, ret; - int a, b, len; - JSString *p; - str = JS_ToStringCheckObject(ctx, this_val); - if (JS_IsException(str)) - return str; - p = JS_VALUE_GET_STRING(str); - a = 0; - b = len = p->len; - if (magic & 1) { - while (a < len && lre_is_space(string_get(p, a))) - a++; - } - if (magic & 2) { - while (b > a && lre_is_space(string_get(p, b - 1))) - b--; - } - ret = js_sub_string(ctx, p, a, b); - JS_FreeValue(ctx, str); - return ret; -} - -static JSValue js_string___quote(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_ToQuotedString(ctx, this_val); -} - -/* return 0 if before the first char */ -static int string_prevc(JSString *p, int *pidx) -{ - int idx, c, c1; - idx = *pidx; - if (idx <= 0) - return 0; - idx--; - if (p->is_wide_char) { - c = p->u.str16[idx]; - if (c >= 0xdc00 && c < 0xe000 && idx > 0) { - c1 = p->u.str16[idx - 1]; - if (c1 >= 0xd800 && c1 <= 0xdc00) { - c = (((c1 & 0x3ff) << 10) | (c & 0x3ff)) + 0x10000; - idx--; - } - } - } else { - c = p->u.str8[idx]; - } - *pidx = idx; - return c; -} - -static BOOL test_final_sigma(JSString *p, int sigma_pos) -{ - int k, c1; - - /* before C: skip case ignorable chars and check there is - a cased letter */ - k = sigma_pos; - for(;;) { - c1 = string_prevc(p, &k); - if (!lre_is_case_ignorable(c1)) - break; - } - if (!lre_is_cased(c1)) - return FALSE; - - /* after C: skip case ignorable chars and check there is - no cased letter */ - k = sigma_pos + 1; - for(;;) { - if (k >= p->len) - return TRUE; - c1 = string_getc(p, &k); - if (!lre_is_case_ignorable(c1)) - break; - } - return !lre_is_cased(c1); -} - -static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue a, b; - int cmp; - - a = JS_ToStringCheckObject(ctx, this_val); - if (JS_IsException(a)) - return JS_EXCEPTION; - b = JS_ToString(ctx, argv[0]); - if (JS_IsException(b)) { - JS_FreeValue(ctx, a); - return JS_EXCEPTION; - } - cmp = js_string_compare(ctx, JS_VALUE_GET_STRING(a), JS_VALUE_GET_STRING(b)); - JS_FreeValue(ctx, a); - JS_FreeValue(ctx, b); - return JS_NewInt32(ctx, cmp); -} - -static JSValue js_string_toLowerCase(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int to_lower) -{ - JSValue val; - StringBuffer b_s, *b = &b_s; - JSString *p; - int i, c, j, l; - uint32_t res[LRE_CC_RES_LEN_MAX]; - - val = JS_ToStringCheckObject(ctx, this_val); - if (JS_IsException(val)) - return val; - p = JS_VALUE_GET_STRING(val); - if (p->len == 0) - return val; - if (string_buffer_init(ctx, b, p->len)) - goto fail; - for(i = 0; i < p->len;) { - c = string_getc(p, &i); - if (c == 0x3a3 && to_lower && test_final_sigma(p, i - 1)) { - res[0] = 0x3c2; /* final sigma */ - l = 1; - } else { - l = lre_case_conv(res, c, to_lower); - } - for(j = 0; j < l; j++) { - if (string_buffer_putc(b, res[j])) - goto fail; - } - } - JS_FreeValue(ctx, val); - return string_buffer_end(b); - fail: - JS_FreeValue(ctx, val); - string_buffer_free(b); - return JS_EXCEPTION; -} - -#ifdef CONFIG_ALL_UNICODE - -/* return (-1, NULL) if exception, otherwise (len, buf) */ -static int JS_ToUTF32String(JSContext *ctx, uint32_t **pbuf, JSValueConst val1) -{ - JSValue val; - JSString *p; - uint32_t *buf; - int i, j, len; - - val = JS_ToString(ctx, val1); - if (JS_IsException(val)) - return -1; - p = JS_VALUE_GET_STRING(val); - len = p->len; - /* UTF32 buffer length is len minus the number of correct surrogates pairs */ - buf = js_malloc(ctx, sizeof(buf[0]) * max_int(len, 1)); - if (!buf) { - JS_FreeValue(ctx, val); - goto fail; - } - for(i = j = 0; i < len;) - buf[j++] = string_getc(p, &i); - JS_FreeValue(ctx, val); - *pbuf = buf; - return j; - fail: - *pbuf = NULL; - return -1; -} - -static JSValue JS_NewUTF32String(JSContext *ctx, const uint32_t *buf, int len) -{ - int i; - StringBuffer b_s, *b = &b_s; - if (string_buffer_init(ctx, b, len)) - return JS_EXCEPTION; - for(i = 0; i < len; i++) { - if (string_buffer_putc(b, buf[i])) - goto fail; - } - return string_buffer_end(b); - fail: - string_buffer_free(b); - return JS_EXCEPTION; -} - -static JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - const char *form, *p; - size_t form_len; - int is_compat, buf_len, out_len; - UnicodeNormalizationEnum n_type; - JSValue val; - uint32_t *buf, *out_buf; - - val = JS_ToStringCheckObject(ctx, this_val); - if (JS_IsException(val)) - return val; - buf_len = JS_ToUTF32String(ctx, &buf, val); - JS_FreeValue(ctx, val); - if (buf_len < 0) - return JS_EXCEPTION; - - if (argc == 0 || JS_IsUndefined(argv[0])) { - n_type = UNICODE_NFC; - } else { - form = JS_ToCStringLen(ctx, &form_len, argv[0]); - if (!form) - goto fail1; - p = form; - if (p[0] != 'N' || p[1] != 'F') - goto bad_form; - p += 2; - is_compat = FALSE; - if (*p == 'K') { - is_compat = TRUE; - p++; - } - if (*p == 'C' || *p == 'D') { - n_type = UNICODE_NFC + is_compat * 2 + (*p - 'C'); - if ((p + 1 - form) != form_len) - goto bad_form; - } else { - bad_form: - JS_FreeCString(ctx, form); - JS_ThrowRangeError(ctx, "bad normalization form"); - fail1: - js_free(ctx, buf); - return JS_EXCEPTION; - } - JS_FreeCString(ctx, form); - } - - out_len = unicode_normalize(&out_buf, buf, buf_len, n_type, - ctx->rt, (DynBufReallocFunc *)js_realloc_rt); - js_free(ctx, buf); - if (out_len < 0) - return JS_EXCEPTION; - val = JS_NewUTF32String(ctx, out_buf, out_len); - js_free(ctx, out_buf); - return val; -} -#endif /* CONFIG_ALL_UNICODE */ - -/* also used for String.prototype.valueOf */ -static JSValue js_string_toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return js_thisStringValue(ctx, this_val); -} - -#if 0 -static JSValue js_string___toStringCheckObject(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_ToStringCheckObject(ctx, argv[0]); -} - -static JSValue js_string___toString(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_ToString(ctx, argv[0]); -} - -static JSValue js_string___advanceStringIndex(JSContext *ctx, JSValueConst - this_val, - int argc, JSValueConst *argv) -{ - JSValue str; - int idx; - BOOL is_unicode; - JSString *p; - - str = JS_ToString(ctx, argv[0]); - if (JS_IsException(str)) - return str; - if (JS_ToInt32Sat(ctx, &idx, argv[1])) { - JS_FreeValue(ctx, str); - return JS_EXCEPTION; - } - is_unicode = JS_ToBool(ctx, argv[2]); - p = JS_VALUE_GET_STRING(str); - if (!is_unicode || (unsigned)idx >= p->len || !p->is_wide_char) { - idx++; - } else { - string_getc(p, &idx); - } - JS_FreeValue(ctx, str); - return JS_NewInt32(ctx, idx); -} -#endif - -static JSValue js_string_iterator_next(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - BOOL *pdone, int magic) -{ - JSArrayIteratorData *it; - uint32_t idx, c, start; - JSString *p; - it = JS_GetOpaque2(ctx, this_val, JS_CLASS_STRING_ITERATOR); - if (!it) { - *pdone = FALSE; - return JS_EXCEPTION; - } - if (JS_IsUndefined(it->obj)) - goto done; - p = JS_VALUE_GET_STRING(it->obj); - idx = it->idx; - if (idx >= p->len) { - JS_FreeValue(ctx, it->obj); - it->obj = JS_UNDEFINED; - done: - *pdone = TRUE; - return JS_UNDEFINED; - } - - start = idx; - c = string_getc(p, (int *)&idx); - it->idx = idx; - *pdone = FALSE; - if (c <= 0xffff) { - return js_new_string_char(ctx, c); - } else { - return js_new_string16(ctx, p->u.str16 + start, 2); - } -} - -/* ES6 Annex B 2.3.2 etc. */ -enum { - magic_string_anchor, - magic_string_big, - magic_string_blink, - magic_string_bold, - magic_string_fixed, - magic_string_fontcolor, - magic_string_fontsize, - magic_string_italics, - magic_string_link, - magic_string_small, - magic_string_strike, - magic_string_sub, - magic_string_sup, -}; - -static JSValue js_string_CreateHTML(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSValue str; - const JSString *p; - StringBuffer b_s, *b = &b_s; - static struct { const char *tag, *attr; } const defs[] = { - { "a", "name" }, { "big", NULL }, { "blink", NULL }, { "b", NULL }, - { "tt", NULL }, { "font", "color" }, { "font", "size" }, { "i", NULL }, - { "a", "href" }, { "small", NULL }, { "strike", NULL }, - { "sub", NULL }, { "sup", NULL }, - }; - str = JS_ToStringCheckObject(ctx, this_val); - if (JS_IsException(str)) - return JS_EXCEPTION; - string_buffer_init(ctx, b, 7); - string_buffer_putc8(b, '<'); - string_buffer_puts8(b, defs[magic].tag); - if (defs[magic].attr) { - // r += " " + attr + "=\"" + value + "\""; - JSValue value; - int i; - string_buffer_putc8(b, ' '); - string_buffer_puts8(b, defs[magic].attr); - string_buffer_puts8(b, "=\""); - value = JS_ToStringCheckObject(ctx, argv[0]); - if (JS_IsException(value)) { - JS_FreeValue(ctx, str); - string_buffer_free(b); - return JS_EXCEPTION; - } - p = JS_VALUE_GET_STRING(value); - for (i = 0; i < p->len; i++) { - int c = string_get(p, i); - if (c == '"') { - string_buffer_puts8(b, """); - } else { - string_buffer_putc16(b, c); - } - } - JS_FreeValue(ctx, value); - string_buffer_putc8(b, '\"'); - } - // return r + ">" + str + ""; - string_buffer_putc8(b, '>'); - string_buffer_concat_value_free(b, str); - string_buffer_puts8(b, "'); - return string_buffer_end(b); -} - -static const JSCFunctionListEntry js_string_proto_funcs[] = { - JS_PROP_INT32_DEF("length", 0, JS_PROP_CONFIGURABLE ), - JS_CFUNC_DEF("charCodeAt", 1, js_string_charCodeAt ), - JS_CFUNC_DEF("charAt", 1, js_string_charAt ), - JS_CFUNC_DEF("concat", 1, js_string_concat ), - JS_CFUNC_DEF("codePointAt", 1, js_string_codePointAt ), - JS_CFUNC_MAGIC_DEF("indexOf", 1, js_string_indexOf, 0 ), - JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_string_indexOf, 1 ), - JS_CFUNC_MAGIC_DEF("includes", 1, js_string_includes, 0 ), - JS_CFUNC_MAGIC_DEF("endsWith", 1, js_string_includes, 2 ), - JS_CFUNC_MAGIC_DEF("startsWith", 1, js_string_includes, 1 ), - JS_CFUNC_MAGIC_DEF("match", 1, js_string_match, JS_ATOM_Symbol_match ), - JS_CFUNC_MAGIC_DEF("matchAll", 1, js_string_match, JS_ATOM_Symbol_matchAll ), - JS_CFUNC_MAGIC_DEF("search", 1, js_string_match, JS_ATOM_Symbol_search ), - JS_CFUNC_DEF("split", 2, js_string_split ), - JS_CFUNC_DEF("substring", 2, js_string_substring ), - JS_CFUNC_DEF("substr", 2, js_string_substr ), - JS_CFUNC_DEF("slice", 2, js_string_slice ), - JS_CFUNC_DEF("repeat", 1, js_string_repeat ), - JS_CFUNC_MAGIC_DEF("replace", 2, js_string_replace, 0 ), - JS_CFUNC_MAGIC_DEF("replaceAll", 2, js_string_replace, 1 ), - JS_CFUNC_MAGIC_DEF("padEnd", 1, js_string_pad, 1 ), - JS_CFUNC_MAGIC_DEF("padStart", 1, js_string_pad, 0 ), - JS_CFUNC_MAGIC_DEF("trim", 0, js_string_trim, 3 ), - JS_CFUNC_MAGIC_DEF("trimEnd", 0, js_string_trim, 2 ), - JS_ALIAS_DEF("trimRight", "trimEnd" ), - JS_CFUNC_MAGIC_DEF("trimStart", 0, js_string_trim, 1 ), - JS_ALIAS_DEF("trimLeft", "trimStart" ), - JS_CFUNC_DEF("toString", 0, js_string_toString ), - JS_CFUNC_DEF("valueOf", 0, js_string_toString ), - JS_CFUNC_DEF("__quote", 1, js_string___quote ), - JS_CFUNC_DEF("localeCompare", 1, js_string_localeCompare ), - JS_CFUNC_MAGIC_DEF("toLowerCase", 0, js_string_toLowerCase, 1 ), - JS_CFUNC_MAGIC_DEF("toUpperCase", 0, js_string_toLowerCase, 0 ), - JS_CFUNC_MAGIC_DEF("toLocaleLowerCase", 0, js_string_toLowerCase, 1 ), - JS_CFUNC_MAGIC_DEF("toLocaleUpperCase", 0, js_string_toLowerCase, 0 ), - JS_CFUNC_MAGIC_DEF("[Symbol.iterator]", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE | 4 ), - /* ES6 Annex B 2.3.2 etc. */ - JS_CFUNC_MAGIC_DEF("anchor", 1, js_string_CreateHTML, magic_string_anchor ), - JS_CFUNC_MAGIC_DEF("big", 0, js_string_CreateHTML, magic_string_big ), - JS_CFUNC_MAGIC_DEF("blink", 0, js_string_CreateHTML, magic_string_blink ), - JS_CFUNC_MAGIC_DEF("bold", 0, js_string_CreateHTML, magic_string_bold ), - JS_CFUNC_MAGIC_DEF("fixed", 0, js_string_CreateHTML, magic_string_fixed ), - JS_CFUNC_MAGIC_DEF("fontcolor", 1, js_string_CreateHTML, magic_string_fontcolor ), - JS_CFUNC_MAGIC_DEF("fontsize", 1, js_string_CreateHTML, magic_string_fontsize ), - JS_CFUNC_MAGIC_DEF("italics", 0, js_string_CreateHTML, magic_string_italics ), - JS_CFUNC_MAGIC_DEF("link", 1, js_string_CreateHTML, magic_string_link ), - JS_CFUNC_MAGIC_DEF("small", 0, js_string_CreateHTML, magic_string_small ), - JS_CFUNC_MAGIC_DEF("strike", 0, js_string_CreateHTML, magic_string_strike ), - JS_CFUNC_MAGIC_DEF("sub", 0, js_string_CreateHTML, magic_string_sub ), - JS_CFUNC_MAGIC_DEF("sup", 0, js_string_CreateHTML, magic_string_sup ), -}; - -static const JSCFunctionListEntry js_string_iterator_proto_funcs[] = { - JS_ITERATOR_NEXT_DEF("next", 0, js_string_iterator_next, 0 ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "String Iterator", JS_PROP_CONFIGURABLE ), -}; - -#ifdef CONFIG_ALL_UNICODE -static const JSCFunctionListEntry js_string_proto_normalize[] = { - JS_CFUNC_DEF("normalize", 0, js_string_normalize ), -}; -#endif - -void JS_AddIntrinsicStringNormalize(JSContext *ctx) -{ -#ifdef CONFIG_ALL_UNICODE - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_normalize, - countof(js_string_proto_normalize)); -#endif -} - -static const JSCFunctionListEntry js_string_funcs[] = { - JS_CFUNC_DEF("fromCharCode", 1, js_string_fromCharCode ), - JS_CFUNC_DEF("fromCodePoint", 1, js_string_fromCodePoint ), - JS_CFUNC_DEF("raw", 1, js_string_raw ), - //JS_CFUNC_DEF("__toString", 1, js_string___toString ), - //JS_CFUNC_DEF("__isSpace", 1, js_string___isSpace ), - //JS_CFUNC_DEF("__toStringCheckObject", 1, js_string___toStringCheckObject ), - //JS_CFUNC_DEF("__advanceStringIndex", 3, js_string___advanceStringIndex ), - //JS_CFUNC_DEF("__GetSubstitution", 6, js_string___GetSubstitution ), -}; - -void JS_AddIntrinsicString(JSContext *ctx) -{ - JSValueConst obj; - ctx->class_proto[JS_CLASS_STRING] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], - JS_CLASS_STRING); - JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_STRING], JS_AtomToString(ctx, JS_ATOM_empty_string)); - obj = JS_NewGlobalCConstructor(ctx, "String", js_string_constructor, 1, - ctx->class_proto[JS_CLASS_STRING]); - JS_SetPropertyFunctionList(ctx, obj, js_string_funcs, - countof(js_string_funcs)); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_funcs, - countof(js_string_proto_funcs)); - ctx->class_proto[JS_CLASS_STRING_ITERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING_ITERATOR], - js_string_iterator_proto_funcs, - countof(js_string_iterator_proto_funcs)); -} diff --git a/third_party/quickjs/strbuf.c b/third_party/quickjs/strbuf.c deleted file mode 100644 index 9d85a255e..000000000 --- a/third_party/quickjs/strbuf.c +++ /dev/null @@ -1,331 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/str/str.h" -#include "third_party/quickjs/internal.h" -#include "third_party/quickjs/libregexp.h" -#include "third_party/quickjs/quickjs.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -/* 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. - */ -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; -} - -int string_buffer_init(JSContext *ctx, StringBuffer *s, int size) -{ - return string_buffer_init2(ctx, s, size, 0); -} - -void string_buffer_free(StringBuffer *s) -{ - js_free(s->ctx, s->str); - s->str = NULL; -} - -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; -} - -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; -} - -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; -} - -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 */ -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 */ -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 */ -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); -} - -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; -} - -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 */ -int string_buffer_puts8(StringBuffer *s, const char *str) -{ - return string_buffer_write8(s, (const uint8_t *)str, strlen(str)); -} - -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); -} - -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); -} - -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; -} - -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; -} - -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); -} diff --git a/third_party/quickjs/test262.conf b/third_party/quickjs/test262.conf deleted file mode 100644 index 06c580988..000000000 --- a/third_party/quickjs/test262.conf +++ /dev/null @@ -1,212 +0,0 @@ -[config] -# general settings for test262 ES6 version - -# framework style: old, new -style=new - -# handle tests tagged as [noStrict]: yes, no, skip -nostrict=yes - -# handle tests tagged as [strictOnly]: yes, no, skip -strict=yes - -# test mode: default, default-nostrict, default-strict, strict, nostrict, both, all -mode=default - -# handle tests flagged as [async]: yes, no, skip -# for these, load 'harness/doneprintHandle.js' prior to test -# and expect `print('Test262:AsyncTestComplete')` to be called for -# successful termination -async=yes - -# handle tests flagged as [module]: yes, no, skip -module=yes - -# output error messages: yes, no -verbose=yes - -# load harness files from this directory -harnessdir=/opt/test262/harness - -# names of harness include files to skip -#harnessexclude= - -# name of the error file for known errors -errorfile=third_party/quickjs/test262_errors.txt - -# exclude tests enumerated in this file (see also [exclude] section) -#excludefile=test262_exclude.txt - -# report test results to this file -reportfile=o/test262_report.txt - -# enumerate tests from this directory -testdir=/opt/test262/test - -[features] -# Standard language features and proposed extensions -# list the features that are included -# skipped features are tagged as such to avoid warnings - -AggregateError -align-detached-buffer-semantics-with-web-reality -arbitrary-module-namespace-names=skip -array-find-from-last=skip -Array.prototype.at=skip -Array.prototype.flat -Array.prototype.flatMap -Array.prototype.flatten -Array.prototype.values -ArrayBuffer -arrow-function -async-functions -async-iteration -Atomics -Atomics.waitAsync=skip -BigInt -caller -class -class-fields-private -class-fields-private-in=skip -class-fields-public -class-methods-private -class-static-block=skip -class-static-fields-public -class-static-fields-private -class-static-methods-private -cleanupSome=skip -coalesce-expression -computed-property-names -const -cross-realm -DataView -DataView.prototype.getFloat32 -DataView.prototype.getFloat64 -DataView.prototype.getInt16 -DataView.prototype.getInt32 -DataView.prototype.getInt8 -DataView.prototype.getUint16 -DataView.prototype.getUint32 -DataView.prototype.setUint8 -default-parameters -destructuring-assignment -destructuring-binding -dynamic-import -error-cause=skip -export-star-as-namespace-from-module -FinalizationGroup=skip -FinalizationRegistry=skip -FinalizationRegistry.prototype.cleanupSome=skip -Float32Array -Float64Array -for-in-order -for-of -generators -globalThis -hashbang -host-gc-required=skip -import.meta -import-assertions=skip -Int16Array -Int32Array -Int8Array -IsHTMLDDA -json-modules=skip -json-superset -legacy-regexp=skip -let -logical-assignment-operators -Map -new.target -numeric-separator-literal -object-rest -object-spread -Object.fromEntries -Object.hasOwn -Object.is -optional-catch-binding -optional-chaining -Promise -Promise.allSettled -Promise.any -Promise.prototype.finally -Proxy -proxy-missing-checks -Reflect -Reflect.construct -Reflect.set -Reflect.setPrototypeOf -regexp-dotall -regexp-lookbehind -regexp-match-indices=skip -regexp-named-groups -regexp-unicode-property-escapes -resizable-arraybuffer=skip -rest-parameters -Set -ShadowRealm=skip -SharedArrayBuffer -string-trimming -String.fromCodePoint -String.prototype.endsWith -String.prototype.includes -String.prototype.at=skip -String.prototype.matchAll -String.prototype.replaceAll -String.prototype.trimEnd -String.prototype.trimStart -super -Symbol -Symbol.asyncIterator -Symbol.hasInstance -Symbol.isConcatSpreadable -Symbol.iterator -Symbol.match -Symbol.matchAll -Symbol.prototype.description -Symbol.replace -Symbol.search -Symbol.species -Symbol.split -Symbol.toPrimitive -Symbol.toStringTag -Symbol.unscopables -tail-call-optimization=skip -template -Temporal=skip -top-level-await=skip -TypedArray -TypedArray.prototype.at=skip -u180e -Uint16Array -Uint32Array -Uint8Array -Uint8ClampedArray -WeakMap -WeakRef=skip -WeakSet -well-formed-json-stringify -__getter__ -__proto__ -__setter__ - -[exclude] -# list excluded tests and directories here - -# intl not supported -/opt/test262/test/intl402/ - -# incompatible with the "caller" feature -/opt/test262/test/built-ins/Function/prototype/restricted-property-caller.js -/opt/test262/test/built-ins/Function/prototype/restricted-property-arguments.js -/opt/test262/test/built-ins/ThrowTypeError/unique-per-realm-function-proto.js - -# slow tests -#/opt/test262/test/built-ins/RegExp/CharacterClassEscapes/ -#/opt/test262/test/built-ins/RegExp/property-escapes/ - -# No threads in Cosmopolitan ATM -/opt/test262/test/built-ins/Atomics/ - -[tests] -# list test files or use config.testdir diff --git a/third_party/quickjs/test262_errors.txt b/third_party/quickjs/test262_errors.txt deleted file mode 100644 index b7f6aef38..000000000 --- a/third_party/quickjs/test262_errors.txt +++ /dev/null @@ -1,35 +0,0 @@ -test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: Test262Error: Expected a ReferenceError but got a ReferenceError -test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: strict mode: Test262Error: Expected a ReferenceError but got a ReferenceError -test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: SyntaxError: invalid group name -test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: strict mode: SyntaxError: invalid group name -test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:46: Test262Error: (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:46: strict mode: Test262Error: (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:47: Test262Error: (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:47: strict mode: Test262Error: (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer-realm.js:37: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:34: TypeError: cannot convert bigint to number (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-minus-zero.js:20: Test262Error: Reflect.set("new TA([42n])", "-0", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-minus-zero.js:20: strict mode: Test262Error: Reflect.set("new TA([42n])", "-0", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-not-integer.js:21: Test262Error: Reflect.set("new TA([42n])", "1.1", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-not-integer.js:21: strict mode: Test262Error: Reflect.set("new TA([42n])", "1.1", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-out-of-bounds.js:27: Test262Error: Reflect.set("new TA([42n])", "-1", 1n) must return false Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-out-of-bounds.js:27: strict mode: Test262Error: Reflect.set("new TA([42n])", "-1", 1n) must return false Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/tonumber-value-detached-buffer.js:24: Test262Error: Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/tonumber-value-detached-buffer.js:24: strict mode: Test262Error: Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer-realm.js:37: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-minus-zero.js:22: Test262Error: Reflect.set(sample, "-0", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-minus-zero.js:22: strict mode: Test262Error: Reflect.set(sample, "-0", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-not-integer.js:22: Test262Error: Reflect.set(sample, "1.1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-not-integer.js:22: strict mode: Test262Error: Reflect.set(sample, "1.1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds.js:22: Test262Error: Reflect.set(sample, "-1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds.js:22: strict mode: Test262Error: Reflect.set(sample, "-1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detached-buffer.js:39: Test262Error: Expected SameValue(«false», «true») to be true (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detached-buffer.js:39: strict mode: Test262Error: Expected SameValue(«false», «true») to be true (Testing with Float64Array.) -test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called -test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called -test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: cannot read property 'c' of undefined -test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: cannot read property '_b' of undefined -test262/test/language/statements/for-of/head-lhs-async-invalid.js:14: unexpected error type: Test262: This statement should not be evaluated. -test262/test/language/statements/for-of/head-lhs-async-invalid.js:14: strict mode: unexpected error type: Test262: This statement should not be evaluated. diff --git a/third_party/quickjs/test262o.conf b/third_party/quickjs/test262o.conf deleted file mode 100644 index 669dead8a..000000000 --- a/third_party/quickjs/test262o.conf +++ /dev/null @@ -1,410 +0,0 @@ -[config] -# general settings for test262 ES5 version - -# framework style: old, new -style=old - -# handle tests tagged as @noStrict: yes, no, skip -nostrict=yes - -# handle tests tagged as @strictOnly: yes, no, skip -strict=yes - -# test mode: default, default-nostrict, default-strict, strict, nostrict, both, all -mode=default - -# output error messages: yes, no -verbose=yes - -# load harness files this directory -harnessdir=test262o/test/harness - -# name of the error file for known errors -errorfile=test262o_errors.txt - -# exclude tests enumerated in this file -#excludefile=test262o_excluded.txt - -# report test results to this file -reportfile=test262o_report.txt - -# enumerate tests from this directory -testdir=test262o/test/suite - -[exclude] -# list excluded tests and directories here - -# intl not supported -test262o/test/suite/intl402/ - -# ES6 != ES5: block scoped function definitions allowed in strict mode -test262o/test/suite/bestPractice/Sbp_A1_T1.js -test262o/test/suite/bestPractice/Sbp_A2_T1.js -test262o/test/suite/bestPractice/Sbp_A2_T2.js -test262o/test/suite/bestPractice/Sbp_A3_T1.js -test262o/test/suite/bestPractice/Sbp_A3_T2.js -test262o/test/suite/bestPractice/Sbp_A4_T1.js -test262o/test/suite/bestPractice/Sbp_A4_T2.js -test262o/test/suite/bestPractice/Sbp_A5_T2.js - -# ES6 != ES5: `y={x};` is shorthand for `y={x:x}` -test262o/test/suite/ch12/12.1/S12.1_A4_T2.js -test262o/test/suite/ch12/12.6/12.6.4/S12.6.4_A15.js - -# ES6 != ES5: function length property is configurable -test262o/test/suite/ch11/11.4/11.4.1/11.4.1-5-a-28-s.js -test262o/test/suite/ch13/13.2/13.2-15-1.js -test262o/test/suite/ch15/15.1/15.1.2/15.1.2.1/S15.1.2.1_A4.2.js -test262o/test/suite/ch15/15.1/15.1.2/15.1.2.2/S15.1.2.2_A9.2.js -test262o/test/suite/ch15/15.1/15.1.2/15.1.2.3/S15.1.2.3_A7.2.js -test262o/test/suite/ch15/15.1/15.1.2/15.1.2.4/S15.1.2.4_A2.2.js -test262o/test/suite/ch15/15.1/15.1.2/15.1.2.5/S15.1.2.5_A2.2.js -test262o/test/suite/ch15/15.1/15.1.3/15.1.3.1/S15.1.3.1_A5.2.js -test262o/test/suite/ch15/15.1/15.1.3/15.1.3.2/S15.1.3.2_A5.2.js -test262o/test/suite/ch15/15.1/15.1.3/15.1.3.3/S15.1.3.3_A5.2.js -test262o/test/suite/ch15/15.1/15.1.3/15.1.3.4/S15.1.3.4_A5.2.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-186.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-187.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-191.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-194.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-201.js -test262o/test/suite/ch15/15.2/15.2.4/15.2.4.2/S15.2.4.2_A9.js -test262o/test/suite/ch15/15.2/15.2.4/15.2.4.3/S15.2.4.3_A9.js -test262o/test/suite/ch15/15.2/15.2.4/15.2.4.4/S15.2.4.4_A9.js -test262o/test/suite/ch15/15.2/15.2.4/15.2.4.5/S15.2.4.5_A9.js -test262o/test/suite/ch15/15.2/15.2.4/15.2.4.6/S15.2.4.6_A9.js -test262o/test/suite/ch15/15.2/15.2.4/15.2.4.7/S15.2.4.7_A9.js -test262o/test/suite/ch15/15.3/15.3.3/15.3.3.2/15.3.3.2-1.js -test262o/test/suite/ch15/15.3/15.3.4/15.3.4.2/S15.3.4.2_A9.js -test262o/test/suite/ch15/15.3/15.3.4/15.3.4.3/S15.3.4.3_A9.js -test262o/test/suite/ch15/15.3/15.3.4/15.3.4.4/S15.3.4.4_A9.js -test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-15-2.js -test262o/test/suite/ch15/15.3/15.3.5/S15.3.5.1_A2_T1.js -test262o/test/suite/ch15/15.3/15.3.5/S15.3.5.1_A2_T2.js -test262o/test/suite/ch15/15.3/15.3.5/S15.3.5.1_A2_T3.js -test262o/test/suite/ch15/15.4/15.4.3/S15.4.3_A2.2.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.2/S15.4.4.2_A4.2.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.3/S15.4.4.3_A4.2.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.4/S15.4.4.4_A4.2.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.5/S15.4.4.5_A6.2.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A5.2.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A6.2.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.8/S15.4.4.8_A5.2.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.9/S15.4.4.9_A5.2.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A5.2.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.11/S15.4.4.11_A7.2.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.12/S15.4.4.12_A5.2.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.13/S15.4.4.13_A5.2.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.4/S15.5.4.4_A9.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.5/S15.5.4.5_A9.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.6/S15.5.4.6_A9.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.7/S15.5.4.7_A9.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.8/S15.5.4.8_A9.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.9/S15.5.4.9_A9.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.10/S15.5.4.10_A9.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.11/S15.5.4.11_A9.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.12/S15.5.4.12_A9.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.13/S15.5.4.13_A9.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.14/S15.5.4.14_A9.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.15/S15.5.4.15_A9.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.16/S15.5.4.16_A9.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.17/S15.5.4.17_A9.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.18/S15.5.4.18_A9.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.19/S15.5.4.19_A9.js -test262o/test/suite/ch15/15.9/15.9.4/15.9.4.2/S15.9.4.2_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.4/15.9.4.3/S15.9.4.3_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.1/S15.9.5.1_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.2/S15.9.5.2_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.3/S15.9.5.3_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.4/S15.9.5.4_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.5/S15.9.5.5_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.6/S15.9.5.6_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.7/S15.9.5.7_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.8/S15.9.5.8_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.9/S15.9.5.9_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.10/S15.9.5.10_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.11/S15.9.5.11_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.12/S15.9.5.12_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.13/S15.9.5.13_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.14/S15.9.5.14_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.15/S15.9.5.15_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.16/S15.9.5.16_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.17/S15.9.5.17_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.18/S15.9.5.18_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.19/S15.9.5.19_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.20/S15.9.5.20_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.21/S15.9.5.21_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.22/S15.9.5.22_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.23/S15.9.5.23_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.24/S15.9.5.24_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.25/S15.9.5.25_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.26/S15.9.5.26_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.27/S15.9.5.27_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.28/S15.9.5.28_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.29/S15.9.5.29_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.30/S15.9.5.30_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.31/S15.9.5.31_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.32/S15.9.5.32_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.33/S15.9.5.33_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.34/S15.9.5.34_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.35/S15.9.5.35_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.36/S15.9.5.36_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.37/S15.9.5.37_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.38/S15.9.5.38_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.39/S15.9.5.39_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.40/S15.9.5.40_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.41/S15.9.5.41_A3_T2.js -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.42/S15.9.5.42_A3_T2.js -test262o/test/suite/ch15/15.10/15.10.6/15.10.6.2/S15.10.6.2_A9.js -test262o/test/suite/ch15/15.10/15.10.6/15.10.6.3/S15.10.6.3_A9.js -test262o/test/suite/ch15/15.10/15.10.6/15.10.6.4/S15.10.6.4_A9.js - -# ES6 != ES5: object literals may have duplicates -test262o/test/suite/ch11/11.1/11.1.5/11.1.5-4-4-a-1-s.js -test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-b-1.js -test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-b-2.js -test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-c-1.js -test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-c-2.js -test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-1.js -test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-2.js -test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-3.js -test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-4.js - -# ES6 != ES5: Date.prototype is no longer an instance of Date -test262o/test/suite/ch15/15.9/15.9.5/15.9.5.40/15.9.5.40_1.js - -# ES6 != ES5: Object.getPrototypeOf converts argument to object -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-1-3.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-1-4.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-1.js - -# ES6 != ES5: Object.getPrototypeOf(NativeError) -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-12.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-13.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-14.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-15.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-16.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-17.js - -# ES6 != ES5: Object.getOwnPropertyDescriptor converts argument to object -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-1-3.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-1-4.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-1.js - -# ES6 != ES5: Object.getOwnPropertyNames converts argument to object -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1-4.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1-5.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1.js - -# ES6 != ES5: Object.seal accepts all types -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-1.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-2.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-3.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-4.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1.js - -# ES6 != ES5: Object.freeze accepts all types -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-1.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-2.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-3.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-4.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1.js - -# ES6 != ES5: Object.preventExtensions accepts all types -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-1.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-2.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-3.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-4.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1.js - -# ES6 != ES5: Object.isSealed accepts all types -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.11/15.2.3.11-1.js - -# ES6 != ES5: Object.isFrozen accepts all types -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-1.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-2.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-3.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-4.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1.js - -# ES6 != ES5: Object.isExtensible accepts all types -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-1.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-2.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-3.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-4.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1.js - -# ES6 != ES5: Object.keys converts argument to object -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-1.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-2.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-3.js - -# ES6 != ES5: source and other properties of RegExp.prototype are not own properties -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-212.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-213.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-214.js -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-215.js - -# ES6 != ES5: String numeric object properties are enumerated first -test262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-44.js - -# ES6: new RegExp(regex, flags) is valid -test262o/test/suite/ch15/15.10/15.10.3/S15.10.3.1_A2_T1.js -test262o/test/suite/ch15/15.10/15.10.3/S15.10.3.1_A2_T2.js -test262o/test/suite/ch15/15.10/15.10.4/15.10.4.1/15.10.4.1-1.js -test262o/test/suite/ch15/15.10/15.10.4/S15.10.4.1_A2_T1.js -test262o/test/suite/ch15/15.10/15.10.4/S15.10.4.1_A2_T2.js - -# ES6 != ES5: RegExp.prototype.test behavior -test262o/test/suite/ch15/15.10/15.10.6/15.10.6.2/S15.10.6.2_A5_T3.js - -# ES6 != ES5: source, global, ignoreCase, multiline, lastIndex are not data properties -# of RegExp objects and RegExp.prototype is not a RegExp object -test262o/test/suite/ch15/15.10/15.10.6/15.10.6.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/15.10.7.1-1.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/15.10.7.1-2.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/S15.10.7.1_A8.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/S15.10.7.1_A9.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/S15.10.7.1_A10.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/15.10.7.2-1.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/15.10.7.2-2.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/S15.10.7.2_A8.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/S15.10.7.2_A9.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/S15.10.7.2_A10.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/15.10.7.3-1.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/15.10.7.3-2.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/S15.10.7.3_A8.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/S15.10.7.3_A9.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/S15.10.7.3_A10.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/15.10.7.4-1.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/15.10.7.4-2.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/S15.10.7.4_A8.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/S15.10.7.4_A9.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/S15.10.7.4_A10.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.5/15.10.7.5-1.js -test262o/test/suite/ch15/15.10/15.10.7/15.10.7.5/15.10.7.5-2.js - -# ES6 != ES5: Error.prototype is a normal object -test262o/test/suite/ch15/15.11/15.11.4/S15.11.4_A2.js - -# ES6 different ToLength() semantics -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.5/S15.4.4.5_A4_T3.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A2_T2.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A3_T1.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A3_T2.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A3_T3.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A2_T2.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A4_T1.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A4_T3.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.8/S15.4.4.8_A3_T3.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.9/S15.4.4.9_A3_T3.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A3_T1.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A3_T2.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A3_T3.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.11/S15.4.4.11_A4_T3.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.12/S15.4.4.12_A3_T1.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.12/S15.4.4.12_A3_T3.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.13/S15.4.4.13_A3_T2.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-7.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-8.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-12.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-14.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-25.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-28.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-29.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-7.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-12.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-25.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-28.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-7.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-8.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-12.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-14.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-25.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-29.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-7.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-8.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-12.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-14.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-25.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-28.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-29.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-7.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-12.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-25.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-7.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-8.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-12.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-14.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-25.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-28.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-29.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-7.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-12.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-25.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-7.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-12.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-25.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-7.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-12.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-25.js - -# ES6 different ToLength() semantics causes near infinite runtime -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-14.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-14.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-14.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-14.js -test262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-14.js - -# ES6 arguments/caller changes -test262o/test/suite/ch10/10.6/10.6-13-b-1-s.js -test262o/test/suite/ch10/10.6/10.6-13-b-2-s.js -test262o/test/suite/ch10/10.6/10.6-13-b-3-s.js -test262o/test/suite/ch10/10.6/10.6-14-1-s.js -test262o/test/suite/ch10/10.6/10.6-14-b-1-s.js -test262o/test/suite/ch10/10.6/10.6-14-b-4-s.js -test262o/test/suite/ch13/13.2/13.2-29-s.js -test262o/test/suite/ch13/13.2/13.2-30-s.js -test262o/test/suite/ch13/13.2/13.2-31-s.js -test262o/test/suite/ch13/13.2/13.2-32-s.js -test262o/test/suite/ch13/13.2/13.2-33-s.js -test262o/test/suite/ch13/13.2/13.2-34-s.js -test262o/test/suite/ch13/13.2/13.2-35-s.js -test262o/test/suite/ch13/13.2/13.2-36-s.js -test262o/test/suite/ch13/13.2/S13.2.3_A1.js -test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-20-1.js -test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-20-4.js -test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-20-5.js -test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-21-1.js -test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-21-4.js -test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-21-5.js - -# u180e is no longer considered as a space -test262o/test/suite/ch09/9.3/9.3.1/S9.3.1_A2.js -test262o/test/suite/ch09/9.3/9.3.1/S9.3.1_A3_T1.js -test262o/test/suite/ch09/9.3/9.3.1/S9.3.1_A3_T2.js -test262o/test/suite/ch15/15.1/15.1.2/15.1.2.2/S15.1.2.2_A2_T10.js -test262o/test/suite/ch15/15.1/15.1.2/15.1.2.3/S15.1.2.3_A2_T10.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-2.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-3.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-4.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-5.js -test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-6.js -test262o/test/suite/ch15/15.10/15.10.2/15.10.2.12/S15.10.2.12_A1_T1.js -test262o/test/suite/ch15/15.10/15.10.2/15.10.2.12/S15.10.2.12_A2_T1.js - -# E6 eval return value is different -test262o/test/suite/ch12/12.6/12.6.3/S12.6.3_A9.js -test262o/test/suite/ch12/12.6/12.6.3/S12.6.3_A9.1.js - -# ECMA 2019 optional-catch-binding feature allows try{}catch{} -test262o/test/suite/ch12/12.14/S12.14_A16_T4.js - -# Syntax error instead of ReferenceError in ES2020 -test262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-1.js -test262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-2.js -test262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-3.js -test262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-4.js - -[tests] -# list test files or use config.testdir diff --git a/third_party/quickjs/test262o_errors.txt b/third_party/quickjs/test262o_errors.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/third_party/quickjs/tests/bjson.c b/third_party/quickjs/tests/bjson.c deleted file mode 100644 index 8e5274134..000000000 --- a/third_party/quickjs/tests/bjson.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * QuickJS: binary JSON module (test only) - * - * Copyright (c) 2017-2019 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "../quickjs-libc.h" -#include "../cutils.h" - -static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - uint8_t *buf; - uint64_t pos, len; - JSValue obj; - size_t size; - int flags; - - if (JS_ToIndex(ctx, &pos, argv[1])) - return JS_EXCEPTION; - if (JS_ToIndex(ctx, &len, argv[2])) - return JS_EXCEPTION; - buf = JS_GetArrayBuffer(ctx, &size, argv[0]); - if (!buf) - return JS_EXCEPTION; - if (pos + len > size) - return JS_ThrowRangeError(ctx, "array buffer overflow"); - flags = 0; - if (JS_ToBool(ctx, argv[3])) - flags |= JS_READ_OBJ_REFERENCE; - obj = JS_ReadObject(ctx, buf + pos, len, flags); - return obj; -} - -static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - size_t len; - uint8_t *buf; - JSValue array; - int flags; - - flags = 0; - if (JS_ToBool(ctx, argv[1])) - flags |= JS_WRITE_OBJ_REFERENCE; - buf = JS_WriteObject(ctx, &len, argv[0], flags); - if (!buf) - return JS_EXCEPTION; - array = JS_NewArrayBufferCopy(ctx, buf, len); - js_free(ctx, buf); - return array; -} - -static const JSCFunctionListEntry js_bjson_funcs[] = { - JS_CFUNC_DEF("read", 4, js_bjson_read ), - JS_CFUNC_DEF("write", 2, js_bjson_write ), -}; - -static int js_bjson_init(JSContext *ctx, JSModuleDef *m) -{ - return JS_SetModuleExportList(ctx, m, js_bjson_funcs, - countof(js_bjson_funcs)); -} - -#ifdef JS_SHARED_LIBRARY -#define JS_INIT_MODULE js_init_module -#else -#define JS_INIT_MODULE js_init_module_bjson -#endif - -JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name) -{ - JSModuleDef *m; - m = JS_NewCModule(ctx, module_name, js_bjson_init); - if (!m) - return NULL; - JS_AddModuleExportList(ctx, m, js_bjson_funcs, countof(js_bjson_funcs)); - return m; -} diff --git a/third_party/quickjs/tests/microbench.js b/third_party/quickjs/tests/microbench.js deleted file mode 100644 index 1c5f52d2e..000000000 --- a/third_party/quickjs/tests/microbench.js +++ /dev/null @@ -1,1065 +0,0 @@ -/* - * Javascript Micro benchmark - * - * Copyright (c) 2017-2019 Fabrice Bellard - * Copyright (c) 2017-2019 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. - */ -import * as std from "std"; - -function pad(str, n) { - str += ""; - while (str.length < n) - str += " "; - return str; -} - -function pad_left(str, n) { - str += ""; - while (str.length < n) - str = " " + str; - return str; -} - -function pad_center(str, n) { - str += ""; - while (str.length < n) { - if ((n - str.length) & 1) - str = str + " "; - else - str = " " + str; - } - return str; -} - -function toPrec(n, prec) { - var i, s; - for (i = 0; i < prec; i++) - n *= 10; - s = "" + Math.round(n); - for (i = s.length - prec; i <= 0; i++) - s = "0" + s; - if (prec > 0) - s = s.substring(0, i) + "." + s.substring(i); - return s; -} - -var ref_data; -var log_data; - -var heads = [ "TEST", "N", "TIME (ns)", "REF (ns)", "SCORE (%)" ]; -var widths = [ 22, 10, 9, 9, 9 ]; -var precs = [ 0, 0, 2, 2, 2 ]; -var total = [ 0, 0, 0, 0, 0 ]; -var total_score = 0; -var total_scale = 0; - -if (typeof console == "undefined") { - var console = { log: print }; -} - -function log_line() { - var i, n, s, a; - s = ""; - for (i = 0, n = arguments.length; i < n; i++) { - if (i > 0) - s += " "; - a = arguments[i]; - if (typeof a == "number") { - total[i] += a; - a = toPrec(a, precs[i]); - s += pad_left(a, widths[i]); - } else { - s += pad_left(a, widths[i]); - } - } - console.log(s); -} - -var clocks_per_sec = 1000000; -var max_iterations = 100; -var clock_threshold = 2000; /* favoring short measuring spans */ -var min_n_argument = 1; -var get_clock; - -if (typeof globalThis.__date_clock != "function") { - console.log("using fallback millisecond clock"); - clocks_per_sec = 1000; - max_iterations = 10; - clock_threshold = 100; - get_clock = Date.now; -} else { - get_clock = globalThis.__date_clock; -} - -function log_one(text, n, ti) { - var ref; - - if (ref_data) - ref = ref_data[text]; - else - ref = null; - - ti = Math.round(ti * 100) / 100; - log_data[text] = ti; - if (typeof ref === "number") { - log_line(text, n, ti, ref, ti * 100 / ref); - total_score += ti * 100 / ref; - total_scale += 100; - } else { - log_line(text, n, ti); - total_score += 100; - total_scale += 100; - } -} - -function bench(f, text) -{ - var i, j, n, t, t1, ti, nb_its, ref, ti_n, ti_n1, min_ti; - - nb_its = n = 1; - if (f.bench) { - ti_n = f(text); - } else { - ti_n = 1000000000; - min_ti = clock_threshold / 10; - for(i = 0; i < 30; i++) { - ti = 1000000000; - for (j = 0; j < max_iterations; j++) { - t = get_clock(); - while ((t1 = get_clock()) == t) - continue; - nb_its = f(n); - if (nb_its < 0) - return; // test failure - t1 = get_clock() - t1; - if (ti > t1) - ti = t1; - } - if (ti >= min_ti) { - ti_n1 = ti / nb_its; - if (ti_n > ti_n1) - ti_n = ti_n1; - } - if (ti >= clock_threshold && n >= min_n_argument) - break; - - n = n * [ 2, 2.5, 2 ][i % 3]; - } - // to use only the best timing from the last loop, uncomment below - //ti_n = ti / nb_its; - } - /* nano seconds per iteration */ - log_one(text, n, ti_n * 1e9 / clocks_per_sec); -} - -var global_res; /* to be sure the code is not optimized */ - -function empty_loop(n) { - var j; - for(j = 0; j < n; j++) { - } - return n; -} - -function date_now(n) { - var j; - for(j = 0; j < n; j++) { - Date.now(); - } - return n; -} - -function prop_read(n) -{ - var obj, sum, j; - obj = {a: 1, b: 2, c:3, d:4 }; - sum = 0; - for(j = 0; j < n; j++) { - sum += obj.a; - sum += obj.b; - sum += obj.c; - sum += obj.d; - } - global_res = sum; - return n * 4; -} - -function prop_write(n) -{ - var obj, j; - obj = {a: 1, b: 2, c:3, d:4 }; - for(j = 0; j < n; j++) { - obj.a = j; - obj.b = j; - obj.c = j; - obj.d = j; - } - return n * 4; -} - -function prop_create(n) -{ - var obj, j; - for(j = 0; j < n; j++) { - obj = new Object(); - obj.a = 1; - obj.b = 2; - obj.c = 3; - obj.d = 4; - } - return n * 4; -} - -function prop_delete(n) -{ - var obj, j; - obj = {}; - for(j = 0; j < n; j++) { - obj[j] = 1; - } - for(j = 0; j < n; j++) { - delete obj[j]; - } - return n; -} - -function array_read(n) -{ - var tab, len, sum, i, j; - tab = []; - len = 10; - for(i = 0; i < len; i++) - tab[i] = i; - sum = 0; - for(j = 0; j < n; j++) { - sum += tab[0]; - sum += tab[1]; - sum += tab[2]; - sum += tab[3]; - sum += tab[4]; - sum += tab[5]; - sum += tab[6]; - sum += tab[7]; - sum += tab[8]; - sum += tab[9]; - } - global_res = sum; - return len * n; -} - -function array_write(n) -{ - var tab, len, i, j; - tab = []; - len = 10; - for(i = 0; i < len; i++) - tab[i] = i; - for(j = 0; j < n; j++) { - tab[0] = j; - tab[1] = j; - tab[2] = j; - tab[3] = j; - tab[4] = j; - tab[5] = j; - tab[6] = j; - tab[7] = j; - tab[8] = j; - tab[9] = j; - } - return len * n; -} - -function array_prop_create(n) -{ - var tab, i, j, len; - len = 1000; - for(j = 0; j < n; j++) { - tab = []; - for(i = 0; i < len; i++) - tab[i] = i; - } - return len * n; -} - -function array_length_decr(n) -{ - var tab, i, j, len; - len = 1000; - tab = []; - for(i = 0; i < len; i++) - tab[i] = i; - for(j = 0; j < n; j++) { - for(i = len - 1; i >= 0; i--) - tab.length = i; - } - return len * n; -} - -function array_hole_length_decr(n) -{ - var tab, i, j, len; - len = 1000; - tab = []; - for(i = 0; i < len; i++) { - if (i != 3) - tab[i] = i; - } - for(j = 0; j < n; j++) { - for(i = len - 1; i >= 0; i--) - tab.length = i; - } - return len * n; -} - -function array_push(n) -{ - var tab, i, j, len; - len = 500; - for(j = 0; j < n; j++) { - tab = []; - for(i = 0; i < len; i++) - tab.push(i); - } - return len * n; -} - -function array_pop(n) -{ - var tab, i, j, len, sum; - len = 500; - for(j = 0; j < n; j++) { - tab = []; - for(i = 0; i < len; i++) - tab[i] = i; - sum = 0; - for(i = 0; i < len; i++) - sum += tab.pop(); - global_res = sum; - } - return len * n; -} - -function typed_array_read(n) -{ - var tab, len, sum, i, j; - len = 10; - tab = new Int32Array(len); - for(i = 0; i < len; i++) - tab[i] = i; - sum = 0; - for(j = 0; j < n; j++) { - sum += tab[0]; - sum += tab[1]; - sum += tab[2]; - sum += tab[3]; - sum += tab[4]; - sum += tab[5]; - sum += tab[6]; - sum += tab[7]; - sum += tab[8]; - sum += tab[9]; - } - global_res = sum; - return len * n; -} - -function typed_array_write(n) -{ - var tab, len, i, j; - len = 10; - tab = new Int32Array(len); - for(i = 0; i < len; i++) - tab[i] = i; - for(j = 0; j < n; j++) { - tab[0] = j; - tab[1] = j; - tab[2] = j; - tab[3] = j; - tab[4] = j; - tab[5] = j; - tab[6] = j; - tab[7] = j; - tab[8] = j; - tab[9] = j; - } - return len * n; -} - -var global_var0; - -function global_read(n) -{ - var sum, j; - global_var0 = 0; - sum = 0; - for(j = 0; j < n; j++) { - sum += global_var0; - sum += global_var0; - sum += global_var0; - sum += global_var0; - } - global_res = sum; - return n * 4; -} - -var global_write = - (1, eval)(`(function global_write(n) - { - var j; - for(j = 0; j < n; j++) { - global_var0 = j; - global_var0 = j; - global_var0 = j; - global_var0 = j; - } - return n * 4; - })`); - -function global_write_strict(n) -{ - var j; - for(j = 0; j < n; j++) { - global_var0 = j; - global_var0 = j; - global_var0 = j; - global_var0 = j; - } - return n * 4; -} - -function local_destruct(n) -{ - var j, v1, v2, v3, v4; - var array = [ 1, 2, 3, 4, 5]; - var o = { a:1, b:2, c:3, d:4 }; - var a, b, c, d; - for(j = 0; j < n; j++) { - [ v1, v2,, v3, ...v4] = array; - ({ a, b, c, d } = o); - ({ a: a, b: b, c: c, d: d } = o); - } - return n * 12; -} - -var global_v1, global_v2, global_v3, global_v4; -var global_a, global_b, global_c, global_d; - -var global_destruct = - (1, eval)(`(function global_destruct(n) - { - var j, v1, v2, v3, v4; - var array = [ 1, 2, 3, 4, 5 ]; - var o = { a:1, b:2, c:3, d:4 }; - var a, b, c, d; - for(j = 0; j < n; j++) { - [ global_v1, global_v2,, global_v3, ...global_v4] = array; - ({ a: global_a, b: global_b, c: global_c, d: global_d } = o); - } - return n * 8; - })`); - -function global_destruct_strict(n) -{ - var j, v1, v2, v3, v4; - var array = [ 1, 2, 3, 4, 5 ]; - var o = { a:1, b:2, c:3, d:4 }; - var a, b, c, d; - for(j = 0; j < n; j++) { - [ global_v1, global_v2,, global_v3, ...global_v4] = array; - ({ a: global_a, b: global_b, c: global_c, d: global_d } = o); - } - return n * 8; -} - -function func_call(n) -{ - function f(a) - { - return 1; - } - - var j, sum; - sum = 0; - for(j = 0; j < n; j++) { - sum += f(j); - sum += f(j); - sum += f(j); - sum += f(j); - } - global_res = sum; - return n * 4; -} - -function closure_var(n) -{ - function f(a) - { - sum++; - } - - var j, sum; - sum = 0; - for(j = 0; j < n; j++) { - f(j); - f(j); - f(j); - f(j); - } - global_res = sum; - return n * 4; -} - -function int_arith(n) -{ - var i, j, sum; - global_res = 0; - for(j = 0; j < n; j++) { - sum = 0; - for(i = 0; i < 1000; i++) { - sum += i * i; - } - global_res += sum; - } - return n * 1000; -} - -function float_arith(n) -{ - var i, j, sum, a, incr, a0; - global_res = 0; - a0 = 0.1; - incr = 1.1; - for(j = 0; j < n; j++) { - sum = 0; - a = a0; - for(i = 0; i < 1000; i++) { - sum += a * a; - a += incr; - } - global_res += sum; - } - return n * 1000; -} - -function bigfloat_arith(n) -{ - var i, j, sum, a, incr, a0; - global_res = 0; - a0 = BigFloat("0.1"); - incr = BigFloat("1.1"); - for(j = 0; j < n; j++) { - sum = 0; - a = a0; - for(i = 0; i < 1000; i++) { - sum += a * a; - a += incr; - } - global_res += sum; - } - return n * 1000; -} - -function float256_arith(n) -{ - return BigFloatEnv.setPrec(bigfloat_arith.bind(null, n), 237, 19); -} - -function bigint_arith(n, bits) -{ - var i, j, sum, a, incr, a0, sum0; - sum0 = global_res = BigInt(0); - a0 = BigInt(1) << BigInt(Math.floor((bits - 10) * 0.5)); - incr = BigInt(1); - for(j = 0; j < n; j++) { - sum = sum0; - a = a0; - for(i = 0; i < 1000; i++) { - sum += a * a; - a += incr; - } - global_res += sum; - } - return n * 1000; -} - -function bigint64_arith(n) -{ - return bigint_arith(n, 64); -} - -function bigint256_arith(n) -{ - return bigint_arith(n, 256); -} - -function set_collection_add(n) -{ - var s, i, j, len = 100; - s = new Set(); - for(j = 0; j < n; j++) { - for(i = 0; i < len; i++) { - s.add(String(i), i); - } - for(i = 0; i < len; i++) { - if (!s.has(String(i))) - throw Error("bug in Set"); - } - } - return n * len; -} - -function array_for(n) -{ - var r, i, j, sum; - r = []; - for(i = 0; i < 100; i++) - r[i] = i; - for(j = 0; j < n; j++) { - sum = 0; - for(i = 0; i < 100; i++) { - sum += r[i]; - } - global_res = sum; - } - return n * 100; -} - -function array_for_in(n) -{ - var r, i, j, sum; - r = []; - for(i = 0; i < 100; i++) - r[i] = i; - for(j = 0; j < n; j++) { - sum = 0; - for(i in r) { - sum += r[i]; - } - global_res = sum; - } - return n * 100; -} - -function array_for_of(n) -{ - var r, i, j, sum; - r = []; - for(i = 0; i < 100; i++) - r[i] = i; - for(j = 0; j < n; j++) { - sum = 0; - for(i of r) { - sum += i; - } - global_res = sum; - } - return n * 100; -} - -function math_min(n) -{ - var i, j, r; - r = 0; - for(j = 0; j < n; j++) { - for(i = 0; i < 1000; i++) - r = Math.min(i, 500); - global_res = r; - } - return n * 1000; -} - -/* incremental string contruction as local var */ -function string_build1(n) -{ - var i, j, r; - r = ""; - for(j = 0; j < n; j++) { - for(i = 0; i < 100; i++) - r += "x"; - global_res = r; - } - return n * 100; -} - -/* incremental string contruction as arg */ -function string_build2(n, r) -{ - var i, j; - r = ""; - for(j = 0; j < n; j++) { - for(i = 0; i < 100; i++) - r += "x"; - global_res = r; - } - return n * 100; -} - -/* incremental string contruction by prepending */ -function string_build3(n, r) -{ - var i, j; - r = ""; - for(j = 0; j < n; j++) { - for(i = 0; i < 100; i++) - r = "x" + r; - global_res = r; - } - return n * 100; -} - -/* incremental string contruction with multiple reference */ -function string_build4(n) -{ - var i, j, r, s; - r = ""; - for(j = 0; j < n; j++) { - for(i = 0; i < 100; i++) { - s = r; - r += "x"; - } - global_res = r; - } - return n * 100; -} - -/* sort bench */ - -function sort_bench(text) { - function random(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[(Math.random() * n) >> 0]; - } - function random8(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[(Math.random() * 256) >> 0]; - } - function random1(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[(Math.random() * 2) >> 0]; - } - function hill(arr, n, def) { - var mid = n >> 1; - for (var i = 0; i < mid; i++) - arr[i] = def[i]; - for (var i = mid; i < n; i++) - arr[i] = def[n - i]; - } - function comb(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[(i & 1) * i]; - } - function crisscross(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[(i & 1) ? n - i : i]; - } - function zero(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[0]; - } - function increasing(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[i]; - } - function decreasing(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[n - 1 - i]; - } - function alternate(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[i ^ 1]; - } - function jigsaw(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[i % (n >> 4)]; - } - function incbutone(arr, n, def) { - for (var i = 0; i < n; i++) - arr[i] = def[i]; - if (n > 0) - arr[n >> 2] = def[n]; - } - function incbutfirst(arr, n, def) { - if (n > 0) - arr[0] = def[n]; - for (var i = 1; i < n; i++) - arr[i] = def[i]; - } - function incbutlast(arr, n, def) { - for (var i = 0; i < n - 1; i++) - arr[i] = def[i + 1]; - if (n > 0) - arr[n - 1] = def[0]; - } - - var sort_cases = [ random, random8, random1, jigsaw, hill, comb, - crisscross, zero, increasing, decreasing, alternate, - incbutone, incbutlast, incbutfirst ]; - - var n = sort_bench.array_size || 10000; - var array_type = sort_bench.array_type || Array; - var def, arr; - var i, j, x, y; - var total = 0; - - var save_total_score = total_score; - var save_total_scale = total_scale; - - // initialize default sorted array (n + 1 elements) - def = new array_type(n + 1); - if (array_type == Array) { - for (i = 0; i <= n; i++) { - def[i] = i + ""; - } - } else { - for (i = 0; i <= n; i++) { - def[i] = i; - } - } - def.sort(); - for (var f of sort_cases) { - var ti = 0, tx = 0; - for (j = 0; j < 100; j++) { - arr = new array_type(n); - f(arr, n, def); - var t1 = get_clock(); - arr.sort(); - t1 = get_clock() - t1; - tx += t1; - if (!ti || ti > t1) - ti = t1; - if (tx >= clocks_per_sec) - break; - } - total += ti; - - i = 0; - x = arr[0]; - if (x !== void 0) { - for (i = 1; i < n; i++) { - y = arr[i]; - if (y === void 0) - break; - if (x > y) - break; - x = y; - } - } - while (i < n && arr[i] === void 0) - i++; - if (i < n) { - console.log("sort_bench: out of order error for " + f.name + - " at offset " + (i - 1) + - ": " + arr[i - 1] + " > " + arr[i]); - } - if (sort_bench.verbose) - log_one("sort_" + f.name, n, ti, n * 100); - } - total_score = save_total_score; - total_scale = save_total_scale; - return total / n / 1000; -} -sort_bench.bench = true; -sort_bench.verbose = false; - -function int_to_string(n) -{ - var s, r, j; - r = 0; - for(j = 0; j < n; j++) { - s = (j + 1).toString(); - } - return n; -} - -function float_to_string(n) -{ - var s, r, j; - r = 0; - for(j = 0; j < n; j++) { - s = (j + 0.1).toString(); - } - return n; -} - -function string_to_int(n) -{ - var s, r, j; - r = 0; - s = "12345"; - r = 0; - for(j = 0; j < n; j++) { - r += (s | 0); - } - global_res = r; - return n; -} - -function string_to_float(n) -{ - var s, r, j; - r = 0; - s = "12345.6"; - r = 0; - for(j = 0; j < n; j++) { - r -= s; - } - global_res = r; - return n; -} - -function load_result(filename) -{ - var f, str, res; - if (typeof std === "undefined") - return null; - f = std.open(filename, "r"); - if (!f) - return null; - str = f.readAsString(); - res = JSON.parse(str); - f.close(); - return res; -} - -function save_result(filename, obj) -{ - var f; - if (typeof std === "undefined") - return; - f = std.open(filename, "w"); - f.puts(JSON.stringify(obj, null, 2)); - f.puts("\n"); - f.close(); -} - -function main(argc, argv, g) -{ - var test_list = [ - empty_loop, - date_now, - prop_read, - prop_write, - prop_create, - prop_delete, - array_read, - array_write, - array_prop_create, - array_length_decr, - array_hole_length_decr, - array_push, - array_pop, - typed_array_read, - typed_array_write, - global_read, - global_write, - global_write_strict, - local_destruct, - global_destruct, - global_destruct_strict, - func_call, - closure_var, - int_arith, - float_arith, - set_collection_add, - array_for, - array_for_in, - array_for_of, - math_min, - string_build1, - string_build2, - //string_build3, - //string_build4, - sort_bench, - int_to_string, - float_to_string, - string_to_int, - string_to_float, - ]; - var tests = []; - var i, j, n, f, name; - - if (typeof BigInt == "function") { - /* BigInt test */ - test_list.push(bigint64_arith); - test_list.push(bigint256_arith); - } - if (typeof BigFloat == "function") { - /* BigFloat test */ - test_list.push(float256_arith); - } - - for (i = 1; i < argc;) { - name = argv[i++]; - if (name == "-a") { - sort_bench.verbose = true; - continue; - } - if (name == "-t") { - name = argv[i++]; - sort_bench.array_type = g[name]; - if (typeof sort_bench.array_type != "function") { - console.log("unknown array type: " + name); - return 1; - } - continue; - } - if (name == "-n") { - sort_bench.array_size = +argv[i++]; - continue; - } - for (j = 0; j < test_list.length; j++) { - f = test_list[j]; - if (name === f.name) { - tests.push(f); - break; - } - } - if (j == test_list.length) { - console.log("unknown benchmark: " + name); - return 1; - } - } - if (tests.length == 0) - tests = test_list; - - ref_data = load_result("microbench.txt"); - log_data = {}; - log_line.apply(null, heads); - n = 0; - - for(i = 0; i < tests.length; i++) { - f = tests[i]; - bench(f, f.name, ref_data, log_data); - if (ref_data && ref_data[f.name]) - n++; - } - if (ref_data) - log_line("total", "", total[2], total[3], total_score * 100 / total_scale); - else - log_line("total", "", total[2]); - - if (tests == test_list) - save_result("microbench-new.txt", log_data); -} - -if (!scriptArgs) - scriptArgs = []; -main(scriptArgs.length, scriptArgs, this); diff --git a/third_party/quickjs/tests/test262.patch b/third_party/quickjs/tests/test262.patch deleted file mode 100644 index 6576bdc28..000000000 --- a/third_party/quickjs/tests/test262.patch +++ /dev/null @@ -1,71 +0,0 @@ -diff --git a/harness/atomicsHelper.js b/harness/atomicsHelper.js -index 9c1217351e..3c24755558 100644 ---- a/harness/atomicsHelper.js -+++ b/harness/atomicsHelper.js -@@ -227,10 +227,14 @@ $262.agent.waitUntil = function(typedArray, index, expected) { - * } - */ - $262.agent.timeouts = { -- yield: 100, -- small: 200, -- long: 1000, -- huge: 10000, -+// yield: 100, -+// small: 200, -+// long: 1000, -+// huge: 10000, -+ yield: 20, -+ small: 20, -+ long: 100, -+ huge: 1000, - }; - - /** -diff --git a/harness/regExpUtils.js b/harness/regExpUtils.js -index be7039fda0..7b38abf8df 100644 ---- a/harness/regExpUtils.js -+++ b/harness/regExpUtils.js -@@ -6,24 +6,27 @@ description: | - defines: [buildString, testPropertyEscapes, matchValidator] - ---*/ - -+if ($262 && typeof $262.codePointRange === "function") { -+ /* use C function to build the codePointRange (much faster with -+ slow JS engines) */ -+ codePointRange = $262.codePointRange; -+} else { -+ codePointRange = function codePointRange(start, end) { -+ const codePoints = []; -+ let length = 0; -+ for (codePoint = start; codePoint < end; codePoint++) { -+ codePoints[length++] = codePoint; -+ } -+ return String.fromCodePoint.apply(null, codePoints); -+ } -+} -+ - function buildString({ loneCodePoints, ranges }) { -- const CHUNK_SIZE = 10000; -- let result = Reflect.apply(String.fromCodePoint, null, loneCodePoints); -- for (let i = 0; i < ranges.length; i++) { -- const range = ranges[i]; -- const start = range[0]; -- const end = range[1]; -- const codePoints = []; -- for (let length = 0, codePoint = start; codePoint <= end; codePoint++) { -- codePoints[length++] = codePoint; -- if (length === CHUNK_SIZE) { -- result += Reflect.apply(String.fromCodePoint, null, codePoints); -- codePoints.length = length = 0; -- } -+ let result = String.fromCodePoint.apply(null, loneCodePoints); -+ for (const [start, end] of ranges) { -+ result += codePointRange(start, end + 1); - } -- result += Reflect.apply(String.fromCodePoint, null, codePoints); -- } -- return result; -+ return result; - } - - function testPropertyEscapes(regex, string, expression) { diff --git a/third_party/quickjs/tests/test_bignum.js b/third_party/quickjs/tests/test_bignum.js deleted file mode 100644 index f4f72a0a6..000000000 --- a/third_party/quickjs/tests/test_bignum.js +++ /dev/null @@ -1,326 +0,0 @@ -"use strict"; - -function assert(actual, expected, message) { - if (arguments.length == 1) - expected = true; - - if (actual === expected) - return; - - if (actual !== null && expected !== null - && typeof actual == 'object' && typeof expected == 'object' - && actual.toString() === expected.toString()) - return; - - throw Error("assertion failed: got |" + actual + "|" + - ", expected |" + expected + "|" + - (message ? " (" + message + ")" : "")); -} - -function assertThrows(err, func) -{ - var ex; - ex = false; - try { - func(); - } catch(e) { - ex = true; - assert(e instanceof err); - } - assert(ex, true, "exception expected"); -} - -// load more elaborate version of assert if available -try { __loadScript("test_assert.js"); } catch(e) {} - -/*----------------*/ - -function bigint_pow(a, n) -{ - var r, i; - r = 1n; - for(i = 0n; i < n; i++) - r *= a; - return r; -} - -/* a must be < b */ -function test_less(a, b) -{ - assert(a < b); - assert(!(b < a)); - assert(a <= b); - assert(!(b <= a)); - assert(b > a); - assert(!(a > b)); - assert(b >= a); - assert(!(a >= b)); - assert(a != b); - assert(!(a == b)); -} - -/* a must be numerically equal to b */ -function test_eq(a, b) -{ - assert(a == b); - assert(b == a); - assert(!(a != b)); - assert(!(b != a)); - assert(a <= b); - assert(b <= a); - assert(!(a < b)); - assert(a >= b); - assert(b >= a); - assert(!(a > b)); -} - -function test_bigint1() -{ - var a, r; - - test_less(2n, 3n); - test_eq(3n, 3n); - - test_less(2, 3n); - test_eq(3, 3n); - - test_less(2.1, 3n); - test_eq(Math.sqrt(4), 2n); - - a = bigint_pow(3n, 100n); - assert((a - 1n) != a); - assert(a == 515377520732011331036461129765621272702107522001n); - assert(a == 0x5a4653ca673768565b41f775d6947d55cf3813d1n); - - r = 1n << 31n; - assert(r, 2147483648n, "1 << 31n === 2147483648n"); - - r = 1n << 32n; - assert(r, 4294967296n, "1 << 32n === 4294967296n"); -} - -function test_bigint2() -{ - assert(BigInt(""), 0n); - assert(BigInt(" 123"), 123n); - assert(BigInt(" 123 "), 123n); - assertThrows(SyntaxError, () => { BigInt("+") } ); - assertThrows(SyntaxError, () => { BigInt("-") } ); - assertThrows(SyntaxError, () => { BigInt("\x00a") } ); - assertThrows(SyntaxError, () => { BigInt(" 123 r") } ); -} - -function test_divrem(div1, a, b, q) -{ - var div, divrem, t; - div = BigInt[div1]; - divrem = BigInt[div1 + "rem"]; - assert(div(a, b) == q); - t = divrem(a, b); - assert(t[0] == q); - assert(a == b * q + t[1]); -} - -function test_idiv1(div, a, b, r) -{ - test_divrem(div, a, b, r[0]); - test_divrem(div, -a, b, r[1]); - test_divrem(div, a, -b, r[2]); - test_divrem(div, -a, -b, r[3]); -} - -/* QuickJS BigInt extensions */ -function test_bigint_ext() -{ - var r; - assert(BigInt.floorLog2(0n) === -1n); - assert(BigInt.floorLog2(7n) === 2n); - - assert(BigInt.sqrt(0xffffffc000000000000000n) === 17592185913343n); - r = BigInt.sqrtrem(0xffffffc000000000000000n); - assert(r[0] === 17592185913343n); - assert(r[1] === 35167191957503n); - - test_idiv1("tdiv", 3n, 2n, [1n, -1n, -1n, 1n]); - test_idiv1("fdiv", 3n, 2n, [1n, -2n, -2n, 1n]); - test_idiv1("cdiv", 3n, 2n, [2n, -1n, -1n, 2n]); - test_idiv1("ediv", 3n, 2n, [1n, -2n, -1n, 2n]); -} - -function test_bigfloat() -{ - var e, a, b, sqrt2; - - assert(typeof 1n === "bigint"); - assert(typeof 1l === "bigfloat"); - assert(1 == 1.0l); - assert(1 !== 1.0l); - - test_less(2l, 3l); - test_eq(3l, 3l); - - test_less(2, 3l); - test_eq(3, 3l); - - test_less(2.1, 3l); - test_eq(Math.sqrt(9), 3l); - - test_less(2n, 3l); - test_eq(3n, 3l); - - e = new BigFloatEnv(128); - assert(e.prec == 128); - a = BigFloat.sqrt(2l, e); - assert(a === BigFloat.parseFloat("0x1.6a09e667f3bcc908b2fb1366ea957d3e", 0, e)); - assert(e.inexact === true); - assert(BigFloat.fpRound(a) == 0x1.6a09e667f3bcc908b2fb1366ea95l); - - b = BigFloatEnv.setPrec(BigFloat.sqrt.bind(null, 2), 128); - assert(a === b); - - assert(BigFloat.isNaN(BigFloat(NaN))); - assert(BigFloat.isFinite(1l)); - assert(!BigFloat.isFinite(1l/0l)); - - assert(BigFloat.abs(-3l) === 3l); - assert(BigFloat.sign(-3l) === -1l); - - assert(BigFloat.exp(0.2l) === 1.2214027581601698339210719946396742l); - assert(BigFloat.log(3l) === 1.0986122886681096913952452369225256l); - assert(BigFloat.pow(2.1l, 1.6l) === 3.277561666451861947162828744873745l); - - assert(BigFloat.sin(-1l) === -0.841470984807896506652502321630299l); - assert(BigFloat.cos(1l) === 0.5403023058681397174009366074429766l); - assert(BigFloat.tan(0.1l) === 0.10033467208545054505808004578111154l); - - assert(BigFloat.asin(0.3l) === 0.30469265401539750797200296122752915l); - assert(BigFloat.acos(0.4l) === 1.1592794807274085998465837940224159l); - assert(BigFloat.atan(0.7l) === 0.610725964389208616543758876490236l); - assert(BigFloat.atan2(7.1l, -5.1l) === 2.1937053809751415549388104628759813l); - - assert(BigFloat.floor(2.5l) === 2l); - assert(BigFloat.ceil(2.5l) === 3l); - assert(BigFloat.trunc(-2.5l) === -2l); - assert(BigFloat.round(2.5l) === 3l); - - assert(BigFloat.fmod(3l,2l) === 1l); - assert(BigFloat.remainder(3l,2l) === -1l); - - /* string conversion */ - assert((1234.125l).toString(), "1234.125"); - assert((1234.125l).toFixed(2), "1234.13"); - assert((1234.125l).toFixed(2, "down"), "1234.12"); - assert((1234.125l).toExponential(), "1.234125e+3"); - assert((1234.125l).toExponential(5), "1.23413e+3"); - assert((1234.125l).toExponential(5, BigFloatEnv.RNDZ), "1.23412e+3"); - assert((1234.125l).toPrecision(6), "1234.13"); - assert((1234.125l).toPrecision(6, BigFloatEnv.RNDZ), "1234.12"); - - /* string conversion with binary base */ - assert((0x123.438l).toString(16), "123.438"); - assert((0x323.438l).toString(16), "323.438"); - assert((0x723.438l).toString(16), "723.438"); - assert((0xf23.438l).toString(16), "f23.438"); - assert((0x123.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "123.44"); - assert((0x323.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "323.44"); - assert((0x723.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "723.44"); - assert((0xf23.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "f23.44"); - assert((0x0.0000438l).toFixed(6, BigFloatEnv.RNDNA, 16), "0.000044"); - assert((0x1230000000l).toFixed(1, BigFloatEnv.RNDNA, 16), "1230000000.0"); - assert((0x123.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "123.44"); - assert((0x123.438l).toPrecision(5, BigFloatEnv.RNDZ, 16), "123.43"); - assert((0x323.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "323.44"); - assert((0x723.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "723.44"); - assert((-0xf23.438l).toPrecision(5, BigFloatEnv.RNDD, 16), "-f23.44"); - assert((0x123.438l).toExponential(4, BigFloatEnv.RNDNA, 16), "1.2344p+8"); -} - -function test_bigdecimal() -{ - assert(1m === 1m); - assert(1m !== 2m); - test_less(1m, 2m); - test_eq(2m, 2m); - - test_less(1, 2m); - test_eq(2, 2m); - - test_less(1.1, 2m); - test_eq(Math.sqrt(4), 2m); - - test_less(2n, 3m); - test_eq(3n, 3m); - - assert(BigDecimal("1234.1") === 1234.1m); - assert(BigDecimal(" 1234.1") === 1234.1m); - assert(BigDecimal(" 1234.1 ") === 1234.1m); - - assert(BigDecimal(0.1) === 0.1m); - assert(BigDecimal(123) === 123m); - assert(BigDecimal(true) === 1m); - - assert(123m + 1m === 124m); - assert(123m - 1m === 122m); - - assert(3.2m * 3m === 9.6m); - assert(10m / 2m === 5m); - assertThrows(RangeError, () => { 10m / 3m } ); - - assert(10m % 3m === 1m); - assert(-10m % 3m === -1m); - - assert(1234.5m ** 3m === 1881365963.625m); - assertThrows(RangeError, () => { 2m ** 3.1m } ); - assertThrows(RangeError, () => { 2m ** -3m } ); - - assert(BigDecimal.sqrt(2m, - { roundingMode: "half-even", - maximumSignificantDigits: 4 }) === 1.414m); - assert(BigDecimal.sqrt(101m, - { roundingMode: "half-even", - maximumFractionDigits: 3 }) === 10.050m); - assert(BigDecimal.sqrt(0.002m, - { roundingMode: "half-even", - maximumFractionDigits: 3 }) === 0.045m); - - assert(BigDecimal.round(3.14159m, - { roundingMode: "half-even", - maximumFractionDigits: 3 }) === 3.142m); - - assert(BigDecimal.add(3.14159m, 0.31212m, - { roundingMode: "half-even", - maximumFractionDigits: 2 }) === 3.45m); - assert(BigDecimal.sub(3.14159m, 0.31212m, - { roundingMode: "down", - maximumFractionDigits: 2 }) === 2.82m); - assert(BigDecimal.mul(3.14159m, 0.31212m, - { roundingMode: "half-even", - maximumFractionDigits: 3 }) === 0.981m); - assert(BigDecimal.mod(3.14159m, 0.31211m, - { roundingMode: "half-even", - maximumFractionDigits: 4 }) === 0.0205m); - assert(BigDecimal.div(20m, 3m, - { roundingMode: "half-even", - maximumSignificantDigits: 3 }) === 6.67m); - assert(BigDecimal.div(20m, 3m, - { roundingMode: "half-even", - maximumFractionDigits: 50 }) === - 6.66666666666666666666666666666666666666666666666667m); - - /* string conversion */ - assert((1234.125m).toString(), "1234.125"); - assert((1234.125m).toFixed(2), "1234.13"); - assert((1234.125m).toFixed(2, "down"), "1234.12"); - assert((1234.125m).toExponential(), "1.234125e+3"); - assert((1234.125m).toExponential(5), "1.23413e+3"); - assert((1234.125m).toExponential(5, "down"), "1.23412e+3"); - assert((1234.125m).toPrecision(6), "1234.13"); - assert((1234.125m).toPrecision(6, "down"), "1234.12"); - assert((-1234.125m).toPrecision(6, "floor"), "-1234.13"); -} - -test_bigint1(); -test_bigint2(); -test_bigint_ext(); -test_bigfloat(); -test_bigdecimal(); diff --git a/third_party/quickjs/tests/test_bjson.js b/third_party/quickjs/tests/test_bjson.js deleted file mode 100644 index fcbb8e6b3..000000000 --- a/third_party/quickjs/tests/test_bjson.js +++ /dev/null @@ -1,191 +0,0 @@ -import * as bjson from "./bjson.so"; - -function assert(actual, expected, message) { - if (arguments.length == 1) - expected = true; - - if (actual === expected) - return; - - if (actual !== null && expected !== null - && typeof actual == 'object' && typeof expected == 'object' - && actual.toString() === expected.toString()) - return; - - throw Error("assertion failed: got |" + actual + "|" + - ", expected |" + expected + "|" + - (message ? " (" + message + ")" : "")); -} - -function toHex(a) -{ - var i, s = "", tab, v; - tab = new Uint8Array(a); - for(i = 0; i < tab.length; i++) { - v = tab[i].toString(16); - if (v.length < 2) - v = "0" + v; - if (i !== 0) - s += " "; - s += v; - } - return s; -} - -function isArrayLike(a) -{ - return Array.isArray(a) || - (a instanceof Uint8ClampedArray) || - (a instanceof Uint8Array) || - (a instanceof Uint16Array) || - (a instanceof Uint32Array) || - (a instanceof Int8Array) || - (a instanceof Int16Array) || - (a instanceof Int32Array) || - (a instanceof Float32Array) || - (a instanceof Float64Array); -} - -function toStr(a) -{ - var s, i, props, prop; - - switch(typeof(a)) { - case "object": - if (a === null) - return "null"; - if (a instanceof Date) { - s = "Date(" + toStr(a.valueOf()) + ")"; - } else if (a instanceof Number) { - s = "Number(" + toStr(a.valueOf()) + ")"; - } else if (a instanceof String) { - s = "String(" + toStr(a.valueOf()) + ")"; - } else if (a instanceof Boolean) { - s = "Boolean(" + toStr(a.valueOf()) + ")"; - } else if (isArrayLike(a)) { - s = "["; - for(i = 0; i < a.length; i++) { - if (i != 0) - s += ","; - s += toStr(a[i]); - } - s += "]"; - } else { - props = Object.keys(a); - s = "{"; - for(i = 0; i < props.length; i++) { - if (i != 0) - s += ","; - prop = props[i]; - s += prop + ":" + toStr(a[prop]); - } - s += "}"; - } - return s; - case "undefined": - return "undefined"; - case "string": - return a.__quote(); - case "number": - case "bigfloat": - if (a == 0 && 1 / a < 0) - return "-0"; - else - return a.toString(); - break; - default: - return a.toString(); - } -} - -function bjson_test(a) -{ - var buf, r, a_str, r_str; - a_str = toStr(a); - buf = bjson.write(a); - if (0) { - print(a_str, "->", toHex(buf)); - } - r = bjson.read(buf, 0, buf.byteLength); - r_str = toStr(r); - if (a_str != r_str) { - print(a_str); - print(r_str); - assert(false); - } -} - -/* test multiple references to an object including circular - references */ -function bjson_test_reference() -{ - var array, buf, i, n, array_buffer; - n = 16; - array = []; - for(i = 0; i < n; i++) - array[i] = {}; - array_buffer = new ArrayBuffer(n); - for(i = 0; i < n; i++) { - array[i].next = array[(i + 1) % n]; - array[i].idx = i; - array[i].typed_array = new Uint8Array(array_buffer, i, 1); - } - buf = bjson.write(array, true); - - array = bjson.read(buf, 0, buf.byteLength, true); - - /* check the result */ - for(i = 0; i < n; i++) { - assert(array[i].next, array[(i + 1) % n]); - assert(array[i].idx, i); - assert(array[i].typed_array.buffer, array_buffer); - assert(array[i].typed_array.length, 1); - assert(array[i].typed_array.byteOffset, i); - } -} - -function bjson_test_all() -{ - var obj; - - bjson_test({x:1, y:2, if:3}); - bjson_test([1, 2, 3]); - bjson_test([1.0, "aa", true, false, undefined, null, NaN, -Infinity, -0.0]); - if (typeof BigInt !== "undefined") { - bjson_test([BigInt("1"), -BigInt("0x123456789"), - BigInt("0x123456789abcdef123456789abcdef")]); - } - if (typeof BigFloat !== "undefined") { - BigFloatEnv.setPrec(function () { - bjson_test([BigFloat("0.1"), BigFloat("-1e30"), BigFloat("0"), - BigFloat("-0"), BigFloat("Infinity"), BigFloat("-Infinity"), - 0.0 / BigFloat("0"), BigFloat.MAX_VALUE, - BigFloat.MIN_VALUE]); - }, 113, 15); - } - if (typeof BigDecimal !== "undefined") { - bjson_test([BigDecimal("0"), - BigDecimal("0.8"), BigDecimal("123321312321321e100"), - BigDecimal("-1233213123213214332333223332e100"), - BigDecimal("1.233e-1000")]); - } - - bjson_test([new Date(1234), new String("abc"), new Number(-12.1), new Boolean(true)]); - - bjson_test(new Int32Array([123123, 222111, -32222])); - bjson_test(new Float64Array([123123, 222111.5])); - - /* tested with a circular reference */ - obj = {}; - obj.x = obj; - try { - bjson.write(obj); - assert(false); - } catch(e) { - assert(e instanceof TypeError); - } - - bjson_test_reference(); -} - -bjson_test_all(); diff --git a/third_party/quickjs/tests/test_builtin.js b/third_party/quickjs/tests/test_builtin.js deleted file mode 100644 index c5c0f833c..000000000 --- a/third_party/quickjs/tests/test_builtin.js +++ /dev/null @@ -1,685 +0,0 @@ -"use strict"; - -function assert(actual, expected, message) { - if (arguments.length == 1) - expected = true; - - if (actual === expected) - return; - - if (actual !== null && expected !== null - && typeof actual == 'object' && typeof expected == 'object' - && actual.toString() === expected.toString()) - return; - - throw Error("assertion failed: got |" + actual + "|" + - ", expected |" + expected + "|" + - (message ? " (" + message + ")" : "")); -} - -function assert_throws(expected_error, func) -{ - var err = false; - try { - func(); - } catch(e) { - err = true; - if (!(e instanceof expected_error)) { - throw Error("unexpected exception type"); - } - } - if (!err) { - throw Error("expected exception"); - } -} - -// load more elaborate version of assert if available -try { __loadScript("test_assert.js"); } catch(e) {} - -/*----------------*/ - -function my_func(a, b) -{ - return a + b; -} - -function test_function() -{ - function f(a, b) { - var i, tab = []; - tab.push(this); - for(i = 0; i < arguments.length; i++) - tab.push(arguments[i]); - return tab; - } - function constructor1(a) { - this.x = a; - } - - var r, g; - - r = my_func.call(null, 1, 2); - assert(r, 3, "call"); - - r = my_func.apply(null, [1, 2]); - assert(r, 3, "apply"); - - r = (function () { return 1; }).apply(null, undefined); - assert(r, 1); - - assert_throws(TypeError, (function() { - Reflect.apply((function () { return 1; }), null, undefined); - })); - - r = new Function("a", "b", "return a + b;"); - assert(r(2,3), 5, "function"); - - g = f.bind(1, 2); - assert(g.length, 1); - assert(g.name, "bound f"); - assert(g(3), [1,2,3]); - - g = constructor1.bind(null, 1); - r = new g(); - assert(r.x, 1); -} - -function test() -{ - var r, a, b, c, err; - - r = Error("hello"); - assert(r.message, "hello", "Error"); - - a = new Object(); - a.x = 1; - assert(a.x, 1, "Object"); - - assert(Object.getPrototypeOf(a), Object.prototype, "getPrototypeOf"); - Object.defineProperty(a, "y", { value: 3, writable: true, configurable: true, enumerable: true }); - assert(a.y, 3, "defineProperty"); - - Object.defineProperty(a, "z", { get: function () { return 4; }, set: function(val) { this.z_val = val; }, configurable: true, enumerable: true }); - assert(a.z, 4, "get"); - a.z = 5; - assert(a.z_val, 5, "set"); - - a = { get z() { return 4; }, set z(val) { this.z_val = val; } }; - assert(a.z, 4, "get"); - a.z = 5; - assert(a.z_val, 5, "set"); - - b = Object.create(a); - assert(Object.getPrototypeOf(b), a, "create"); - c = {u:2}; - /* XXX: refcount bug in 'b' instead of 'a' */ - Object.setPrototypeOf(a, c); - assert(Object.getPrototypeOf(a), c, "setPrototypeOf"); - - a = {}; - assert(a.toString(), "[object Object]", "toString"); - - a = {x:1}; - assert(Object.isExtensible(a), true, "extensible"); - Object.preventExtensions(a); - - err = false; - try { - a.y = 2; - } catch(e) { - err = true; - } - assert(Object.isExtensible(a), false, "extensible"); - assert(typeof a.y, "undefined", "extensible"); - assert(err, true, "extensible"); -} - -function test_enum() -{ - var a, tab; - a = {x:1, - "18014398509481984": 1, - "9007199254740992": 1, - "9007199254740991": 1, - "4294967296": 1, - "4294967295": 1, - y:1, - "4294967294": 1, - "1": 2}; - tab = Object.keys(a); -// console.log("tab=" + tab.toString()); - assert(tab, ["1","4294967294","x","18014398509481984","9007199254740992","9007199254740991","4294967296","4294967295","y"], "keys"); -} - -function test_array() -{ - var a, err; - - a = [1, 2, 3]; - assert(a.length, 3, "array"); - assert(a[2], 3, "array1"); - - a = new Array(10); - assert(a.length, 10, "array2"); - - a = new Array(1, 2); - assert(a.length === 2 && a[0] === 1 && a[1] === 2, true, "array3"); - - a = [1, 2, 3]; - a.length = 2; - assert(a.length === 2 && a[0] === 1 && a[1] === 2, true, "array4"); - - a = []; - a[1] = 10; - a[4] = 3; - assert(a.length, 5); - - a = [1,2]; - a.length = 5; - a[4] = 1; - a.length = 4; - assert(a[4] !== 1, true, "array5"); - - a = [1,2]; - a.push(3,4); - assert(a.join(), "1,2,3,4", "join"); - - a = [1,2,3,4,5]; - Object.defineProperty(a, "3", { configurable: false }); - err = false; - try { - a.length = 2; - } catch(e) { - err = true; - } - assert(err && a.toString() === "1,2,3,4"); -} - -function test_string() -{ - var a; - a = String("abc"); - assert(a.length, 3, "string"); - assert(a[1], "b", "string"); - assert(a.charCodeAt(1), 0x62, "string"); - assert(String.fromCharCode(65), "A", "string"); - assert(String.fromCharCode.apply(null, [65, 66, 67]), "ABC", "string"); - assert(a.charAt(1), "b"); - assert(a.charAt(-1), ""); - assert(a.charAt(3), ""); - - a = "abcd"; - assert(a.substring(1, 3), "bc", "substring"); - a = String.fromCharCode(0x20ac); - assert(a.charCodeAt(0), 0x20ac, "unicode"); - assert(a, "€", "unicode"); - assert(a, "\u20ac", "unicode"); - assert(a, "\u{20ac}", "unicode"); - assert("a", "\x61", "unicode"); - - a = "\u{10ffff}"; - assert(a.length, 2, "unicode"); - assert(a, "\u{dbff}\u{dfff}", "unicode"); - assert(a.codePointAt(0), 0x10ffff); - assert(String.fromCodePoint(0x10ffff), a); - - assert("a".concat("b", "c"), "abc"); - - assert("abcabc".indexOf("cab"), 2); - assert("abcabc".indexOf("cab2"), -1); - assert("abc".indexOf("c"), 2); - - assert("aaa".indexOf("a"), 0); - assert("aaa".indexOf("a", NaN), 0); - assert("aaa".indexOf("a", -Infinity), 0); - assert("aaa".indexOf("a", -1), 0); - assert("aaa".indexOf("a", -0), 0); - assert("aaa".indexOf("a", 0), 0); - assert("aaa".indexOf("a", 1), 1); - assert("aaa".indexOf("a", 2), 2); - assert("aaa".indexOf("a", 3), -1); - assert("aaa".indexOf("a", 4), -1); - assert("aaa".indexOf("a", Infinity), -1); - - assert("aaa".indexOf(""), 0); - assert("aaa".indexOf("", NaN), 0); - assert("aaa".indexOf("", -Infinity), 0); - assert("aaa".indexOf("", -1), 0); - assert("aaa".indexOf("", -0), 0); - assert("aaa".indexOf("", 0), 0); - assert("aaa".indexOf("", 1), 1); - assert("aaa".indexOf("", 2), 2); - assert("aaa".indexOf("", 3), 3); - assert("aaa".indexOf("", 4), 3); - assert("aaa".indexOf("", Infinity), 3); - - assert("aaa".lastIndexOf("a"), 2); - assert("aaa".lastIndexOf("a", NaN), 2); - assert("aaa".lastIndexOf("a", -Infinity), 0); - assert("aaa".lastIndexOf("a", -1), 0); - assert("aaa".lastIndexOf("a", -0), 0); - assert("aaa".lastIndexOf("a", 0), 0); - assert("aaa".lastIndexOf("a", 1), 1); - assert("aaa".lastIndexOf("a", 2), 2); - assert("aaa".lastIndexOf("a", 3), 2); - assert("aaa".lastIndexOf("a", 4), 2); - assert("aaa".lastIndexOf("a", Infinity), 2); - - assert("aaa".lastIndexOf(""), 3); - assert("aaa".lastIndexOf("", NaN), 3); - assert("aaa".lastIndexOf("", -Infinity), 0); - assert("aaa".lastIndexOf("", -1), 0); - assert("aaa".lastIndexOf("", -0), 0); - assert("aaa".lastIndexOf("", 0), 0); - assert("aaa".lastIndexOf("", 1), 1); - assert("aaa".lastIndexOf("", 2), 2); - assert("aaa".lastIndexOf("", 3), 3); - assert("aaa".lastIndexOf("", 4), 3); - assert("aaa".lastIndexOf("", Infinity), 3); - - assert("a,b,c".split(","), ["a","b","c"]); - assert(",b,c".split(","), ["","b","c"]); - assert("a,b,".split(","), ["a","b",""]); - - assert("aaaa".split(), [ "aaaa" ]); - assert("aaaa".split(undefined, 0), [ ]); - assert("aaaa".split(""), [ "a", "a", "a", "a" ]); - assert("aaaa".split("", 0), [ ]); - assert("aaaa".split("", 1), [ "a" ]); - assert("aaaa".split("", 2), [ "a", "a" ]); - assert("aaaa".split("a"), [ "", "", "", "", "" ]); - assert("aaaa".split("a", 2), [ "", "" ]); - assert("aaaa".split("aa"), [ "", "", "" ]); - assert("aaaa".split("aa", 0), [ ]); - assert("aaaa".split("aa", 1), [ "" ]); - assert("aaaa".split("aa", 2), [ "", "" ]); - assert("aaaa".split("aaa"), [ "", "a" ]); - assert("aaaa".split("aaaa"), [ "", "" ]); - assert("aaaa".split("aaaaa"), [ "aaaa" ]); - assert("aaaa".split("aaaaa", 0), [ ]); - assert("aaaa".split("aaaaa", 1), [ "aaaa" ]); - - assert(eval('"\0"'), "\0"); - - assert("abc".padStart(Infinity, ""), "abc"); -} - -function test_math() -{ - var a; - a = 1.4; - assert(Math.floor(a), 1); - assert(Math.ceil(a), 2); - assert(Math.imul(0x12345678, 123), -1088058456); - assert(Math.fround(0.1), 0.10000000149011612); - assert(Math.hypot() == 0); - assert(Math.hypot(-2) == 2); - assert(Math.hypot(3, 4) == 5); - assert(Math.abs(Math.hypot(3, 4, 5) - 7.0710678118654755) <= 1e-15); -} - -function test_number() -{ - assert(parseInt("123"), 123); - assert(parseInt(" 123r"), 123); - assert(parseInt("0x123"), 0x123); - assert(parseInt("0o123"), 0); - assert(+" 123 ", 123); - assert(+"0b111", 7); - assert(+"0o123", 83); - assert(parseFloat("0x1234"), 0); - assert(parseFloat("Infinity"), Infinity); - assert(parseFloat("-Infinity"), -Infinity); - assert(parseFloat("123.2"), 123.2); - assert(parseFloat("123.2e3"), 123200); - assert(Number.isNaN(Number("+"))); - assert(Number.isNaN(Number("-"))); - assert(Number.isNaN(Number("\x00a"))); - - assert((25).toExponential(0), "3e+1"); - assert((-25).toExponential(0), "-3e+1"); - assert((2.5).toPrecision(1), "3"); - assert((-2.5).toPrecision(1), "-3"); - assert((1.125).toFixed(2), "1.13"); - assert((-1.125).toFixed(2), "-1.13"); -} - -function test_eval2() -{ - var g_call_count = 0; - /* force non strict mode for f1 and f2 */ - var f1 = new Function("eval", "eval(1, 2)"); - var f2 = new Function("eval", "eval(...[1, 2])"); - function g(a, b) { - assert(a, 1); - assert(b, 2); - g_call_count++; - } - f1(g); - f2(g); - assert(g_call_count, 2); -} - -function test_eval() -{ - function f(b) { - var x = 1; - return eval(b); - } - var r, a; - - r = eval("1+1;"); - assert(r, 2, "eval"); - - r = eval("var my_var=2; my_var;"); - assert(r, 2, "eval"); - assert(typeof my_var, "undefined"); - - assert(eval("if (1) 2; else 3;"), 2); - assert(eval("if (0) 2; else 3;"), 3); - - assert(f.call(1, "this"), 1); - - a = 2; - assert(eval("a"), 2); - - eval("a = 3"); - assert(a, 3); - - assert(f("arguments.length", 1), 2); - assert(f("arguments[1]", 1), 1); - - a = 4; - assert(f("a"), 4); - f("a=3"); - assert(a, 3); - - test_eval2(); -} - -function test_typed_array() -{ - var buffer, a, i, str; - - a = new Uint8Array(4); - assert(a.length, 4); - for(i = 0; i < a.length; i++) - a[i] = i; - assert(a.join(","), "0,1,2,3"); - a[0] = -1; - assert(a[0], 255); - - a = new Int8Array(3); - a[0] = 255; - assert(a[0], -1); - - a = new Int32Array(3); - a[0] = Math.pow(2, 32) - 1; - assert(a[0], -1); - assert(a.BYTES_PER_ELEMENT, 4); - - a = new Uint8ClampedArray(4); - a[0] = -100; - a[1] = 1.5; - a[2] = 0.5; - a[3] = 1233.5; - assert(a.toString(), "0,2,0,255"); - - buffer = new ArrayBuffer(16); - assert(buffer.byteLength, 16); - a = new Uint32Array(buffer, 12, 1); - assert(a.length, 1); - a[0] = -1; - - a = new Uint16Array(buffer, 2); - a[0] = -1; - - a = new Float32Array(buffer, 8, 1); - a[0] = 1; - - a = new Uint8Array(buffer); - - str = a.toString(); - /* test little and big endian cases */ - if (str !== "0,0,255,255,0,0,0,0,0,0,128,63,255,255,255,255" && - str !== "0,0,255,255,0,0,0,0,63,128,0,0,255,255,255,255") { - assert(false); - } - - assert(a.buffer, buffer); - - a = new Uint8Array([1, 2, 3, 4]); - assert(a.toString(), "1,2,3,4"); - a.set([10, 11], 2); - assert(a.toString(), "1,2,10,11"); -} - -function test_json() -{ - var a, s; - s = '{"x":1,"y":true,"z":null,"a":[1,2,3],"s":"str"}'; - a = JSON.parse(s); - assert(a.x, 1); - assert(a.y, true); - assert(a.z, null); - assert(JSON.stringify(a), s); - - /* indentation test */ - assert(JSON.stringify([[{x:1,y:{},z:[]},2,3]],undefined,1), -`[ - [ - { - "x": 1, - "y": {}, - "z": [] - }, - 2, - 3 - ] -]`); -} - -function test_date() -{ - var d = new Date(1506098258091), a, s; - assert(d.toISOString(), "2017-09-22T16:37:38.091Z"); - d.setUTCHours(18, 10, 11); - assert(d.toISOString(), "2017-09-22T18:10:11.091Z"); - a = Date.parse(d.toISOString()); - assert((new Date(a)).toISOString(), d.toISOString()); - s = new Date("2020-01-01T01:01:01.1Z").toISOString(); - assert(s == "2020-01-01T01:01:01.100Z"); - s = new Date("2020-01-01T01:01:01.12Z").toISOString(); - assert(s == "2020-01-01T01:01:01.120Z"); - s = new Date("2020-01-01T01:01:01.123Z").toISOString(); - assert(s == "2020-01-01T01:01:01.123Z"); - s = new Date("2020-01-01T01:01:01.1234Z").toISOString(); - assert(s == "2020-01-01T01:01:01.123Z"); - s = new Date("2020-01-01T01:01:01.12345Z").toISOString(); - assert(s == "2020-01-01T01:01:01.123Z"); - s = new Date("2020-01-01T01:01:01.1235Z").toISOString(); - assert(s == "2020-01-01T01:01:01.124Z"); - s = new Date("2020-01-01T01:01:01.9999Z").toISOString(); - assert(s == "2020-01-01T01:01:02.000Z"); -} - -function test_regexp() -{ - var a, str; - str = "abbbbbc"; - a = /(b+)c/.exec(str); - assert(a[0], "bbbbbc"); - assert(a[1], "bbbbb"); - assert(a.index, 1); - assert(a.input, str); - a = /(b+)c/.test(str); - assert(a, true); - assert(/\x61/.exec("a")[0], "a"); - assert(/\u0061/.exec("a")[0], "a"); - assert(/\ca/.exec("\x01")[0], "\x01"); - assert(/\\a/.exec("\\a")[0], "\\a"); - assert(/\c0/.exec("\\c0")[0], "\\c0"); - - a = /(\.(?=com|org)|\/)/.exec("ah.com"); - assert(a.index === 2 && a[0] === "."); - - a = /(\.(?!com|org)|\/)/.exec("ah.com"); - assert(a, null); - - a = /(?=(a+))/.exec("baaabac"); - assert(a.index === 1 && a[0] === "" && a[1] === "aaa"); - - a = /(z)((a+)?(b+)?(c))*/.exec("zaacbbbcac"); - assert(a, ["zaacbbbcac","z","ac","a",,"c"]); - - a = eval("/\0a/"); - assert(a.toString(), "/\0a/"); - assert(a.exec("\0a")[0], "\0a"); - - assert(/{1a}/.toString(), "/{1a}/"); - a = /a{1+/.exec("a{11"); - assert(a, ["a{11"] ); -} - -function test_symbol() -{ - var a, b, obj, c; - a = Symbol("abc"); - obj = {}; - obj[a] = 2; - assert(obj[a], 2); - assert(typeof obj["abc"], "undefined"); - assert(String(a), "Symbol(abc)"); - b = Symbol("abc"); - assert(a == a); - assert(a === a); - assert(a != b); - assert(a !== b); - - b = Symbol.for("abc"); - c = Symbol.for("abc"); - assert(b === c); - assert(b !== a); - - assert(Symbol.keyFor(b), "abc"); - assert(Symbol.keyFor(a), undefined); - - a = Symbol("aaa"); - assert(a.valueOf(), a); - assert(a.toString(), "Symbol(aaa)"); - - b = Object(a); - assert(b.valueOf(), a); - assert(b.toString(), "Symbol(aaa)"); -} - -function test_map() -{ - var a, i, n, tab, o, v; - n = 1000; - a = new Map(); - tab = []; - for(i = 0; i < n; i++) { - v = { }; - o = { id: i }; - tab[i] = [o, v]; - a.set(o, v); - } - - assert(a.size, n); - for(i = 0; i < n; i++) { - assert(a.get(tab[i][0]), tab[i][1]); - } - - i = 0; - a.forEach(function (v, o) { - assert(o, tab[i++][0]); - assert(a.has(o)); - assert(a.delete(o)); - assert(!a.has(o)); - }); - - assert(a.size, 0); -} - -function test_weak_map() -{ - var a, i, n, tab, o, v, n2; - a = new WeakMap(); - n = 10; - tab = []; - for(i = 0; i < n; i++) { - v = { }; - o = { id: i }; - tab[i] = [o, v]; - a.set(o, v); - } - o = null; - - n2 = n >> 1; - for(i = 0; i < n2; i++) { - a.delete(tab[i][0]); - } - for(i = n2; i < n; i++) { - tab[i][0] = null; /* should remove the object from the WeakMap too */ - } - /* the WeakMap should be empty here */ -} - -function test_generator() -{ - function *f() { - var ret; - yield 1; - ret = yield 2; - assert(ret, "next_arg"); - return 3; - } - function *f2() { - yield 1; - yield 2; - return "ret_val"; - } - function *f1() { - var ret = yield *f2(); - assert(ret, "ret_val"); - return 3; - } - var g, v; - g = f(); - v = g.next(); - assert(v.value === 1 && v.done === false); - v = g.next(); - assert(v.value === 2 && v.done === false); - v = g.next("next_arg"); - assert(v.value === 3 && v.done === true); - v = g.next(); - assert(v.value === undefined && v.done === true); - - g = f1(); - v = g.next(); - assert(v.value === 1 && v.done === false); - v = g.next(); - assert(v.value === 2 && v.done === false); - v = g.next(); - assert(v.value === 3 && v.done === true); - v = g.next(); - assert(v.value === undefined && v.done === true); -} - -test(); -test_function(); -test_enum(); -test_array(); -test_string(); -test_math(); -test_number(); -test_eval(); -test_typed_array(); -test_json(); -test_date(); -test_regexp(); -test_symbol(); -test_map(); -test_weak_map(); -test_generator(); diff --git a/third_party/quickjs/tests/test_closure.js b/third_party/quickjs/tests/test_closure.js deleted file mode 100644 index aa1d17ed4..000000000 --- a/third_party/quickjs/tests/test_closure.js +++ /dev/null @@ -1,221 +0,0 @@ -function assert(actual, expected, message) { - if (arguments.length == 1) - expected = true; - - if (actual === expected) - return; - - if (actual !== null && expected !== null - && typeof actual == 'object' && typeof expected == 'object' - && actual.toString() === expected.toString()) - return; - - throw Error("assertion failed: got |" + actual + "|" + - ", expected |" + expected + "|" + - (message ? " (" + message + ")" : "")); -} - -// load more elaborate version of assert if available -try { __loadScript("test_assert.js"); } catch(e) {} - -/*----------------*/ - -var log_str = ""; - -function log(str) -{ - log_str += str + ","; -} - -function f(a, b, c) -{ - var x = 10; - log("a="+a); - function g(d) { - function h() { - log("d=" + d); - log("x=" + x); - } - log("b=" + b); - log("c=" + c); - h(); - } - g(4); - return g; -} - -var g1 = f(1, 2, 3); -g1(5); - -assert(log_str, "a=1,b=2,c=3,d=4,x=10,b=2,c=3,d=5,x=10,", "closure1"); - -function test_closure1() -{ - function f2() - { - var val = 1; - - function set(a) { - val = a; - } - function get(a) { - return val; - } - return { "set": set, "get": get }; - } - - var obj = f2(); - obj.set(10); - var r; - r = obj.get(); - assert(r, 10, "closure2"); -} - -function test_closure2() -{ - var expr_func = function myfunc1(n) { - function myfunc2(n) { - return myfunc1(n - 1); - } - if (n == 0) - return 0; - else - return myfunc2(n); - }; - var r; - r = expr_func(1); - assert(r, 0, "expr_func"); -} - -function test_closure3() -{ - function fib(n) - { - if (n <= 0) - return 0; - else if (n == 1) - return 1; - else - return fib(n - 1) + fib(n - 2); - } - - var fib_func = function fib1(n) - { - if (n <= 0) - return 0; - else if (n == 1) - return 1; - else - return fib1(n - 1) + fib1(n - 2); - }; - - assert(fib(6), 8, "fib"); - assert(fib_func(6), 8, "fib_func"); -} - -function test_arrow_function() -{ - "use strict"; - - function f1() { - return (() => arguments)(); - } - function f2() { - return (() => this)(); - } - function f3() { - return (() => eval("this"))(); - } - function f4() { - return (() => eval("new.target"))(); - } - var a; - - a = f1(1, 2); - assert(a.length, 2); - assert(a[0] === 1 && a[1] === 2); - - assert(f2.call("this_val") === "this_val"); - assert(f3.call("this_val") === "this_val"); - assert(new f4() === f4); - - var o1 = { f() { return this; } }; - var o2 = { f() { - return (() => eval("super.f()"))(); - } }; - o2.__proto__ = o1; - - assert(o2.f() === o2); -} - -function test_with() -{ - var o1 = { x: "o1", y: "o1" }; - var x = "local"; - eval('var z="var_obj";'); - assert(z === "var_obj"); - with (o1) { - assert(x === "o1"); - assert(eval("x") === "o1"); - var f = function () { - o2 = { x: "o2" }; - with (o2) { - assert(x === "o2"); - assert(y === "o1"); - assert(z === "var_obj"); - assert(eval("x") === "o2"); - assert(eval("y") === "o1"); - assert(eval("z") === "var_obj"); - assert(eval('eval("x")') === "o2"); - } - }; - f(); - } -} - -function test_eval_closure() -{ - var tab; - - tab = []; - for(let i = 0; i < 3; i++) { - eval("tab.push(function g1() { return i; })"); - } - for(let i = 0; i < 3; i++) { - assert(tab[i]() === i); - } - - tab = []; - for(let i = 0; i < 3; i++) { - let f = function f() { - eval("tab.push(function g2() { return i; })"); - }; - f(); - } - for(let i = 0; i < 3; i++) { - assert(tab[i]() === i); - } -} - -function test_eval_const() -{ - const a = 1; - var success = false; - var f = function () { - eval("a = 1"); - }; - try { - f(); - } catch(e) { - success = (e instanceof TypeError); - } - assert(success); -} - -test_closure1(); -test_closure2(); -test_closure3(); -test_arrow_function(); -test_with(); -test_eval_closure(); -test_eval_const(); diff --git a/third_party/quickjs/tests/test_language.js b/third_party/quickjs/tests/test_language.js deleted file mode 100644 index 8d13deb94..000000000 --- a/third_party/quickjs/tests/test_language.js +++ /dev/null @@ -1,547 +0,0 @@ -function assert(actual, expected, message) { - if (arguments.length == 1) - expected = true; - - if (actual === expected) - return; - - if (actual !== null && expected !== null - && typeof actual == 'object' && typeof expected == 'object' - && actual.toString() === expected.toString()) - return; - - throw Error("assertion failed: got |" + actual + "|" + - ", expected |" + expected + "|" + - (message ? " (" + message + ")" : "")); -} - -function assert_throws(expected_error, func) -{ - var err = false; - try { - func(); - } catch(e) { - err = true; - if (!(e instanceof expected_error)) { - throw Error("unexpected exception type"); - } - } - if (!err) { - throw Error("expected exception"); - } -} - -// load more elaborate version of assert if available -try { __loadScript("test_assert.js"); } catch(e) {} - -/*----------------*/ - -function test_op1() -{ - var r, a; - r = 1 + 2; - assert(r, 3, "1 + 2 === 3"); - - r = 1 - 2; - assert(r, -1, "1 - 2 === -1"); - - r = -1; - assert(r, -1, "-1 === -1"); - - r = +2; - assert(r, 2, "+2 === 2"); - - r = 2 * 3; - assert(r, 6, "2 * 3 === 6"); - - r = 4 / 2; - assert(r, 2, "4 / 2 === 2"); - - r = 4 % 3; - assert(r, 1, "4 % 3 === 3"); - - r = 4 << 2; - assert(r, 16, "4 << 2 === 16"); - - r = 1 << 0; - assert(r, 1, "1 << 0 === 1"); - - r = 1 << 31; - assert(r, -2147483648, "1 << 31 === -2147483648"); - - r = 1 << 32; - assert(r, 1, "1 << 32 === 1"); - - r = (1 << 31) < 0; - assert(r, true, "(1 << 31) < 0 === true"); - - r = -4 >> 1; - assert(r, -2, "-4 >> 1 === -2"); - - r = -4 >>> 1; - assert(r, 0x7ffffffe, "-4 >>> 1 === 0x7ffffffe"); - - r = 1 & 1; - assert(r, 1, "1 & 1 === 1"); - - r = 0 | 1; - assert(r, 1, "0 | 1 === 1"); - - r = 1 ^ 1; - assert(r, 0, "1 ^ 1 === 0"); - - r = ~1; - assert(r, -2, "~1 === -2"); - - r = !1; - assert(r, false, "!1 === false"); - - assert((1 < 2), true, "(1 < 2) === true"); - - assert((2 > 1), true, "(2 > 1) === true"); - - assert(('b' > 'a'), true, "('b' > 'a') === true"); - - assert(2 ** 8, 256, "2 ** 8 === 256"); -} - -function test_cvt() -{ - assert((NaN | 0) === 0); - assert((Infinity | 0) === 0); - assert(((-Infinity) | 0) === 0); - assert(("12345" | 0) === 12345); - assert(("0x12345" | 0) === 0x12345); - assert(((4294967296 * 3 - 4) | 0) === -4); - - assert(("12345" >>> 0) === 12345); - assert(("0x12345" >>> 0) === 0x12345); - assert((NaN >>> 0) === 0); - assert((Infinity >>> 0) === 0); - assert(((-Infinity) >>> 0) === 0); - assert(((4294967296 * 3 - 4) >>> 0) === (4294967296 - 4)); -} - -function test_eq() -{ - assert(null == undefined); - assert(undefined == null); - assert(true == 1); - assert(0 == false); - assert("" == 0); - assert("123" == 123); - assert("122" != 123); - assert((new Number(1)) == 1); - assert(2 == (new Number(2))); - assert((new String("abc")) == "abc"); - assert({} != "abc"); -} - -function test_inc_dec() -{ - var a, r; - - a = 1; - r = a++; - assert(r === 1 && a === 2, true, "++"); - - a = 1; - r = ++a; - assert(r === 2 && a === 2, true, "++"); - - a = 1; - r = a--; - assert(r === 1 && a === 0, true, "--"); - - a = 1; - r = --a; - assert(r === 0 && a === 0, true, "--"); - - a = {x:true}; - a.x++; - assert(a.x, 2, "++"); - - a = {x:true}; - a.x--; - assert(a.x, 0, "--"); - - a = [true]; - a[0]++; - assert(a[0], 2, "++"); - - a = {x:true}; - r = a.x++; - assert(r === 1 && a.x === 2, true, "++"); - - a = {x:true}; - r = a.x--; - assert(r === 1 && a.x === 0, true, "--"); - - a = [true]; - r = a[0]++; - assert(r === 1 && a[0] === 2, true, "++"); - - a = [true]; - r = a[0]--; - assert(r === 1 && a[0] === 0, true, "--"); -} - -function F(x) -{ - this.x = x; -} - -function test_op2() -{ - var a, b; - a = new Object; - a.x = 1; - assert(a.x, 1, "new"); - b = new F(2); - assert(b.x, 2, "new"); - - a = {x : 2}; - assert(("x" in a), true, "in"); - assert(("y" in a), false, "in"); - - a = {}; - assert((a instanceof Object), true, "instanceof"); - assert((a instanceof String), false, "instanceof"); - - assert((typeof 1), "number", "typeof"); - assert((typeof Object), "function", "typeof"); - assert((typeof null), "object", "typeof"); - assert((typeof unknown_var), "undefined", "typeof"); - - a = {x: 1, if: 2, async: 3}; - assert(a.if === 2); - assert(a.async === 3); -} - -function test_delete() -{ - var a, err; - - a = {x: 1, y: 1}; - assert((delete a.x), true, "delete"); - assert(("x" in a), false, "delete"); - - /* the following are not tested by test262 */ - assert(delete "abc"[100], true); - - err = false; - try { - delete null.a; - } catch(e) { - err = (e instanceof TypeError); - } - assert(err, true, "delete"); - - err = false; - try { - a = { f() { delete super.a; } }; - a.f(); - } catch(e) { - err = (e instanceof ReferenceError); - } - assert(err, true, "delete"); -} - -function test_prototype() -{ - var f = function f() { }; - assert(f.prototype.constructor, f, "prototype"); - - var g = function g() { }; - /* QuickJS bug */ - Object.defineProperty(g, "prototype", { writable: false }); - assert(g.prototype.constructor, g, "prototype"); -} - -function test_arguments() -{ - function f2() { - assert(arguments.length, 2, "arguments"); - assert(arguments[0], 1, "arguments"); - assert(arguments[1], 3, "arguments"); - } - f2(1, 3); -} - -function test_class() -{ - var o; - class C { - constructor() { - this.x = 10; - } - f() { - return 1; - } - static F() { - return -1; - } - get y() { - return 12; - } - }; - class D extends C { - constructor() { - super(); - this.z = 20; - } - g() { - return 2; - } - static G() { - return -2; - } - h() { - return super.f(); - } - static H() { - return super["F"](); - } - } - - assert(C.F() === -1); - assert(Object.getOwnPropertyDescriptor(C.prototype, "y").get.name === "get y"); - - o = new C(); - assert(o.f() === 1); - assert(o.x === 10); - - assert(D.F() === -1); - assert(D.G() === -2); - assert(D.H() === -1); - - o = new D(); - assert(o.f() === 1); - assert(o.g() === 2); - assert(o.x === 10); - assert(o.z === 20); - assert(o.h() === 1); - - /* test class name scope */ - var E1 = class E { static F() { return E; } }; - assert(E1 === E1.F()); -}; - -function test_template() -{ - var a, b; - b = 123; - a = `abc${b}d`; - assert(a, "abc123d"); - - a = String.raw `abc${b}d`; - assert(a, "abc123d"); - - a = "aaa"; - b = "bbb"; - assert(`aaa${a, b}ccc`, "aaabbbccc"); -} - -function test_template_skip() -{ - var a = "Bar"; - var { b = `${a + `a${a}` }baz` } = {}; - assert(b, "BaraBarbaz"); -} - -function test_object_literal() -{ - var x = 0, get = 1, set = 2; async = 3; - a = { get: 2, set: 3, async: 4 }; - assert(JSON.stringify(a), '{"get":2,"set":3,"async":4}'); - - a = { x, get, set, async }; - assert(JSON.stringify(a), '{"x":0,"get":1,"set":2,"async":3}'); -} - -function test_regexp_skip() -{ - var a, b; - [a, b = /abc\(/] = [1]; - assert(a === 1); - - [a, b =/abc\(/] = [2]; - assert(a === 2); -} - -function test_labels() -{ - do x: { break x; } while(0); - if (1) - x: { break x; } - else - x: { break x; } - with ({}) x: { break x; }; - while (0) x: { break x; }; -} - -function test_destructuring() -{ - function * g () { return 0; }; - var [x] = g(); - assert(x, void 0); -} - -function test_spread() -{ - var x; - x = [1, 2, ...[3, 4]]; - assert(x.toString(), "1,2,3,4"); - - x = [ ...[ , ] ]; - assert(Object.getOwnPropertyNames(x).toString(), "0,length"); -} - -function test_function_length() -{ - assert( ((a, b = 1, c) => {}).length, 1); - assert( (([a,b]) => {}).length, 1); - assert( (({a,b}) => {}).length, 1); - assert( ((c, [a,b] = 1, d) => {}).length, 1); -} - -function test_argument_scope() -{ - var f; - var c = "global"; - - f = function(a = eval("var arguments")) {}; - assert_throws(SyntaxError, f); - - f = function(a = eval("1"), b = arguments[0]) { return b; }; - assert(f(12), 12); - - f = function(a, b = arguments[0]) { return b; }; - assert(f(12), 12); - - f = function(a, b = () => arguments) { return b; }; - assert(f(12)()[0], 12); - - f = function(a = eval("1"), b = () => arguments) { return b; }; - assert(f(12)()[0], 12); - - (function() { - "use strict"; - f = function(a = this) { return a; }; - assert(f.call(123), 123); - - f = function f(a = f) { return a; }; - assert(f(), f); - - f = function f(a = eval("f")) { return a; }; - assert(f(), f); - })(); - - f = (a = eval("var c = 1"), probe = () => c) => { - var c = 2; - assert(c, 2); - assert(probe(), 1); - } - f(); - - f = (a = eval("var arguments = 1"), probe = () => arguments) => { - var arguments = 2; - assert(arguments, 2); - assert(probe(), 1); - } - f(); - - f = function f(a = eval("var c = 1"), b = c, probe = () => c) { - assert(b, 1); - assert(c, 1); - assert(probe(), 1) - } - f(); - - assert(c, "global"); - f = function f(a, b = c, probe = () => c) { - eval("var c = 1"); - assert(c, 1); - assert(b, "global"); - assert(probe(), "global") - } - f(); - assert(c, "global"); - - f = function f(a = eval("var c = 1"), probe = (d = eval("c")) => d) { - assert(probe(), 1) - } - f(); -} - -function test_function_expr_name() -{ - var f; - - /* non strict mode test : assignment to the function name silently - fails */ - - f = function myfunc() { - myfunc = 1; - return myfunc; - }; - assert(f(), f); - - f = function myfunc() { - myfunc = 1; - (() => { - myfunc = 1; - })(); - return myfunc; - }; - assert(f(), f); - - f = function myfunc() { - eval("myfunc = 1"); - return myfunc; - }; - assert(f(), f); - - /* strict mode test : assignment to the function name raises a - TypeError exception */ - - f = function myfunc() { - "use strict"; - myfunc = 1; - }; - assert_throws(TypeError, f); - - f = function myfunc() { - "use strict"; - (() => { - myfunc = 1; - })(); - }; - assert_throws(TypeError, f); - - f = function myfunc() { - "use strict"; - eval("myfunc = 1"); - }; - assert_throws(TypeError, f); -} - -test_op1(); -test_cvt(); -test_eq(); -test_inc_dec(); -test_op2(); -test_delete(); -test_prototype(); -test_arguments(); -test_class(); -test_template(); -test_template_skip(); -test_object_literal(); -test_regexp_skip(); -test_labels(); -test_destructuring(); -test_spread(); -test_function_length(); -test_argument_scope(); -test_function_expr_name(); diff --git a/third_party/quickjs/tests/test_loop.js b/third_party/quickjs/tests/test_loop.js deleted file mode 100644 index 5fda9d8e3..000000000 --- a/third_party/quickjs/tests/test_loop.js +++ /dev/null @@ -1,368 +0,0 @@ -function assert(actual, expected, message) { - if (arguments.length == 1) - expected = true; - - if (actual === expected) - return; - - if (actual !== null && expected !== null - && typeof actual == 'object' && typeof expected == 'object' - && actual.toString() === expected.toString()) - return; - - throw Error("assertion failed: got |" + actual + "|" + - ", expected |" + expected + "|" + - (message ? " (" + message + ")" : "")); -} - -// load more elaborate version of assert if available -try { __loadScript("test_assert.js"); } catch(e) {} - -/*----------------*/ - -function test_while() -{ - var i, c; - i = 0; - c = 0; - while (i < 3) { - c++; - i++; - } - assert(c === 3); -} - -function test_while_break() -{ - var i, c; - i = 0; - c = 0; - while (i < 3) { - c++; - if (i == 1) - break; - i++; - } - assert(c === 2 && i === 1); -} - -function test_do_while() -{ - var i, c; - i = 0; - c = 0; - do { - c++; - i++; - } while (i < 3); - assert(c === 3 && i === 3); -} - -function test_for() -{ - var i, c; - c = 0; - for(i = 0; i < 3; i++) { - c++; - } - assert(c === 3 && i === 3); - - c = 0; - for(var j = 0; j < 3; j++) { - c++; - } - assert(c === 3 && j === 3); -} - -function test_for_in() -{ - var i, tab, a, b; - - tab = []; - for(i in {x:1, y: 2}) { - tab.push(i); - } - assert(tab.toString(), "x,y", "for_in"); - - /* prototype chain test */ - a = {x:2, y: 2, "1": 3}; - b = {"4" : 3 }; - Object.setPrototypeOf(a, b); - tab = []; - for(i in a) { - tab.push(i); - } - assert(tab.toString(), "1,x,y,4", "for_in"); - - /* non enumerable properties hide enumerables ones in the - prototype chain */ - a = {y: 2, "1": 3}; - Object.defineProperty(a, "x", { value: 1 }); - b = {"x" : 3 }; - Object.setPrototypeOf(a, b); - tab = []; - for(i in a) { - tab.push(i); - } - assert(tab.toString(), "1,y", "for_in"); - - /* array optimization */ - a = []; - for(i = 0; i < 10; i++) - a.push(i); - tab = []; - for(i in a) { - tab.push(i); - } - assert(tab.toString(), "0,1,2,3,4,5,6,7,8,9", "for_in"); - - /* iterate with a field */ - a={x:0}; - tab = []; - for(a.x in {x:1, y: 2}) { - tab.push(a.x); - } - assert(tab.toString(), "x,y", "for_in"); - - /* iterate with a variable field */ - a=[0]; - tab = []; - for(a[0] in {x:1, y: 2}) { - tab.push(a[0]); - } - assert(tab.toString(), "x,y", "for_in"); - - /* variable definition in the for in */ - tab = []; - for(var j in {x:1, y: 2}) { - tab.push(j); - } - assert(tab.toString(), "x,y", "for_in"); - - /* variable assigment in the for in */ - tab = []; - for(var k = 2 in {x:1, y: 2}) { - tab.push(k); - } - assert(tab.toString(), "x,y", "for_in"); -} - -function test_for_in2() -{ - var i; - tab = []; - for(i in {x:1, y: 2, z:3}) { - if (i === "y") - continue; - tab.push(i); - } - assert(tab.toString() == "x,z"); - - tab = []; - for(i in {x:1, y: 2, z:3}) { - if (i === "z") - break; - tab.push(i); - } - assert(tab.toString() == "x,y"); -} - -function test_for_break() -{ - var i, c; - c = 0; - L1: for(i = 0; i < 3; i++) { - c++; - if (i == 0) - continue; - while (1) { - break L1; - } - } - assert(c === 2 && i === 1); -} - -function test_switch1() -{ - var i, a, s; - s = ""; - for(i = 0; i < 3; i++) { - a = "?"; - switch(i) { - case 0: - a = "a"; - break; - case 1: - a = "b"; - break; - default: - a = "c"; - break; - } - s += a; - } - assert(s === "abc" && i === 3); -} - -function test_switch2() -{ - var i, a, s; - s = ""; - for(i = 0; i < 4; i++) { - a = "?"; - switch(i) { - case 0: - a = "a"; - break; - case 1: - a = "b"; - break; - case 2: - continue; - default: - a = "" + i; - break; - } - s += a; - } - assert(s === "ab3" && i === 4); -} - -function test_try_catch1() -{ - try { - throw "hello"; - } catch (e) { - assert(e, "hello", "catch"); - return; - } - assert(false, "catch"); -} - -function test_try_catch2() -{ - var a; - try { - a = 1; - } catch (e) { - a = 2; - } - assert(a, 1, "catch"); -} - -function test_try_catch3() -{ - var s; - s = ""; - try { - s += "t"; - } catch (e) { - s += "c"; - } finally { - s += "f"; - } - assert(s, "tf", "catch"); -} - -function test_try_catch4() -{ - var s; - s = ""; - try { - s += "t"; - throw "c"; - } catch (e) { - s += e; - } finally { - s += "f"; - } - assert(s, "tcf", "catch"); -} - -function test_try_catch5() -{ - var s; - s = ""; - for(;;) { - try { - s += "t"; - break; - s += "b"; - } finally { - s += "f"; - } - } - assert(s, "tf", "catch"); -} - -function test_try_catch6() -{ - function f() { - try { - s += 't'; - return 1; - } finally { - s += "f"; - } - } - var s = ""; - assert(f() === 1); - assert(s, "tf", "catch6"); -} - -function test_try_catch7() -{ - var s; - s = ""; - - try { - try { - s += "t"; - throw "a"; - } finally { - s += "f"; - } - } catch(e) { - s += e; - } finally { - s += "g"; - } - assert(s, "tfag", "catch"); -} - -function test_try_catch8() -{ - var i, s; - - s = ""; - for(var i in {x:1, y:2}) { - try { - s += i; - throw "a"; - } catch (e) { - s += e; - } finally { - s += "f"; - } - } - assert(s === "xafyaf"); -} - -test_while(); -test_while_break(); -test_do_while(); -test_for(); -test_for_break(); -test_switch1(); -test_switch2(); -test_for_in(); -test_for_in2(); - -test_try_catch1(); -test_try_catch2(); -test_try_catch3(); -test_try_catch4(); -test_try_catch5(); -test_try_catch6(); -test_try_catch7(); -test_try_catch8(); diff --git a/third_party/quickjs/tests/test_op_overloading.js b/third_party/quickjs/tests/test_op_overloading.js deleted file mode 100644 index d08a85eef..000000000 --- a/third_party/quickjs/tests/test_op_overloading.js +++ /dev/null @@ -1,207 +0,0 @@ -"use strict"; - -function assert(actual, expected, message) { - if (arguments.length == 1) - expected = true; - - if (actual === expected) - return; - - if (actual !== null && expected !== null - && typeof actual == 'object' && typeof expected == 'object' - && actual.toString() === expected.toString()) - return; - - throw Error("assertion failed: got |" + actual + "|" + - ", expected |" + expected + "|" + - (message ? " (" + message + ")" : "")); -} - -/* operators overloading with Operators.create() */ -function test_operators_create() { - class Vec2 - { - constructor(x, y) { - this.x = x; - this.y = y; - } - static mul_scalar(p1, a) { - var r = new Vec2(); - r.x = p1.x * a; - r.y = p1.y * a; - return r; - } - toString() { - return "Vec2(" + this.x + "," + this.y + ")"; - } - } - - Vec2.prototype[Symbol.operatorSet] = Operators.create( - { - "+"(p1, p2) { - var r = new Vec2(); - r.x = p1.x + p2.x; - r.y = p1.y + p2.y; - return r; - }, - "-"(p1, p2) { - var r = new Vec2(); - r.x = p1.x - p2.x; - r.y = p1.y - p2.y; - return r; - }, - "=="(a, b) { - return a.x == b.x && a.y == b.y; - }, - "<"(a, b) { - var r; - /* lexicographic order */ - if (a.x == b.x) - r = (a.y < b.y); - else - r = (a.x < b.x); - return r; - }, - "++"(a) { - var r = new Vec2(); - r.x = a.x + 1; - r.y = a.y + 1; - return r; - } - }, - { - left: Number, - "*"(a, b) { - return Vec2.mul_scalar(b, a); - } - }, - { - right: Number, - "*"(a, b) { - return Vec2.mul_scalar(a, b); - } - }); - - var a = new Vec2(1, 2); - var b = new Vec2(3, 4); - var r; - - r = a * 2 + 3 * b; - assert(r.x === 11 && r.y === 16); - assert(a == a, true); - assert(a == b, false); - assert(a != a, false); - assert(a < b, true); - assert(a <= b, true); - assert(b < a, false); - assert(b <= a, false); - assert(a <= a, true); - assert(a >= a, true); - a++; - assert(a.x === 2 && a.y === 3); - r = ++a; - assert(a.x === 3 && a.y === 4); - assert(r === a); -} - -/* operators overloading thru inheritance */ -function test_operators() -{ - var Vec2; - - function mul_scalar(p1, a) { - var r = new Vec2(); - r.x = p1.x * a; - r.y = p1.y * a; - return r; - } - - var vec2_ops = Operators({ - "+"(p1, p2) { - var r = new Vec2(); - r.x = p1.x + p2.x; - r.y = p1.y + p2.y; - return r; - }, - "-"(p1, p2) { - var r = new Vec2(); - r.x = p1.x - p2.x; - r.y = p1.y - p2.y; - return r; - }, - "=="(a, b) { - return a.x == b.x && a.y == b.y; - }, - "<"(a, b) { - var r; - /* lexicographic order */ - if (a.x == b.x) - r = (a.y < b.y); - else - r = (a.x < b.x); - return r; - }, - "++"(a) { - var r = new Vec2(); - r.x = a.x + 1; - r.y = a.y + 1; - return r; - } - }, - { - left: Number, - "*"(a, b) { - return mul_scalar(b, a); - } - }, - { - right: Number, - "*"(a, b) { - return mul_scalar(a, b); - } - }); - - Vec2 = class Vec2 extends vec2_ops - { - constructor(x, y) { - super(); - this.x = x; - this.y = y; - } - toString() { - return "Vec2(" + this.x + "," + this.y + ")"; - } - } - - var a = new Vec2(1, 2); - var b = new Vec2(3, 4); - var r; - - r = a * 2 + 3 * b; - assert(r.x === 11 && r.y === 16); - assert(a == a, true); - assert(a == b, false); - assert(a != a, false); - assert(a < b, true); - assert(a <= b, true); - assert(b < a, false); - assert(b <= a, false); - assert(a <= a, true); - assert(a >= a, true); - a++; - assert(a.x === 2 && a.y === 3); - r = ++a; - assert(a.x === 3 && a.y === 4); - assert(r === a); -} - -function test_default_op() -{ - assert(Object(1) + 2, 3); - assert(Object(1) + true, 2); - assert(-Object(1), -1); -} - -test_operators_create(); -test_operators(); -test_default_op(); diff --git a/third_party/quickjs/tests/test_qjscalc.js b/third_party/quickjs/tests/test_qjscalc.js deleted file mode 100644 index 1483466d2..000000000 --- a/third_party/quickjs/tests/test_qjscalc.js +++ /dev/null @@ -1,256 +0,0 @@ -"use math"; -"use strict"; - -function assert(actual, expected, message) { - if (arguments.length == 1) - expected = true; - - if (actual === expected) - return; - - if (actual !== null && expected !== null - && typeof actual == 'object' && typeof expected == 'object' - && actual.toString() === expected.toString()) - return; - - throw Error("assertion failed: got |" + actual + "|" + - ", expected |" + expected + "|" + - (message ? " (" + message + ")" : "")); -} - -function assertThrows(err, func) -{ - var ex; - ex = false; - try { - func(); - } catch(e) { - ex = true; - assert(e instanceof err); - } - assert(ex, true, "exception expected"); -} - -// load more elaborate version of assert if available -try { __loadScript("test_assert.js"); } catch(e) {} - -/*----------------*/ - -function pow(a, n) -{ - var r, i; - r = 1; - for(i = 0; i < n; i++) - r *= a; - return r; -} - -function test_integer() -{ - var a, r; - a = pow(3, 100); - assert((a - 1) != a); - assert(a == 515377520732011331036461129765621272702107522001); - assert(a == 0x5a4653ca673768565b41f775d6947d55cf3813d1); - assert(Integer.isInteger(1) === true); - assert(Integer.isInteger(1.0) === false); - - assert(Integer.floorLog2(0) === -1); - assert(Integer.floorLog2(7) === 2); - - r = 1 << 31; - assert(r, 2147483648, "1 << 31 === 2147483648"); - - r = 1 << 32; - assert(r, 4294967296, "1 << 32 === 4294967296"); - - r = (1 << 31) < 0; - assert(r, false, "(1 << 31) < 0 === false"); - - assert(typeof 1 === "number"); - assert(typeof 9007199254740991 === "number"); - assert(typeof 9007199254740992 === "bigint"); -} - -function test_float() -{ - assert(typeof 1.0 === "bigfloat"); - assert(1 == 1.0); - assert(1 !== 1.0); -} - -/* jscalc tests */ - -function test_modulo() -{ - var i, p, a, b; - - /* Euclidian modulo operator */ - assert((-3) % 2 == 1); - assert(3 % (-2) == 1); - - p = 101; - for(i = 1; i < p; i++) { - a = Integer.invmod(i, p); - assert(a >= 0 && a < p); - assert((i * a) % p == 1); - } - - assert(Integer.isPrime(2^107-1)); - assert(!Integer.isPrime((2^107-1) * (2^89-1))); - a = Integer.factor((2^89-1)*2^3*11*13^2*1009); - assert(a == [ 2,2,2,11,13,13,1009,618970019642690137449562111 ]); -} - -function test_fraction() -{ - assert((1/3 + 1).toString(), "4/3") - assert((2/3)^30, 1073741824/205891132094649); - assert(1/3 < 2/3); - assert(1/3 < 1); - assert(1/3 == 1.0/3); - assert(1.0/3 < 2/3); -} - -function test_mod() -{ - var a, b, p; - - a = Mod(3, 101); - b = Mod(-1, 101); - assert((a + b) == Mod(2, 101)); - assert(a ^ 100 == Mod(1, 101)); - - p = 2 ^ 607 - 1; /* mersenne prime */ - a = Mod(3, p) ^ (p - 1); - assert(a == Mod(1, p)); -} - -function test_polynomial() -{ - var a, b, q, r, t, i; - a = (1 + X) ^ 4; - assert(a == X^4+4*X^3+6*X^2+4*X+1); - - r = (1 + X); - q = (1+X+X^2); - b = (1 - X^2); - a = q * b + r; - t = Polynomial.divrem(a, b); - assert(t[0] == q); - assert(t[1] == r); - - a = 1 + 2*X + 3*X^2; - assert(a.apply(0.1) == 1.23); - - a = 1-2*X^2+2*X^3; - assert(deriv(a) == (6*X^2-4*X)); - assert(deriv(integ(a)) == a); - - a = (X-1)*(X-2)*(X-3)*(X-4)*(X-0.1); - r = polroots(a); - for(i = 0; i < r.length; i++) { - b = abs(a.apply(r[i])); - assert(b <= 1e-13); - } -} - -function test_poly_mod() -{ - var a, p; - - /* modulo using polynomials */ - p = X^2 + X + 1; - a = PolyMod(3+X, p) ^ 10; - assert(a == PolyMod(-3725*X-18357, p)); - - a = PolyMod(1/X, 1+X^2); - assert(a == PolyMod(-X, X^2+1)); -} - -function test_rfunc() -{ - var a; - a = (X+1)/((X+1)*(X-1)); - assert(a == 1/(X-1)); - a = (X + 2) / (X - 2); - assert(a.apply(1/3) == -7/5); - - assert(deriv((X^2-X+1)/(X-1)) == (X^2-2*X)/(X^2-2*X+1)); -} - -function test_series() -{ - var a, b; - a = 1+X+O(X^5); - b = a.inverse(); - assert(b == 1-X+X^2-X^3+X^4+O(X^5)); - assert(deriv(b) == -1+2*X-3*X^2+4*X^3+O(X^4)); - assert(deriv(integ(b)) == b); - - a = Series(1/(1-X), 5); - assert(a == 1+X+X^2+X^3+X^4+O(X^5)); - b = a.apply(0.1); - assert(b == 1.1111); - - assert(exp(3*X^2+O(X^10)) == 1+3*X^2+9/2*X^4+9/2*X^6+27/8*X^8+O(X^10)); - assert(sin(X+O(X^6)) == X-1/6*X^3+1/120*X^5+O(X^6)); - assert(cos(X+O(X^6)) == 1-1/2*X^2+1/24*X^4+O(X^6)); - assert(tan(X+O(X^8)) == X+1/3*X^3+2/15*X^5+17/315*X^7+O(X^8)); - assert((1+X+O(X^6))^(2+X) == 1+2*X+2*X^2+3/2*X^3+5/6*X^4+5/12*X^5+O(X^6)); -} - -function test_matrix() -{ - var a, b, r; - a = [[1, 2],[3, 4]]; - b = [3, 4]; - r = a * b; - assert(r == [11, 25]); - r = (a^-1) * 2; - assert(r == [[-4, 2],[3, -1]]); - - assert(norm2([1,2,3]) == 14); - - assert(diag([1,2,3]) == [ [ 1, 0, 0 ], [ 0, 2, 0 ], [ 0, 0, 3 ] ]); - assert(trans(a) == [ [ 1, 3 ], [ 2, 4 ] ]); - assert(trans([1,2,3]) == [[1,2,3]]); - assert(trace(a) == 5); - - assert(charpoly(Matrix.hilbert(4)) == X^4-176/105*X^3+3341/12600*X^2-41/23625*X+1/6048000); - assert(det(Matrix.hilbert(4)) == 1/6048000); - - a = [[1,2,1],[-2,-3,1],[3,5,0]]; - assert(rank(a) == 2); - assert(ker(a) == [ [ 5 ], [ -3 ], [ 1 ] ]); - - assert(dp([1, 2, 3], [3, -4, -7]) === -26); - assert(cp([1, 2, 3], [3, -4, -7]) == [ -2, 16, -10 ]); -} - -function assert_eq(a, ref) -{ - assert(abs(a / ref - 1.0) <= 1e-15); -} - -function test_trig() -{ - assert_eq(sin(1/2), 0.479425538604203); - assert_eq(sin(2+3*I), 9.154499146911428-4.168906959966565*I); - assert_eq(cos(2+3*I), -4.189625690968807-9.109227893755337*I); - assert_eq((2+0.5*I)^(1.1-0.5*I), 2.494363021357619-0.23076804554558092*I); - assert_eq(sqrt(2*I), 1 + I); -} - -test_integer(); -test_float(); - -test_modulo(); -test_fraction(); -test_mod(); -test_polynomial(); -test_poly_mod(); -test_rfunc(); -test_series(); -test_matrix(); -test_trig(); diff --git a/third_party/quickjs/tests/test_std.js b/third_party/quickjs/tests/test_std.js deleted file mode 100644 index 3ea6e3456..000000000 --- a/third_party/quickjs/tests/test_std.js +++ /dev/null @@ -1,281 +0,0 @@ -import * as std from "std"; -import * as os from "os"; - -function assert(actual, expected, message) { - if (arguments.length == 1) - expected = true; - - if (actual === expected) - return; - - if (actual !== null && expected !== null - && typeof actual == 'object' && typeof expected == 'object' - && actual.toString() === expected.toString()) - return; - - throw Error("assertion failed: got |" + actual + "|" + - ", expected |" + expected + "|" + - (message ? " (" + message + ")" : "")); -} - -// load more elaborate version of assert if available -try { std.loadScript("test_assert.js"); } catch(e) {} - -/*----------------*/ - -function test_printf() -{ - assert(std.sprintf("a=%d s=%s", 123, "abc"), "a=123 s=abc"); - assert(std.sprintf("%010d", 123), "0000000123"); - assert(std.sprintf("%x", -2), "fffffffe"); - assert(std.sprintf("%lx", -2), "fffffffffffffffe"); - assert(std.sprintf("%10.1f", 2.1), " 2.1"); - assert(std.sprintf("%*.*f", 10, 2, -2.13), " -2.13"); - assert(std.sprintf("%#lx", 0x7fffffffffffffffn), "0x7fffffffffffffff"); -} - -function test_file1() -{ - var f, len, str, size, buf, ret, i, str1; - - f = std.tmpfile(); - str = "hello world\n"; - f.puts(str); - - f.seek(0, std.SEEK_SET); - str1 = f.readAsString(); - assert(str1 === str); - - f.seek(0, std.SEEK_END); - size = f.tell(); - assert(size === str.length); - - f.seek(0, std.SEEK_SET); - - buf = new Uint8Array(size); - ret = f.read(buf.buffer, 0, size); - assert(ret === size); - for(i = 0; i < size; i++) - assert(buf[i] === str.charCodeAt(i)); - - f.close(); -} - -function test_file2() -{ - var f, str, i, size; - f = std.tmpfile(); - str = "hello world\n"; - size = str.length; - for(i = 0; i < size; i++) - f.putByte(str.charCodeAt(i)); - f.seek(0, std.SEEK_SET); - for(i = 0; i < size; i++) { - assert(str.charCodeAt(i) === f.getByte()); - } - assert(f.getByte() === -1); - f.close(); -} - -function test_getline() -{ - var f, line, line_count, lines, i; - - lines = ["hello world", "line 1", "line 2" ]; - f = std.tmpfile(); - for(i = 0; i < lines.length; i++) { - f.puts(lines[i], "\n"); - } - - f.seek(0, std.SEEK_SET); - assert(!f.eof()); - line_count = 0; - for(;;) { - line = f.getline(); - if (line === null) - break; - assert(line == lines[line_count]); - line_count++; - } - assert(f.eof()); - assert(line_count === lines.length); - - f.close(); -} - -function test_popen() -{ - var str, f, fname = "tmp_file.txt"; - var content = "hello world"; - - f = std.open(fname, "w"); - f.puts(content); - f.close(); - - /* test loadFile */ - assert(std.loadFile(fname), content); - - /* execute the 'cat' shell command */ - f = std.popen("cat " + fname, "r"); - str = f.readAsString(); - f.close(); - - assert(str, content); - - os.remove(fname); -} - -function test_ext_json() -{ - var expected, input, obj; - expected = '{"x":false,"y":true,"z2":null,"a":[1,8,160],"s":"str"}'; - input = `{ "x":false, /*comments are allowed */ - "y":true, // also a comment - z2:null, // unquoted property names - "a":[+1,0o10,0xa0,], // plus prefix, octal, hexadecimal - "s":"str",} // trailing comma in objects and arrays - `; - obj = std.parseExtJSON(input); - assert(JSON.stringify(obj), expected); -} - -function test_os() -{ - var fd, fpath, fname, fdir, buf, buf2, i, files, err, fdate, st, link_path; - - assert(os.isatty(0)); - - fdir = "test_tmp_dir"; - fname = "tmp_file.txt"; - fpath = fdir + "/" + fname; - link_path = fdir + "/test_link"; - - os.remove(link_path); - os.remove(fpath); - os.remove(fdir); - - err = os.mkdir(fdir, 0o755); - assert(err === 0); - - fd = os.open(fpath, os.O_RDWR | os.O_CREAT | os.O_TRUNC); - assert(fd >= 0); - - buf = new Uint8Array(10); - for(i = 0; i < buf.length; i++) - buf[i] = i; - assert(os.write(fd, buf.buffer, 0, buf.length) === buf.length); - - assert(os.seek(fd, 0, std.SEEK_SET) === 0); - buf2 = new Uint8Array(buf.length); - assert(os.read(fd, buf2.buffer, 0, buf2.length) === buf2.length); - - for(i = 0; i < buf.length; i++) - assert(buf[i] == buf2[i]); - - if (typeof BigInt !== "undefined") { - assert(os.seek(fd, BigInt(6), std.SEEK_SET), BigInt(6)); - assert(os.read(fd, buf2.buffer, 0, 1) === 1); - assert(buf[6] == buf2[0]); - } - - assert(os.close(fd) === 0); - - [files, err] = os.readdir(fdir); - assert(err, 0); - assert(files.indexOf(fname) >= 0); - - fdate = 10000; - - err = os.utimes(fpath, fdate, fdate); - assert(err, 0); - - [st, err] = os.stat(fpath); - assert(err, 0); - assert(st.mode & os.S_IFMT, os.S_IFREG); - assert(st.mtime, fdate); - - err = os.symlink(fname, link_path); - assert(err === 0); - - [st, err] = os.lstat(link_path); - assert(err, 0); - assert(st.mode & os.S_IFMT, os.S_IFLNK); - - [buf, err] = os.readlink(link_path); - assert(err, 0); - assert(buf, fname); - - assert(os.remove(link_path) === 0); - - [buf, err] = os.getcwd(); - assert(err, 0); - - [buf2, err] = os.realpath("."); - assert(err, 0); - - assert(buf, buf2); - - assert(os.remove(fpath) === 0); - - fd = os.open(fpath, os.O_RDONLY); - assert(fd < 0); - - assert(os.remove(fdir) === 0); -} - -function test_os_exec() -{ - var ret, fds, pid, f, status; - - ret = os.exec(["true"]); - assert(ret, 0); - - ret = os.exec(["/bin/sh", "-c", "exit 1"], { usePath: false }); - assert(ret, 1); - - fds = os.pipe(); - pid = os.exec(["sh", "-c", "echo $FOO"], { - stdout: fds[1], - block: false, - env: { FOO: "hello" }, - } ); - assert(pid >= 0); - os.close(fds[1]); /* close the write end (as it is only in the child) */ - f = std.fdopen(fds[0], "r"); - assert(f.getline(), "hello"); - assert(f.getline(), null); - f.close(); - [ret, status] = os.waitpid(pid, 0); - assert(ret, pid); - assert(status & 0x7f, 0); /* exited */ - assert(status >> 8, 0); /* exit code */ - - pid = os.exec(["cat"], { block: false } ); - assert(pid >= 0); - os.kill(pid, os.SIGQUIT); - [ret, status] = os.waitpid(pid, 0); - assert(ret, pid); - assert(status & 0x7f, os.SIGQUIT); -} - -function test_timer() -{ - var th, i; - - /* just test that a timer can be inserted and removed */ - th = []; - for(i = 0; i < 3; i++) - th[i] = os.setTimeout(function () { }, 1000); - for(i = 0; i < 3; i++) - os.clearTimeout(th[i]); -} - -test_printf(); -test_file1(); -test_file2(); -test_getline(); -test_popen(); -test_os(); -test_os_exec(); -test_timer(); -test_ext_json(); diff --git a/third_party/quickjs/tests/test_worker.js b/third_party/quickjs/tests/test_worker.js deleted file mode 100644 index 4b52bf82c..000000000 --- a/third_party/quickjs/tests/test_worker.js +++ /dev/null @@ -1,62 +0,0 @@ -/* os.Worker API test */ -import * as std from "std"; -import * as os from "os"; - -function assert(actual, expected, message) { - if (arguments.length == 1) - expected = true; - - if (actual === expected) - return; - - if (actual !== null && expected !== null - && typeof actual == 'object' && typeof expected == 'object' - && actual.toString() === expected.toString()) - return; - - throw Error("assertion failed: got |" + actual + "|" + - ", expected |" + expected + "|" + - (message ? " (" + message + ")" : "")); -} - -var worker; - -function test_worker() -{ - var counter; - - worker = new os.Worker("./test_worker_module.js"); - - counter = 0; - worker.onmessage = function (e) { - var ev = e.data; -// print("recv", JSON.stringify(ev)); - switch(ev.type) { - case "num": - assert(ev.num, counter); - counter++; - if (counter == 10) { - /* test SharedArrayBuffer modification */ - let sab = new SharedArrayBuffer(10); - let buf = new Uint8Array(sab); - worker.postMessage({ type: "sab", buf: buf }); - } - break; - case "sab_done": - { - let buf = ev.buf; - /* check that the SharedArrayBuffer was modified */ - assert(buf[2], 10); - worker.postMessage({ type: "abort" }); - } - break; - case "done": - /* terminate */ - worker.onmessage = null; - break; - } - }; -} - - -test_worker(); diff --git a/third_party/quickjs/tests/test_worker_module.js b/third_party/quickjs/tests/test_worker_module.js deleted file mode 100644 index c783e1fec..000000000 --- a/third_party/quickjs/tests/test_worker_module.js +++ /dev/null @@ -1,31 +0,0 @@ -/* Worker code for test_worker.js */ -import * as std from "std"; -import * as os from "os"; - -var parent = os.Worker.parent; - -function handle_msg(e) { - var ev = e.data; - // print("child_recv", JSON.stringify(ev)); - switch(ev.type) { - case "abort": - parent.postMessage({ type: "done" }); - break; - case "sab": - /* modify the SharedArrayBuffer */ - ev.buf[2] = 10; - parent.postMessage({ type: "sab_done", buf: ev.buf }); - break; - } -} - -function worker_main() { - var i; - - parent.onmessage = handle_msg; - for(i = 0; i < 10; i++) { - parent.postMessage({ type: "num", num: i }); - } -} - -worker_main(); diff --git a/third_party/quickjs/tok.c b/third_party/quickjs/tok.c deleted file mode 100644 index f81c22778..000000000 --- a/third_party/quickjs/tok.c +++ /dev/null @@ -1,695 +0,0 @@ -/* - * QuickJS Javascript Engine - * - * Copyright (c) 2017-2021 Fabrice Bellard - * Copyright (c) 2017-2021 Charlie Gordon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "libc/str/str.h" -#include "third_party/quickjs/internal.h" -#include "third_party/quickjs/libregexp.h" - -asm(".ident\t\"\\n\\n\ -QuickJS (MIT License)\\n\ -Copyright (c) 2017-2021 Fabrice Bellard\\n\ -Copyright (c) 2017-2021 Charlie Gordon\""); -asm(".include \"libc/disclaimer.inc\""); - -/* '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; -} - -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_PRIVATE_NAME: - JS_FreeAtom(s->ctx, token->u.ident.atom); - break; - default: - if (token->val >= TOK_FIRST_KEYWORD && - token->val <= TOK_LAST_KEYWORD) { - JS_FreeAtom(s->ctx, token->u.ident.atom); - } - break; - } -} - -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': case 'b': case 'c': case 'd': - case 'e': case 'f': case 'g': case 'h': - case 'i': case 'j': case 'k': case 'l': - case 'm': case 'n': case 'o': case 'p': - case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': - case 'A': case 'B': case 'C': case 'D': - case 'E': case 'F': case 'G': case 'H': - case 'I': case 'J': case 'K': case 'L': - case 'M': case 'N': case 'O': case 'P': - case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': - case '_': - case '$': - /* identifier */ - p++; - ident_has_escape = FALSE; - has_ident: - atom = parse_ident(s, &p, &ident_has_escape, c, FALSE); - if (atom == JS_ATOM_NULL) - goto fail; - s->token.u.ident.atom = atom; - s->token.u.ident.has_escape = ident_has_escape; - s->token.u.ident.is_reserved = FALSE; - 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 (isdigit(p[1]) && (s->cur_func->js_mode & JS_MODE_STRICT)) { - js_parse_error(s, "octal literals are deprecated in strict mode"); - goto fail; - } - goto parse_number; - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': - case '9': - /* number */ - parse_number: - { - JSValue ret; - const uint8_t *p1; - int flags, 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 `