diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000000..80a1ec7bc3
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,9 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+This project adheres to [Semantic Versioning](http://semver.org/).
+
+## 31.05.2025
+- updated QuickJs to 2025-04-26 build
+
+## 31.05.2025
+- fixed last release for building with MSVC
\ No newline at end of file
diff --git a/JSTest.sln b/JSTest.sln
new file mode 100644
index 0000000000..d3451d0f71
--- /dev/null
+++ b/JSTest.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.12.35506.116 d17.12
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JSTest", "JSTest.vcxproj", "{05D4BCD1-30A9-4341-BD68-C89506F0AD7F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {05D4BCD1-30A9-4341-BD68-C89506F0AD7F}.Debug|x64.ActiveCfg = Debug|x64
+ {05D4BCD1-30A9-4341-BD68-C89506F0AD7F}.Debug|x64.Build.0 = Debug|x64
+ {05D4BCD1-30A9-4341-BD68-C89506F0AD7F}.Debug|x86.ActiveCfg = Debug|Win32
+ {05D4BCD1-30A9-4341-BD68-C89506F0AD7F}.Debug|x86.Build.0 = Debug|Win32
+ {05D4BCD1-30A9-4341-BD68-C89506F0AD7F}.Release|x64.ActiveCfg = Release|x64
+ {05D4BCD1-30A9-4341-BD68-C89506F0AD7F}.Release|x64.Build.0 = Release|x64
+ {05D4BCD1-30A9-4341-BD68-C89506F0AD7F}.Release|x86.ActiveCfg = Release|Win32
+ {05D4BCD1-30A9-4341-BD68-C89506F0AD7F}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/JSTest.vcxproj b/JSTest.vcxproj
new file mode 100644
index 0000000000..4b5b250ad9
--- /dev/null
+++ b/JSTest.vcxproj
@@ -0,0 +1,207 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ false
+ false
+ false
+ false
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 17.0
+ Win32Proj
+ {05d4bcd1-30a9-4341-bd68-c89506f0ad7f}
+ JSTest
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TurnOffAllWarnings
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ ./
+
+
+ Console
+ true
+
+
+
+
+ TurnOffAllWarnings
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ ./
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+ TurnOffAllWarnings
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp20
+ ./
+
+
+ Console
+ true
+
+
+
+
+ TurnOffAllWarnings
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ ./
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
\ No newline at end of file
diff --git a/JSTest.vcxproj.filters b/JSTest.vcxproj.filters
new file mode 100644
index 0000000000..38fc34b174
--- /dev/null
+++ b/JSTest.vcxproj.filters
@@ -0,0 +1,102 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {20602fca-a07b-410d-9e82-527e5997b761}
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ quickjs
+
+
+ quickjs
+
+
+ quickjs
+
+
+ quickjs
+
+
+ quickjs
+
+
+ quickjs
+
+
+
+
+ Header Files
+
+
+ quickjs
+
+
+ quickjs
+
+
+ quickjs
+
+
+ quickjs
+
+
+ quickjs
+
+
+ quickjs
+
+
+ quickjs
+
+
+ quickjs
+
+
+ quickjs
+
+
+ quickjs
+
+
+ quickjs
+
+
+
\ No newline at end of file
diff --git a/qjs.cpp b/qjs.cpp
index 79fd87f8ba..47ccfa5467 100644
--- a/qjs.cpp
+++ b/qjs.cpp
@@ -13,12 +13,14 @@ static JSContext *JS_NewCustomContext(JSRuntime *rt)
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");
@@ -34,7 +36,7 @@ int main(int argc, char ** argv)
js_std_init_handlers(rt);
/* loader for ES6 modules */
- JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
+ JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL);
qjs::Context context(JS_NewCustomContext(rt));
auto ctx = context.ctx;
diff --git a/quickjs/CMakeLists.txt b/quickjs/CMakeLists.txt
index 2664223d55..b1c18f3fec 100644
--- a/quickjs/CMakeLists.txt
+++ b/quickjs/CMakeLists.txt
@@ -2,7 +2,7 @@ project(quickjs LANGUAGES C)
file(STRINGS VERSION version)
-set(quickjs_src quickjs.c libbf.c libunicode.c libregexp.c cutils.c quickjs-libc.c)
+set(quickjs_src quickjs.c dtoa.c libunicode.c libregexp.c cutils.c quickjs-libc.c)
set(quickjs_def CONFIG_VERSION="${version}" _GNU_SOURCE CONFIG_BIGNUM)
add_library(quickjs ${quickjs_src})
diff --git a/quickjs/VERSION b/quickjs/VERSION
index 08d122201d..c76e76d1f1 100644
--- a/quickjs/VERSION
+++ b/quickjs/VERSION
@@ -1 +1 @@
-2023-12-09
+2025-04-26
diff --git a/quickjs/cutils.c b/quickjs/cutils.c
index a02fb76886..80099905fb 100644
--- a/quickjs/cutils.c
+++ b/quickjs/cutils.c
@@ -1,6 +1,6 @@
/*
* C utilities
- *
+ *
* Copyright (c) 2017 Fabrice Bellard
* Copyright (c) 2018 Charlie Gordon
*
@@ -29,6 +29,28 @@
#include "cutils.h"
+#ifdef _MSC_VER
+
+ // From: https://stackoverflow.com/a/26085827
+int gettimeofday(struct timeval * tp, struct timezone * tzp)
+{
+ static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL);
+
+ SYSTEMTIME system_time;
+ FILETIME file_time;
+ uint64_t time;
+
+ GetSystemTime(&system_time);
+ SystemTimeToFileTime(&system_time, &file_time);
+ time = ((uint64_t)file_time.dwLowDateTime);
+ time += ((uint64_t)file_time.dwHighDateTime) << 32;
+
+ tp->tv_sec = (long)((time - EPOCH) / 10000000L);
+ tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
+
+ return 0;
+}
+#endif
void pstrcpy(char *buf, int buf_size, const char *str)
{
int c;
@@ -140,7 +162,7 @@ int dbuf_put(DynBuf *s, const uint8_t *data, size_t len)
if (dbuf_realloc(s, s->size + len))
return -1;
}
- memcpy(s->buf + s->size, data, len);
+ memcpy_no_ub(s->buf + s->size, data, len);
s->size += len;
return 0;
}
@@ -172,10 +194,12 @@ int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
va_list ap;
char buf[128];
int len;
-
+
va_start(ap, fmt);
len = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
+ if (len < 0)
+ return -1;
if (len < sizeof(buf)) {
/* fast case */
return dbuf_put(s, (uint8_t *)buf, len);
diff --git a/quickjs/cutils.h b/quickjs/cutils.h
index 31f7cd84a0..ceb18522ed 100644
--- a/quickjs/cutils.h
+++ b/quickjs/cutils.h
@@ -1,6 +1,6 @@
/*
* C utilities
- *
+ *
* Copyright (c) 2017 Fabrice Bellard
* Copyright (c) 2018 Charlie Gordon
*
@@ -26,16 +26,35 @@
#define CUTILS_H
#include
+#include
#include
+#ifdef _MSC_VER
+#include
+#include
+#else
+#include
+#endif
+
/* set if CPU is big endian */
#undef WORDS_BIGENDIAN
-#define likely(x) __builtin_expect(!!(x), 1)
-#define unlikely(x) __builtin_expect(!!(x), 0)
-#define force_inline inline __attribute__((always_inline))
-#define no_inline __attribute__((noinline))
-#define __maybe_unused __attribute__((unused))
+#ifndef __has_attribute
+ #define likely(x) (x)
+ #define unlikely(x) (x)
+ #define force_inline __forceinline
+ #define no_inline __declspec(noinline)
+ #define __maybe_unused
+ #define __attribute__(x)
+ #define __attribute(x)
+ typedef intptr_t ssize_t;
+#else
+ #define likely(x) __builtin_expect(!!(x), 1)
+ #define unlikely(x) __builtin_expect(!!(x), 0)
+ #define force_inline inline __attribute__((always_inline))
+ #define no_inline __attribute__((noinline))
+ #define __maybe_unused __attribute__((unused))
+#endif
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
@@ -48,6 +67,16 @@
#ifndef countof
#define countof(x) (sizeof(x) / sizeof((x)[0]))
#endif
+#ifndef container_of
+/* return the pointer of type 'type *' containing 'ptr' as field 'member' */
+#define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member)))
+#endif
+
+#if !defined(_MSC_VER) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define minimum_length(n) static n
+#else
+#define minimum_length(n) n
+#endif
typedef int BOOL;
@@ -63,6 +92,12 @@ char *pstrcat(char *buf, int buf_size, const char *s);
int strstart(const char *str, const char *val, const char **ptr);
int has_suffix(const char *str, const char *suffix);
+/* Prevent UB when n == 0 and (src == NULL or dest == NULL) */
+static inline void memcpy_no_ub(void *dest, const void *src, size_t n) {
+ if (n)
+ memcpy(dest, src, n);
+}
+
static inline int max_int(int a, int b)
{
if (a > b)
@@ -114,27 +149,91 @@ static inline int64_t min_int64(int64_t a, int64_t b)
/* WARNING: undefined if a = 0 */
static inline int clz32(unsigned int a)
{
+#ifdef _MSC_VER
+ unsigned long idx;
+ _BitScanReverse(&idx, a);
+ return 31 ^ idx;
+#else
return __builtin_clz(a);
+#endif
}
/* WARNING: undefined if a = 0 */
static inline int clz64(uint64_t a)
{
+#ifdef _MSC_VER
+ unsigned long where;
+ // BitScanReverse scans from MSB to LSB for first set bit.
+ // Returns 0 if no set bit is found.
+#if INTPTR_MAX >= INT64_MAX // 64-bit
+ if (_BitScanReverse64(&where, a))
+ return (int)(63 - where);
+#else
+ // Scan the high 32 bits.
+ if (_BitScanReverse(&where, (uint32_t)(a >> 32)))
+ return (int)(63 - (where + 32)); // Create a bit offset from the MSB.
+ // Scan the low 32 bits.
+ if (_BitScanReverse(&where, (uint32_t)(a)))
+ return (int)(63 - where);
+#endif
+ return 64; // Undefined Behavior.
+#else
return __builtin_clzll(a);
+#endif
}
/* WARNING: undefined if a = 0 */
static inline int ctz32(unsigned int a)
{
+#ifdef _MSC_VER
+ unsigned long idx;
+ _BitScanForward(&idx, a);
+ return 31 ^ idx;
+#else
return __builtin_ctz(a);
+#endif
}
/* WARNING: undefined if a = 0 */
static inline int ctz64(uint64_t a)
{
+#ifdef _MSC_VER
+ unsigned long where;
+ // Search from LSB to MSB for first set bit.
+ // Returns zero if no set bit is found.
+#if INTPTR_MAX >= INT64_MAX // 64-bit
+ if (_BitScanForward64(&where, a))
+ return (int)(where);
+#else
+ // Win32 doesn't have _BitScanForward64 so emulate it with two 32 bit calls.
+ // Scan the Low Word.
+ if (_BitScanForward(&where, (uint32_t)(a)))
+ return (int)(where);
+ // Scan the High Word.
+ if (_BitScanForward(&where, (uint32_t)(a >> 32)))
+ return (int)(where + 32); // Create a bit offset from the LSB.
+#endif
+ return 64;
+#else
return __builtin_ctzll(a);
+#endif
}
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+struct packed_u64 {
+ uint64_t v;
+};
+
+struct packed_u32 {
+ uint32_t v;
+};
+
+struct packed_u16 {
+ uint16_t v;
+};
+#pragma pack(pop)
+#else
struct __attribute__((packed)) packed_u64 {
uint64_t v;
};
@@ -146,6 +245,7 @@ struct __attribute__((packed)) packed_u32 {
struct __attribute__((packed)) packed_u16 {
uint16_t v;
};
+#endif
static inline uint64_t get_u64(const uint8_t *tab)
{
@@ -207,28 +307,34 @@ static inline void put_u8(uint8_t *tab, uint8_t val)
*tab = val;
}
+#ifndef bswap16
static inline uint16_t bswap16(uint16_t x)
{
return (x >> 8) | (x << 8);
}
+#endif
+#ifndef bswap32
static inline uint32_t bswap32(uint32_t v)
{
return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) |
((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24);
}
+#endif
+#ifndef bswap64
static inline uint64_t bswap64(uint64_t v)
{
- return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) |
- ((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) |
- ((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) |
- ((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) |
- ((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) |
- ((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) |
- ((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) |
+ return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) |
+ ((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) |
+ ((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) |
+ ((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) |
+ ((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) |
+ ((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) |
+ ((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) |
((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8));
}
+#endif
/* XXX: should take an extra argument to pass slack information to the caller */
typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size);
@@ -278,6 +384,36 @@ static inline void dbuf_set_error(DynBuf *s)
int unicode_to_utf8(uint8_t *buf, unsigned int c);
int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp);
+static inline BOOL is_surrogate(uint32_t c)
+{
+ return (c >> 11) == (0xD800 >> 11); // 0xD800-0xDFFF
+}
+
+static inline BOOL is_hi_surrogate(uint32_t c)
+{
+ return (c >> 10) == (0xD800 >> 10); // 0xD800-0xDBFF
+}
+
+static inline BOOL is_lo_surrogate(uint32_t c)
+{
+ return (c >> 10) == (0xDC00 >> 10); // 0xDC00-0xDFFF
+}
+
+static inline uint32_t get_hi_surrogate(uint32_t c)
+{
+ return (c >> 10) - (0x10000 >> 10) + 0xD800;
+}
+
+static inline uint32_t get_lo_surrogate(uint32_t c)
+{
+ return (c & 0x3FF) | 0xDC00;
+}
+
+static inline uint32_t from_surrogate(uint32_t hi, uint32_t lo)
+{
+ return 0x10000 + 0x400 * (hi - 0xD800) + (lo - 0xDC00);
+}
+
static inline int from_hex(int c)
{
if (c >= '0' && c <= '9')
@@ -294,4 +430,80 @@ void rqsort(void *base, size_t nmemb, size_t size,
int (*cmp)(const void *, const void *, void *),
void *arg);
+static inline uint64_t float64_as_uint64(double d)
+{
+ union {
+ double d;
+ uint64_t u64;
+ } u;
+ u.d = d;
+ return u.u64;
+}
+
+static inline double uint64_as_float64(uint64_t u64)
+{
+ union {
+ double d;
+ uint64_t u64;
+ } u;
+ u.u64 = u64;
+ return u.d;
+}
+
+static inline double fromfp16(uint16_t v)
+{
+ double d;
+ uint32_t v1;
+ v1 = v & 0x7fff;
+ if (unlikely(v1 >= 0x7c00))
+ v1 += 0x1f8000; /* NaN or infinity */
+ d = uint64_as_float64(((uint64_t)(v >> 15) << 63) | ((uint64_t)v1 << (52 - 10)));
+ return d * 0x1p1008;
+}
+
+static inline uint16_t tofp16(double d)
+{
+ uint64_t a, addend;
+ uint32_t v, sgn;
+ int shift;
+
+ a = float64_as_uint64(d);
+ sgn = a >> 63;
+ a = a & 0x7fffffffffffffff;
+ if (unlikely(a > 0x7ff0000000000000)) {
+ /* nan */
+ v = 0x7c01;
+ } else if (a < 0x3f10000000000000) { /* 0x1p-14 */
+ /* subnormal f16 number or zero */
+ if (a <= 0x3e60000000000000) { /* 0x1p-25 */
+ v = 0x0000; /* zero */
+ } else {
+ shift = 1051 - (a >> 52);
+ a = ((uint64_t)1 << 52) | (a & (((uint64_t)1 << 52) - 1));
+ addend = ((a >> shift) & 1) + (((uint64_t)1 << (shift - 1)) - 1);
+ v = (a + addend) >> shift;
+ }
+ } else {
+ /* normal number or infinity */
+ a -= 0x3f00000000000000; /* adjust the exponent */
+ /* round */
+ addend = ((a >> (52 - 10)) & 1) + (((uint64_t)1 << (52 - 11)) - 1);
+ v = (a + addend) >> (52 - 10);
+ /* overflow ? */
+ if (unlikely(v > 0x7c00))
+ v = 0x7c00;
+ }
+ return v | (sgn << 15);
+}
+
+static inline int isfp16nan(uint16_t v)
+{
+ return (v & 0x7FFF) > 0x7C00;
+}
+
+static inline int isfp16zero(uint16_t v)
+{
+ return (v & 0x7FFF) == 0;
+}
+
#endif /* CUTILS_H */
diff --git a/quickjs/dtoa.c b/quickjs/dtoa.c
new file mode 100644
index 0000000000..dc139e6b1f
--- /dev/null
+++ b/quickjs/dtoa.c
@@ -0,0 +1,1621 @@
+/*
+ * Tiny float64 printing and parsing library
+ *
+ * Copyright (c) 2024 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "cutils.h"
+#include "dtoa.h"
+
+#pragma warning(disable:4146)
+
+/*
+ TODO:
+ - test n_digits=101 instead of 100
+ - simplify subnormal handling
+ - reduce max memory usage
+ - free format: could add shortcut if exact result
+ - use 64 bit limb_t when possible
+ - use another algorithm for free format dtoa in base 10 (ryu ?)
+*/
+
+#define USE_POW5_TABLE
+/* use fast path to print small integers in free format */
+#define USE_FAST_INT
+
+#define LIMB_LOG2_BITS 5
+
+#define LIMB_BITS (1 << LIMB_LOG2_BITS)
+
+typedef int32_t slimb_t;
+typedef uint32_t limb_t;
+typedef uint64_t dlimb_t;
+
+#define LIMB_DIGITS 9
+
+#define JS_RADIX_MAX 36
+
+#define DBIGNUM_LEN_MAX 52 /* ~ 2^(1072+53)*36^100 (dtoa) */
+#define MANT_LEN_MAX 18 /* < 36^100 */
+
+typedef intptr_t mp_size_t;
+
+/* the represented number is sum(i, tab[i]*2^(LIMB_BITS * i)) */
+typedef struct {
+ int len; /* >= 1 */
+ limb_t tab[];
+} mpb_t;
+
+static limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n)
+{
+ size_t i;
+ limb_t k, a;
+
+ k=b;
+ for(i=0;i> LIMB_BITS;
+ }
+ return l;
+}
+
+/* WARNING: d must be >= 2^(LIMB_BITS-1) */
+static inline limb_t udiv1norm_init(limb_t d)
+{
+ limb_t a0, a1;
+ a1 = -d - 1;
+ a0 = -1;
+ return (((dlimb_t)a1 << LIMB_BITS) | a0) / d;
+}
+
+/* return the quotient and the remainder in '*pr'of 'a1*2^LIMB_BITS+a0
+ / d' with 0 <= a1 < d. */
+static inline limb_t udiv1norm(limb_t *pr, limb_t a1, limb_t a0,
+ limb_t d, limb_t d_inv)
+{
+ limb_t n1m, n_adj, q, r, ah;
+ dlimb_t a;
+ n1m = ((slimb_t)a0 >> (LIMB_BITS - 1));
+ n_adj = a0 + (n1m & d);
+ a = (dlimb_t)d_inv * (a1 - n1m) + n_adj;
+ q = (a >> LIMB_BITS) + a1;
+ /* compute a - q * r and update q so that the remainder is between
+ 0 and d - 1 */
+ a = ((dlimb_t)a1 << LIMB_BITS) | a0;
+ a = a - (dlimb_t)q * d - d;
+ ah = a >> LIMB_BITS;
+ q += 1 + ah;
+ r = (limb_t)a + (ah & d);
+ *pr = r;
+ return q;
+}
+
+static limb_t mp_div1(limb_t *tabr, const limb_t *taba, limb_t n,
+ limb_t b, limb_t r)
+{
+ slimb_t i;
+ dlimb_t a1;
+ for(i = n - 1; i >= 0; i--) {
+ a1 = ((dlimb_t)r << LIMB_BITS) | taba[i];
+ tabr[i] = a1 / b;
+ r = a1 % b;
+ }
+ return r;
+}
+
+/* r = (a + high*B^n) >> shift. Return the remainder r (0 <= r < 2^shift).
+ 1 <= shift <= LIMB_BITS - 1 */
+static limb_t mp_shr(limb_t *tab_r, const limb_t *tab, mp_size_t n,
+ int shift, limb_t high)
+{
+ mp_size_t i;
+ limb_t l, a;
+
+ assert(shift >= 1 && shift < LIMB_BITS);
+ l = high;
+ for(i = n - 1; i >= 0; i--) {
+ a = tab[i];
+ tab_r[i] = (a >> shift) | (l << (LIMB_BITS - shift));
+ l = a;
+ }
+ return l & (((limb_t)1 << shift) - 1);
+}
+
+/* r = (a << shift) + low. 1 <= shift <= LIMB_BITS - 1, 0 <= low <
+ 2^shift. */
+static limb_t mp_shl(limb_t *tab_r, const limb_t *tab, mp_size_t n,
+ int shift, limb_t low)
+{
+ mp_size_t i;
+ limb_t l, a;
+
+ assert(shift >= 1 && shift < LIMB_BITS);
+ l = low;
+ for(i = 0; i < n; i++) {
+ a = tab[i];
+ tab_r[i] = (a << shift) | l;
+ l = (a >> (LIMB_BITS - shift));
+ }
+ return l;
+}
+
+static no_inline limb_t mp_div1norm(limb_t *tabr, const limb_t *taba, limb_t n,
+ limb_t b, limb_t r, limb_t b_inv, int shift)
+{
+ slimb_t i;
+
+ if (shift != 0) {
+ r = (r << shift) | mp_shl(tabr, taba, n, shift, 0);
+ }
+ for(i = n - 1; i >= 0; i--) {
+ tabr[i] = udiv1norm(&r, r, taba[i], b, b_inv);
+ }
+ r >>= shift;
+ return r;
+}
+
+static __maybe_unused void mpb_dump(const char *str, const mpb_t *a)
+{
+ int i;
+
+ printf("%s= 0x", str);
+ for(i = a->len - 1; i >= 0; i--) {
+ printf("%08x", a->tab[i]);
+ if (i != 0)
+ printf("_");
+ }
+ printf("\n");
+}
+
+static void mpb_renorm(mpb_t *r)
+{
+ while (r->len > 1 && r->tab[r->len - 1] == 0)
+ r->len--;
+}
+
+#ifdef USE_POW5_TABLE
+static const uint32_t pow5_table[17] = {
+ 0x00000005, 0x00000019, 0x0000007d, 0x00000271,
+ 0x00000c35, 0x00003d09, 0x0001312d, 0x0005f5e1,
+ 0x001dcd65, 0x009502f9, 0x02e90edd, 0x0e8d4a51,
+ 0x48c27395, 0x6bcc41e9, 0x1afd498d, 0x86f26fc1,
+ 0xa2bc2ec5,
+};
+
+static const uint8_t pow5h_table[4] = {
+ 0x00000001, 0x00000007, 0x00000023, 0x000000b1,
+};
+
+static const uint32_t pow5_inv_table[13] = {
+ 0x99999999, 0x47ae147a, 0x0624dd2f, 0xa36e2eb1,
+ 0x4f8b588e, 0x0c6f7a0b, 0xad7f29ab, 0x5798ee23,
+ 0x12e0be82, 0xb7cdfd9d, 0x5fd7fe17, 0x19799812,
+ 0xc25c2684,
+};
+#endif
+
+/* return a^b */
+static uint64_t pow_ui(uint32_t a, uint32_t b)
+{
+ int i, n_bits;
+ uint64_t r;
+ if (b == 0)
+ return 1;
+ if (b == 1)
+ return a;
+#ifdef USE_POW5_TABLE
+ if ((a == 5 || a == 10) && b <= 17) {
+ r = pow5_table[b - 1];
+ if (b >= 14) {
+ r |= (uint64_t)pow5h_table[b - 14] << 32;
+ }
+ if (a == 10)
+ r <<= b;
+ return r;
+ }
+#endif
+ r = a;
+ n_bits = 32 - clz32(b);
+ for(i = n_bits - 2; i >= 0; i--) {
+ r *= r;
+ if ((b >> i) & 1)
+ r *= a;
+ }
+ return r;
+}
+
+static uint32_t pow_ui_inv(uint32_t *pr_inv, int *pshift, uint32_t a, uint32_t b)
+{
+ uint32_t r_inv, r;
+ int shift;
+#ifdef USE_POW5_TABLE
+ if (a == 5 && b >= 1 && b <= 13) {
+ r = pow5_table[b - 1];
+ shift = clz32(r);
+ r <<= shift;
+ r_inv = pow5_inv_table[b - 1];
+ } else
+#endif
+ {
+ r = pow_ui(a, b);
+ shift = clz32(r);
+ r <<= shift;
+ r_inv = udiv1norm_init(r);
+ }
+ *pshift = shift;
+ *pr_inv = r_inv;
+ return r;
+}
+
+enum {
+ JS_RNDN, /* round to nearest, ties to even */
+ JS_RNDNA, /* round to nearest, ties away from zero */
+ JS_RNDZ,
+};
+
+static int mpb_get_bit(const mpb_t *r, int k)
+{
+ int l;
+
+ l = (unsigned)k / LIMB_BITS;
+ k = k & (LIMB_BITS - 1);
+ if (l >= r->len)
+ return 0;
+ else
+ return (r->tab[l] >> k) & 1;
+}
+
+/* compute round(r / 2^shift). 'shift' can be negative */
+static void mpb_shr_round(mpb_t *r, int shift, int rnd_mode)
+{
+ int l, i;
+
+ if (shift == 0)
+ return;
+ if (shift < 0) {
+ shift = -shift;
+ l = (unsigned)shift / LIMB_BITS;
+ shift = shift & (LIMB_BITS - 1);
+ if (shift != 0) {
+ r->tab[r->len] = mp_shl(r->tab, r->tab, r->len, shift, 0);
+ r->len++;
+ mpb_renorm(r);
+ }
+ if (l > 0) {
+ for(i = r->len - 1; i >= 0; i--)
+ r->tab[i + l] = r->tab[i];
+ for(i = 0; i < l; i++)
+ r->tab[i] = 0;
+ r->len += l;
+ }
+ } else {
+ limb_t bit1, bit2;
+ int k, add_one;
+
+ switch(rnd_mode) {
+ default:
+ case JS_RNDZ:
+ add_one = 0;
+ break;
+ case JS_RNDN:
+ case JS_RNDNA:
+ bit1 = mpb_get_bit(r, shift - 1);
+ if (bit1) {
+ if (rnd_mode == JS_RNDNA) {
+ bit2 = 1;
+ } else {
+ /* bit2 = oring of all the bits after bit1 */
+ bit2 = 0;
+ if (shift >= 2) {
+ k = shift - 1;
+ l = (unsigned)k / LIMB_BITS;
+ k = k & (LIMB_BITS - 1);
+ for(i = 0; i < min_int(l, r->len); i++)
+ bit2 |= r->tab[i];
+ if (l < r->len)
+ bit2 |= r->tab[l] & (((limb_t)1 << k) - 1);
+ }
+ }
+ if (bit2) {
+ add_one = 1;
+ } else {
+ /* round to even */
+ add_one = mpb_get_bit(r, shift);
+ }
+ } else {
+ add_one = 0;
+ }
+ break;
+ }
+
+ l = (unsigned)shift / LIMB_BITS;
+ shift = shift & (LIMB_BITS - 1);
+ if (l >= r->len) {
+ r->len = 1;
+ r->tab[0] = add_one;
+ } else {
+ if (l > 0) {
+ r->len -= l;
+ for(i = 0; i < r->len; i++)
+ r->tab[i] = r->tab[i + l];
+ }
+ if (shift != 0) {
+ mp_shr(r->tab, r->tab, r->len, shift, 0);
+ mpb_renorm(r);
+ }
+ if (add_one) {
+ limb_t a;
+ a = mp_add_ui(r->tab, 1, r->len);
+ if (a)
+ r->tab[r->len++] = a;
+ }
+ }
+ }
+}
+
+/* return -1, 0 or 1 */
+static int mpb_cmp(const mpb_t *a, const mpb_t *b)
+{
+ mp_size_t i;
+ if (a->len < b->len)
+ return -1;
+ else if (a->len > b->len)
+ return 1;
+ for(i = a->len - 1; i >= 0; i--) {
+ if (a->tab[i] != b->tab[i]) {
+ if (a->tab[i] < b->tab[i])
+ return -1;
+ else
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void mpb_set_u64(mpb_t *r, uint64_t m)
+{
+#if LIMB_BITS == 64
+ r->tab[0] = m;
+ r->len = 1;
+#else
+ r->tab[0] = m;
+ r->tab[1] = m >> LIMB_BITS;
+ if (r->tab[1] == 0)
+ r->len = 1;
+ else
+ r->len = 2;
+#endif
+}
+
+static uint64_t mpb_get_u64(mpb_t *r)
+{
+#if LIMB_BITS == 64
+ return r->tab[0];
+#else
+ if (r->len == 1) {
+ return r->tab[0];
+ } else {
+ return r->tab[0] | ((uint64_t)r->tab[1] << LIMB_BITS);
+ }
+#endif
+}
+
+/* floor_log2() = position of the first non zero bit or -1 if zero. */
+static int mpb_floor_log2(mpb_t *a)
+{
+ limb_t v;
+ v = a->tab[a->len - 1];
+ if (v == 0)
+ return -1;
+ else
+ return a->len * LIMB_BITS - 1 - clz32(v);
+}
+
+#define MUL_LOG2_RADIX_BASE_LOG2 24
+
+/* round((1 << MUL_LOG2_RADIX_BASE_LOG2)/log2(i + 2)) */
+static const uint32_t mul_log2_radix_table[JS_RADIX_MAX - 1] = {
+ 0x000000, 0xa1849d, 0x000000, 0x6e40d2,
+ 0x6308c9, 0x5b3065, 0x000000, 0x50c24e,
+ 0x4d104d, 0x4a0027, 0x4768ce, 0x452e54,
+ 0x433d00, 0x418677, 0x000000, 0x3ea16b,
+ 0x3d645a, 0x3c43c2, 0x3b3b9a, 0x3a4899,
+ 0x39680b, 0x3897b3, 0x37d5af, 0x372069,
+ 0x367686, 0x35d6df, 0x354072, 0x34b261,
+ 0x342bea, 0x33ac62, 0x000000, 0x32bfd9,
+ 0x3251dd, 0x31e8d6, 0x318465,
+};
+
+/* return floor(a / log2(radix)) for -2048 <= a <= 2047 */
+static int mul_log2_radix(int a, int radix)
+{
+ int radix_bits, mult;
+
+ if ((radix & (radix - 1)) == 0) {
+ /* if the radix is a power of two better to do it exactly */
+ radix_bits = 31 - clz32(radix);
+ if (a < 0)
+ a -= radix_bits - 1;
+ return a / radix_bits;
+ } else {
+ mult = mul_log2_radix_table[radix - 2];
+ return ((int64_t)a * mult) >> MUL_LOG2_RADIX_BASE_LOG2;
+ }
+}
+
+#if 0
+static void build_mul_log2_radix_table(void)
+{
+ int base, radix, mult, col, base_log2;
+
+ base_log2 = 24;
+ base = 1 << base_log2;
+ col = 0;
+ for(radix = 2; radix <= 36; radix++) {
+ if ((radix & (radix - 1)) == 0)
+ mult = 0;
+ else
+ mult = lrint((double)base / log2(radix));
+ printf("0x%06x, ", mult);
+ if (++col == 4) {
+ printf("\n");
+ col = 0;
+ }
+ }
+ printf("\n");
+}
+
+static void mul_log2_radix_test(void)
+{
+ int radix, i, ref, r;
+
+ for(radix = 2; radix <= 36; radix++) {
+ for(i = -2048; i <= 2047; i++) {
+ ref = (int)floor((double)i / log2(radix));
+ r = mul_log2_radix(i, radix);
+ if (ref != r) {
+ printf("ERROR: radix=%d i=%d r=%d ref=%d\n",
+ radix, i, r, ref);
+ exit(1);
+ }
+ }
+ }
+ if (0)
+ build_mul_log2_radix_table();
+}
+#endif
+
+static void u32toa_len(char *buf, uint32_t n, size_t len)
+{
+ int digit, i;
+ for(i = len - 1; i >= 0; i--) {
+ digit = n % 10;
+ n = n / 10;
+ buf[i] = digit + '0';
+ }
+}
+
+/* for power of 2 radixes. len >= 1 */
+static void u64toa_bin_len(char *buf, uint64_t n, unsigned int radix_bits, int len)
+{
+ int digit, i;
+ unsigned int mask;
+
+ mask = (1 << radix_bits) - 1;
+ for(i = len - 1; i >= 0; i--) {
+ digit = n & mask;
+ n >>= radix_bits;
+ if (digit < 10)
+ digit += '0';
+ else
+ digit += 'a' - 10;
+ buf[i] = digit;
+ }
+}
+
+/* len >= 1. 2 <= radix <= 36 */
+static void limb_to_a(char *buf, limb_t n, unsigned int radix, int len)
+{
+ int digit, i;
+
+ if (radix == 10) {
+ /* specific case with constant divisor */
+#if LIMB_BITS == 32
+ u32toa_len(buf, n, len);
+#else
+ /* XXX: optimize */
+ for(i = len - 1; i >= 0; i--) {
+ digit = (limb_t)n % 10;
+ n = (limb_t)n / 10;
+ buf[i] = digit + '0';
+ }
+#endif
+ } else {
+ for(i = len - 1; i >= 0; i--) {
+ digit = (limb_t)n % radix;
+ n = (limb_t)n / radix;
+ if (digit < 10)
+ digit += '0';
+ else
+ digit += 'a' - 10;
+ buf[i] = digit;
+ }
+ }
+}
+
+size_t u32toa(char *buf, uint32_t n)
+{
+ char buf1[10], *q;
+ size_t len;
+
+ q = buf1 + sizeof(buf1);
+ do {
+ *--q = n % 10 + '0';
+ n /= 10;
+ } while (n != 0);
+ len = buf1 + sizeof(buf1) - q;
+ memcpy(buf, q, len);
+ return len;
+}
+
+size_t i32toa(char *buf, int32_t n)
+{
+ if (n >= 0) {
+ return u32toa(buf, n);
+ } else {
+ buf[0] = '-';
+ return u32toa(buf + 1, -(uint32_t)n) + 1;
+ }
+}
+
+#ifdef USE_FAST_INT
+size_t u64toa(char *buf, uint64_t n)
+{
+ if (n < 0x100000000) {
+ return u32toa(buf, n);
+ } else {
+ uint64_t n1;
+ char *q = buf;
+ uint32_t n2;
+
+ n1 = n / 1000000000;
+ n %= 1000000000;
+ if (n1 >= 0x100000000) {
+ n2 = n1 / 1000000000;
+ n1 = n1 % 1000000000;
+ /* at most two digits */
+ if (n2 >= 10) {
+ *q++ = n2 / 10 + '0';
+ n2 %= 10;
+ }
+ *q++ = n2 + '0';
+ u32toa_len(q, n1, 9);
+ q += 9;
+ } else {
+ q += u32toa(q, n1);
+ }
+ u32toa_len(q, n, 9);
+ q += 9;
+ return q - buf;
+ }
+}
+
+size_t i64toa(char *buf, int64_t n)
+{
+ if (n >= 0) {
+ return u64toa(buf, n);
+ } else {
+ buf[0] = '-';
+ return u64toa(buf + 1, -(uint64_t)n) + 1;
+ }
+}
+
+/* XXX: only tested for 1 <= n < 2^53 */
+size_t u64toa_radix(char *buf, uint64_t n, unsigned int radix)
+{
+ int radix_bits, l;
+ if (likely(radix == 10))
+ return u64toa(buf, n);
+ if ((radix & (radix - 1)) == 0) {
+ radix_bits = 31 - clz32(radix);
+ if (n == 0)
+ l = 1;
+ else
+ l = (64 - clz64(n) + radix_bits - 1) / radix_bits;
+ u64toa_bin_len(buf, n, radix_bits, l);
+ return l;
+ } else {
+ char buf1[41], *q; /* maximum length for radix = 3 */
+ size_t len;
+ int digit;
+ q = buf1 + sizeof(buf1);
+ do {
+ digit = n % radix;
+ n /= radix;
+ if (digit < 10)
+ digit += '0';
+ else
+ digit += 'a' - 10;
+ *--q = digit;
+ } while (n != 0);
+ len = buf1 + sizeof(buf1) - q;
+ memcpy(buf, q, len);
+ return len;
+ }
+}
+
+size_t i64toa_radix(char *buf, int64_t n, unsigned int radix)
+{
+ if (n >= 0) {
+ return u64toa_radix(buf, n, radix);
+ } else {
+ buf[0] = '-';
+ return u64toa_radix(buf + 1, -(uint64_t)n, radix) + 1;
+ }
+}
+#endif /* USE_FAST_INT */
+
+static const uint8_t digits_per_limb_table[JS_RADIX_MAX - 1] = {
+#if LIMB_BITS == 32
+32,20,16,13,12,11,10,10, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+#else
+64,40,32,27,24,22,21,20,19,18,17,17,16,16,16,15,15,15,14,14,14,14,13,13,13,13,13,13,13,12,12,12,12,12,12,
+#endif
+};
+
+static const uint32_t radix_base_table[JS_RADIX_MAX - 1] = {
+ 0x00000000, 0xcfd41b91, 0x00000000, 0x48c27395,
+ 0x81bf1000, 0x75db9c97, 0x40000000, 0xcfd41b91,
+ 0x3b9aca00, 0x8c8b6d2b, 0x19a10000, 0x309f1021,
+ 0x57f6c100, 0x98c29b81, 0x00000000, 0x18754571,
+ 0x247dbc80, 0x3547667b, 0x4c4b4000, 0x6b5a6e1d,
+ 0x94ace180, 0xcaf18367, 0x0b640000, 0x0e8d4a51,
+ 0x1269ae40, 0x17179149, 0x1cb91000, 0x23744899,
+ 0x2b73a840, 0x34e63b41, 0x40000000, 0x4cfa3cc1,
+ 0x5c13d840, 0x6d91b519, 0x81bf1000,
+};
+
+/* XXX: remove the table ? */
+static uint8_t dtoa_max_digits_table[JS_RADIX_MAX - 1] = {
+ 54, 35, 28, 24, 22, 20, 19, 18, 17, 17, 16, 16, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12,
+};
+
+/* we limit the maximum number of significant digits for atod to about
+ 128 bits of precision for non power of two bases. The only
+ requirement for Javascript is at least 20 digits in base 10. For
+ power of two bases, we do an exact rounding in all the cases. */
+static uint8_t atod_max_digits_table[JS_RADIX_MAX - 1] = {
+ 64, 80, 32, 55, 49, 45, 21, 40, 38, 37, 35, 34, 33, 32, 16, 31, 30, 30, 29, 29, 28, 28, 27, 27, 27, 26, 26, 26, 26, 25, 12, 25, 25, 24, 24,
+};
+
+/* if abs(d) >= B^max_exponent, it is an overflow */
+static const int16_t max_exponent[JS_RADIX_MAX - 1] = {
+ 1024, 647, 512, 442, 397, 365, 342, 324,
+ 309, 297, 286, 277, 269, 263, 256, 251,
+ 246, 242, 237, 234, 230, 227, 224, 221,
+ 218, 216, 214, 211, 209, 207, 205, 203,
+ 202, 200, 199,
+};
+
+/* if abs(d) <= B^min_exponent, it is an underflow */
+static const int16_t min_exponent[JS_RADIX_MAX - 1] = {
+-1075, -679, -538, -463, -416, -383, -359, -340,
+ -324, -311, -300, -291, -283, -276, -269, -263,
+ -258, -254, -249, -245, -242, -238, -235, -232,
+ -229, -227, -224, -222, -220, -217, -215, -214,
+ -212, -210, -208,
+};
+
+#if 0
+void build_tables(void)
+{
+ int r, j, radix, n, col, i;
+
+ /* radix_base_table */
+ for(radix = 2; radix <= 36; radix++) {
+ r = 1;
+ for(j = 0; j < digits_per_limb_table[radix - 2]; j++) {
+ r *= radix;
+ }
+ printf(" 0x%08x,", r);
+ if ((radix % 4) == 1)
+ printf("\n");
+ }
+ printf("\n");
+
+ /* dtoa_max_digits_table */
+ for(radix = 2; radix <= 36; radix++) {
+ /* Note: over estimated when the radix is a power of two */
+ printf(" %d,", 1 + (int)ceil(53.0 / log2(radix)));
+ }
+ printf("\n");
+
+ /* atod_max_digits_table */
+ for(radix = 2; radix <= 36; radix++) {
+ if ((radix & (radix - 1)) == 0) {
+ /* 64 bits is more than enough */
+ n = (int)floor(64.0 / log2(radix));
+ } else {
+ n = (int)floor(128.0 / log2(radix));
+ }
+ printf(" %d,", n);
+ }
+ printf("\n");
+
+ printf("static const int16_t max_exponent[JS_RADIX_MAX - 1] = {\n");
+ col = 0;
+ for(radix = 2; radix <= 36; radix++) {
+ printf("%5d, ", (int)ceil(1024 / log2(radix)));
+ if (++col == 8) {
+ col = 0;
+ printf("\n");
+ }
+ }
+ printf("\n};\n\n");
+
+ printf("static const int16_t min_exponent[JS_RADIX_MAX - 1] = {\n");
+ col = 0;
+ for(radix = 2; radix <= 36; radix++) {
+ printf("%5d, ", (int)floor(-1075 / log2(radix)));
+ if (++col == 8) {
+ col = 0;
+ printf("\n");
+ }
+ }
+ printf("\n};\n\n");
+
+ printf("static const uint32_t pow5_table[16] = {\n");
+ col = 0;
+ for(i = 2; i <= 17; i++) {
+ r = 1;
+ for(j = 0; j < i; j++) {
+ r *= 5;
+ }
+ printf("0x%08x, ", r);
+ if (++col == 4) {
+ col = 0;
+ printf("\n");
+ }
+ }
+ printf("\n};\n\n");
+
+ /* high part */
+ printf("static const uint8_t pow5h_table[4] = {\n");
+ col = 0;
+ for(i = 14; i <= 17; i++) {
+ uint64_t r1;
+ r1 = 1;
+ for(j = 0; j < i; j++) {
+ r1 *= 5;
+ }
+ printf("0x%08x, ", (uint32_t)(r1 >> 32));
+ if (++col == 4) {
+ col = 0;
+ printf("\n");
+ }
+ }
+ printf("\n};\n\n");
+}
+#endif
+
+/* n_digits >= 1. 0 <= dot_pos <= n_digits. If dot_pos == n_digits,
+ the dot is not displayed. 'a' is modified. */
+static int output_digits(char *buf,
+ mpb_t *a, int radix, int n_digits1,
+ int dot_pos)
+{
+ int n_digits, digits_per_limb, radix_bits, n, len;
+
+ n_digits = n_digits1;
+ if ((radix & (radix - 1)) == 0) {
+ /* radix = 2^radix_bits */
+ radix_bits = 31 - clz32(radix);
+ } else {
+ radix_bits = 0;
+ }
+ digits_per_limb = digits_per_limb_table[radix - 2];
+ if (radix_bits != 0) {
+ for(;;) {
+ n = min_int(n_digits, digits_per_limb);
+ n_digits -= n;
+ u64toa_bin_len(buf + n_digits, a->tab[0], radix_bits, n);
+ if (n_digits == 0)
+ break;
+ mpb_shr_round(a, digits_per_limb * radix_bits, JS_RNDZ);
+ }
+ } else {
+ limb_t r;
+ while (n_digits != 0) {
+ n = min_int(n_digits, digits_per_limb);
+ n_digits -= n;
+ r = mp_div1(a->tab, a->tab, a->len, radix_base_table[radix - 2], 0);
+ mpb_renorm(a);
+ limb_to_a(buf + n_digits, r, radix, n);
+ }
+ }
+
+ /* add the dot */
+ len = n_digits1;
+ if (dot_pos != n_digits1) {
+ memmove(buf + dot_pos + 1, buf + dot_pos, n_digits1 - dot_pos);
+ buf[dot_pos] = '.';
+ len++;
+ }
+ return len;
+}
+
+/* return (a, e_offset) such that a = a * (radix1*2^radix_shift)^f *
+ 2^-e_offset. 'f' can be negative. */
+static int mul_pow(mpb_t *a, int radix1, int radix_shift, int f, BOOL is_int, int e)
+{
+ int e_offset, d, n, n0;
+
+ e_offset = -f * radix_shift;
+ if (radix1 != 1) {
+ d = digits_per_limb_table[radix1 - 2];
+ if (f >= 0) {
+ limb_t h, b;
+
+ b = 0;
+ n0 = 0;
+ while (f != 0) {
+ n = min_int(f, d);
+ if (n != n0) {
+ b = pow_ui(radix1, n);
+ n0 = n;
+ }
+ h = mp_mul1(a->tab, a->tab, a->len, b, 0);
+ if (h != 0) {
+ a->tab[a->len++] = h;
+ }
+ f -= n;
+ }
+ } else {
+ int extra_bits, l, shift;
+ limb_t r, rem, b, b_inv;
+
+ f = -f;
+ l = (f + d - 1) / d; /* high bound for the number of limbs (XXX: make it better) */
+ e_offset += l * LIMB_BITS;
+ if (!is_int) {
+ /* at least 'e' bits are needed in the final result for rounding */
+ extra_bits = max_int(e - mpb_floor_log2(a), 0);
+ } else {
+ /* at least two extra bits are needed in the final result
+ for rounding */
+ extra_bits = max_int(2 + e - e_offset, 0);
+ }
+ e_offset += extra_bits;
+ mpb_shr_round(a, -(l * LIMB_BITS + extra_bits), JS_RNDZ);
+
+ b = 0;
+ b_inv = 0;
+ shift = 0;
+ n0 = 0;
+ rem = 0;
+ while (f != 0) {
+ n = min_int(f, d);
+ if (n != n0) {
+ b = pow_ui_inv(&b_inv, &shift, radix1, n);
+ n0 = n;
+ }
+ r = mp_div1norm(a->tab, a->tab, a->len, b, 0, b_inv, shift);
+ rem |= r;
+ mpb_renorm(a);
+ f -= n;
+ }
+ /* if the remainder is non zero, use it for rounding */
+ a->tab[0] |= (rem != 0);
+ }
+ }
+ return e_offset;
+}
+
+/* tmp1 = round(m*2^e*radix^f). 'tmp0' is a temporary storage */
+static void mul_pow_round(mpb_t *tmp1, uint64_t m, int e, int radix1, int radix_shift, int f,
+ int rnd_mode)
+{
+ int e_offset;
+
+ mpb_set_u64(tmp1, m);
+ e_offset = mul_pow(tmp1, radix1, radix_shift, f, TRUE, e);
+ mpb_shr_round(tmp1, -e + e_offset, rnd_mode);
+}
+
+/* return round(a*2^e_offset) rounded as a float64. 'a' is modified */
+static uint64_t round_to_d(int *pe, mpb_t *a, int e_offset, int rnd_mode)
+{
+ int e;
+ uint64_t m;
+
+ if (a->tab[0] == 0 && a->len == 1) {
+ /* zero result */
+ m = 0;
+ e = 0; /* don't care */
+ } else {
+ int prec, prec1, e_min;
+ e = mpb_floor_log2(a) + 1 - e_offset;
+ prec1 = 53;
+ e_min = -1021;
+ if (e < e_min) {
+ /* subnormal result or zero */
+ prec = prec1 - (e_min - e);
+ } else {
+ prec = prec1;
+ }
+ mpb_shr_round(a, e + e_offset - prec, rnd_mode);
+ m = mpb_get_u64(a);
+ m <<= (53 - prec);
+ /* mantissa overflow due to rounding */
+ if (m >= (uint64_t)1 << 53) {
+ m >>= 1;
+ e++;
+ }
+ }
+ *pe = e;
+ return m;
+}
+
+/* return (m, e) such that m*2^(e-53) = round(a * radix^f) with 2^52
+ <= m < 2^53 or m = 0.
+ 'a' is modified. */
+static uint64_t mul_pow_round_to_d(int *pe, mpb_t *a,
+ int radix1, int radix_shift, int f, int rnd_mode)
+{
+ int e_offset;
+
+ e_offset = mul_pow(a, radix1, radix_shift, f, FALSE, 55);
+ return round_to_d(pe, a, e_offset, rnd_mode);
+}
+
+#ifdef JS_DTOA_DUMP_STATS
+static int out_len_count[17];
+
+void js_dtoa_dump_stats(void)
+{
+ int i, sum;
+ sum = 0;
+ for(i = 0; i < 17; i++)
+ sum += out_len_count[i];
+ for(i = 0; i < 17; i++) {
+ printf("%2d %8d %5.2f%%\n",
+ i + 1, out_len_count[i], (double)out_len_count[i] / sum * 100);
+ }
+}
+#endif
+
+/* return a maximum bound of the string length. The bound depends on
+ 'd' only if format = JS_DTOA_FORMAT_FRAC or if JS_DTOA_EXP_DISABLED
+ is enabled. */
+int js_dtoa_max_len(double d, int radix, int n_digits, int flags)
+{
+ int fmt = flags & JS_DTOA_FORMAT_MASK;
+ int n, e;
+ uint64_t a;
+
+ if (fmt != JS_DTOA_FORMAT_FRAC) {
+ if (fmt == JS_DTOA_FORMAT_FREE) {
+ n = dtoa_max_digits_table[radix - 2];
+ } else {
+ n = n_digits;
+ }
+ if ((flags & JS_DTOA_EXP_MASK) == JS_DTOA_EXP_DISABLED) {
+ /* no exponential */
+ a = float64_as_uint64(d);
+ e = (a >> 52) & 0x7ff;
+ if (e == 0x7ff) {
+ /* NaN, Infinity */
+ n = 0;
+ } else {
+ e -= 1023;
+ /* XXX: adjust */
+ n += 10 + abs(mul_log2_radix(e - 1, radix));
+ }
+ } else {
+ /* extra: sign, 1 dot and exponent "e-1000" */
+ n += 1 + 1 + 6;
+ }
+ } else {
+ a = float64_as_uint64(d);
+ e = (a >> 52) & 0x7ff;
+ if (e == 0x7ff) {
+ /* NaN, Infinity */
+ n = 0;
+ } else {
+ /* high bound for the integer part */
+ e -= 1023;
+ /* x < 2^(e + 1) */
+ if (e < 0) {
+ n = 1;
+ } else {
+ n = 2 + mul_log2_radix(e - 1, radix);
+ }
+ /* sign, extra digit, 1 dot */
+ n += 1 + 1 + 1 + n_digits;
+ }
+ }
+ return max_int(n, 9); /* also include NaN and [-]Infinity */
+}
+
+#if defined(__SANITIZE_ADDRESS__) && 0
+static void *dtoa_malloc(uint64_t **pptr, size_t size)
+{
+ return malloc(size);
+}
+static void dtoa_free(void *ptr)
+{
+ free(ptr);
+}
+#else
+static void *dtoa_malloc(uint64_t **pptr, size_t size)
+{
+ void *ret;
+ ret = *pptr;
+ *pptr += (size + 7) / 8;
+ return ret;
+}
+
+static void dtoa_free(void *ptr)
+{
+}
+#endif
+
+/* return the length */
+int js_dtoa(char *buf, double d, int radix, int n_digits, int flags,
+ JSDTOATempMem *tmp_mem)
+{
+ uint64_t a, m, *mptr = tmp_mem->mem;
+ int e, sgn, l, E, P, i, E_max, radix1, radix_shift;
+ char *q;
+ mpb_t *tmp1, *mant_max;
+ int fmt = flags & JS_DTOA_FORMAT_MASK;
+
+ tmp1 = dtoa_malloc(&mptr, sizeof(mpb_t) + sizeof(limb_t) * DBIGNUM_LEN_MAX);
+ mant_max = dtoa_malloc(&mptr, sizeof(mpb_t) + sizeof(limb_t) * MANT_LEN_MAX);
+ assert((mptr - tmp_mem->mem) <= sizeof(JSDTOATempMem) / sizeof(mptr[0]));
+
+ radix_shift = ctz32(radix);
+ radix1 = radix >> radix_shift;
+ a = float64_as_uint64(d);
+ sgn = a >> 63;
+ e = (a >> 52) & 0x7ff;
+ m = a & (((uint64_t)1 << 52) - 1);
+ q = buf;
+ if (e == 0x7ff) {
+ if (m == 0) {
+ if (sgn)
+ *q++ = '-';
+ memcpy(q, "Infinity", 8);
+ q += 8;
+ } else {
+ memcpy(q, "NaN", 3);
+ q += 3;
+ }
+ goto done;
+ } else if (e == 0) {
+ if (m == 0) {
+ tmp1->len = 1;
+ tmp1->tab[0] = 0;
+ E = 1;
+ if (fmt == JS_DTOA_FORMAT_FREE)
+ P = 1;
+ else if (fmt == JS_DTOA_FORMAT_FRAC)
+ P = n_digits + 1;
+ else
+ P = n_digits;
+ /* "-0" is displayed as "0" if JS_DTOA_MINUS_ZERO is not present */
+ if (sgn && (flags & JS_DTOA_MINUS_ZERO))
+ *q++ = '-';
+ goto output;
+ }
+ /* denormal number: convert to a normal number */
+ l = clz64(m) - 11;
+ e -= l - 1;
+ m <<= l;
+ } else {
+ m |= (uint64_t)1 << 52;
+ }
+ if (sgn)
+ *q++ = '-';
+ /* remove the bias */
+ e -= 1022;
+ /* d = 2^(e-53)*m */
+ // printf("m=0x%016" PRIx64 " e=%d\n", m, e);
+#ifdef USE_FAST_INT
+ if (fmt == JS_DTOA_FORMAT_FREE &&
+ e >= 1 && e <= 53 &&
+ (m & (((uint64_t)1 << (53 - e)) - 1)) == 0 &&
+ (flags & JS_DTOA_EXP_MASK) != JS_DTOA_EXP_ENABLED) {
+ m >>= 53 - e;
+ /* 'm' is never zero */
+ q += u64toa_radix(q, m, radix);
+ goto done;
+ }
+#endif
+
+ /* this choice of E implies F=round(x*B^(P-E) is such as:
+ B^(P-1) <= F < 2.B^P. */
+ E = 1 + mul_log2_radix(e - 1, radix);
+
+ if (fmt == JS_DTOA_FORMAT_FREE) {
+ int P_max, E0, e1, E_found, P_found;
+ uint64_t m1, mant_found, mant, mant_max1;
+ /* P_max is guarranteed to work by construction */
+ P_max = dtoa_max_digits_table[radix - 2];
+ E0 = E;
+ E_found = 0;
+ P_found = 0;
+ mant_found = 0;
+ /* find the minimum number of digits by successive tries */
+ P = P_max; /* P_max is guarateed to work */
+ for(;;) {
+ /* mant_max always fits on 64 bits */
+ mant_max1 = pow_ui(radix, P);
+ /* compute the mantissa in base B */
+ E = E0;
+ for(;;) {
+ /* XXX: add inexact flag */
+ mul_pow_round(tmp1, m, e - 53, radix1, radix_shift, P - E, JS_RNDN);
+ mant = mpb_get_u64(tmp1);
+ if (mant < mant_max1)
+ break;
+ E++; /* at most one iteration is possible */
+ }
+ /* remove useless trailing zero digits */
+ while ((mant % radix) == 0) {
+ mant /= radix;
+ P--;
+ }
+ /* garanteed to work for P = P_max */
+ if (P_found == 0)
+ goto prec_found;
+ /* convert back to base 2 */
+ mpb_set_u64(tmp1, mant);
+ m1 = mul_pow_round_to_d(&e1, tmp1, radix1, radix_shift, E - P, JS_RNDN);
+ // printf("P=%2d: m=0x%016" PRIx64 " e=%d m1=0x%016" PRIx64 " e1=%d\n", P, m, e, m1, e1);
+ /* Note: (m, e) is never zero here, so the exponent for m1
+ = 0 does not matter */
+ if (m1 == m && e1 == e) {
+ prec_found:
+ P_found = P;
+ E_found = E;
+ mant_found = mant;
+ if (P == 1)
+ break;
+ P--; /* try lower exponent */
+ } else {
+ break;
+ }
+ }
+ P = P_found;
+ E = E_found;
+ mpb_set_u64(tmp1, mant_found);
+#ifdef JS_DTOA_DUMP_STATS
+ if (radix == 10) {
+ out_len_count[P - 1]++;
+ }
+#endif
+ } else if (fmt == JS_DTOA_FORMAT_FRAC) {
+ int len;
+
+ assert(n_digits >= 0 && n_digits <= JS_DTOA_MAX_DIGITS);
+ /* P = max_int(E, 1) + n_digits; */
+ /* frac is rounded using RNDNA */
+ mul_pow_round(tmp1, m, e - 53, radix1, radix_shift, n_digits, JS_RNDNA);
+
+ /* we add one extra digit on the left and remove it if needed
+ to avoid testing if the result is < radix^P */
+ len = output_digits(q, tmp1, radix, max_int(E + 1, 1) + n_digits,
+ max_int(E + 1, 1));
+ if (q[0] == '0' && len >= 2 && q[1] != '.') {
+ len--;
+ memmove(q, q + 1, len);
+ }
+ q += len;
+ goto done;
+ } else {
+ int pow_shift;
+ assert(n_digits >= 1 && n_digits <= JS_DTOA_MAX_DIGITS);
+ P = n_digits;
+ /* mant_max = radix^P */
+ mant_max->len = 1;
+ mant_max->tab[0] = 1;
+ pow_shift = mul_pow(mant_max, radix1, radix_shift, P, FALSE, 0);
+ mpb_shr_round(mant_max, pow_shift, JS_RNDZ);
+
+ for(;;) {
+ /* fixed and frac are rounded using RNDNA */
+ mul_pow_round(tmp1, m, e - 53, radix1, radix_shift, P - E, JS_RNDNA);
+ if (mpb_cmp(tmp1, mant_max) < 0)
+ break;
+ E++; /* at most one iteration is possible */
+ }
+ }
+ output:
+ if (fmt == JS_DTOA_FORMAT_FIXED)
+ E_max = n_digits;
+ else
+ E_max = dtoa_max_digits_table[radix - 2] + 4;
+ if ((flags & JS_DTOA_EXP_MASK) == JS_DTOA_EXP_ENABLED ||
+ ((flags & JS_DTOA_EXP_MASK) == JS_DTOA_EXP_AUTO && (E <= -6 || E > E_max))) {
+ q += output_digits(q, tmp1, radix, P, 1);
+ E--;
+ if (radix == 10) {
+ *q++ = 'e';
+ } else if (radix1 == 1 && radix_shift <= 4) {
+ E *= radix_shift;
+ *q++ = 'p';
+ } else {
+ *q++ = '@';
+ }
+ if (E < 0) {
+ *q++ = '-';
+ E = -E;
+ } else {
+ *q++ = '+';
+ }
+ q += u32toa(q, E);
+ } else if (E <= 0) {
+ *q++ = '0';
+ *q++ = '.';
+ for(i = 0; i < -E; i++)
+ *q++ = '0';
+ q += output_digits(q, tmp1, radix, P, P);
+ } else {
+ q += output_digits(q, tmp1, radix, P, min_int(P, E));
+ for(i = 0; i < E - P; i++)
+ *q++ = '0';
+ }
+ done:
+ *q = '\0';
+ dtoa_free(mant_max);
+ dtoa_free(tmp1);
+ return q - buf;
+}
+
+static inline int to_digit(int c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ else if (c >= 'A' && c <= 'Z')
+ return c - 'A' + 10;
+ else if (c >= 'a' && c <= 'z')
+ return c - 'a' + 10;
+ else
+ return 36;
+}
+
+/* r = r * radix_base + a. radix_base = 0 means radix_base = 2^32 */
+static void mpb_mul1_base(mpb_t *r, limb_t radix_base, limb_t a)
+{
+ int i;
+ if (r->tab[0] == 0 && r->len == 1) {
+ r->tab[0] = a;
+ } else {
+ if (radix_base == 0) {
+ for(i = r->len; i >= 0; i--) {
+ r->tab[i + 1] = r->tab[i];
+ }
+ r->tab[0] = a;
+ } else {
+ r->tab[r->len] = mp_mul1(r->tab, r->tab, r->len,
+ radix_base, a);
+ }
+ r->len++;
+ mpb_renorm(r);
+ }
+}
+
+/* XXX: add fast path for small integers */
+double js_atod(const char *str, const char **pnext, int radix, int flags,
+ JSATODTempMem *tmp_mem)
+{
+ uint64_t *mptr = tmp_mem->mem;
+ const char *p, *p_start;
+ limb_t cur_limb, radix_base, extra_digits;
+ int is_neg, digit_count, limb_digit_count, digits_per_limb, sep, radix1, radix_shift;
+ int radix_bits, expn, e, max_digits, expn_offset, dot_pos, sig_pos, pos;
+ mpb_t *tmp0;
+ double dval;
+ BOOL is_bin_exp, is_zero, expn_overflow;
+ uint64_t m, a;
+
+ tmp0 = dtoa_malloc(&mptr, sizeof(mpb_t) + sizeof(limb_t) * DBIGNUM_LEN_MAX);
+ assert((mptr - tmp_mem->mem) <= sizeof(JSATODTempMem) / sizeof(mptr[0]));
+ /* optional separator between digits */
+ sep = (flags & JS_ATOD_ACCEPT_UNDERSCORES) ? '_' : 256;
+
+ p = str;
+ is_neg = 0;
+ if (p[0] == '+') {
+ p++;
+ p_start = p;
+ } else if (p[0] == '-') {
+ is_neg = 1;
+ p++;
+ p_start = p;
+ } else {
+ p_start = p;
+ }
+
+ if (p[0] == '0') {
+ if ((p[1] == 'x' || p[1] == 'X') &&
+ (radix == 0 || radix == 16)) {
+ p += 2;
+ radix = 16;
+ } else if ((p[1] == 'o' || p[1] == 'O') &&
+ radix == 0 && (flags & JS_ATOD_ACCEPT_BIN_OCT)) {
+ p += 2;
+ radix = 8;
+ } else if ((p[1] == 'b' || p[1] == 'B') &&
+ radix == 0 && (flags & JS_ATOD_ACCEPT_BIN_OCT)) {
+ p += 2;
+ radix = 2;
+ } else if ((p[1] >= '0' && p[1] <= '9') &&
+ radix == 0 && (flags & JS_ATOD_ACCEPT_LEGACY_OCTAL)) {
+ int i;
+ sep = 256;
+ for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++)
+ continue;
+ if (p[i] == '8' || p[i] == '9')
+ goto no_prefix;
+ p += 1;
+ radix = 8;
+ } else {
+ goto no_prefix;
+ }
+ /* there must be a digit after the prefix */
+ if (to_digit((uint8_t)*p) >= radix)
+ goto fail;
+ no_prefix: ;
+ } else {
+ if (!(flags & JS_ATOD_INT_ONLY) && strstart(p, "Infinity", &p))
+ goto overflow;
+ }
+ if (radix == 0)
+ radix = 10;
+
+ cur_limb = 0;
+ expn_offset = 0;
+ digit_count = 0;
+ limb_digit_count = 0;
+ max_digits = atod_max_digits_table[radix - 2];
+ digits_per_limb = digits_per_limb_table[radix - 2];
+ radix_base = radix_base_table[radix - 2];
+ radix_shift = ctz32(radix);
+ radix1 = radix >> radix_shift;
+ if (radix1 == 1) {
+ /* radix = 2^radix_bits */
+ radix_bits = radix_shift;
+ } else {
+ radix_bits = 0;
+ }
+ tmp0->len = 1;
+ tmp0->tab[0] = 0;
+ extra_digits = 0;
+ pos = 0;
+ dot_pos = -1;
+ /* skip leading zeros */
+ for(;;) {
+ if (*p == '.' && (p > p_start || to_digit(p[1]) < radix) &&
+ !(flags & JS_ATOD_INT_ONLY)) {
+ if (*p == sep)
+ goto fail;
+ if (dot_pos >= 0)
+ break;
+ dot_pos = pos;
+ p++;
+ }
+ if (*p == sep && p > p_start && p[1] == '0')
+ p++;
+ if (*p != '0')
+ break;
+ p++;
+ pos++;
+ }
+
+ sig_pos = pos;
+ for(;;) {
+ limb_t c;
+ if (*p == '.' && (p > p_start || to_digit(p[1]) < radix) &&
+ !(flags & JS_ATOD_INT_ONLY)) {
+ if (*p == sep)
+ goto fail;
+ if (dot_pos >= 0)
+ break;
+ dot_pos = pos;
+ p++;
+ }
+ if (*p == sep && p > p_start && to_digit(p[1]) < radix)
+ p++;
+ c = to_digit(*p);
+ if (c >= radix)
+ break;
+ p++;
+ pos++;
+ if (digit_count < max_digits) {
+ /* XXX: could be faster when radix_bits != 0 */
+ cur_limb = cur_limb * radix + c;
+ limb_digit_count++;
+ if (limb_digit_count == digits_per_limb) {
+ mpb_mul1_base(tmp0, radix_base, cur_limb);
+ cur_limb = 0;
+ limb_digit_count = 0;
+ }
+ digit_count++;
+ } else {
+ extra_digits |= c;
+ }
+ }
+ if (limb_digit_count != 0) {
+ mpb_mul1_base(tmp0, pow_ui(radix, limb_digit_count), cur_limb);
+ }
+ if (digit_count == 0) {
+ is_zero = TRUE;
+ expn_offset = 0;
+ } else {
+ is_zero = FALSE;
+ if (dot_pos < 0)
+ dot_pos = pos;
+ expn_offset = sig_pos + digit_count - dot_pos;
+ }
+
+ /* Use the extra digits for rounding if the base is a power of
+ two. Otherwise they are just truncated. */
+ if (radix_bits != 0 && extra_digits != 0) {
+ tmp0->tab[0] |= 1;
+ }
+
+ /* parse the exponent, if any */
+ expn = 0;
+ expn_overflow = FALSE;
+ is_bin_exp = FALSE;
+ if (!(flags & JS_ATOD_INT_ONLY) &&
+ ((radix == 10 && (*p == 'e' || *p == 'E')) ||
+ (radix != 10 && (*p == '@' ||
+ (radix_bits >= 1 && radix_bits <= 4 && (*p == 'p' || *p == 'P'))))) &&
+ p > p_start) {
+ BOOL exp_is_neg;
+ int c;
+ is_bin_exp = (*p == 'p' || *p == 'P');
+ p++;
+ exp_is_neg = 0;
+ if (*p == '+') {
+ p++;
+ } else if (*p == '-') {
+ exp_is_neg = 1;
+ p++;
+ }
+ c = to_digit(*p);
+ if (c >= 10)
+ goto fail; /* XXX: could stop before the exponent part */
+ expn = c;
+ p++;
+ for(;;) {
+ if (*p == sep && to_digit(p[1]) < 10)
+ p++;
+ c = to_digit(*p);
+ if (c >= 10)
+ break;
+ if (!expn_overflow) {
+ if (unlikely(expn > ((INT32_MAX - 2 - 9) / 10))) {
+ expn_overflow = TRUE;
+ } else {
+ expn = expn * 10 + c;
+ }
+ }
+ p++;
+ }
+ if (exp_is_neg)
+ expn = -expn;
+ /* if zero result, the exponent can be arbitrarily large */
+ if (!is_zero && expn_overflow) {
+ if (exp_is_neg)
+ a = 0;
+ else
+ a = (uint64_t)0x7ff << 52; /* infinity */
+ goto done;
+ }
+ }
+
+ if (p == p_start)
+ goto fail;
+
+ if (is_zero) {
+ a = 0;
+ } else {
+ int expn1;
+ if (radix_bits != 0) {
+ if (!is_bin_exp)
+ expn *= radix_bits;
+ expn -= expn_offset * radix_bits;
+ expn1 = expn + digit_count * radix_bits;
+ if (expn1 >= 1024 + radix_bits)
+ goto overflow;
+ else if (expn1 <= -1075)
+ goto underflow;
+ m = round_to_d(&e, tmp0, -expn, JS_RNDN);
+ } else {
+ expn -= expn_offset;
+ expn1 = expn + digit_count;
+ if (expn1 >= max_exponent[radix - 2] + 1)
+ goto overflow;
+ else if (expn1 <= min_exponent[radix - 2])
+ goto underflow;
+ m = mul_pow_round_to_d(&e, tmp0, radix1, radix_shift, expn, JS_RNDN);
+ }
+ if (m == 0) {
+ underflow:
+ a = 0;
+ } else if (e > 1024) {
+ overflow:
+ /* overflow */
+ a = (uint64_t)0x7ff << 52;
+ } else if (e < -1073) {
+ /* underflow */
+ /* XXX: check rounding */
+ a = 0;
+ } else if (e < -1021) {
+ /* subnormal */
+ a = m >> (-e - 1021);
+ } else {
+ a = ((uint64_t)(e + 1022) << 52) | (m & (((uint64_t)1 << 52) - 1));
+ }
+ }
+ done:
+ a |= (uint64_t)is_neg << 63;
+ dval = uint64_as_float64(a);
+ done1:
+ if (pnext)
+ *pnext = p;
+ dtoa_free(tmp0);
+ return dval;
+ fail:
+ dval = NAN;
+ goto done1;
+}
diff --git a/quickjs/dtoa.h b/quickjs/dtoa.h
new file mode 100644
index 0000000000..de76f1a3fe
--- /dev/null
+++ b/quickjs/dtoa.h
@@ -0,0 +1,83 @@
+/*
+ * Tiny float64 printing and parsing library
+ *
+ * Copyright (c) 2024 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+//#define JS_DTOA_DUMP_STATS
+
+/* maximum number of digits for fixed and frac formats */
+#define JS_DTOA_MAX_DIGITS 101
+
+/* radix != 10 is only supported with flags = JS_DTOA_FORMAT_FREE */
+/* use as many digits as necessary */
+#define JS_DTOA_FORMAT_FREE (0 << 0)
+/* use n_digits significant digits (1 <= n_digits <= JS_DTOA_MAX_DIGITS) */
+#define JS_DTOA_FORMAT_FIXED (1 << 0)
+/* force fractional format: [-]dd.dd with n_digits fractional digits.
+ 0 <= n_digits <= JS_DTOA_MAX_DIGITS */
+#define JS_DTOA_FORMAT_FRAC (2 << 0)
+#define JS_DTOA_FORMAT_MASK (3 << 0)
+
+/* select exponential notation either in fixed or free format */
+#define JS_DTOA_EXP_AUTO (0 << 2)
+#define JS_DTOA_EXP_ENABLED (1 << 2)
+#define JS_DTOA_EXP_DISABLED (2 << 2)
+#define JS_DTOA_EXP_MASK (3 << 2)
+
+#define JS_DTOA_MINUS_ZERO (1 << 4) /* show the minus sign for -0 */
+
+/* only accepts integers (no dot, no exponent) */
+#define JS_ATOD_INT_ONLY (1 << 0)
+/* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */
+#define JS_ATOD_ACCEPT_BIN_OCT (1 << 1)
+/* accept O prefix as octal if radix == 0 and properly formed (Annex B) */
+#define JS_ATOD_ACCEPT_LEGACY_OCTAL (1 << 2)
+/* accept _ between digits as a digit separator */
+#define JS_ATOD_ACCEPT_UNDERSCORES (1 << 3)
+
+typedef struct {
+ uint64_t mem[37];
+} JSDTOATempMem;
+
+typedef struct {
+ uint64_t mem[27];
+} JSATODTempMem;
+
+/* return a maximum bound of the string length */
+int js_dtoa_max_len(double d, int radix, int n_digits, int flags);
+/* return the string length */
+int js_dtoa(char *buf, double d, int radix, int n_digits, int flags,
+ JSDTOATempMem *tmp_mem);
+double js_atod(const char *str, const char **pnext, int radix, int flags,
+ JSATODTempMem *tmp_mem);
+
+#ifdef JS_DTOA_DUMP_STATS
+void js_dtoa_dump_stats(void);
+#endif
+
+/* additional exported functions */
+size_t u32toa(char *buf, uint32_t n);
+size_t i32toa(char *buf, int32_t n);
+size_t u64toa(char *buf, uint64_t n);
+size_t i64toa(char *buf, int64_t n);
+size_t u64toa_radix(char *buf, uint64_t n, unsigned int radix);
+size_t i64toa_radix(char *buf, int64_t n, unsigned int radix);
diff --git a/quickjs/libbf.c b/quickjs/libbf.c
deleted file mode 100644
index 234b956b4d..0000000000
--- a/quickjs/libbf.c
+++ /dev/null
@@ -1,8473 +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
-#include
-#include
-#include
-#include
-#include
-
-#ifdef __AVX2__
-#include
-#endif
-
-#include "cutils.h"
-#include "libbf.h"
-
-/* enable it to check the multiplication result */
-//#define USE_MUL_CHECK
-#ifdef CONFIG_BIGNUM
-/* enable it to use FFT/NTT multiplication */
-#define USE_FFT_MUL
-/* enable decimal floating point support */
-#define USE_BF_DEC
-#endif
-
-//#define inline __attribute__((always_inline))
-
-#ifdef __AVX2__
-#define FFT_MUL_THRESHOLD 100 /* in limbs of the smallest factor */
-#else
-#define FFT_MUL_THRESHOLD 100 /* in limbs of the smallest factor */
-#endif
-
-/* 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 no_inline 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;
-}
-
-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;
-}
-
-#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)
-{
- memset(s, 0, 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);
- r->tab[0] = a0 << shift;
- r->tab[1] = shld(a1, a0, 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;
- 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 */
- memset(tabb_inv, 0, 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)) {
-#ifdef USE_FFT_MUL
- fail:
-#endif
- 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;
- memset(taba, 0, 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);
- memset(a1, 0, (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 no_inline 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;
-
-#ifdef USE_BF_DEC
- 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
-#endif
- {
- 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;
-}
-
-static inline int to_digit(int c)
-{
- if (c >= '0' && c <= '9')
- return c - '0';
- else if (c >= 'A' && c <= 'Z')
- return c - 'A' + 10;
- else if (c >= 'a' && c <= 'z')
- return c - 'a' + 10;
- else
- return 36;
-}
-
-/* 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) */
- memset(a->tab, 0, (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);
- memset(c, 0, 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 */
-
-#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;
- memset(taba, 0, 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);
- memset(a1, 0, (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__)
-
-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 no_inline 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 no_inline 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 = _mm256_load_pd(&buf[i]);
- a0 = ntt_mul_mod(a0, c, mf, m_inv);
- _mm256_store_pd(&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 no_inline 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 no_inline 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 no_inline 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 no_inline 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
- memset(tabr, 0, 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 no_inline 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 */
- memset(tabr, 0, 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 no_inline 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 */
- memset(tabr, 0, 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;
- memset(s, 0, 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] = _mm256_set1_pd(m);
- s->ntt_mods_inv_vec[j] = _mm256_set1_pd(1.0 / (double)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__)
- s->ntt_mods_cr_vec[l] = _mm256_set1_pd(int_to_ntt_limb2(ntt_mods_cr[l],
- ntt_mods[k]));
-#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 no_inline 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/quickjs/libbf.h b/quickjs/libbf.h
deleted file mode 100644
index 48e9d956a2..0000000000
--- a/quickjs/libbf.h
+++ /dev/null
@@ -1,535 +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.
- */
-#ifndef LIBBF_H
-#define LIBBF_H
-
-#include
-#include
-
-#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);
-
-#endif /* LIBBF_H */
diff --git a/quickjs/libregexp-opcode.h b/quickjs/libregexp-opcode.h
index f90c23b347..ebab751dfc 100644
--- a/quickjs/libregexp-opcode.h
+++ b/quickjs/libregexp-opcode.h
@@ -1,6 +1,6 @@
/*
* Regular Expression Engine
- *
+ *
* Copyright (c) 2017-2018 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -26,11 +26,15 @@
DEF(invalid, 1) /* never used */
DEF(char, 3)
+DEF(char_i, 3)
DEF(char32, 5)
+DEF(char32_i, 5)
DEF(dot, 1)
DEF(any, 1) /* same as dot but match any character including line terminator */
DEF(line_start, 1)
+DEF(line_start_m, 1)
DEF(line_end, 1)
+DEF(line_end_m, 1)
DEF(goto, 5)
DEF(split_goto_first, 5)
DEF(split_next_first, 5)
@@ -42,16 +46,21 @@ DEF(loop, 5) /* decrement the top the stack and goto if != 0 */
DEF(push_i32, 5) /* push integer on the stack */
DEF(drop, 1)
DEF(word_boundary, 1)
+DEF(word_boundary_i, 1)
DEF(not_word_boundary, 1)
+DEF(not_word_boundary_i, 1)
DEF(back_reference, 2)
-DEF(backward_back_reference, 2) /* must come after back_reference */
+DEF(back_reference_i, 2) /* must come after */
+DEF(backward_back_reference, 2) /* must come after */
+DEF(backward_back_reference_i, 2) /* must come after */
DEF(range, 3) /* variable length */
+DEF(range_i, 3) /* variable length */
DEF(range32, 3) /* variable length */
+DEF(range32_i, 3) /* variable length */
DEF(lookahead, 5)
DEF(negative_lookahead, 5)
DEF(push_char_pos, 1) /* push the character position on the stack */
-DEF(bne_char_pos, 5) /* pop one stack element and jump if equal to the character
- position */
+DEF(check_advance, 1) /* pop one stack element and check that it is different from the character position */
DEF(prev, 1) /* go to the previous char */
DEF(simple_greedy_quant, 17)
diff --git a/quickjs/libregexp.c b/quickjs/libregexp.c
index dab8fa1e2e..2b33c86953 100644
--- a/quickjs/libregexp.c
+++ b/quickjs/libregexp.c
@@ -1,6 +1,6 @@
/*
* Regular Expression Engine
- *
+ *
* Copyright (c) 2017-2018 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -30,13 +30,11 @@
#include "cutils.h"
#include "libregexp.h"
+#include "libunicode.h"
/*
TODO:
- - Add full unicode canonicalize rules for character ranges (not
- really useful but needed for exact "ignorecase" compatibility).
-
- Add a lock step execution mode (=linear time execution guaranteed)
when the regular expression is "simple" i.e. no backreference nor
complicated lookahead. The opcodes are designed for this execution
@@ -56,6 +54,9 @@ typedef enum {
#define CAPTURE_COUNT_MAX 255
#define STACK_SIZE_MAX 255
+/* must be large enough to have a negligible runtime cost and small
+ enough to call the interrupt callback often. */
+#define INTERRUPT_COUNTER_INIT 10000
/* unicode code points */
#define CP_LS 0x2028
@@ -69,8 +70,10 @@ typedef struct {
const uint8_t *buf_end;
const uint8_t *buf_start;
int re_flags;
- BOOL is_utf16;
+ BOOL is_unicode;
+ BOOL unicode_sets; /* if set, is_unicode is also set */
BOOL ignore_case;
+ BOOL multi_line;
BOOL dotall;
int capture_count;
int total_capture_count; /* -1 = not computed yet */
@@ -101,10 +104,11 @@ static const REOpCode reopcode_info[REOP_COUNT] = {
};
#define RE_HEADER_FLAGS 0
-#define RE_HEADER_CAPTURE_COUNT 1
-#define RE_HEADER_STACK_SIZE 2
+#define RE_HEADER_CAPTURE_COUNT 2
+#define RE_HEADER_STACK_SIZE 3
+#define RE_HEADER_BYTECODE_LEN 4
-#define RE_HEADER_LEN 7
+#define RE_HEADER_LEN 8
static inline int is_digit(int c) {
return c >= '0' && c <= '9';
@@ -120,31 +124,262 @@ static int dbuf_insert(DynBuf *s, int pos, int len)
return 0;
}
-/* canonicalize with the specific JS regexp rules */
-static uint32_t lre_canonicalize(uint32_t c, BOOL is_utf16)
+typedef struct REString {
+ struct REString *next;
+ uint32_t hash;
+ uint32_t len;
+ uint32_t buf[];
+} REString;
+
+typedef struct {
+ /* the string list is the union of 'char_range' and of the strings
+ in hash_table[]. The strings in hash_table[] have a length !=
+ 1. */
+ CharRange cr;
+ uint32_t n_strings;
+ uint32_t hash_size;
+ int hash_bits;
+ REString **hash_table;
+} REStringList;
+
+static uint32_t re_string_hash(int len, const uint32_t *buf)
{
- 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];
+ int i;
+ uint32_t h;
+ h = 1;
+ for(i = 0; i < len; i++)
+ h = h * 263 + buf[i];
+ return h * 0x61C88647;
+}
+
+static void re_string_list_init(REParseState *s1, REStringList *s)
+{
+ cr_init(&s->cr, s1->opaque, lre_realloc);
+ s->n_strings = 0;
+ s->hash_size = 0;
+ s->hash_bits = 0;
+ s->hash_table = NULL;
+}
+
+static void re_string_list_free(REStringList *s)
+{
+ REString *p, *p_next;
+ int i;
+ for(i = 0; i < s->hash_size; i++) {
+ for(p = s->hash_table[i]; p != NULL; p = p_next) {
+ p_next = p->next;
+ lre_realloc(s->cr.mem_opaque, p, 0);
}
+ }
+ lre_realloc(s->cr.mem_opaque, s->hash_table, 0);
+
+ cr_free(&s->cr);
+}
+
+static void lre_print_char(int c, BOOL is_range)
+{
+ if (c == '\'' || c == '\\' ||
+ (is_range && (c == '-' || c == ']'))) {
+ printf("\\%c", c);
+ } else if (c >= ' ' && c <= 126) {
+ printf("%c", c);
} else {
- 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];
+ printf("\\u{%04x}", c);
+ }
+}
+
+static __maybe_unused void re_string_list_dump(const char *str, const REStringList *s)
+{
+ REString *p;
+ const CharRange *cr;
+ int i, j, k;
+
+ printf("%s:\n", str);
+ printf(" ranges: [");
+ cr = &s->cr;
+ for(i = 0; i < cr->len; i += 2) {
+ lre_print_char(cr->points[i], TRUE);
+ if (cr->points[i] != cr->points[i + 1] - 1) {
+ printf("-");
+ lre_print_char(cr->points[i + 1] - 1, TRUE);
+ }
+ }
+ printf("]\n");
+
+ j = 0;
+ for(i = 0; i < s->hash_size; i++) {
+ for(p = s->hash_table[i]; p != NULL; p = p->next) {
+ printf(" %d/%d: '", j, s->n_strings);
+ for(k = 0; k < p->len; k++) {
+ lre_print_char(p->buf[k], FALSE);
+ }
+ printf("'\n");
+ j++;
}
}
- return c;
+}
+
+static int re_string_find2(REStringList *s, int len, const uint32_t *buf,
+ uint32_t h0, BOOL add_flag)
+{
+ uint32_t h = 0; /* avoid warning */
+ REString *p;
+ if (s->n_strings != 0) {
+ h = h0 >> (32 - s->hash_bits);
+ for(p = s->hash_table[h]; p != NULL; p = p->next) {
+ if (p->hash == h0 && p->len == len &&
+ !memcmp(p->buf, buf, len * sizeof(buf[0]))) {
+ return 1;
+ }
+ }
+ }
+ /* not found */
+ if (!add_flag)
+ return 0;
+ /* increase the size of the hash table if needed */
+ if (unlikely((s->n_strings + 1) > s->hash_size)) {
+ REString **new_hash_table, *p_next;
+ int new_hash_bits, i;
+ uint32_t new_hash_size;
+ new_hash_bits = max_int(s->hash_bits + 1, 4);
+ new_hash_size = 1 << new_hash_bits;
+ new_hash_table = lre_realloc(s->cr.mem_opaque, NULL,
+ sizeof(new_hash_table[0]) * new_hash_size);
+ if (!new_hash_table)
+ return -1;
+ memset(new_hash_table, 0, sizeof(new_hash_table[0]) * new_hash_size);
+ for(i = 0; i < s->hash_size; i++) {
+ for(p = s->hash_table[i]; p != NULL; p = p_next) {
+ p_next = p->next;
+ h = p->hash >> (32 - new_hash_bits);
+ p->next = new_hash_table[h];
+ new_hash_table[h] = p;
+ }
+ }
+ lre_realloc(s->cr.mem_opaque, s->hash_table, 0);
+ s->hash_bits = new_hash_bits;
+ s->hash_size = new_hash_size;
+ s->hash_table = new_hash_table;
+ h = h0 >> (32 - s->hash_bits);
+ }
+
+ p = lre_realloc(s->cr.mem_opaque, NULL, sizeof(REString) + len * sizeof(buf[0]));
+ if (!p)
+ return -1;
+ p->next = s->hash_table[h];
+ s->hash_table[h] = p;
+ s->n_strings++;
+ p->hash = h0;
+ p->len = len;
+ memcpy(p->buf, buf, sizeof(buf[0]) * len);
+ return 1;
+}
+
+static int re_string_find(REStringList *s, int len, const uint32_t *buf,
+ BOOL add_flag)
+{
+ uint32_t h0;
+ h0 = re_string_hash(len, buf);
+ return re_string_find2(s, len, buf, h0, add_flag);
+}
+
+/* return -1 if memory error, 0 if OK */
+static int re_string_add(REStringList *s, int len, const uint32_t *buf)
+{
+ if (len == 1) {
+ return cr_union_interval(&s->cr, buf[0], buf[0]);
+ }
+ if (re_string_find(s, len, buf, TRUE) < 0)
+ return -1;
+ return 0;
+}
+
+/* a = a op b */
+static int re_string_list_op(REStringList *a, REStringList *b, int op)
+{
+ int i, ret;
+ REString *p, **pp;
+
+ if (cr_op1(&a->cr, b->cr.points, b->cr.len, op))
+ return -1;
+
+ switch(op) {
+ case CR_OP_UNION:
+ if (b->n_strings != 0) {
+ for(i = 0; i < b->hash_size; i++) {
+ for(p = b->hash_table[i]; p != NULL; p = p->next) {
+ if (re_string_find2(a, p->len, p->buf, p->hash, TRUE) < 0)
+ return -1;
+ }
+ }
+ }
+ break;
+ case CR_OP_INTER:
+ case CR_OP_SUB:
+ for(i = 0; i < a->hash_size; i++) {
+ pp = &a->hash_table[i];
+ for(;;) {
+ p = *pp;
+ if (p == NULL)
+ break;
+ ret = re_string_find2(b, p->len, p->buf, p->hash, FALSE);
+ if (op == CR_OP_SUB)
+ ret = !ret;
+ if (!ret) {
+ /* remove it */
+ *pp = p->next;
+ a->n_strings--;
+ lre_realloc(a->cr.mem_opaque, p, 0);
+ } else {
+ /* keep it */
+ pp = &p->next;
+ }
+ }
+ }
+ break;
+ default:
+ abort();
+ }
+ return 0;
+}
+
+static int re_string_list_canonicalize(REParseState *s1,
+ REStringList *s, BOOL is_unicode)
+{
+ if (cr_regexp_canonicalize(&s->cr, is_unicode))
+ return -1;
+ if (s->n_strings != 0) {
+ REStringList a_s, *a = &a_s;
+ int i, j;
+ REString *p;
+
+ /* XXX: simplify */
+ re_string_list_init(s1, a);
+
+ a->n_strings = s->n_strings;
+ a->hash_size = s->hash_size;
+ a->hash_bits = s->hash_bits;
+ a->hash_table = s->hash_table;
+
+ s->n_strings = 0;
+ s->hash_size = 0;
+ s->hash_bits = 0;
+ s->hash_table = NULL;
+
+ for(i = 0; i < a->hash_size; i++) {
+ for(p = a->hash_table[i]; p != NULL; p = p->next) {
+ for(j = 0; j < p->len; j++) {
+ p->buf[j] = lre_canonicalize(p->buf[j], is_unicode);
+ }
+ if (re_string_add(s, p->len, p->buf)) {
+ re_string_list_free(a);
+ return -1;
+ }
+ }
+ }
+ re_string_list_free(a);
+ }
+ return 0;
}
static const uint16_t char_range_d[] = {
@@ -170,32 +405,6 @@ static const uint16_t char_range_s[] = {
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,
@@ -215,80 +424,55 @@ typedef enum {
CHAR_RANGE_W,
} CharRangeEnum;
-static const uint16_t *char_range_table[] = {
+static const uint16_t * const char_range_table[] = {
char_range_d,
char_range_s,
char_range_w,
};
-static int cr_init_char_range(REParseState *s, CharRange *cr, uint32_t c)
+static int cr_init_char_range(REParseState *s, REStringList *cr, uint32_t c)
{
BOOL invert;
const uint16_t *c_pt;
int len, i;
-
+
invert = c & 1;
c_pt = char_range_table[c >> 1];
len = *c_pt++;
- cr_init(cr, s->opaque, lre_realloc);
+ re_string_list_init(s, cr);
for(i = 0; i < len * 2; i++) {
- if (cr_add_point(cr, c_pt[i]))
+ if (cr_add_point(&cr->cr, c_pt[i]))
goto fail;
}
if (invert) {
- if (cr_invert(cr))
+ if (cr_invert(&cr->cr))
goto fail;
}
return 0;
fail:
- cr_free(cr);
+ re_string_list_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);
+ re_flags = lre_get_flags(buf);
+ bc_len = get_u32(buf + RE_HEADER_BYTECODE_LEN);
assert(bc_len + RE_HEADER_LEN <= buf_len);
printf("flags: 0x%x capture_count=%d stack_size=%d\n",
- re_flags, buf[1], buf[2]);
+ re_flags, buf[RE_HEADER_CAPTURE_COUNT], buf[RE_HEADER_STACK_SIZE]);
if (re_flags & LRE_FLAG_NAMED_GROUPS) {
const char *p;
p = (char *)buf + RE_HEADER_LEN + bc_len;
printf("named groups: ");
- for(i = 1; i < buf[1]; i++) {
+ for(i = 1; i < buf[RE_HEADER_CAPTURE_COUNT]; i++) {
if (i != 1)
printf(",");
printf("<%s>", p);
@@ -316,6 +500,7 @@ static __maybe_unused void lre_dump_bytecode(const uint8_t *buf,
printf("%s", reopcode_info[opcode].name);
switch(opcode) {
case REOP_char:
+ case REOP_char_i:
val = get_u16(buf + pos + 1);
if (val >= ' ' && val <= 126)
printf(" '%c'", val);
@@ -323,6 +508,7 @@ static __maybe_unused void lre_dump_bytecode(const uint8_t *buf,
printf(" 0x%04x", val);
break;
case REOP_char32:
+ case REOP_char32_i:
val = get_u32(buf + pos + 1);
if (val >= ' ' && val <= 126)
printf(" '%c'", val);
@@ -335,7 +521,6 @@ static __maybe_unused void lre_dump_bytecode(const uint8_t *buf,
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);
@@ -350,7 +535,9 @@ static __maybe_unused void lre_dump_bytecode(const uint8_t *buf,
case REOP_save_start:
case REOP_save_end:
case REOP_back_reference:
+ case REOP_back_reference_i:
case REOP_backward_back_reference:
+ case REOP_backward_back_reference_i:
printf(" %u", buf[pos + 1]);
break;
case REOP_save_reset:
@@ -361,6 +548,7 @@ static __maybe_unused void lre_dump_bytecode(const uint8_t *buf,
printf(" %d", val);
break;
case REOP_range:
+ case REOP_range_i:
{
int n, i;
n = get_u16(buf + pos + 1);
@@ -372,6 +560,7 @@ static __maybe_unused void lre_dump_bytecode(const uint8_t *buf,
}
break;
case REOP_range32:
+ case REOP_range32_i:
{
int n, i;
n = get_u16(buf + pos + 1);
@@ -448,7 +637,7 @@ 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(;;) {
@@ -520,7 +709,7 @@ int lre_parse_escape(const uint8_t **pp, int allow_utf16)
{
int h, n, i;
uint32_t c1;
-
+
if (*p == '{' && allow_utf16) {
p++;
c = 0;
@@ -550,7 +739,7 @@ int lre_parse_escape(const uint8_t **pp, int allow_utf16)
}
c = (c << 4) | h;
}
- if (c >= 0xd800 && c < 0xdc00 &&
+ if (is_hi_surrogate(c) &&
allow_utf16 == 2 && p[0] == '\\' && p[1] == 'u') {
/* convert an escaped surrogate pair into a
unicode char */
@@ -561,9 +750,9 @@ int lre_parse_escape(const uint8_t **pp, int allow_utf16)
break;
c1 = (c1 << 4) | h;
}
- if (i == 4 && c1 >= 0xdc00 && c1 < 0xe000) {
+ if (i == 4 && is_lo_surrogate(c1)) {
p += 6;
- c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
+ c = from_surrogate(c, c1);
}
}
}
@@ -610,8 +799,16 @@ static BOOL is_unicode_char(int c)
(c == '_'));
}
-static int parse_unicode_property(REParseState *s, CharRange *cr,
- const uint8_t **pp, BOOL is_inv)
+/* XXX: memory error test */
+static void seq_prop_cb(void *opaque, const uint32_t *seq, int seq_len)
+{
+ REStringList *sl = opaque;
+ re_string_add(sl, seq_len, seq);
+}
+
+static int parse_unicode_property(REParseState *s, REStringList *cr,
+ const uint8_t **pp, BOOL is_inv,
+ BOOL allow_sequence_prop)
{
const uint8_t *p;
char name[64], value[64];
@@ -651,51 +848,76 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
} 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);
+ re_string_list_init(s, cr);
+ ret = unicode_script(&cr->cr, value, script_ext);
if (ret) {
- cr_free(cr);
+ re_string_list_free(cr);
if (ret == -2)
return re_parse_error(s, "unknown unicode script");
else
goto out_of_memory;
}
} else if (!strcmp(name, "General_Category") || !strcmp(name, "gc")) {
- cr_init(cr, s->opaque, lre_realloc);
- ret = unicode_general_category(cr, value);
+ re_string_list_init(s, cr);
+ ret = unicode_general_category(&cr->cr, value);
if (ret) {
- cr_free(cr);
+ re_string_list_free(cr);
if (ret == -2)
return re_parse_error(s, "unknown unicode general category");
else
goto out_of_memory;
}
} else if (value[0] == '\0') {
- cr_init(cr, s->opaque, lre_realloc);
- ret = unicode_general_category(cr, name);
+ re_string_list_init(s, cr);
+ ret = unicode_general_category(&cr->cr, name);
if (ret == -1) {
- cr_free(cr);
+ re_string_list_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;
+ ret = unicode_prop(&cr->cr, name);
+ if (ret == -1) {
+ re_string_list_free(cr);
+ goto out_of_memory;
}
}
+ if (ret < 0 && !is_inv && allow_sequence_prop) {
+ CharRange cr_tmp;
+ cr_init(&cr_tmp, s->opaque, lre_realloc);
+ ret = unicode_sequence_prop(name, seq_prop_cb, cr, &cr_tmp);
+ cr_free(&cr_tmp);
+ if (ret == -1) {
+ re_string_list_free(cr);
+ goto out_of_memory;
+ }
+ }
+ if (ret < 0)
+ goto unknown_property_name;
} else {
unknown_property_name:
return re_parse_error(s, "unknown unicode property name");
}
+ /* the ordering of case folding and inversion differs with
+ unicode_sets. 'unicode_sets' ordering is more consistent */
+ /* XXX: the spec seems incorrect, we do it as the other engines
+ seem to do it. */
+ if (s->ignore_case && s->unicode_sets) {
+ if (re_string_list_canonicalize(s, cr, s->is_unicode)) {
+ re_string_list_free(cr);
+ goto out_of_memory;
+ }
+ }
if (is_inv) {
- if (cr_invert(cr)) {
- cr_free(cr);
- return -1;
+ if (cr_invert(&cr->cr)) {
+ re_string_list_free(cr);
+ goto out_of_memory;
+ }
+ }
+ if (s->ignore_case && !s->unicode_sets) {
+ if (re_string_list_canonicalize(s, cr, s->is_unicode)) {
+ re_string_list_free(cr);
+ goto out_of_memory;
}
}
*pp = p;
@@ -705,16 +927,67 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
}
#endif /* CONFIG_ALL_UNICODE */
+static int get_class_atom(REParseState *s, REStringList *cr,
+ const uint8_t **pp, BOOL inclass);
+
+static int parse_class_string_disjunction(REParseState *s, REStringList *cr,
+ const uint8_t **pp)
+{
+ const uint8_t *p;
+ DynBuf str;
+ int c;
+
+ p = *pp;
+ if (*p != '{')
+ return re_parse_error(s, "expecting '{' after \\q");
+
+ dbuf_init2(&str, s->opaque, lre_realloc);
+ re_string_list_init(s, cr);
+
+ p++;
+ for(;;) {
+ str.size = 0;
+ while (*p != '}' && *p != '|') {
+ c = get_class_atom(s, NULL, &p, FALSE);
+ if (c < 0)
+ goto fail;
+ if (dbuf_put_u32(&str, c)) {
+ re_parse_out_of_memory(s);
+ goto fail;
+ }
+ }
+ if (re_string_add(cr, str.size / 4, (uint32_t *)str.buf)) {
+ re_parse_out_of_memory(s);
+ goto fail;
+ }
+ if (*p == '}')
+ break;
+ p++;
+ }
+ if (s->ignore_case) {
+ if (re_string_list_canonicalize(s, cr, TRUE))
+ goto fail;
+ }
+ p++; /* skip the '}' */
+ dbuf_free(&str);
+ *pp = p;
+ return 0;
+ fail:
+ dbuf_free(&str);
+ re_string_list_free(cr);
+ return -1;
+}
+
/* return -1 if error otherwise the character or a class range
- (CLASS_RANGE_BASE). In case of class range, 'cr' is
+ (CLASS_RANGE_BASE) if cr != NULL. In case of class range, 'cr' is
initialized. Otherwise, it is ignored. */
-static int get_class_atom(REParseState *s, CharRange *cr,
+static int get_class_atom(REParseState *s, REStringList *cr,
const uint8_t **pp, BOOL inclass)
{
const uint8_t *p;
uint32_t c;
int ret;
-
+
p = *pp;
c = *p;
@@ -743,6 +1016,8 @@ static int get_class_atom(REParseState *s, CharRange *cr,
case 'W':
c = CHAR_RANGE_W;
class_range:
+ if (!cr)
+ goto default_escape;
if (cr_init_char_range(s, cr, c))
return -1;
c = CLASS_RANGE_BASE;
@@ -752,10 +1027,10 @@ static int get_class_atom(REParseState *s, CharRange *cr,
if ((c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(((c >= '0' && c <= '9') || c == '_') &&
- inclass && !s->is_utf16)) { /* Annex B.1.4 */
+ inclass && !s->is_unicode)) { /* Annex B.1.4 */
c &= 0x1f;
p++;
- } else if (s->is_utf16) {
+ } else if (s->is_unicode) {
goto invalid_escape;
} else {
/* otherwise return '\' and 'c' */
@@ -763,27 +1038,54 @@ static int get_class_atom(REParseState *s, CharRange *cr,
c = '\\';
}
break;
+ case '-':
+ if (!inclass && s->is_unicode)
+ goto invalid_escape;
+ break;
+ case '^':
+ case '$':
+ case '\\':
+ case '.':
+ case '*':
+ case '+':
+ case '?':
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case '|':
+ case '/':
+ /* always valid to escape these characters */
+ break;
#ifdef CONFIG_ALL_UNICODE
case 'p':
case 'P':
- if (s->is_utf16) {
- if (parse_unicode_property(s, cr, &p, (c == 'P')))
+ if (s->is_unicode && cr) {
+ if (parse_unicode_property(s, cr, &p, (c == 'P'), s->unicode_sets))
return -1;
c = CLASS_RANGE_BASE;
break;
}
- /* fall thru */
+ goto default_escape;
#endif
+ case 'q':
+ if (s->unicode_sets && cr && inclass) {
+ if (parse_class_string_disjunction(s, cr, &p))
+ return -1;
+ c = CLASS_RANGE_BASE;
+ break;
+ }
+ goto default_escape;
default:
+ default_escape:
p--;
- ret = lre_parse_escape(&p, s->is_utf16 * 2);
+ ret = lre_parse_escape(&p, s->is_unicode * 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) {
+ if (s->is_unicode) {
invalid_escape:
return re_parse_error(s, "invalid escape sequence in regular expression");
} else {
@@ -800,12 +1102,54 @@ static int get_class_atom(REParseState *s, CharRange *cr,
return re_parse_error(s, "unexpected end");
}
/* fall thru */
+ goto normal_char;
+
+ case '&':
+ case '!':
+ case '#':
+ case '$':
+ case '%':
+ case '*':
+ case '+':
+ case ',':
+ case '.':
+ case ':':
+ case ';':
+ case '<':
+ case '=':
+ case '>':
+ case '?':
+ case '@':
+ case '^':
+ case '`':
+ case '~':
+ if (s->unicode_sets && p[1] == c) {
+ /* forbidden double characters */
+ return re_parse_error(s, "invalid class set operation in regular expression");
+ }
+ goto normal_char;
+
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case '/':
+ case '-':
+ case '|':
+ if (s->unicode_sets) {
+ /* invalid characters in unicode sets */
+ return re_parse_error(s, "invalid character in class in regular expression");
+ }
+ goto normal_char;
+
default:
normal_char:
/* normal char */
if (c >= 128) {
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
- if ((unsigned)c > 0xffff && !s->is_utf16) {
+ if ((unsigned)c > 0xffff && !s->is_unicode) {
/* XXX: should handle non BMP-1 code points */
return re_parse_error(s, "malformed unicode char");
}
@@ -822,13 +1166,11 @@ 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];
@@ -837,7 +1179,7 @@ static int re_emit_range(REParseState *s, const CharRange *cr)
if (high <= 0xffff) {
/* can use 16 bit ranges with the conversion that 0xffff =
infinity */
- re_emit_op_u16(s, REOP_range, len);
+ re_emit_op_u16(s, s->ignore_case ? REOP_range_i : REOP_range, len);
for(i = 0; i < cr->len; i += 2) {
dbuf_put_u16(&s->byte_code, cr->points[i]);
high = cr->points[i + 1] - 1;
@@ -846,7 +1188,7 @@ static int re_emit_range(REParseState *s, const CharRange *cr)
dbuf_put_u16(&s->byte_code, high);
}
} else {
- re_emit_op_u16(s, REOP_range32, len);
+ re_emit_op_u16(s, s->ignore_case ? REOP_range32_i : REOP_range32, len);
for(i = 0; i < cr->len; i += 2) {
dbuf_put_u32(&s->byte_code, cr->points[i]);
dbuf_put_u32(&s->byte_code, cr->points[i + 1] - 1);
@@ -856,176 +1198,362 @@ static int re_emit_range(REParseState *s, const CharRange *cr)
return 0;
}
-static int re_parse_char_class(REParseState *s, const uint8_t **pp)
+static int re_string_cmp_len(const void *a, const void *b, void *arg)
+{
+ REString *p1 = *(REString **)a;
+ REString *p2 = *(REString **)b;
+ return (p1->len < p2->len) - (p1->len > p2->len);
+}
+
+static void re_emit_char(REParseState *s, int c)
+{
+ if (c <= 0xffff)
+ re_emit_op_u16(s, s->ignore_case ? REOP_char_i : REOP_char, c);
+ else
+ re_emit_op_u32(s, s->ignore_case ? REOP_char32_i : REOP_char32, c);
+}
+
+static int re_emit_string_list(REParseState *s, const REStringList *sl)
+{
+ REString **tab, *p;
+ int i, j, split_pos, last_match_pos, n;
+ BOOL has_empty_string, is_last;
+
+ // re_string_list_dump("sl", sl);
+ if (sl->n_strings == 0) {
+ /* simple case: only characters */
+ if (re_emit_range(s, &sl->cr))
+ return -1;
+ } else {
+ /* at least one string list is present : match the longest ones first */
+ /* XXX: add a new op_switch opcode to compile as a trie */
+ tab = lre_realloc(s->opaque, NULL, sizeof(tab[0]) * sl->n_strings);
+ if (!tab) {
+ re_parse_out_of_memory(s);
+ return -1;
+ }
+ has_empty_string = FALSE;
+ n = 0;
+ for(i = 0; i < sl->hash_size; i++) {
+ for(p = sl->hash_table[i]; p != NULL; p = p->next) {
+ if (p->len == 0) {
+ has_empty_string = TRUE;
+ } else {
+ tab[n++] = p;
+ }
+ }
+ }
+ assert(n <= sl->n_strings);
+
+ rqsort(tab, n, sizeof(tab[0]), re_string_cmp_len, NULL);
+
+ last_match_pos = -1;
+ for(i = 0; i < n; i++) {
+ p = tab[i];
+ is_last = !has_empty_string && sl->cr.len == 0 && i == (n - 1);
+ if (!is_last)
+ split_pos = re_emit_op_u32(s, REOP_split_next_first, 0);
+ else
+ split_pos = 0;
+ for(j = 0; j < p->len; j++) {
+ re_emit_char(s, p->buf[j]);
+ }
+ if (!is_last) {
+ last_match_pos = re_emit_op_u32(s, REOP_goto, last_match_pos);
+ put_u32(s->byte_code.buf + split_pos, s->byte_code.size - (split_pos + 4));
+ }
+ }
+
+ if (sl->cr.len != 0) {
+ /* char range */
+ is_last = !has_empty_string;
+ if (!is_last)
+ split_pos = re_emit_op_u32(s, REOP_split_next_first, 0);
+ else
+ split_pos = 0; /* not used */
+ if (re_emit_range(s, &sl->cr)) {
+ lre_realloc(s->opaque, tab, 0);
+ return -1;
+ }
+ if (!is_last)
+ put_u32(s->byte_code.buf + split_pos, s->byte_code.size - (split_pos + 4));
+ }
+
+ /* patch the 'goto match' */
+ while (last_match_pos != -1) {
+ int next_pos = get_u32(s->byte_code.buf + last_match_pos);
+ put_u32(s->byte_code.buf + last_match_pos, s->byte_code.size - (last_match_pos + 4));
+ last_match_pos = next_pos;
+ }
+
+ lre_realloc(s->opaque, tab, 0);
+ }
+ return 0;
+}
+
+static int re_parse_nested_class(REParseState *s, REStringList *cr, const uint8_t **pp);
+
+static int re_parse_class_set_operand(REParseState *s, REStringList *cr, const uint8_t **pp)
+{
+ int c1;
+ const uint8_t *p = *pp;
+
+ if (*p == '[') {
+ if (re_parse_nested_class(s, cr, pp))
+ return -1;
+ } else {
+ c1 = get_class_atom(s, cr, pp, TRUE);
+ if (c1 < 0)
+ return -1;
+ if (c1 < CLASS_RANGE_BASE) {
+ /* create a range with a single character */
+ re_string_list_init(s, cr);
+ if (s->ignore_case)
+ c1 = lre_canonicalize(c1, s->is_unicode);
+ if (cr_union_interval(&cr->cr, c1, c1)) {
+ re_string_list_free(cr);
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int re_parse_nested_class(REParseState *s, REStringList *cr, const uint8_t **pp)
{
const uint8_t *p;
uint32_t c1, c2;
- CharRange cr_s, *cr = &cr_s;
- CharRange cr1_s, *cr1 = &cr1_s;
- BOOL invert;
-
- cr_init(cr, s->opaque, lre_realloc);
+ int ret;
+ REStringList cr1_s, *cr1 = &cr1_s;
+ BOOL invert, is_first;
+
+ if (lre_check_stack_overflow(s->opaque, 0))
+ return re_parse_error(s, "stack overflow");
+
+ re_string_list_init(s, cr);
p = *pp;
p++; /* skip '[' */
+
invert = FALSE;
if (*p == '^') {
p++;
invert = TRUE;
}
+
+ /* handle unions */
+ is_first = TRUE;
for(;;) {
if (*p == ']')
break;
- 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)
+ if (*p == '[' && s->unicode_sets) {
+ if (re_parse_nested_class(s, cr1, &p))
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;
+ goto class_union;
} 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;
+ c1 = get_class_atom(s, cr1, &p, TRUE);
+ if ((int)c1 < 0)
+ goto fail;
+ if (*p == '-' && p[1] != ']') {
+ const uint8_t *p0 = p + 1;
+ if (p[1] == '-' && s->unicode_sets && is_first)
+ goto class_atom; /* first character class followed by '--' */
+ if (c1 >= CLASS_RANGE_BASE) {
+ if (s->is_unicode) {
+ re_string_list_free(cr1);
+ goto invalid_class_range;
+ }
+ /* Annex B: match '-' character */
+ goto class_atom;
+ }
+ c2 = get_class_atom(s, cr1, &p0, TRUE);
+ if ((int)c2 < 0)
+ goto fail;
+ if (c2 >= CLASS_RANGE_BASE) {
+ re_string_list_free(cr1);
+ if (s->is_unicode) {
+ goto invalid_class_range;
+ }
+ /* Annex B: match '-' character */
+ goto class_atom;
+ }
+ p = p0;
+ if (c2 < c1) {
+ invalid_class_range:
+ re_parse_error(s, "invalid class range");
+ goto fail;
+ }
+ if (s->ignore_case) {
+ CharRange cr2_s, *cr2 = &cr2_s;
+ cr_init(cr2, s->opaque, lre_realloc);
+ if (cr_add_interval(cr2, c1, c2 + 1) ||
+ cr_regexp_canonicalize(cr2, s->is_unicode) ||
+ cr_op1(&cr->cr, cr2->points, cr2->len, CR_OP_UNION)) {
+ cr_free(cr2);
+ goto memory_error;
+ }
+ cr_free(cr2);
+ } else {
+ if (cr_union_interval(&cr->cr, c1, c2))
+ goto memory_error;
+ }
+ is_first = FALSE; /* union operation */
} else {
- if (cr_union_interval(cr, c1, c1))
- goto memory_error;
+ class_atom:
+ if (c1 >= CLASS_RANGE_BASE) {
+ class_union:
+ ret = re_string_list_op(cr, cr1, CR_OP_UNION);
+ re_string_list_free(cr1);
+ if (ret)
+ goto memory_error;
+ } else {
+ if (s->ignore_case)
+ c1 = lre_canonicalize(c1, s->is_unicode);
+ if (cr_union_interval(&cr->cr, c1, c1))
+ goto memory_error;
+ }
}
}
+ if (s->unicode_sets && is_first) {
+ if (*p == '&' && p[1] == '&' && p[2] != '&') {
+ /* handle '&&' */
+ for(;;) {
+ if (*p == ']') {
+ break;
+ } else if (*p == '&' && p[1] == '&' && p[2] != '&') {
+ p += 2;
+ } else {
+ goto invalid_operation;
+ }
+ if (re_parse_class_set_operand(s, cr1, &p))
+ goto fail;
+ ret = re_string_list_op(cr, cr1, CR_OP_INTER);
+ re_string_list_free(cr1);
+ if (ret)
+ goto memory_error;
+ }
+ } else if (*p == '-' && p[1] == '-') {
+ /* handle '--' */
+ for(;;) {
+ if (*p == ']') {
+ break;
+ } else if (*p == '-' && p[1] == '-') {
+ p += 2;
+ } else {
+ invalid_operation:
+ re_parse_error(s, "invalid operation in regular expression");
+ goto fail;
+ }
+ if (re_parse_class_set_operand(s, cr1, &p))
+ goto fail;
+ ret = re_string_list_op(cr, cr1, CR_OP_SUB);
+ re_string_list_free(cr1);
+ if (ret)
+ goto memory_error;
+ }
+ }
+ }
+ is_first = FALSE;
}
- if (s->ignore_case) {
- if (cr_canonicalize(cr))
- goto memory_error;
- }
+
+ p++; /* skip ']' */
+ *pp = p;
if (invert) {
- if (cr_invert(cr))
+ /* XXX: add may_contain_string syntax check to be fully
+ compliant. The test here accepts more input than the
+ spec. */
+ if (cr->n_strings != 0) {
+ re_parse_error(s, "negated character class with strings in regular expression debugger eval code");
+ goto fail;
+ }
+ if (cr_invert(&cr->cr))
goto memory_error;
}
- 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);
+ re_string_list_free(cr);
+ return -1;
+}
+
+static int re_parse_char_class(REParseState *s, const uint8_t **pp)
+{
+ REStringList cr_s, *cr = &cr_s;
+
+ if (re_parse_nested_class(s, cr, pp))
+ return -1;
+ if (re_emit_string_list(s, cr))
+ goto fail;
+ re_string_list_free(cr);
+ return 0;
+ fail:
+ re_string_list_free(cr);
return -1;
}
/* Return:
- 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)
+ - true if the opcodes may not advance the char pointer
+ - false if the opcodes always advance the char pointer
*/
-static int re_check_advance(const uint8_t *bc_buf, int bc_buf_len)
+static BOOL re_need_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 */
+ int pos, opcode, len;
+ uint32_t val;
+ BOOL ret;
+
+ ret = TRUE;
pos = 0;
- has_back_reference = FALSE;
- memset(capture_bitmap, 0, sizeof(capture_bitmap));
-
while (pos < bc_buf_len) {
opcode = bc_buf[pos];
len = reopcode_info[opcode].size;
switch(opcode) {
case REOP_range:
+ case REOP_range_i:
val = get_u16(bc_buf + pos + 1);
len += val * 4;
goto simple_char;
case REOP_range32:
+ case REOP_range32_i:
val = get_u16(bc_buf + pos + 1);
len += val * 8;
goto simple_char;
case REOP_char:
+ case REOP_char_i:
case REOP_char32:
+ case REOP_char32_i:
case REOP_dot:
case REOP_any:
simple_char:
- if (ret == -2)
- ret = 1;
+ ret = FALSE;
break;
case REOP_line_start:
+ case REOP_line_start_m:
case REOP_line_end:
+ case REOP_line_end_m:
case REOP_push_i32:
case REOP_push_char_pos:
case REOP_drop:
case REOP_word_boundary:
+ case REOP_word_boundary_i:
case REOP_not_word_boundary:
+ case REOP_not_word_boundary_i:
case REOP_prev:
/* no effect */
break;
case REOP_save_start:
case REOP_save_end:
- 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_back_reference_i:
case REOP_backward_back_reference:
- val = bc_buf[pos + 1];
- capture_bitmap[val] |= 2;
- has_back_reference = TRUE;
+ case REOP_backward_back_reference_i:
break;
default:
- /* safe behvior: we cannot predict the outcome */
- if (ret == -2)
- ret = 0;
- break;
+ /* safe behavior: we cannot predict the outcome */
+ return TRUE;
}
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;
}
@@ -1035,7 +1563,7 @@ 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) {
@@ -1043,24 +1571,32 @@ static int re_is_simple_quantifier(const uint8_t *bc_buf, int bc_buf_len)
len = reopcode_info[opcode].size;
switch(opcode) {
case REOP_range:
+ case REOP_range_i:
val = get_u16(bc_buf + pos + 1);
len += val * 4;
goto simple_char;
case REOP_range32:
+ case REOP_range32_i:
val = get_u16(bc_buf + pos + 1);
len += val * 8;
goto simple_char;
case REOP_char:
+ case REOP_char_i:
case REOP_char32:
+ case REOP_char32_i:
case REOP_dot:
case REOP_any:
simple_char:
count++;
break;
case REOP_line_start:
+ case REOP_line_start_m:
case REOP_line_end:
+ case REOP_line_end_m:
case REOP_word_boundary:
+ case REOP_word_boundary_i:
case REOP_not_word_boundary:
+ case REOP_not_word_boundary_i:
break;
default:
return -1;
@@ -1090,10 +1626,10 @@ static int re_parse_group_name(char *buf, int buf_size, const uint8_t **pp)
break;
} else if (c >= 128) {
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
- if (c >= 0xD800 && c <= 0xDBFF) {
+ if (is_hi_surrogate(c)) {
d = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
- if (d >= 0xDC00 && d <= 0xDFFF) {
- c = 0x10000 + 0x400 * (c - 0xD800) + (d - 0xDC00);
+ if (is_lo_surrogate(d)) {
+ c = from_surrogate(c, d);
p = p1;
}
}
@@ -1200,10 +1736,11 @@ 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;
+ if (!p) return -1;
buf_end = (char *)s->group_names.buf + s->group_names.size;
+ name_len = strlen(name);
capture_index = 1;
while (p < buf_end) {
len = strlen(p);
@@ -1217,13 +1754,48 @@ static int find_group_name(REParseState *s, const char *name)
static int re_parse_disjunction(REParseState *s, BOOL is_backward_dir);
+static int re_parse_modifiers(REParseState *s, const uint8_t **pp)
+{
+ const uint8_t *p = *pp;
+ int mask = 0;
+ int val;
+
+ for(;;) {
+ if (*p == 'i') {
+ val = LRE_FLAG_IGNORECASE;
+ } else if (*p == 'm') {
+ val = LRE_FLAG_MULTILINE;
+ } else if (*p == 's') {
+ val = LRE_FLAG_DOTALL;
+ } else {
+ break;
+ }
+ if (mask & val)
+ return re_parse_error(s, "duplicate modifier: '%c'", *p);
+ mask |= val;
+ p++;
+ }
+ *pp = p;
+ return mask;
+}
+
+static BOOL update_modifier(BOOL val, int add_mask, int remove_mask,
+ int mask)
+{
+ if (add_mask & mask)
+ val = TRUE;
+ if (remove_mask & mask)
+ val = FALSE;
+ return val;
+}
+
static int re_parse_term(REParseState *s, BOOL is_backward_dir)
{
const uint8_t *p;
int c, last_atom_start, quant_min, quant_max, last_capture_count;
BOOL greedy, add_zero_advance_check, is_neg, is_backward_lookahead;
- CharRange cr_s, *cr = &cr_s;
-
+ REStringList cr_s, *cr = &cr_s;
+
last_atom_start = -1;
last_capture_count = 0;
p = s->buf_ptr;
@@ -1231,11 +1803,11 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
switch(c) {
case '^':
p++;
- re_emit_op(s, REOP_line_start);
+ re_emit_op(s, s->multi_line ? REOP_line_start_m : REOP_line_start);
break;
case '$':
p++;
- re_emit_op(s, REOP_line_end);
+ re_emit_op(s, s->multi_line ? REOP_line_end_m : REOP_line_end);
break;
case '.':
p++;
@@ -1248,7 +1820,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
re_emit_op(s, REOP_prev);
break;
case '{':
- if (s->is_utf16) {
+ if (s->is_unicode) {
return re_parse_error(s, "syntax error");
} else if (!is_digit(p[1])) {
/* Annex B: we accept '{' not followed by digits as a
@@ -1285,6 +1857,44 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
p = s->buf_ptr;
if (re_parse_expect(s, &p, ')'))
return -1;
+ } else if (p[2] == 'i' || p[2] == 'm' || p[2] == 's' || p[2] == '-') {
+ BOOL saved_ignore_case, saved_multi_line, saved_dotall;
+ int add_mask, remove_mask;
+ p += 2;
+ remove_mask = 0;
+ add_mask = re_parse_modifiers(s, &p);
+ if (add_mask < 0)
+ return -1;
+ if (*p == '-') {
+ p++;
+ remove_mask = re_parse_modifiers(s, &p);
+ if (remove_mask < 0)
+ return -1;
+ }
+ if ((add_mask == 0 && remove_mask == 0) ||
+ (add_mask & remove_mask) != 0) {
+ return re_parse_error(s, "invalid modifiers");
+ }
+ if (re_parse_expect(s, &p, ':'))
+ return -1;
+ saved_ignore_case = s->ignore_case;
+ saved_multi_line = s->multi_line;
+ saved_dotall = s->dotall;
+ s->ignore_case = update_modifier(s->ignore_case, add_mask, remove_mask, LRE_FLAG_IGNORECASE);
+ s->multi_line = update_modifier(s->multi_line, add_mask, remove_mask, LRE_FLAG_MULTILINE);
+ s->dotall = update_modifier(s->dotall, add_mask, remove_mask, LRE_FLAG_DOTALL);
+
+ last_atom_start = s->byte_code.size;
+ last_capture_count = s->capture_count;
+ s->buf_ptr = p;
+ if (re_parse_disjunction(s, is_backward_dir))
+ return -1;
+ p = s->buf_ptr;
+ if (re_parse_expect(s, &p, ')'))
+ return -1;
+ s->ignore_case = saved_ignore_case;
+ s->multi_line = saved_multi_line;
+ s->dotall = saved_dotall;
} else if ((p[2] == '=' || p[2] == '!')) {
is_neg = (p[2] == '!');
is_backward_lookahead = FALSE;
@@ -1300,7 +1910,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
lookahead:
/* Annex B allows lookahead to be used as an atom for
the quantifiers */
- if (!s->is_utf16 && !is_backward_lookahead) {
+ if (!s->is_unicode && !is_backward_lookahead) {
last_atom_start = s->byte_code.size;
last_capture_count = s->capture_count;
}
@@ -1346,15 +1956,15 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
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;
}
@@ -1363,20 +1973,24 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
switch(p[1]) {
case 'b':
case 'B':
- re_emit_op(s, REOP_word_boundary + (p[1] != 'b'));
+ if (p[1] != 'b') {
+ re_emit_op(s, s->ignore_case ? REOP_not_word_boundary_i : REOP_not_word_boundary);
+ } else {
+ re_emit_op(s, s->ignore_case ? REOP_word_boundary_i : REOP_word_boundary);
+ }
p += 2;
break;
case 'k':
{
const uint8_t *p1;
int dummy_res;
-
+
p1 = p;
if (p1[2] != '<') {
/* annex B: we tolerate invalid group names in non
unicode mode if there is no named capture
definition */
- if (s->is_utf16 || re_has_named_captures(s))
+ if (s->is_unicode || re_has_named_captures(s))
return re_parse_error(s, "expecting group name");
else
goto parse_class_atom;
@@ -1384,7 +1998,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
p1 += 3;
if (re_parse_group_name(s->u.tmp_buf, sizeof(s->u.tmp_buf),
&p1)) {
- if (s->is_utf16 || re_has_named_captures(s))
+ if (s->is_unicode || re_has_named_captures(s))
return re_parse_error(s, "invalid group name");
else
goto parse_class_atom;
@@ -1395,7 +2009,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
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))
+ if (s->is_unicode || re_has_named_captures(s))
return re_parse_error(s, "group name not defined");
else
goto parse_class_atom;
@@ -1407,7 +2021,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
case '0':
p += 2;
c = 0;
- if (s->is_utf16) {
+ if (s->is_unicode) {
if (is_digit(*p)) {
return re_parse_error(s, "invalid decimal escape in regular expression");
}
@@ -1423,13 +2037,13 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
goto normal_char;
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8':
- case '9':
+ 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) {
+ if (!s->is_unicode) {
/* Annex B.1.4: accept legacy octal */
p = q;
if (*p <= '7') {
@@ -1452,7 +2066,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
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);
+
+ re_emit_op_u8(s, REOP_back_reference + 2 * is_backward_dir + s->ignore_case, c);
}
break;
default:
@@ -1471,7 +2086,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
break;
case ']':
case '}':
- if (s->is_utf16)
+ if (s->is_unicode)
return re_parse_error(s, "syntax error");
goto parse_class_atom;
default:
@@ -1486,18 +2101,14 @@ static int re_parse_term(REParseState *s, BOOL 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);
+ ret = re_emit_string_list(s, cr);
+ re_string_list_free(cr);
if (ret)
return -1;
} else {
if (s->ignore_case)
- c = lre_canonicalize(c, s->is_utf16);
- if (c <= 0xffff)
- re_emit_op_u16(s, REOP_char, c);
- else
- re_emit_op_u32(s, REOP_char32, c);
+ c = lre_canonicalize(c, s->is_unicode);
+ re_emit_char(s, c);
}
if (is_backward_dir)
re_emit_op(s, REOP_prev);
@@ -1529,7 +2140,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
/* 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)
+ if (s->is_unicode)
goto invalid_quant_count;
break;
}
@@ -1548,7 +2159,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
quant_max = INT32_MAX; /* infinity */
}
}
- if (*p != '}' && !s->is_utf16) {
+ if (*p != '}' && !s->is_unicode) {
/* Annex B: normal atom if invalid '{' syntax */
p = p1;
break;
@@ -1567,7 +2178,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
}
if (greedy) {
int len, pos;
-
+
if (quant_max > 0) {
/* specific optimization for simple quantifiers */
if (dbuf_error(&s->byte_code))
@@ -1576,7 +2187,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
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;
@@ -1593,15 +2204,17 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
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;
}
-
+ /* the spec tells that if there is no advance when
+ running the atom after the first quant_min times,
+ then there is no match. We remove this test when we
+ are sure the atom always advances the position. */
+ add_zero_advance_check = re_need_check_advance(s->byte_code.buf + last_atom_start,
+ s->byte_code.size - last_atom_start);
+
{
int len, pos;
len = s->byte_code.size - last_atom_start;
@@ -1617,38 +2230,34 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
}
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) {
+ } else if (quant_max == 1 || quant_max == INT32_MAX) {
+ BOOL has_goto = (quant_max == INT32_MAX);
if (dbuf_insert(&s->byte_code, last_atom_start, 5 + add_zero_advance_check))
goto out_of_memory;
s->byte_code.buf[last_atom_start] = REOP_split_goto_first +
greedy;
put_u32(s->byte_code.buf + last_atom_start + 1,
- len + 5 + add_zero_advance_check);
+ len + 5 * has_goto + add_zero_advance_check * 2);
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);
+ re_emit_op(s, REOP_check_advance);
}
+ if (has_goto)
+ re_emit_goto(s, REOP_goto, last_atom_start);
} else {
- if (dbuf_insert(&s->byte_code, last_atom_start, 10))
+ if (dbuf_insert(&s->byte_code, last_atom_start, 10 + add_zero_advance_check))
goto out_of_memory;
pos = last_atom_start;
s->byte_code.buf[pos++] = REOP_push_i32;
put_u32(s->byte_code.buf + pos, quant_max);
pos += 4;
s->byte_code.buf[pos++] = REOP_split_goto_first + greedy;
- put_u32(s->byte_code.buf + pos, len + 5);
+ put_u32(s->byte_code.buf + pos, len + 5 + add_zero_advance_check * 2);
+ pos += 4;
+ if (add_zero_advance_check) {
+ s->byte_code.buf[pos++] = REOP_push_char_pos;
+ re_emit_op(s, REOP_check_advance);
+ }
re_emit_goto(s, REOP_loop, last_atom_start + 5);
re_emit_op(s, REOP_drop);
}
@@ -1672,22 +2281,25 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
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);
+ len + 5 + add_zero_advance_check * 2);
if (add_zero_advance_check)
re_emit_op(s, REOP_push_char_pos);
/* copy the atom */
dbuf_put_self(&s->byte_code, last_atom_start, len);
if (add_zero_advance_check)
- re_emit_goto(s, REOP_bne_char_pos, pos);
- else
- re_emit_goto(s, REOP_goto, pos);
+ re_emit_op(s, REOP_check_advance);
+ re_emit_goto(s, REOP_goto, pos);
} else if (quant_max > quant_min) {
re_emit_op_u32(s, REOP_push_i32, quant_max - quant_min);
pos = s->byte_code.size;
- re_emit_op_u32(s, REOP_split_goto_first + greedy, len + 5);
+ re_emit_op_u32(s, REOP_split_goto_first + greedy,
+ len + 5 + add_zero_advance_check * 2);
+ if (add_zero_advance_check)
+ re_emit_op(s, REOP_push_char_pos);
/* copy the atom */
dbuf_put_self(&s->byte_code, last_atom_start, len);
-
+ if (add_zero_advance_check)
+ re_emit_op(s, REOP_check_advance);
re_emit_goto(s, REOP_loop, pos);
re_emit_op(s, REOP_drop);
}
@@ -1739,14 +2351,14 @@ static int re_parse_alternative(REParseState *s, BOOL is_backward_dir)
}
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;
@@ -1766,7 +2378,7 @@ static int re_parse_disjunction(REParseState *s, BOOL is_backward_dir)
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);
@@ -1779,7 +2391,7 @@ 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;
@@ -1801,15 +2413,17 @@ static int compute_stack_size(const uint8_t *bc_buf, int bc_buf_len)
}
break;
case REOP_drop:
- case REOP_bne_char_pos:
+ case REOP_check_advance:
assert(stack_size > 0);
stack_size--;
break;
case REOP_range:
+ case REOP_range_i:
val = get_u16(bc_buf + pos + 1);
len += val * 4;
break;
case REOP_range32:
+ case REOP_range32_i:
val = get_u16(bc_buf + pos + 1);
len += val * 8;
break;
@@ -1830,29 +2444,31 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
REParseState s_s, *s = &s_s;
int stack_size;
BOOL is_sticky;
-
+
memset(s, 0, sizeof(*s));
s->opaque = opaque;
s->buf_ptr = (const uint8_t *)buf;
s->buf_end = s->buf_ptr + buf_len;
s->buf_start = s->buf_ptr;
s->re_flags = re_flags;
- s->is_utf16 = ((re_flags & LRE_FLAG_UTF16) != 0);
+ s->is_unicode = ((re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0);
is_sticky = ((re_flags & LRE_FLAG_STICKY) != 0);
s->ignore_case = ((re_flags & LRE_FLAG_IGNORECASE) != 0);
+ s->multi_line = ((re_flags & LRE_FLAG_MULTILINE) != 0);
s->dotall = ((re_flags & LRE_FLAG_DOTALL) != 0);
+ s->unicode_sets = ((re_flags & LRE_FLAG_UNICODE_SETS) != 0);
s->capture_count = 1;
s->total_capture_count = -1;
s->has_named_captures = -1;
-
+
dbuf_init2(&s->byte_code, opaque, lre_realloc);
dbuf_init2(&s->group_names, opaque, lre_realloc);
- dbuf_putc(&s->byte_code, re_flags); /* first element is the flags */
+ dbuf_put_u16(&s->byte_code, re_flags); /* first element is the flags */
dbuf_putc(&s->byte_code, 0); /* second element is the number of captures */
dbuf_putc(&s->byte_code, 0); /* stack size */
dbuf_put_u32(&s->byte_code, 0); /* bytecode length */
-
+
if (!is_sticky) {
/* iterate thru all positions (about the same as .*?( ... ) )
. We do it without an explicit loop so that lock step
@@ -1874,7 +2490,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
}
re_emit_op_u8(s, REOP_save_end, 0);
-
+
re_emit_op(s, REOP_match);
if (*s->buf_ptr != '\0') {
@@ -1886,28 +2502,30 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
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);
+ put_u32(s->byte_code.buf + RE_HEADER_BYTECODE_LEN,
+ s->byte_code.size - RE_HEADER_LEN);
/* add the named groups if needed */
if (s->group_names.size > (s->capture_count - 1)) {
dbuf_put(&s->byte_code, s->group_names.buf, s->group_names.size);
- s->byte_code.buf[RE_HEADER_FLAGS] |= LRE_FLAG_NAMED_GROUPS;
+ put_u16(s->byte_code.buf + RE_HEADER_FLAGS,
+ lre_get_flags(s->byte_code.buf) | LRE_FLAG_NAMED_GROUPS);
}
dbuf_free(&s->group_names);
-
+
#ifdef DUMP_REOP
lre_dump_bytecode(s->byte_code.buf, s->byte_code.size);
#endif
-
+
error_msg[0] = '\0';
*plen = s->byte_code.size;
return s->byte_code.buf;
@@ -1926,93 +2544,86 @@ static BOOL is_word_char(uint32_t c)
(c == '_'));
}
-#define GET_CHAR(c, cptr, cbuf_end) \
+#define GET_CHAR(c, cptr, cbuf_end, cbuf_type) \
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; \
+ const uint16_t *_p = (const uint16_t *)cptr; \
+ const uint16_t *_end = (const uint16_t *)cbuf_end; \
+ c = *_p++; \
+ if (is_hi_surrogate(c) && cbuf_type == 2) { \
+ if (_p < _end && is_lo_surrogate(*_p)) { \
+ c = from_surrogate(c, *_p++); \
} \
} \
+ cptr = (const void *)_p; \
} \
} while (0)
-#define PEEK_CHAR(c, cptr, cbuf_end) \
- 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; \
+#define PEEK_CHAR(c, cptr, cbuf_end, cbuf_type) \
+ do { \
+ if (cbuf_type == 0) { \
+ c = cptr[0]; \
+ } else { \
+ const uint16_t *_p = (const uint16_t *)cptr; \
+ const uint16_t *_end = (const uint16_t *)cbuf_end; \
+ c = *_p++; \
+ if (is_hi_surrogate(c) && cbuf_type == 2) { \
+ if (_p < _end && is_lo_surrogate(*_p)) { \
+ c = from_surrogate(c, *_p); \
} \
} \
- } \
+ } \
} while (0)
-#define PEEK_PREV_CHAR(c, cptr, cbuf_start) \
- 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; \
+#define PEEK_PREV_CHAR(c, cptr, cbuf_start, cbuf_type) \
+ do { \
+ if (cbuf_type == 0) { \
+ c = cptr[-1]; \
+ } else { \
+ const uint16_t *_p = (const uint16_t *)cptr - 1; \
+ const uint16_t *_start = (const uint16_t *)cbuf_start; \
+ c = *_p; \
+ if (is_lo_surrogate(c) && cbuf_type == 2) { \
+ if (_p > _start && is_hi_surrogate(_p[-1])) { \
+ c = from_surrogate(*--_p, c); \
} \
} \
} \
} while (0)
-#define GET_PREV_CHAR(c, cptr, cbuf_start) \
- 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; \
+#define GET_PREV_CHAR(c, cptr, cbuf_start, cbuf_type) \
+ do { \
+ if (cbuf_type == 0) { \
+ cptr--; \
+ c = cptr[0]; \
+ } else { \
+ const uint16_t *_p = (const uint16_t *)cptr - 1; \
+ const uint16_t *_start = (const uint16_t *)cbuf_start; \
+ c = *_p; \
+ if (is_lo_surrogate(c) && cbuf_type == 2) { \
+ if (_p > _start && is_hi_surrogate(_p[-1])) { \
+ c = from_surrogate(*--_p, c); \
} \
} \
+ cptr = (const void *)_p; \
} \
} while (0)
-#define PREV_CHAR(cptr, cbuf_start) \
- 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; \
+#define PREV_CHAR(cptr, cbuf_start, cbuf_type) \
+ do { \
+ if (cbuf_type == 0) { \
+ cptr--; \
+ } else { \
+ const uint16_t *_p = (const uint16_t *)cptr - 1; \
+ const uint16_t *_start = (const uint16_t *)cbuf_start; \
+ if (is_lo_surrogate(*_p) && cbuf_type == 2) { \
+ if (_p > _start && is_hi_surrogate(_p[-1])) { \
+ --_p; \
} \
} \
+ cptr = (const void *)_p; \
} \
} while (0)
@@ -2038,12 +2649,11 @@ 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 cbuf_type;
int capture_count;
int stack_size_max;
- BOOL multi_line;
- BOOL ignore_case;
- BOOL is_utf16;
+ BOOL is_unicode;
+ int interrupt_counter;
void *opaque; /* used for stack overflow check */
size_t state_size;
@@ -2090,7 +2700,17 @@ static int push_state(REExecContext *s,
return 0;
}
-/* return 1 if match, 0 if not match or -1 if error. */
+static int lre_poll_timeout(REExecContext *s)
+{
+ if (unlikely(--s->interrupt_counter <= 0)) {
+ s->interrupt_counter = INTERRUPT_COUNTER_INIT;
+ if (lre_check_timeout(s->opaque))
+ return LRE_RET_TIMEOUT;
+ }
+ return 0;
+}
+
+/* return 1 if match, 0 if not match or < 0 if error. */
static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
StackInt *stack, int stack_len,
const uint8_t *pc, const uint8_t *cptr,
@@ -2100,7 +2720,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
int cbuf_type;
uint32_t val, c;
const uint8_t *cbuf_end;
-
+
cbuf_type = s->cbuf_type;
cbuf_end = s->cbuf_end;
@@ -2121,6 +2741,8 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
ret = 0;
recurse:
for(;;) {
+ if (lre_poll_timeout(s))
+ return LRE_RET_TIMEOUT;
if (s->state_stack_len == 0)
return ret;
rs = (REExecState *)(s->state_stack +
@@ -2152,7 +2774,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
/* go backward */
char_count = get_u32(pc + 12);
for(i = 0; i < char_count; i++) {
- PREV_CHAR(cptr, s->cbuf);
+ PREV_CHAR(cptr, s->cbuf, cbuf_type);
}
pc = (pc + 16) + (int)get_u32(pc);
rs->cptr = cptr;
@@ -2178,18 +2800,20 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
}
break;
case REOP_char32:
+ case REOP_char32_i:
val = get_u32(pc);
pc += 4;
goto test_char;
case REOP_char:
+ case REOP_char_i:
val = get_u16(pc);
pc += 2;
test_char:
if (cptr >= cbuf_end)
goto no_match;
- GET_CHAR(c, cptr, cbuf_end);
- if (s->ignore_case) {
- c = lre_canonicalize(c, s->is_utf16);
+ GET_CHAR(c, cptr, cbuf_end, cbuf_type);
+ if (opcode == REOP_char_i || opcode == REOP_char32_i) {
+ c = lre_canonicalize(c, s->is_unicode);
}
if (val != c)
goto no_match;
@@ -2198,7 +2822,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
case REOP_split_next_first:
{
const uint8_t *pc1;
-
+
val = get_u32(pc);
pc += 4;
if (opcode == REOP_split_next_first) {
@@ -2210,7 +2834,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
ret = push_state(s, capture, stack, stack_len,
pc1, cptr, RE_EXEC_STATE_SPLIT, 0);
if (ret < 0)
- return -1;
+ return LRE_RET_MEMORY_ERROR;
break;
}
case REOP_lookahead:
@@ -2222,42 +2846,46 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
RE_EXEC_STATE_LOOKAHEAD + opcode - REOP_lookahead,
0);
if (ret < 0)
- return -1;
+ return LRE_RET_MEMORY_ERROR;
break;
-
+
case REOP_goto:
val = get_u32(pc);
pc += 4 + (int)val;
+ if (lre_poll_timeout(s))
+ return LRE_RET_TIMEOUT;
break;
case REOP_line_start:
+ case REOP_line_start_m:
if (cptr == s->cbuf)
break;
- if (!s->multi_line)
+ if (opcode == REOP_line_start)
goto no_match;
- PEEK_PREV_CHAR(c, cptr, s->cbuf);
+ PEEK_PREV_CHAR(c, cptr, s->cbuf, cbuf_type);
if (!is_line_terminator(c))
goto no_match;
break;
case REOP_line_end:
+ case REOP_line_end_m:
if (cptr == cbuf_end)
break;
- if (!s->multi_line)
+ if (opcode == REOP_line_end)
goto no_match;
- PEEK_CHAR(c, cptr, cbuf_end);
+ PEEK_CHAR(c, cptr, cbuf_end, cbuf_type);
if (!is_line_terminator(c))
goto no_match;
break;
case REOP_dot:
if (cptr == cbuf_end)
goto no_match;
- GET_CHAR(c, cptr, cbuf_end);
+ GET_CHAR(c, cptr, cbuf_end, cbuf_type);
if (is_line_terminator(c))
goto no_match;
break;
case REOP_any:
if (cptr == cbuf_end)
goto no_match;
- GET_CHAR(c, cptr, cbuf_end);
+ GET_CHAR(c, cptr, cbuf_end, cbuf_type);
break;
case REOP_save_start:
case REOP_save_end:
@@ -2292,45 +2920,55 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
pc += 4;
if (--stack[stack_len - 1] != 0) {
pc += (int)val;
+ if (lre_poll_timeout(s))
+ return LRE_RET_TIMEOUT;
}
break;
case REOP_push_char_pos:
stack[stack_len++] = (uintptr_t)cptr;
break;
- case REOP_bne_char_pos:
- val = get_u32(pc);
- pc += 4;
- if (stack[--stack_len] != (uintptr_t)cptr)
- pc += (int)val;
+ case REOP_check_advance:
+ if (stack[--stack_len] == (uintptr_t)cptr)
+ goto no_match;
break;
case REOP_word_boundary:
+ case REOP_word_boundary_i:
case REOP_not_word_boundary:
+ case REOP_not_word_boundary_i:
{
BOOL v1, v2;
+ int ignore_case = (opcode == REOP_word_boundary_i || opcode == REOP_not_word_boundary_i);
+ BOOL is_boundary = (opcode == REOP_word_boundary || opcode == REOP_word_boundary_i);
/* char before */
if (cptr == s->cbuf) {
v1 = FALSE;
} else {
- PEEK_PREV_CHAR(c, cptr, s->cbuf);
+ PEEK_PREV_CHAR(c, cptr, s->cbuf, cbuf_type);
+ if (ignore_case)
+ c = lre_canonicalize(c, s->is_unicode);
v1 = is_word_char(c);
}
/* current char */
if (cptr >= cbuf_end) {
v2 = FALSE;
} else {
- PEEK_CHAR(c, cptr, cbuf_end);
+ PEEK_CHAR(c, cptr, cbuf_end, cbuf_type);
+ if (ignore_case)
+ c = lre_canonicalize(c, s->is_unicode);
v2 = is_word_char(c);
}
- if (v1 ^ v2 ^ (REOP_not_word_boundary - opcode))
+ if (v1 ^ v2 ^ is_boundary)
goto no_match;
}
break;
case REOP_back_reference:
+ case REOP_back_reference_i:
case REOP_backward_back_reference:
+ case REOP_backward_back_reference_i:
{
const uint8_t *cptr1, *cptr1_end, *cptr1_start;
uint32_t c1, c2;
-
+
val = *pc++;
if (val >= s->capture_count)
goto no_match;
@@ -2338,16 +2976,17 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
cptr1_end = capture[2 * val + 1];
if (!cptr1_start || !cptr1_end)
break;
- if (opcode == REOP_back_reference) {
+ if (opcode == REOP_back_reference ||
+ opcode == REOP_back_reference_i) {
cptr1 = cptr1_start;
while (cptr1 < cptr1_end) {
if (cptr >= cbuf_end)
goto no_match;
- GET_CHAR(c1, cptr1, cptr1_end);
- GET_CHAR(c2, cptr, cbuf_end);
- if (s->ignore_case) {
- c1 = lre_canonicalize(c1, s->is_utf16);
- c2 = lre_canonicalize(c2, s->is_utf16);
+ GET_CHAR(c1, cptr1, cptr1_end, cbuf_type);
+ GET_CHAR(c2, cptr, cbuf_end, cbuf_type);
+ if (opcode == REOP_back_reference_i) {
+ c1 = lre_canonicalize(c1, s->is_unicode);
+ c2 = lre_canonicalize(c2, s->is_unicode);
}
if (c1 != c2)
goto no_match;
@@ -2357,11 +2996,11 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
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);
+ GET_PREV_CHAR(c1, cptr1, cptr1_start, cbuf_type);
+ GET_PREV_CHAR(c2, cptr, s->cbuf, cbuf_type);
+ if (opcode == REOP_backward_back_reference_i) {
+ c1 = lre_canonicalize(c1, s->is_unicode);
+ c2 = lre_canonicalize(c2, s->is_unicode);
}
if (c1 != c2)
goto no_match;
@@ -2370,17 +3009,18 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
}
break;
case REOP_range:
+ case REOP_range_i:
{
int n;
uint32_t low, high, idx_min, idx_max, idx;
-
+
n = get_u16(pc); /* n must be >= 1 */
pc += 2;
if (cptr >= cbuf_end)
goto no_match;
- GET_CHAR(c, cptr, cbuf_end);
- if (s->ignore_case) {
- c = lre_canonicalize(c, s->is_utf16);
+ GET_CHAR(c, cptr, cbuf_end, cbuf_type);
+ if (opcode == REOP_range_i) {
+ c = lre_canonicalize(c, s->is_unicode);
}
idx_min = 0;
low = get_u16(pc + 0 * 4);
@@ -2410,17 +3050,18 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
}
break;
case REOP_range32:
+ case REOP_range32_i:
{
int n;
uint32_t low, high, idx_min, idx_max, idx;
-
+
n = get_u16(pc); /* n must be >= 1 */
pc += 2;
if (cptr >= cbuf_end)
goto no_match;
- GET_CHAR(c, cptr, cbuf_end);
- if (s->ignore_case) {
- c = lre_canonicalize(c, s->is_utf16);
+ GET_CHAR(c, cptr, cbuf_end, cbuf_type);
+ if (opcode == REOP_range32_i) {
+ c = lre_canonicalize(c, s->is_unicode);
}
idx_min = 0;
low = get_u32(pc + 0 * 8);
@@ -2450,7 +3091,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
/* go to the previous char */
if (cptr == s->cbuf)
goto no_match;
- PREV_CHAR(cptr, s->cbuf);
+ PREV_CHAR(cptr, s->cbuf, cbuf_type);
break;
case REOP_simple_greedy_quant:
{
@@ -2458,19 +3099,22 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
size_t q;
intptr_t res;
const uint8_t *pc1;
-
+
next_pos = get_u32(pc);
quant_min = get_u32(pc + 4);
quant_max = get_u32(pc + 8);
pc += 16;
pc1 = pc;
pc += (int)next_pos;
-
+
q = 0;
for(;;) {
+ if (lre_poll_timeout(s))
+ return LRE_RET_TIMEOUT;
res = lre_exec_backtrack(s, capture, stack, stack_len,
pc1, cptr, TRUE);
- if (res == -1)
+ if (res == LRE_RET_MEMORY_ERROR ||
+ res == LRE_RET_TIMEOUT)
return res;
if (!res)
break;
@@ -2488,7 +3132,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
RE_EXEC_STATE_GREEDY_QUANT,
q - quant_min);
if (ret < 0)
- return -1;
+ return LRE_RET_MEMORY_ERROR;
}
}
break;
@@ -2498,7 +3142,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
}
}
-/* Return 1 if match, 0 if not match or -1 if error. cindex is the
+/* Return 1 if match, 0 if not match or < 0 if error (see LRE_RET_x). cindex is the
starting position of the match and must be such as 0 <= cindex <=
clen. */
int lre_exec(uint8_t **capture,
@@ -2508,18 +3152,17 @@ int lre_exec(uint8_t **capture,
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;
+
+ re_flags = lre_get_flags(bc_buf);
+ s->is_unicode = (re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0;
s->capture_count = bc_buf[RE_HEADER_CAPTURE_COUNT];
s->stack_size_max = bc_buf[RE_HEADER_STACK_SIZE];
s->cbuf = cbuf;
s->cbuf_end = cbuf + (clen << cbuf_type);
s->cbuf_type = cbuf_type;
- if (s->cbuf_type == 1 && s->is_utf16)
+ if (s->cbuf_type == 1 && s->is_unicode)
s->cbuf_type = 2;
+ s->interrupt_counter = INTERRUPT_COUNTER_INIT;
s->opaque = opaque;
s->state_size = sizeof(REExecState) +
@@ -2528,7 +3171,7 @@ int lre_exec(uint8_t **capture,
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]);
@@ -2546,7 +3189,7 @@ int lre_get_capture_count(const uint8_t *bc_buf)
int lre_get_flags(const uint8_t *bc_buf)
{
- return bc_buf[RE_HEADER_FLAGS];
+ return get_u16(bc_buf + RE_HEADER_FLAGS);
}
/* Return NULL if no group names. Otherwise, return a pointer to
@@ -2556,8 +3199,8 @@ 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);
+ re_bytecode_len = get_u32(bc_buf + RE_HEADER_BYTECODE_LEN);
+ return (const char *)(bc_buf + RE_HEADER_LEN + re_bytecode_len);
}
#ifdef TEST
@@ -2574,27 +3217,28 @@ void *lre_realloc(void *opaque, void *ptr, size_t size)
int main(int argc, char **argv)
{
- int len, ret, i;
+ int len, flags, ret, i;
uint8_t *bc;
char error_msg[64];
uint8_t *capture[CAPTURE_COUNT_MAX * 2];
const char *input;
int input_len, capture_count;
-
- if (argc < 3) {
- printf("usage: %s regexp input\n", argv[0]);
- exit(1);
+
+ if (argc < 4) {
+ printf("usage: %s regexp flags input\n", argv[0]);
+ return 1;
}
+ flags = atoi(argv[2]);
bc = lre_compile(&len, error_msg, sizeof(error_msg), argv[1],
- strlen(argv[1]), 0, NULL);
+ strlen(argv[1]), flags, NULL);
if (!bc) {
fprintf(stderr, "error: %s\n", error_msg);
exit(1);
}
- input = argv[2];
+ input = argv[3];
input_len = strlen(input);
-
+
ret = lre_exec(capture, bc, (uint8_t *)input, 0, input_len, 0, NULL);
printf("ret=%d\n", ret);
if (ret == 1) {
diff --git a/quickjs/libregexp.h b/quickjs/libregexp.h
index 9aedb7e937..da76e4cef6 100644
--- a/quickjs/libregexp.h
+++ b/quickjs/libregexp.h
@@ -1,6 +1,6 @@
/*
* Regular Expression Engine
- *
+ *
* Copyright (c) 2017-2018 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -25,19 +25,20 @@
#define LIBREGEXP_H
#include
-
-#include "libunicode.h"
-
-#define LRE_BOOL int /* for documentation purposes */
+#include
#define LRE_FLAG_GLOBAL (1 << 0)
#define LRE_FLAG_IGNORECASE (1 << 1)
#define LRE_FLAG_MULTILINE (1 << 2)
#define LRE_FLAG_DOTALL (1 << 3)
-#define LRE_FLAG_UTF16 (1 << 4)
+#define LRE_FLAG_UNICODE (1 << 4)
#define LRE_FLAG_STICKY (1 << 5)
-
+#define LRE_FLAG_INDICES (1 << 6) /* Unused by libregexp, just recorded. */
#define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */
+#define LRE_FLAG_UNICODE_SETS (1 << 8)
+
+#define LRE_RET_MEMORY_ERROR (-1)
+#define LRE_RET_TIMEOUT (-2)
uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
const char *buf, size_t buf_len, int re_flags,
@@ -50,43 +51,11 @@ int lre_exec(uint8_t **capture,
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);
+/* must be provided by the user, return non zero if overflow */
+int lre_check_stack_overflow(void *opaque, size_t alloca_size);
+/* must be provided by the user, return non zero if time out */
+int lre_check_timeout(void *opaque);
void *lre_realloc(void *opaque, void *ptr, size_t size);
-/* JS identifier test */
-extern uint32_t const lre_id_start_table_ascii[4];
-extern uint32_t const lre_id_continue_table_ascii[4];
-
-static inline int lre_js_is_ident_first(int c)
-{
- if ((uint32_t)c < 128) {
- return (lre_id_start_table_ascii[c >> 5] >> (c & 31)) & 1;
- } else {
-#ifdef CONFIG_ALL_UNICODE
- return lre_is_id_start(c);
-#else
- return !lre_is_space(c);
-#endif
- }
-}
-
-static inline int lre_js_is_ident_next(int c)
-{
- if ((uint32_t)c < 128) {
- return (lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1;
- } else {
- /* ZWNJ and ZWJ are accepted in identifiers */
-#ifdef CONFIG_ALL_UNICODE
- return lre_is_id_continue(c) || c == 0x200C || c == 0x200D;
-#else
- return !lre_is_space(c) || c == 0x200C || c == 0x200D;
-#endif
- }
-}
-
-#undef LRE_BOOL
-
#endif /* LIBREGEXP_H */
diff --git a/quickjs/libunicode-table.h b/quickjs/libunicode-table.h
index b64178b488..67df6b3a3c 100644
--- a/quickjs/libunicode-table.h
+++ b/quickjs/libunicode-table.h
@@ -3,7 +3,7 @@
#include
-static const uint32_t case_conv_table1[370] = {
+static const uint32_t case_conv_table1[378] = {
0x00209a30, 0x00309a00, 0x005a8173, 0x00601730,
0x006c0730, 0x006f81b3, 0x00701700, 0x007c0700,
0x007f8100, 0x00803040, 0x009801c3, 0x00988190,
@@ -13,140 +13,143 @@ static const uint32_t case_conv_table1[370] = {
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,
+ 0x00cd0100, 0x00cd8101, 0x00ce0130, 0x00ce8130,
+ 0x00cf0100, 0x00cf8130, 0x00d00640, 0x00d30130,
+ 0x00d38240, 0x00d48130, 0x00d60240, 0x00d70130,
+ 0x00d78240, 0x00d88230, 0x00d98440, 0x00db8130,
+ 0x00dc0240, 0x00de0240, 0x00df8100, 0x00e20350,
+ 0x00e38350, 0x00e50350, 0x00e69040, 0x00ee8100,
+ 0x00ef1240, 0x00f801b4, 0x00f88350, 0x00fa0240,
+ 0x00fb0130, 0x00fb8130, 0x00fc2840, 0x01100130,
+ 0x01111240, 0x011d0131, 0x011d8240, 0x011e8130,
+ 0x011f0131, 0x011f8201, 0x01208240, 0x01218130,
+ 0x01220130, 0x01228130, 0x01230a40, 0x01280101,
+ 0x01288101, 0x01290101, 0x01298100, 0x012a0100,
+ 0x012b0200, 0x012c8100, 0x012d8100, 0x012e0101,
+ 0x01300100, 0x01308101, 0x01318100, 0x01320101,
+ 0x01328101, 0x01330101, 0x01340100, 0x01348100,
+ 0x01350101, 0x01358101, 0x01360101, 0x01378100,
+ 0x01388101, 0x01390100, 0x013a8100, 0x013e8101,
+ 0x01400100, 0x01410101, 0x01418100, 0x01438101,
+ 0x01440100, 0x01448100, 0x01450200, 0x01460100,
+ 0x01490100, 0x014e8101, 0x014f0101, 0x01a28173,
+ 0x01b80440, 0x01bb0240, 0x01bd8300, 0x01bf8130,
+ 0x01c30130, 0x01c40330, 0x01c60130, 0x01c70230,
+ 0x01c801d0, 0x01c89130, 0x01d18930, 0x01d60100,
+ 0x01d68300, 0x01d801d3, 0x01d89100, 0x01e10173,
+ 0x01e18900, 0x01e60100, 0x01e68200, 0x01e78130,
+ 0x01e80173, 0x01e88173, 0x01ea8173, 0x01eb0173,
+ 0x01eb8100, 0x01ec1840, 0x01f80173, 0x01f88173,
+ 0x01f90100, 0x01f98100, 0x01fa01a0, 0x01fa8173,
+ 0x01fb8240, 0x01fc8130, 0x01fd0240, 0x01fe8330,
+ 0x02001030, 0x02082030, 0x02182000, 0x02281000,
+ 0x02302240, 0x02453640, 0x02600130, 0x02608e40,
+ 0x02678100, 0x02686040, 0x0298a630, 0x02b0a600,
+ 0x02c381b5, 0x08502631, 0x08638131, 0x08668131,
+ 0x08682b00, 0x087e8300, 0x09d05011, 0x09f80610,
+ 0x09fc0620, 0x0e400174, 0x0e408174, 0x0e410174,
+ 0x0e418174, 0x0e420174, 0x0e428174, 0x0e430174,
+ 0x0e438180, 0x0e440180, 0x0e448240, 0x0e482b30,
+ 0x0e5e8330, 0x0ebc8101, 0x0ebe8101, 0x0ec70101,
+ 0x0f007e40, 0x0f3f1840, 0x0f4b01b5, 0x0f4b81b6,
+ 0x0f4c01b6, 0x0f4c81b6, 0x0f4d01b7, 0x0f4d8180,
+ 0x0f4f0130, 0x0f506040, 0x0f800800, 0x0f840830,
+ 0x0f880600, 0x0f8c0630, 0x0f900800, 0x0f940830,
+ 0x0f980800, 0x0f9c0830, 0x0fa00600, 0x0fa40630,
+ 0x0fa801b0, 0x0fa88100, 0x0fa901d3, 0x0fa98100,
+ 0x0faa01d3, 0x0faa8100, 0x0fab01d3, 0x0fab8100,
+ 0x0fac8130, 0x0fad8130, 0x0fae8130, 0x0faf8130,
+ 0x0fb00800, 0x0fb40830, 0x0fb80200, 0x0fb90400,
+ 0x0fbb0201, 0x0fbc0201, 0x0fbd0201, 0x0fbe0201,
+ 0x0fc008b7, 0x0fc40867, 0x0fc808b8, 0x0fcc0868,
+ 0x0fd008b8, 0x0fd40868, 0x0fd80200, 0x0fd901b9,
+ 0x0fd981b1, 0x0fda01b9, 0x0fdb01b1, 0x0fdb81d7,
+ 0x0fdc0230, 0x0fdd0230, 0x0fde0161, 0x0fdf0173,
+ 0x0fe101b9, 0x0fe181b2, 0x0fe201ba, 0x0fe301b2,
+ 0x0fe381d8, 0x0fe40430, 0x0fe60162, 0x0fe80201,
+ 0x0fe901d0, 0x0fe981d0, 0x0feb01b0, 0x0feb81d0,
+ 0x0fec0230, 0x0fed0230, 0x0ff00201, 0x0ff101d3,
+ 0x0ff181d3, 0x0ff201ba, 0x0ff28101, 0x0ff301b0,
+ 0x0ff381d3, 0x0ff40231, 0x0ff50230, 0x0ff60131,
+ 0x0ff901ba, 0x0ff981b2, 0x0ffa01bb, 0x0ffb01b2,
+ 0x0ffb81d9, 0x0ffc0230, 0x0ffd0230, 0x0ffe0162,
+ 0x109301a0, 0x109501a0, 0x109581a0, 0x10990131,
+ 0x10a70101, 0x10b01031, 0x10b81001, 0x10c18240,
+ 0x125b1a31, 0x12681a01, 0x16003031, 0x16183001,
+ 0x16300240, 0x16310130, 0x16318130, 0x16320130,
+ 0x16328100, 0x16330100, 0x16338640, 0x16368130,
+ 0x16370130, 0x16378130, 0x16380130, 0x16390240,
+ 0x163a8240, 0x163f0230, 0x16406440, 0x16758440,
+ 0x16790240, 0x16802600, 0x16938100, 0x16968100,
+ 0x53202e40, 0x53401c40, 0x53910e40, 0x53993e40,
+ 0x53bc8440, 0x53be8130, 0x53bf0a40, 0x53c58240,
+ 0x53c68130, 0x53c80440, 0x53ca0101, 0x53cb1440,
+ 0x53d50130, 0x53d58130, 0x53d60130, 0x53d68130,
+ 0x53d70130, 0x53d80130, 0x53d88130, 0x53d90130,
+ 0x53d98131, 0x53da1040, 0x53e20131, 0x53e28130,
+ 0x53e30130, 0x53e38440, 0x53e58130, 0x53e60240,
+ 0x53e80240, 0x53eb0640, 0x53ee0130, 0x53fa8240,
+ 0x55a98101, 0x55b85020, 0x7d8001b2, 0x7d8081b2,
+ 0x7d8101b2, 0x7d8181da, 0x7d8201da, 0x7d8281b3,
+ 0x7d8301b3, 0x7d8981bb, 0x7d8a01bb, 0x7d8a81bb,
+ 0x7d8b01bc, 0x7d8b81bb, 0x7f909a31, 0x7fa09a01,
+ 0x82002831, 0x82142801, 0x82582431, 0x826c2401,
+ 0x82b80b31, 0x82be0f31, 0x82c60731, 0x82ca0231,
+ 0x82cb8b01, 0x82d18f01, 0x82d98701, 0x82dd8201,
+ 0x86403331, 0x86603301, 0x86a81631, 0x86b81601,
0x8c502031, 0x8c602001, 0xb7202031, 0xb7302001,
0xf4802231, 0xf4912201,
};
-static const uint8_t case_conv_table2[370] = {
+static const uint8_t case_conv_table2[378] = {
0x01, 0x00, 0x9c, 0x06, 0x07, 0x4d, 0x03, 0x04,
0x10, 0x00, 0x8f, 0x0b, 0x00, 0x00, 0x11, 0x00,
- 0x08, 0x00, 0x53, 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,
+ 0x08, 0x00, 0x53, 0x4b, 0x52, 0x00, 0x53, 0x00,
+ 0x54, 0x00, 0x3b, 0x55, 0x56, 0x00, 0x58, 0x5a,
+ 0x40, 0x5f, 0x5e, 0x00, 0x47, 0x52, 0x63, 0x65,
+ 0x43, 0x66, 0x00, 0x68, 0x00, 0x6a, 0x00, 0x6c,
+ 0x00, 0x6e, 0x00, 0x70, 0x00, 0x00, 0x41, 0x00,
+ 0x00, 0x00, 0x00, 0x1a, 0x00, 0x93, 0x00, 0x00,
+ 0x20, 0x36, 0x00, 0x28, 0x00, 0x24, 0x00, 0x24,
+ 0x25, 0x2d, 0x00, 0x13, 0x6d, 0x6f, 0x00, 0x29,
+ 0x27, 0x2a, 0x14, 0x16, 0x18, 0x1b, 0x1c, 0x41,
+ 0x1e, 0x42, 0x1f, 0x4e, 0x3c, 0x40, 0x22, 0x21,
+ 0x44, 0x21, 0x43, 0x26, 0x28, 0x27, 0x29, 0x23,
+ 0x2b, 0x4b, 0x2d, 0x46, 0x2f, 0x4c, 0x31, 0x4d,
+ 0x33, 0x47, 0x45, 0x99, 0x00, 0x00, 0x97, 0x91,
+ 0x7f, 0x80, 0x85, 0x86, 0x12, 0x82, 0x84, 0x78,
+ 0x79, 0x12, 0x7d, 0xa3, 0x7e, 0x7a, 0x7b, 0x8c,
+ 0x92, 0x98, 0xa6, 0xa0, 0x87, 0x00, 0x9a, 0xa1,
+ 0x95, 0x77, 0x33, 0x95, 0x00, 0x90, 0x00, 0x76,
+ 0x9b, 0x9a, 0x99, 0x98, 0x00, 0x00, 0xa0, 0x00,
+ 0x9e, 0x00, 0xa3, 0xa2, 0x15, 0x31, 0x32, 0x33,
+ 0xb7, 0xb8, 0x55, 0xac, 0xab, 0x12, 0x14, 0x1e,
+ 0x21, 0x22, 0x22, 0x2a, 0x34, 0x35, 0x00, 0xa8,
+ 0xa9, 0x39, 0x22, 0x4c, 0x00, 0x00, 0x97, 0x01,
+ 0x5a, 0xda, 0x1d, 0x36, 0x05, 0x00, 0xc7, 0xc6,
+ 0xc9, 0xc8, 0xcb, 0xca, 0xcd, 0xcc, 0xcf, 0xce,
+ 0xc4, 0xd8, 0x45, 0xd9, 0x42, 0xda, 0x46, 0xdb,
+ 0xd1, 0xd3, 0xd5, 0xd7, 0xdd, 0xdc, 0xf1, 0xf9,
+ 0x01, 0x11, 0x0a, 0x12, 0x80, 0x9f, 0x00, 0x21,
+ 0x80, 0xa3, 0xf0, 0x00, 0xc0, 0x40, 0xc6, 0x60,
+ 0xea, 0xde, 0xe6, 0x99, 0xc0, 0x00, 0x00, 0x06,
+ 0x60, 0xdf, 0x29, 0x00, 0x15, 0x12, 0x06, 0x16,
+ 0xfb, 0xe0, 0x09, 0x15, 0x12, 0x84, 0x0b, 0xc6,
+ 0x16, 0x02, 0xe2, 0x06, 0xc0, 0x40, 0x00, 0x46,
+ 0x60, 0xe1, 0xe3, 0x6d, 0x37, 0x38, 0x39, 0x18,
+ 0x17, 0x1a, 0x19, 0x00, 0x1d, 0x1c, 0x1f, 0x1e,
+ 0x00, 0x61, 0xba, 0x67, 0x45, 0x48, 0x00, 0x50,
+ 0x64, 0x4f, 0x51, 0x00, 0x00, 0x49, 0x00, 0x00,
+ 0x00, 0xa5, 0xa6, 0xa7, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xb9, 0x00, 0x00, 0x5c, 0x00, 0x4a, 0x00,
+ 0x5d, 0x57, 0x59, 0x62, 0x60, 0x72, 0x6b, 0x71,
+ 0x54, 0x00, 0x3e, 0x69, 0xbb, 0x00, 0x5b, 0x00,
+ 0x00, 0x00, 0x25, 0x00, 0x48, 0xaa, 0x8a, 0x8b,
+ 0x8c, 0xab, 0xac, 0x58, 0x58, 0xaf, 0x94, 0xb0,
+ 0x6f, 0xb2, 0x63, 0x62, 0x65, 0x64, 0x67, 0x66,
+ 0x6c, 0x6d, 0x6e, 0x6f, 0x68, 0x69, 0x6a, 0x6b,
+ 0x71, 0x70, 0x73, 0x72, 0x75, 0x74, 0x77, 0x76,
+ 0x79, 0x78,
};
static const uint16_t case_conv_ext[58] = {
@@ -160,41 +163,44 @@ static const uint16_t case_conv_ext[58] = {
0x006b, 0x00e5,
};
-static const uint8_t unicode_prop_Cased1_table[196] = {
+static const uint8_t unicode_prop_Cased1_table[193] = {
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, 0x4b, 0x72,
- 0x80, 0x4c, 0x02, 0xf8, 0x02, 0x80, 0x8f, 0x80,
- 0xb0, 0x40, 0xdb, 0x08, 0x80, 0x41, 0xd0, 0x80,
- 0x8c, 0x80, 0x8f, 0x8c, 0xe4, 0x03, 0x01, 0x89,
- 0x00, 0x14, 0x28, 0x10, 0x11, 0x02, 0x01, 0x18,
- 0x0b, 0x24, 0x4b, 0x26, 0x01, 0x01, 0x86, 0xe5,
- 0x80, 0x60, 0x79, 0xb6, 0x81, 0x40, 0x91, 0x81,
- 0xbd, 0x88, 0x94, 0x05, 0x80, 0x98, 0x80, 0xa2,
- 0x00, 0x80, 0x9b, 0x12, 0x82, 0x43, 0x34, 0xa2,
- 0x06, 0x80, 0x8d, 0x60, 0x5c, 0x15, 0x01, 0x10,
- 0xa9, 0x80, 0x88, 0x60, 0xcc, 0x44, 0xd4, 0x80,
- 0xc6, 0x01, 0x08, 0x09, 0x0b, 0x80, 0x8b, 0x00,
- 0x06, 0x80, 0xc0, 0x03, 0x0f, 0x06, 0x80, 0x9b,
- 0x03, 0x04, 0x00, 0x16, 0x80, 0x41, 0x53, 0x81,
- 0x98, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80,
- 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80,
- 0x9e, 0x80, 0x98, 0x07, 0x47, 0x33, 0x89, 0x80,
- 0x93, 0x2d, 0x41, 0x04, 0xbd, 0x50, 0xc1, 0x99,
- 0x85, 0x99, 0x85, 0x99,
+ 0x80, 0x9b, 0x81, 0x8d, 0x02, 0x80, 0xe1, 0x80,
+ 0x91, 0x85, 0x9a, 0x01, 0x00, 0x01, 0x11, 0x03,
+ 0x04, 0x08, 0x01, 0x08, 0x30, 0x08, 0x01, 0x15,
+ 0x20, 0x00, 0x39, 0x99, 0x31, 0x9d, 0x84, 0x40,
+ 0x94, 0x80, 0xd6, 0x82, 0xa6, 0x80, 0x41, 0x62,
+ 0x80, 0xa6, 0x80, 0x4b, 0x72, 0x80, 0x4c, 0x02,
+ 0xf8, 0x02, 0x80, 0x8f, 0x80, 0xb0, 0x40, 0xdb,
+ 0x08, 0x80, 0x41, 0xd0, 0x80, 0x8c, 0x80, 0x8f,
+ 0x8c, 0xe4, 0x03, 0x01, 0x89, 0x00, 0x14, 0x28,
+ 0x10, 0x11, 0x02, 0x01, 0x18, 0x0b, 0x24, 0x4b,
+ 0x26, 0x01, 0x01, 0x86, 0xe5, 0x80, 0x60, 0x79,
+ 0xb6, 0x81, 0x40, 0x91, 0x81, 0xbd, 0x88, 0x94,
+ 0x05, 0x80, 0x98, 0x80, 0xa2, 0x00, 0x80, 0x9b,
+ 0x12, 0x82, 0x43, 0x34, 0xa2, 0x06, 0x80, 0x8d,
+ 0x60, 0x5c, 0x15, 0x01, 0x10, 0xa9, 0x80, 0x88,
+ 0x60, 0xcc, 0x44, 0xd4, 0x80, 0xc6, 0x01, 0x08,
+ 0x09, 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0,
+ 0x03, 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00,
+ 0x16, 0x80, 0x41, 0x53, 0x81, 0x98, 0x80, 0x98,
+ 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98,
+ 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98,
+ 0x07, 0x47, 0x33, 0x89, 0x80, 0x93, 0x2d, 0x41,
+ 0x04, 0xbd, 0x50, 0xc1, 0x99, 0x85, 0x99, 0x85,
+ 0x99,
};
-static const uint8_t unicode_prop_Cased1_index[21] = {
- 0xb9, 0x02, 0xe0, 0xc0, 0x1d, 0x20, 0xe5, 0x2c,
- 0x20, 0xb1, 0x07, 0x21, 0xc1, 0xd6, 0x21, 0x4a,
- 0xf1, 0x01, 0x8a, 0xf1, 0x01,
+static const uint8_t unicode_prop_Cased1_index[18] = {
+ 0xb9, 0x02, 0x80, // 002B9 at 36
+ 0xa0, 0x1e, 0x40, // 01EA0 at 66
+ 0x9e, 0xa6, 0x40, // 0A69E at 98
+ 0xbb, 0x07, 0x01, // 107BB at 128
+ 0xdb, 0xd6, 0x01, // 1D6DB at 160
+ 0x8a, 0xf1, 0x01, // 1F18A at 192 (upper bound)
};
-static const uint8_t unicode_prop_Case_Ignorable_table[737] = {
+static const uint8_t unicode_prop_Case_Ignorable_table[764] = {
0xa6, 0x05, 0x80, 0x8a, 0x80, 0xa2, 0x00, 0x80,
0xc6, 0x03, 0x00, 0x03, 0x01, 0x81, 0x41, 0xf6,
0x40, 0xbf, 0x19, 0x18, 0x88, 0x08, 0x80, 0x40,
@@ -203,7 +209,7 @@ static const uint8_t unicode_prop_Case_Ignorable_table[737] = {
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,
+ 0x97, 0x97, 0xaa, 0x82, 0xab, 0x06, 0x0c, 0x88,
0xa8, 0xb9, 0xb6, 0x00, 0x03, 0x3b, 0x02, 0x86,
0x89, 0x81, 0x8c, 0x80, 0x8e, 0x80, 0xb9, 0x03,
0x1f, 0x80, 0x93, 0x81, 0x99, 0x01, 0x81, 0xb8,
@@ -257,26 +263,29 @@ static const uint8_t unicode_prop_Case_Ignorable_table[737] = {
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, 0xcf, 0x82, 0xc5, 0x8a, 0xb0,
- 0x83, 0xfa, 0x80, 0xb5, 0x8e, 0xa8, 0x01, 0x81,
- 0x89, 0x82, 0xb0, 0x19, 0x09, 0x03, 0x80, 0x89,
- 0x80, 0xb1, 0x82, 0xa3, 0x20, 0x87, 0xbd, 0x80,
- 0x8b, 0x81, 0xb3, 0x88, 0x89, 0x19, 0x80, 0xde,
- 0x11, 0x00, 0x0d, 0x01, 0x80, 0x40, 0x9c, 0x02,
- 0x87, 0x94, 0x81, 0xb8, 0x0a, 0x80, 0xa4, 0x32,
- 0x84, 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, 0x8a, 0x81, 0xb3, 0x24, 0x00, 0x80,
- 0x54, 0xec, 0x90, 0x85, 0x8e, 0x60, 0x36, 0x99,
- 0x84, 0xba, 0x86, 0x88, 0x83, 0x44, 0x0a, 0x80,
+ 0xa5, 0x80, 0x99, 0x20, 0x80, 0x41, 0x3a, 0x81,
+ 0xce, 0x83, 0xc5, 0x8a, 0xb0, 0x83, 0xfa, 0x80,
+ 0xb5, 0x8e, 0xa8, 0x01, 0x81, 0x89, 0x82, 0xb0,
+ 0x19, 0x09, 0x03, 0x80, 0x89, 0x80, 0xb1, 0x82,
+ 0xa3, 0x20, 0x87, 0xbd, 0x80, 0x8b, 0x81, 0xb3,
+ 0x88, 0x89, 0x19, 0x80, 0xde, 0x11, 0x00, 0x0d,
+ 0x01, 0x80, 0x40, 0x9c, 0x02, 0x87, 0x94, 0x81,
+ 0xb8, 0x0a, 0x80, 0xa4, 0x32, 0x84, 0xc5, 0x85,
+ 0x8c, 0x00, 0x00, 0x80, 0x8d, 0x81, 0xd4, 0x39,
+ 0x10, 0x80, 0x96, 0x80, 0xd3, 0x28, 0x03, 0x08,
+ 0x81, 0x40, 0xed, 0x1d, 0x08, 0x81, 0x9a, 0x81,
+ 0xd4, 0x39, 0x00, 0x81, 0xe9, 0x00, 0x01, 0x28,
+ 0x80, 0xe4, 0x00, 0x01, 0x18, 0x84, 0x41, 0x02,
+ 0x88, 0x01, 0x40, 0xff, 0x08, 0x03, 0x80, 0x40,
+ 0x8f, 0x19, 0x0b, 0x80, 0x9f, 0x89, 0xa7, 0x29,
+ 0x1f, 0x80, 0x88, 0x29, 0x82, 0xad, 0x8c, 0x01,
+ 0x41, 0x95, 0x30, 0x28, 0x80, 0xd1, 0x95, 0x0e,
+ 0x01, 0x01, 0xf9, 0x2a, 0x00, 0x08, 0x30, 0x80,
+ 0xc7, 0x0a, 0x00, 0x80, 0x41, 0x5a, 0x81, 0x8a,
+ 0x81, 0xb3, 0x24, 0x00, 0x80, 0x96, 0x80, 0x54,
+ 0xd4, 0x90, 0x85, 0x8e, 0x60, 0x2c, 0xc7, 0x8b,
+ 0x12, 0x49, 0xbf, 0x84, 0xba, 0x86, 0x88, 0x83,
+ 0x41, 0xfb, 0x82, 0xa7, 0x81, 0x41, 0xe1, 0x80,
0xbe, 0x90, 0xbf, 0x08, 0x81, 0x60, 0x40, 0x0a,
0x18, 0x30, 0x81, 0x4c, 0x9d, 0x08, 0x83, 0x52,
0x5b, 0xad, 0x81, 0x96, 0x42, 0x1f, 0x82, 0x88,
@@ -285,24 +294,39 @@ static const uint8_t unicode_prop_Case_Ignorable_table[737] = {
0x20, 0x8e, 0x45, 0x4f, 0x30, 0x90, 0x0e, 0x01,
0x04, 0x84, 0xbd, 0xa0, 0x80, 0x40, 0x9f, 0x8d,
0x41, 0x6f, 0x80, 0xbc, 0x83, 0x41, 0xfa, 0x84,
- 0x43, 0xdf, 0x86, 0xec, 0x87, 0x4a, 0xae, 0x84,
- 0x6c, 0x0c, 0x00, 0x80, 0x9d, 0xdf, 0xff, 0x40,
- 0xef,
+ 0x40, 0xfd, 0x81, 0x42, 0xdf, 0x86, 0xec, 0x87,
+ 0x4a, 0xae, 0x84, 0x6c, 0x0c, 0x00, 0x80, 0x9d,
+ 0xdf, 0xff, 0x40, 0xef,
};
-static const uint8_t unicode_prop_Case_Ignorable_index[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, 0x75, 0x10, 0x01,
- 0xeb, 0x12, 0x21, 0x41, 0x16, 0x01, 0x5c, 0x1a,
- 0x01, 0x43, 0x1f, 0x01, 0x2e, 0xcf, 0x41, 0x25,
- 0xe0, 0x01, 0xf0, 0x01, 0x0e,
+static const uint8_t unicode_prop_Case_Ignorable_index[72] = {
+ 0xbe, 0x05, 0x00, // 005BE at 32
+ 0xfe, 0x07, 0x00, // 007FE at 64
+ 0x52, 0x0a, 0xa0, // 00A52 at 101
+ 0xc1, 0x0b, 0x00, // 00BC1 at 128
+ 0x82, 0x0d, 0x00, // 00D82 at 160
+ 0x3f, 0x10, 0x80, // 0103F at 196
+ 0xd4, 0x17, 0x40, // 017D4 at 226
+ 0xcf, 0x1a, 0x20, // 01ACF at 257
+ 0xf5, 0x1c, 0x00, // 01CF5 at 288
+ 0x80, 0x20, 0x00, // 02080 at 320
+ 0x16, 0xa0, 0x00, // 0A016 at 352
+ 0xc6, 0xa8, 0x00, // 0A8C6 at 384
+ 0xc2, 0xaa, 0x60, // 0AAC2 at 419
+ 0x56, 0xfe, 0x20, // 0FE56 at 449
+ 0xb1, 0x07, 0x01, // 107B1 at 480
+ 0x02, 0x10, 0x01, // 11002 at 512
+ 0x42, 0x12, 0x41, // 11242 at 546
+ 0xc4, 0x14, 0x21, // 114C4 at 577
+ 0xe1, 0x19, 0x81, // 119E1 at 612
+ 0x48, 0x1d, 0x01, // 11D48 at 640
+ 0x44, 0x6b, 0x01, // 16B44 at 672
+ 0x83, 0xd1, 0x21, // 1D183 at 705
+ 0x3e, 0xe1, 0x01, // 1E13E at 736
+ 0xf0, 0x01, 0x0e, // E01F0 at 768 (upper bound)
};
-static const uint8_t unicode_prop_ID_Start_table[1100] = {
+static const uint8_t unicode_prop_ID_Start_table[1133] = {
0xc0, 0x99, 0x85, 0x99, 0xae, 0x80, 0x89, 0x03,
0x04, 0x96, 0x80, 0x9e, 0x80, 0x41, 0xc9, 0x83,
0x8b, 0x8d, 0x26, 0x00, 0x80, 0x40, 0x80, 0x20,
@@ -346,7 +370,7 @@ static const uint8_t unicode_prop_ID_Start_table[1100] = {
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,
+ 0x81, 0x8a, 0x84, 0xaa, 0x0a, 0xa8, 0x18, 0x28,
0x0a, 0x04, 0x40, 0xbf, 0xbf, 0x41, 0x15, 0x0d,
0x81, 0xa5, 0x0d, 0x0f, 0x00, 0x00, 0x00, 0x80,
0x9e, 0x81, 0xb4, 0x06, 0x00, 0x12, 0x06, 0x13,
@@ -362,8 +386,8 @@ static const uint8_t unicode_prop_ID_Start_table[1100] = {
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,
+ 0x88, 0x81, 0xe6, 0x81, 0xc2, 0x09, 0x00, 0x07,
+ 0x94, 0x8f, 0x02, 0x03, 0x80, 0x96, 0x9c, 0xb3,
0x8d, 0xb1, 0xbd, 0x2a, 0x00, 0x81, 0x8a, 0x9b,
0x89, 0x96, 0x98, 0x9c, 0x86, 0xae, 0x9b, 0x80,
0x8f, 0x20, 0x89, 0x89, 0x20, 0xa8, 0x96, 0x10,
@@ -383,91 +407,117 @@ static const uint8_t unicode_prop_ID_Start_table[1100] = {
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,
+ 0x80, 0x8a, 0x80, 0x8e, 0x06, 0x01, 0x82, 0xb3,
+ 0x8b, 0x41, 0x36, 0x88, 0x95, 0x89, 0x87, 0x97,
+ 0x28, 0xa9, 0x80, 0x88, 0xc4, 0x29, 0x00, 0xab,
+ 0x01, 0x10, 0x81, 0x96, 0x89, 0x96, 0x88, 0x9e,
+ 0xc0, 0x92, 0x01, 0x89, 0x95, 0x89, 0x99, 0xc5,
+ 0xb7, 0x29, 0xbf, 0x80, 0x8e, 0x18, 0x10, 0x9c,
+ 0xa9, 0x9c, 0x82, 0x9c, 0xa2, 0x38, 0x9b, 0x9a,
+ 0xb5, 0x89, 0x95, 0x89, 0x92, 0x8c, 0x91, 0xed,
+ 0xc8, 0xb6, 0xb2, 0x8c, 0xb2, 0x8c, 0xa3, 0xa5,
+ 0x9b, 0x88, 0x96, 0x40, 0xf9, 0xa9, 0x29, 0x8f,
+ 0x82, 0xba, 0x9c, 0x89, 0x07, 0x95, 0xa9, 0x91,
0xad, 0x94, 0x9a, 0x96, 0x8b, 0xb4, 0xb8, 0x09,
0x80, 0x8c, 0xac, 0x9f, 0x98, 0x99, 0xa3, 0x9c,
0x01, 0x07, 0xa2, 0x10, 0x8b, 0xaf, 0x8d, 0x83,
0x94, 0x00, 0x80, 0xa2, 0x91, 0x80, 0x98, 0x92,
0x81, 0xbe, 0x30, 0x00, 0x18, 0x8e, 0x80, 0x89,
0x86, 0xae, 0xa5, 0x39, 0x09, 0x95, 0x06, 0x01,
- 0x04, 0x10, 0x91, 0x80, 0x8b, 0x84, 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, 0x8e, 0x00, 0x8c, 0x80,
- 0xa1, 0xfb, 0x80, 0xce, 0x43, 0x99, 0xe5, 0xee,
- 0x90, 0x40, 0xc3, 0x4a, 0x4b, 0xe0, 0x8e, 0x44,
- 0x2f, 0x90, 0x85, 0x4f, 0xb8, 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, 0x8e, 0x80, 0x9c,
- 0x11, 0x80, 0x8d, 0x1f, 0x41, 0x8b, 0x49, 0x03,
- 0xea, 0x84, 0x8c, 0x82, 0x88, 0x86, 0x89, 0x57,
- 0x65, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b,
- 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f,
- 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80,
- 0x41, 0x53, 0x81, 0x98, 0x80, 0x98, 0x80, 0x9e,
- 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e,
- 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07, 0x47,
- 0x33, 0x9e, 0x2d, 0x41, 0x04, 0xbd, 0x40, 0x91,
- 0xac, 0x89, 0x86, 0x8f, 0x80, 0x41, 0x40, 0x9d,
- 0x91, 0xab, 0x41, 0xe3, 0x9b, 0x42, 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, 0x39,
- 0x85, 0x40, 0xdd, 0x81, 0x56, 0x81, 0x8d, 0x5d,
- 0x30, 0x4c, 0x1e, 0x42, 0x1d, 0x45, 0xe1, 0x53,
- 0x4a, 0x84, 0x50, 0x5f,
+ 0x04, 0x10, 0x91, 0x80, 0x8b, 0x84, 0x9d, 0x89,
+ 0x00, 0x08, 0x80, 0xa5, 0x00, 0x98, 0x00, 0x80,
+ 0xab, 0xb4, 0x91, 0x83, 0x93, 0x82, 0x9d, 0xaf,
+ 0x93, 0x08, 0x80, 0x40, 0xb7, 0xae, 0xa8, 0x83,
+ 0xa3, 0xaf, 0x93, 0x80, 0xba, 0xaa, 0x8c, 0x80,
+ 0xc6, 0x9a, 0xa4, 0x86, 0x40, 0xb8, 0xab, 0xf3,
+ 0xbf, 0x9e, 0x39, 0x01, 0x38, 0x08, 0x97, 0x8e,
+ 0x00, 0x80, 0xdd, 0x39, 0xa6, 0x8f, 0x00, 0x80,
+ 0x9b, 0x80, 0x89, 0xa7, 0x30, 0x94, 0x80, 0x8a,
+ 0xad, 0x92, 0x80, 0x91, 0xc8, 0x40, 0xc6, 0xa0,
+ 0x9e, 0x88, 0x80, 0xa4, 0x90, 0x80, 0xb0, 0x9d,
+ 0xef, 0x30, 0x08, 0xa5, 0x94, 0x80, 0x98, 0x28,
+ 0x08, 0x9f, 0x8d, 0x80, 0x41, 0x46, 0x92, 0x8e,
+ 0x00, 0x8c, 0x80, 0xa1, 0xfb, 0x80, 0xce, 0x43,
+ 0x99, 0xe5, 0xee, 0x90, 0x40, 0xc3, 0x4a, 0x4b,
+ 0xe0, 0x8e, 0x44, 0x2f, 0x90, 0x85, 0x98, 0x4f,
+ 0x9a, 0x84, 0x42, 0x46, 0x5a, 0xb8, 0x9d, 0x46,
+ 0xe1, 0x42, 0x38, 0x86, 0x9e, 0x90, 0xce, 0x90,
+ 0x9d, 0x91, 0xaf, 0x8f, 0x83, 0x9e, 0x94, 0x84,
+ 0x92, 0x41, 0xaf, 0xac, 0x40, 0xd2, 0xbf, 0xff,
+ 0xca, 0x20, 0xc1, 0x8c, 0xbf, 0x08, 0x80, 0x9b,
+ 0x57, 0xf7, 0x87, 0x44, 0xd5, 0xa8, 0x89, 0x60,
+ 0x22, 0xe6, 0x18, 0x30, 0x08, 0x41, 0x22, 0x8e,
+ 0x80, 0x9c, 0x11, 0x80, 0x8d, 0x1f, 0x41, 0x8b,
+ 0x49, 0x03, 0xea, 0x84, 0x8c, 0x82, 0x88, 0x86,
+ 0x89, 0x57, 0x65, 0xd4, 0x80, 0xc6, 0x01, 0x08,
+ 0x09, 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0,
+ 0x03, 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00,
+ 0x16, 0x80, 0x41, 0x53, 0x81, 0x98, 0x80, 0x98,
+ 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98,
+ 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98,
+ 0x07, 0x47, 0x33, 0x9e, 0x2d, 0x41, 0x04, 0xbd,
+ 0x40, 0x91, 0xac, 0x89, 0x86, 0x8f, 0x80, 0x41,
+ 0x40, 0x9d, 0x91, 0xab, 0x41, 0xe3, 0x9b, 0x40,
+ 0xe3, 0x9d, 0x08, 0x41, 0xee, 0x30, 0x18, 0x08,
+ 0x8e, 0x80, 0x40, 0xc4, 0xba, 0xc3, 0x30, 0x44,
+ 0xb3, 0x18, 0x9a, 0x01, 0x00, 0x08, 0x80, 0x89,
+ 0x03, 0x00, 0x00, 0x28, 0x18, 0x00, 0x00, 0x02,
+ 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00, 0x80, 0x89,
+ 0x80, 0x90, 0x22, 0x04, 0x80, 0x90, 0x51, 0x43,
+ 0x60, 0xa6, 0xdf, 0x9f, 0x50, 0x39, 0x85, 0x40,
+ 0xdd, 0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x8e,
+ 0x42, 0x6d, 0x49, 0xa1, 0x42, 0x1d, 0x45, 0xe1,
+ 0x53, 0x4a, 0x84, 0x50, 0x5f,
};
-static const uint8_t unicode_prop_ID_Start_index[105] = {
- 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, 0x34, 0x13, 0x01,
- 0x1b, 0x17, 0x21, 0x8a, 0x1a, 0x01, 0x34, 0x1f,
- 0x21, 0xbf, 0x6a, 0x01, 0x23, 0xb1, 0xa1, 0xad,
- 0xd4, 0x01, 0x6f, 0xd7, 0x01, 0xff, 0xe7, 0x61,
- 0x5e, 0xee, 0x01, 0xe1, 0xeb, 0x22, 0xb0, 0x23,
- 0x03,
+static const uint8_t unicode_prop_ID_Start_index[108] = {
+ 0xf6, 0x03, 0x20, // 003F6 at 33
+ 0xa6, 0x07, 0x00, // 007A6 at 64
+ 0xa9, 0x09, 0x20, // 009A9 at 97
+ 0xb1, 0x0a, 0x00, // 00AB1 at 128
+ 0xba, 0x0b, 0x20, // 00BBA at 161
+ 0x3b, 0x0d, 0x20, // 00D3B at 193
+ 0xc7, 0x0e, 0x20, // 00EC7 at 225
+ 0x49, 0x12, 0x00, // 01249 at 256
+ 0x9b, 0x16, 0x00, // 0169B at 288
+ 0xac, 0x19, 0x00, // 019AC at 320
+ 0xc0, 0x1d, 0x80, // 01DC0 at 356
+ 0x80, 0x20, 0x20, // 02080 at 385
+ 0x70, 0x2d, 0x00, // 02D70 at 416
+ 0x00, 0x32, 0x00, // 03200 at 448
+ 0xdd, 0xa7, 0x00, // 0A7DD at 480
+ 0x4c, 0xaa, 0x20, // 0AA4C at 513
+ 0xc7, 0xd7, 0x20, // 0D7C7 at 545
+ 0xfc, 0xfd, 0x20, // 0FDFC at 577
+ 0x9d, 0x02, 0x21, // 1029D at 609
+ 0x96, 0x05, 0x01, // 10596 at 640
+ 0x9f, 0x08, 0x01, // 1089F at 672
+ 0x49, 0x0c, 0x21, // 10C49 at 705
+ 0x76, 0x10, 0x21, // 11076 at 737
+ 0xa9, 0x12, 0x01, // 112A9 at 768
+ 0xb0, 0x14, 0x01, // 114B0 at 800
+ 0x42, 0x19, 0x41, // 11942 at 834
+ 0x90, 0x1c, 0x01, // 11C90 at 864
+ 0xf1, 0x2f, 0x21, // 12FF1 at 897
+ 0x90, 0x6b, 0x21, // 16B90 at 929
+ 0x33, 0xb1, 0x21, // 1B133 at 961
+ 0x06, 0xd5, 0x01, // 1D506 at 992
+ 0xc3, 0xd7, 0x01, // 1D7C3 at 1024
+ 0xff, 0xe7, 0x21, // 1E7FF at 1057
+ 0x63, 0xee, 0x01, // 1EE63 at 1088
+ 0x5e, 0xee, 0x42, // 2EE5E at 1122
+ 0xb0, 0x23, 0x03, // 323B0 at 1152 (upper bound)
};
-static const uint8_t unicode_prop_ID_Continue1_table[660] = {
+static const uint8_t unicode_prop_ID_Continue1_table[695] = {
0xaf, 0x89, 0xa4, 0x80, 0xd6, 0x80, 0x42, 0x47,
0xef, 0x96, 0x80, 0x40, 0xfa, 0x84, 0x41, 0x08,
0xac, 0x00, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xaf,
0x9e, 0x28, 0xe4, 0x31, 0x29, 0x08, 0x19, 0x89,
0x96, 0x80, 0x9d, 0x9a, 0xda, 0x8a, 0x8e, 0x89,
0xa0, 0x88, 0x88, 0x80, 0x97, 0x18, 0x88, 0x02,
- 0x04, 0xaa, 0x82, 0xbb, 0x87, 0xa9, 0x97, 0x80,
+ 0x04, 0xaa, 0x82, 0xba, 0x88, 0xa9, 0x97, 0x80,
0xa0, 0xb5, 0x10, 0x91, 0x06, 0x89, 0x09, 0x89,
0x90, 0x82, 0xb7, 0x00, 0x31, 0x09, 0x82, 0x88,
0x80, 0x89, 0x09, 0x89, 0x8d, 0x01, 0x82, 0xb7,
@@ -496,70 +546,88 @@ static const uint8_t unicode_prop_ID_Continue1_table[660] = {
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, 0xcf, 0x82, 0xc5, 0x8a,
- 0xb0, 0x83, 0xf9, 0x82, 0xb4, 0x8e, 0x9e, 0x8a,
- 0x09, 0x89, 0x83, 0xac, 0x8a, 0x30, 0xac, 0x89,
- 0x2a, 0xa3, 0x8d, 0x80, 0x89, 0x21, 0xab, 0x80,
- 0x8b, 0x82, 0xaf, 0x8d, 0x3b, 0x80, 0x8b, 0xd1,
- 0x8b, 0x28, 0x08, 0x40, 0x9c, 0x8b, 0x84, 0x89,
- 0x2b, 0xb6, 0x08, 0x31, 0x09, 0x82, 0x88, 0x80,
- 0x89, 0x09, 0x32, 0x84, 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, 0x88, 0x08, 0x80,
- 0xaf, 0x32, 0x84, 0x8c, 0x89, 0x54, 0xe5, 0x05,
- 0x8e, 0x60, 0x36, 0x09, 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, 0xe3,
- 0x80, 0x40, 0x9f, 0x86, 0x88, 0x89, 0x41, 0x63,
- 0x80, 0xbc, 0x8d, 0x41, 0xf1, 0x8d, 0x43, 0xd5,
- 0x86, 0xec, 0x34, 0x89, 0x52, 0x95, 0x89, 0x6c,
- 0x05, 0x05, 0x40, 0xef,
+ 0x28, 0x0a, 0x40, 0xc5, 0xbf, 0x42, 0x0b, 0x81,
+ 0xb0, 0x81, 0x92, 0x80, 0xfa, 0x8c, 0x18, 0x82,
+ 0x8b, 0x4b, 0xfd, 0x82, 0x40, 0x8c, 0x80, 0xdf,
+ 0x9f, 0x42, 0x29, 0x85, 0xe8, 0x81, 0xdf, 0x80,
+ 0x60, 0x75, 0x23, 0x89, 0xc4, 0x03, 0x89, 0x9f,
+ 0x81, 0xcf, 0x81, 0x41, 0x0f, 0x02, 0x03, 0x80,
+ 0x96, 0x23, 0x80, 0xd2, 0x81, 0xb1, 0x91, 0x89,
+ 0x89, 0x85, 0x91, 0x8c, 0x8a, 0x9b, 0x87, 0x98,
+ 0x8c, 0xab, 0x83, 0xae, 0x8d, 0x8e, 0x89, 0x8a,
+ 0x80, 0x89, 0x89, 0xae, 0x8d, 0x8b, 0x07, 0x09,
+ 0x89, 0xa0, 0x82, 0xb1, 0x00, 0x11, 0x0c, 0x08,
+ 0x80, 0xa8, 0x24, 0x81, 0x40, 0xeb, 0x38, 0x09,
+ 0x89, 0x60, 0x4f, 0x23, 0x80, 0x42, 0xe0, 0x8f,
+ 0x8f, 0x8f, 0x11, 0x97, 0x82, 0x40, 0xbf, 0x89,
+ 0xa4, 0x80, 0xa4, 0x80, 0x42, 0x96, 0x80, 0x40,
+ 0xe1, 0x80, 0x40, 0x94, 0x84, 0x41, 0x24, 0x89,
+ 0x45, 0x56, 0x10, 0x0c, 0x83, 0xa7, 0x13, 0x80,
+ 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x1f, 0x89, 0x85,
+ 0x89, 0x9e, 0x84, 0x41, 0x3c, 0x81, 0xce, 0x83,
+ 0xc5, 0x8a, 0xb0, 0x83, 0xf9, 0x82, 0xb4, 0x8e,
+ 0x9e, 0x8a, 0x09, 0x89, 0x83, 0xac, 0x8a, 0x30,
+ 0xac, 0x89, 0x2a, 0xa3, 0x8d, 0x80, 0x89, 0x21,
+ 0xab, 0x80, 0x8b, 0x82, 0xaf, 0x8d, 0x3b, 0x80,
+ 0x8b, 0xd1, 0x8b, 0x28, 0x08, 0x40, 0x9c, 0x8b,
+ 0x84, 0x89, 0x2b, 0xb6, 0x08, 0x31, 0x09, 0x82,
+ 0x88, 0x80, 0x89, 0x09, 0x32, 0x84, 0xc2, 0x88,
+ 0x00, 0x08, 0x03, 0x04, 0x00, 0x8d, 0x81, 0xd1,
+ 0x91, 0x88, 0x89, 0x18, 0xd0, 0x93, 0x8b, 0x89,
+ 0x40, 0xd4, 0x31, 0x88, 0x9a, 0x81, 0xd1, 0x90,
+ 0x8e, 0x89, 0xd0, 0x8c, 0x87, 0x89, 0x85, 0x93,
+ 0xb8, 0x8e, 0x83, 0x89, 0x40, 0xf1, 0x8e, 0x40,
+ 0xa4, 0x89, 0xc5, 0x28, 0x09, 0x18, 0x00, 0x81,
+ 0x8b, 0x89, 0xf6, 0x31, 0x32, 0x80, 0x9b, 0x89,
+ 0xa7, 0x30, 0x1f, 0x80, 0x88, 0x8a, 0xad, 0x8f,
+ 0x41, 0x55, 0x89, 0xb4, 0x38, 0x87, 0x8f, 0x89,
+ 0xb7, 0x95, 0x80, 0x8d, 0xf9, 0x2a, 0x00, 0x08,
+ 0x30, 0x07, 0x89, 0xaf, 0x20, 0x08, 0x27, 0x89,
+ 0x41, 0x48, 0x83, 0x88, 0x08, 0x80, 0xaf, 0x32,
+ 0x84, 0x8c, 0x8a, 0x54, 0xe4, 0x05, 0x8e, 0x60,
+ 0x2c, 0xc7, 0x9b, 0x49, 0x25, 0x89, 0xd5, 0x89,
+ 0xa5, 0x84, 0xba, 0x86, 0x98, 0x89, 0x42, 0x15,
+ 0x89, 0x41, 0xd4, 0x00, 0xb6, 0x33, 0xd0, 0x80,
+ 0x8a, 0x81, 0x60, 0x4c, 0xaa, 0x81, 0x50, 0x50,
+ 0x89, 0x42, 0x05, 0xad, 0x81, 0x96, 0x42, 0x1d,
+ 0x22, 0x2f, 0x39, 0x86, 0x9d, 0x83, 0x40, 0x93,
+ 0x82, 0x45, 0x88, 0xb1, 0x41, 0xff, 0xb6, 0x83,
+ 0xb1, 0x38, 0x8d, 0x80, 0x95, 0x20, 0x8e, 0x45,
+ 0x4f, 0x30, 0x90, 0x0e, 0x01, 0x04, 0xe3, 0x80,
+ 0x40, 0x9f, 0x86, 0x88, 0x89, 0x41, 0x63, 0x80,
+ 0xbc, 0x8d, 0x41, 0xf1, 0x8d, 0x40, 0xf3, 0x08,
+ 0x89, 0x42, 0xd4, 0x86, 0xec, 0x34, 0x89, 0x52,
+ 0x95, 0x89, 0x6c, 0x05, 0x05, 0x40, 0xef,
};
-static const uint8_t unicode_prop_ID_Continue1_index[63] = {
- 0xfa, 0x06, 0x00, 0x70, 0x09, 0x00, 0xf0, 0x0a,
- 0x40, 0x57, 0x0c, 0x00, 0xf0, 0x0d, 0x60, 0xc7,
- 0x0f, 0x20, 0xea, 0x17, 0x40, 0x05, 0x1b, 0x00,
- 0x41, 0x20, 0x00, 0x0c, 0xa8, 0x80, 0x37, 0xaa,
- 0x20, 0x50, 0xfe, 0x20, 0x3a, 0x0d, 0x21, 0x74,
- 0x11, 0x01, 0x5a, 0x14, 0x21, 0x44, 0x19, 0x81,
- 0x5a, 0x1d, 0xa1, 0xf5, 0x6a, 0x21, 0x45, 0xd2,
- 0x41, 0xaf, 0xe2, 0x21, 0xf0, 0x01, 0x0e,
+static const uint8_t unicode_prop_ID_Continue1_index[66] = {
+ 0xfa, 0x06, 0x00, // 006FA at 32
+ 0x70, 0x09, 0x00, // 00970 at 64
+ 0xf0, 0x0a, 0x40, // 00AF0 at 98
+ 0x57, 0x0c, 0x00, // 00C57 at 128
+ 0xf0, 0x0d, 0x60, // 00DF0 at 163
+ 0xc7, 0x0f, 0x20, // 00FC7 at 193
+ 0xea, 0x17, 0x40, // 017EA at 226
+ 0x05, 0x1b, 0x00, // 01B05 at 256
+ 0x0e, 0x20, 0x00, // 0200E at 288
+ 0xa0, 0xa6, 0x20, // 0A6A0 at 321
+ 0xe6, 0xa9, 0x20, // 0A9E6 at 353
+ 0x10, 0xfe, 0x00, // 0FE10 at 384
+ 0x40, 0x0a, 0x01, // 10A40 at 416
+ 0xc3, 0x10, 0x01, // 110C3 at 448
+ 0x4e, 0x13, 0x01, // 1134E at 480
+ 0x41, 0x16, 0x01, // 11641 at 512
+ 0x0b, 0x1a, 0x01, // 11A0B at 544
+ 0xaa, 0x1d, 0x01, // 11DAA at 576
+ 0x7a, 0x6d, 0x21, // 16D7A at 609
+ 0x45, 0xd2, 0x21, // 1D245 at 641
+ 0xaf, 0xe2, 0x01, // 1E2AF at 672
+ 0xf0, 0x01, 0x0e, // E01F0 at 704 (upper bound)
};
#ifdef CONFIG_ALL_UNICODE
-static const uint8_t unicode_cc_table[899] = {
+static const uint8_t unicode_cc_table[916] = {
0xb2, 0xcf, 0xd4, 0x00, 0xe8, 0x03, 0xdc, 0x00,
0xe8, 0x00, 0xd8, 0x04, 0xdc, 0x01, 0xca, 0x03,
0xdc, 0x01, 0xca, 0x0a, 0xdc, 0x04, 0x01, 0x03,
@@ -583,7 +651,7 @@ static const uint8_t unicode_cc_table[899] = {
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,
+ 0xaa, 0x02, 0xdc, 0xb0, 0x0a, 0xc1, 0x02, 0xdc,
0xc3, 0xa9, 0xc4, 0x04, 0xdc, 0xcd, 0x80, 0x00,
0xdc, 0xc1, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xc2,
0x02, 0xdc, 0x42, 0x1b, 0xc2, 0x00, 0xdc, 0xc1,
@@ -641,55 +709,75 @@ static const uint8_t unicode_cc_table[899] = {
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, 0x1f, 0x02, 0xdc, 0xb0, 0x15,
- 0x01, 0xdc, 0xc2, 0x00, 0xdc, 0xc0, 0x03, 0xdc,
- 0xb0, 0x00, 0xc0, 0x00, 0xdc, 0xc0, 0x00, 0xdc,
- 0xb0, 0x8f, 0x00, 0x09, 0xa8, 0x00, 0x09, 0x8d,
- 0x00, 0x09, 0xb0, 0x08, 0x00, 0x09, 0x00, 0x07,
- 0xb0, 0x14, 0xc2, 0xaf, 0x01, 0x09, 0xb0, 0x0d,
- 0x00, 0x07, 0xb0, 0x1b, 0x00, 0x09, 0x88, 0x00,
- 0x07, 0xb0, 0x39, 0x00, 0x09, 0x00, 0x07, 0xb0,
- 0x81, 0x00, 0x07, 0x00, 0x09, 0xb0, 0x1f, 0x01,
- 0x07, 0x8f, 0x00, 0x09, 0x97, 0xc6, 0x82, 0xc4,
- 0xb0, 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, 0xb1, 0x78,
- 0x01, 0x09, 0xb8, 0x43, 0x7c, 0x04, 0x01, 0xb0,
- 0x0a, 0xc6, 0xb4, 0x88, 0x01, 0x06, 0xb8, 0x44,
- 0x7b, 0x00, 0x01, 0xb8, 0x0c, 0x95, 0x01, 0xd8,
- 0x02, 0x01, 0x82, 0x00, 0xe2, 0x04, 0xd8, 0x87,
- 0x07, 0xdc, 0x81, 0xc4, 0x01, 0xdc, 0x9d, 0xc3,
- 0xb0, 0x63, 0xc2, 0xb8, 0x05, 0x8a, 0xc6, 0x80,
- 0xd0, 0x81, 0xc6, 0x80, 0xc1, 0x80, 0xc4, 0xb0,
- 0x33, 0xc0, 0xb0, 0x6f, 0xc6, 0xb1, 0x46, 0xc0,
- 0xb0, 0x0c, 0xc3, 0xb1, 0xcb, 0x01, 0xe8, 0x00,
- 0xdc, 0xc0, 0xb3, 0xaf, 0x06, 0xdc, 0xb0, 0x3c,
- 0xc5, 0x00, 0x07,
+ 0x74, 0xc0, 0x00, 0xdc, 0xb2, 0x0c, 0xc3, 0xb0,
+ 0x10, 0xc4, 0xb1, 0x0c, 0xc1, 0xb0, 0x1f, 0x02,
+ 0xdc, 0xb0, 0x15, 0x01, 0xdc, 0xc2, 0x00, 0xdc,
+ 0xc0, 0x03, 0xdc, 0xb0, 0x00, 0xc0, 0x00, 0xdc,
+ 0xc0, 0x00, 0xdc, 0xb0, 0x8f, 0x00, 0x09, 0xa8,
+ 0x00, 0x09, 0x8d, 0x00, 0x09, 0xb0, 0x08, 0x00,
+ 0x09, 0x00, 0x07, 0xb0, 0x14, 0xc2, 0xaf, 0x01,
+ 0x09, 0xb0, 0x0d, 0x00, 0x07, 0xb0, 0x1b, 0x00,
+ 0x09, 0x88, 0x00, 0x07, 0xb0, 0x39, 0x00, 0x09,
+ 0x00, 0x07, 0xb0, 0x81, 0x00, 0x07, 0x00, 0x09,
+ 0xb0, 0x1f, 0x01, 0x07, 0x8f, 0x00, 0x09, 0x97,
+ 0xc6, 0x82, 0xc4, 0xb0, 0x28, 0x02, 0x09, 0xb0,
+ 0x40, 0x00, 0x09, 0x82, 0x00, 0x07, 0x96, 0xc0,
+ 0xb0, 0x32, 0x00, 0x09, 0x00, 0x07, 0xb0, 0xca,
+ 0x00, 0x09, 0x00, 0x07, 0xb0, 0x4d, 0x00, 0x09,
+ 0xb0, 0x45, 0x00, 0x09, 0x00, 0x07, 0xb0, 0x42,
+ 0x00, 0x09, 0xb0, 0xdc, 0x00, 0x09, 0x00, 0x07,
+ 0xb0, 0xd1, 0x01, 0x09, 0x83, 0x00, 0x07, 0xb0,
+ 0x6b, 0x00, 0x09, 0xb0, 0x22, 0x00, 0x09, 0x91,
+ 0x00, 0x09, 0xb0, 0x20, 0x00, 0x09, 0xb1, 0x74,
+ 0x00, 0x09, 0xb0, 0xd1, 0x00, 0x07, 0x80, 0x01,
+ 0x09, 0xb0, 0x20, 0x00, 0x09, 0xb1, 0x78, 0x01,
+ 0x09, 0xb8, 0x39, 0xbb, 0x00, 0x09, 0xb8, 0x01,
+ 0x8f, 0x04, 0x01, 0xb0, 0x0a, 0xc6, 0xb4, 0x88,
+ 0x01, 0x06, 0xb8, 0x44, 0x7b, 0x00, 0x01, 0xb8,
+ 0x0c, 0x95, 0x01, 0xd8, 0x02, 0x01, 0x82, 0x00,
+ 0xe2, 0x04, 0xd8, 0x87, 0x07, 0xdc, 0x81, 0xc4,
+ 0x01, 0xdc, 0x9d, 0xc3, 0xb0, 0x63, 0xc2, 0xb8,
+ 0x05, 0x8a, 0xc6, 0x80, 0xd0, 0x81, 0xc6, 0x80,
+ 0xc1, 0x80, 0xc4, 0xb0, 0x33, 0xc0, 0xb0, 0x6f,
+ 0xc6, 0xb1, 0x46, 0xc0, 0xb0, 0x0c, 0xc3, 0xb1,
+ 0xcb, 0x01, 0xe8, 0x00, 0xdc, 0xc0, 0xb0, 0xcd,
+ 0xc0, 0x00, 0xdc, 0xb2, 0xaf, 0x06, 0xdc, 0xb0,
+ 0x3c, 0xc5, 0x00, 0x07,
};
static const uint8_t unicode_cc_index[87] = {
- 0x4d, 0x03, 0x00, 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, 0x51, 0x0f, 0x01, 0x73,
- 0x11, 0x01, 0x75, 0x13, 0x01, 0x2b, 0x17, 0x21,
- 0x3f, 0x1c, 0x21, 0x9e, 0xbc, 0x21, 0x08, 0xe0,
- 0x01, 0x44, 0xe9, 0x01, 0x4b, 0xe9, 0x01,
+ 0x4d, 0x03, 0x00, // 0034D at 32
+ 0x97, 0x05, 0x20, // 00597 at 65
+ 0xc6, 0x05, 0x00, // 005C6 at 96
+ 0xe7, 0x06, 0x00, // 006E7 at 128
+ 0x45, 0x07, 0x00, // 00745 at 160
+ 0x9c, 0x08, 0x00, // 0089C at 192
+ 0x4d, 0x09, 0x00, // 0094D at 224
+ 0x3c, 0x0b, 0x00, // 00B3C at 256
+ 0x3d, 0x0d, 0x00, // 00D3D at 288
+ 0x36, 0x0f, 0x00, // 00F36 at 320
+ 0x38, 0x10, 0x20, // 01038 at 353
+ 0x3a, 0x19, 0x00, // 0193A at 384
+ 0xcb, 0x1a, 0x20, // 01ACB at 417
+ 0xd3, 0x1c, 0x00, // 01CD3 at 448
+ 0xcf, 0x1d, 0x00, // 01DCF at 480
+ 0xe2, 0x20, 0x00, // 020E2 at 512
+ 0x2e, 0x30, 0x20, // 0302E at 545
+ 0x2b, 0xa9, 0x20, // 0A92B at 577
+ 0xed, 0xab, 0x00, // 0ABED at 608
+ 0x39, 0x0a, 0x01, // 10A39 at 640
+ 0x4c, 0x0f, 0x01, // 10F4C at 672
+ 0x35, 0x11, 0x21, // 11135 at 705
+ 0x66, 0x13, 0x01, // 11366 at 736
+ 0x40, 0x16, 0x01, // 11640 at 768
+ 0x47, 0x1a, 0x01, // 11A47 at 800
+ 0xf0, 0x6a, 0x21, // 16AF0 at 833
+ 0x8a, 0xd1, 0x01, // 1D18A at 864
+ 0xec, 0xe4, 0x21, // 1E4EC at 897
+ 0x4b, 0xe9, 0x01, // 1E94B at 928 (upper bound)
};
-static const uint32_t unicode_decomp_table1[699] = {
+static const uint32_t unicode_decomp_table1[709] = {
0x00280081, 0x002a0097, 0x002a8081, 0x002bc097,
0x002c8115, 0x002d0097, 0x002d4081, 0x002e0097,
0x002e4115, 0x002f0199, 0x00302016, 0x00400842,
@@ -832,42 +920,45 @@ static const uint32_t unicode_decomp_table1[699] = {
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, 0x780c049f, 0x780e419f,
- 0x780f059f, 0x7811c203, 0x7812d0ad, 0x781b0103,
- 0x7b80022d, 0x7b814dad, 0x7b884203, 0x7b89c081,
- 0x7b8a452d, 0x7b8d0403, 0x7b908081, 0x7b91dc03,
- 0x7ba0052d, 0x7ba2c8ad, 0x7ba84483, 0x7baac8ad,
- 0x7c400097, 0x7c404521, 0x7c440d25, 0x7c4a8087,
- 0x7c4ac115, 0x7c4b4117, 0x7c4c0d1f, 0x7c528217,
- 0x7c538099, 0x7c53c097, 0x7c5a8197, 0x7c640097,
- 0x7c80012f, 0x7c808081, 0x7c841603, 0x7c9004c1,
- 0x7c940103, 0x7efc051f, 0xbe0001ac, 0xbe00d110,
- 0xbe0947ac, 0xbe0d3910, 0xbe29872c, 0xbe2d022c,
- 0xbe2e3790, 0xbe49ff90, 0xbe69bc10,
+ 0x3ff4831f, 0x3ff6819f, 0x3ff80783, 0x41724092,
+ 0x41790092, 0x41e04d83, 0x41e70f91, 0x44268192,
+ 0x442ac092, 0x444b8112, 0x44d2c112, 0x44e0c192,
+ 0x44e38092, 0x44e44092, 0x44f14212, 0x452ec212,
+ 0x456e8112, 0x464e0092, 0x58484412, 0x5b5a0192,
+ 0x73358d1f, 0x733c051f, 0x74578392, 0x746ec312,
+ 0x75000d1f, 0x75068d1f, 0x750d0d1f, 0x7513839f,
+ 0x7515891f, 0x751a0d1f, 0x75208d1f, 0x75271015,
+ 0x752f439f, 0x7531459f, 0x75340d1f, 0x753a8d1f,
+ 0x75410395, 0x7543441f, 0x7545839f, 0x75478d1f,
+ 0x754e0795, 0x7552839f, 0x75548d1f, 0x755b0d1f,
+ 0x75618d1f, 0x75680d1f, 0x756e8d1f, 0x75750d1f,
+ 0x757b8d1f, 0x75820d1f, 0x75888d1f, 0x758f0d1f,
+ 0x75958d1f, 0x759c0d1f, 0x75a28d1f, 0x75a90103,
+ 0x75aa089f, 0x75ae4081, 0x75ae839f, 0x75b04081,
+ 0x75b08c9f, 0x75b6c081, 0x75b7032d, 0x75b8889f,
+ 0x75bcc081, 0x75bd039f, 0x75bec081, 0x75bf0c9f,
+ 0x75c54081, 0x75c5832d, 0x75c7089f, 0x75cb4081,
+ 0x75cb839f, 0x75cd4081, 0x75cd8c9f, 0x75d3c081,
+ 0x75d4032d, 0x75d5889f, 0x75d9c081, 0x75da039f,
+ 0x75dbc081, 0x75dc0c9f, 0x75e24081, 0x75e2832d,
+ 0x75e4089f, 0x75e84081, 0x75e8839f, 0x75ea4081,
+ 0x75ea8c9f, 0x75f0c081, 0x75f1042d, 0x75f3851f,
+ 0x75f6051f, 0x75f8851f, 0x75fb051f, 0x75fd851f,
+ 0x780c049f, 0x780e419f, 0x780f059f, 0x7811c203,
+ 0x7812d0ad, 0x781b0103, 0x7b80022d, 0x7b814dad,
+ 0x7b884203, 0x7b89c081, 0x7b8a452d, 0x7b8d0403,
+ 0x7b908081, 0x7b91dc03, 0x7ba0052d, 0x7ba2c8ad,
+ 0x7ba84483, 0x7baac8ad, 0x7c400097, 0x7c404521,
+ 0x7c440d25, 0x7c4a8087, 0x7c4ac115, 0x7c4b4117,
+ 0x7c4c0d1f, 0x7c528217, 0x7c538099, 0x7c53c097,
+ 0x7c5a8197, 0x7c640097, 0x7c80012f, 0x7c808081,
+ 0x7c841603, 0x7c9004c1, 0x7c940103, 0x7efc051f,
+ 0xbe0001ac, 0xbe00d110, 0xbe0947ac, 0xbe0d3910,
+ 0xbe29872c, 0xbe2d022c, 0xbe2e3790, 0xbe49ff90,
+ 0xbe69bc10,
};
-static const uint16_t unicode_decomp_table2[699] = {
+static const uint16_t unicode_decomp_table2[709] = {
0x0020, 0x0000, 0x0061, 0x0002, 0x0004, 0x0006, 0x03bc, 0x0008,
0x000a, 0x000c, 0x0015, 0x0095, 0x00a5, 0x00b9, 0x00c1, 0x00c3,
0x00c7, 0x00cb, 0x00d1, 0x00d7, 0x00dd, 0x00e0, 0x00e6, 0x00f8,
@@ -939,26 +1030,27 @@ static const uint16_t unicode_decomp_table2[699] = {
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, 0x1e0a,
- 0x1e0c, 0x1e0e, 0x1e16, 0x1e39, 0x1e3d, 0x1e43, 0x1e60, 0x062d,
- 0x1e68, 0x1e74, 0x062c, 0x1e84, 0x1ef4, 0x1f00, 0x1f13, 0x1f25,
- 0x1f38, 0x1f3a, 0x1f3e, 0x1f44, 0x1f4a, 0x1f4c, 0x1f50, 0x1f52,
- 0x1f5a, 0x1f5d, 0x1f5f, 0x1f65, 0x1f67, 0x30b5, 0x1f6d, 0x1fc5,
- 0x1fdb, 0x1fdf, 0x1fe1, 0x1fe6, 0x2033, 0x2044, 0x2145, 0x2155,
- 0x215b, 0x2255, 0x2373,
+ 0x1c26, 0x1c28, 0x1c2a, 0x1c48, 0x1c4d, 0x1c52, 0x1c88, 0x1cce,
+ 0x1cdc, 0x1ce1, 0x1cea, 0x1cf3, 0x1d01, 0x1d06, 0x1d0b, 0x1d1d,
+ 0x1d2f, 0x1d38, 0x1d3d, 0x1d61, 0x1d6f, 0x1d71, 0x1d73, 0x1d93,
+ 0x1dae, 0x1db0, 0x1db2, 0x1db4, 0x1db6, 0x1db8, 0x1dba, 0x1dbc,
+ 0x1ddc, 0x1dde, 0x1de0, 0x1de2, 0x1de4, 0x1deb, 0x1ded, 0x1def,
+ 0x1df1, 0x1e00, 0x1e02, 0x1e04, 0x1e06, 0x1e08, 0x1e0a, 0x1e0c,
+ 0x1e0e, 0x1e10, 0x1e12, 0x1e14, 0x1e16, 0x1e18, 0x1e1a, 0x1e1c,
+ 0x1e20, 0x03f4, 0x1e22, 0x2207, 0x1e24, 0x2202, 0x1e26, 0x1e2e,
+ 0x03f4, 0x1e30, 0x2207, 0x1e32, 0x2202, 0x1e34, 0x1e3c, 0x03f4,
+ 0x1e3e, 0x2207, 0x1e40, 0x2202, 0x1e42, 0x1e4a, 0x03f4, 0x1e4c,
+ 0x2207, 0x1e4e, 0x2202, 0x1e50, 0x1e58, 0x03f4, 0x1e5a, 0x2207,
+ 0x1e5c, 0x2202, 0x1e5e, 0x1e68, 0x1e6a, 0x1e6c, 0x1e6e, 0x1e70,
+ 0x1e72, 0x1e74, 0x1e76, 0x1e78, 0x1e80, 0x1ea3, 0x1ea7, 0x1ead,
+ 0x1eca, 0x062d, 0x1ed2, 0x1ede, 0x062c, 0x1eee, 0x1f5e, 0x1f6a,
+ 0x1f7d, 0x1f8f, 0x1fa2, 0x1fa4, 0x1fa8, 0x1fae, 0x1fb4, 0x1fb6,
+ 0x1fba, 0x1fbc, 0x1fc4, 0x1fc7, 0x1fc9, 0x1fcf, 0x1fd1, 0x30b5,
+ 0x1fd7, 0x202f, 0x2045, 0x2049, 0x204b, 0x2050, 0x209d, 0x20ae,
+ 0x21af, 0x21bf, 0x21c5, 0x22bf, 0x23dd,
};
-static const uint8_t unicode_decomp_data[9345] = {
+static const uint8_t unicode_decomp_data[9451] = {
0x20, 0x88, 0x20, 0x84, 0x32, 0x33, 0x20, 0x81,
0x20, 0xa7, 0x31, 0x6f, 0x31, 0xd0, 0x34, 0x31,
0xd0, 0x32, 0x33, 0xd0, 0x34, 0x41, 0x80, 0x41,
@@ -1864,273 +1956,286 @@ static const uint8_t unicode_decomp_data[9345] = {
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,
+ 0xd2, 0x05, 0x07, 0x03, 0x01, 0xda, 0x05, 0x07,
+ 0x03, 0x01, 0xd0, 0x02, 0xd1, 0x02, 0xe6, 0x00,
+ 0x99, 0x02, 0x53, 0x02, 0x00, 0x00, 0xa3, 0x02,
+ 0x66, 0xab, 0xa5, 0x02, 0xa4, 0x02, 0x56, 0x02,
+ 0x57, 0x02, 0x91, 0x1d, 0x58, 0x02, 0x5e, 0x02,
+ 0xa9, 0x02, 0x64, 0x02, 0x62, 0x02, 0x60, 0x02,
+ 0x9b, 0x02, 0x27, 0x01, 0x9c, 0x02, 0x67, 0x02,
+ 0x84, 0x02, 0xaa, 0x02, 0xab, 0x02, 0x6c, 0x02,
+ 0x04, 0xdf, 0x8e, 0xa7, 0x6e, 0x02, 0x05, 0xdf,
+ 0x8e, 0x02, 0x06, 0xdf, 0xf8, 0x00, 0x76, 0x02,
+ 0x77, 0x02, 0x71, 0x00, 0x7a, 0x02, 0x08, 0xdf,
+ 0x7d, 0x02, 0x7e, 0x02, 0x80, 0x02, 0xa8, 0x02,
+ 0xa6, 0x02, 0x67, 0xab, 0xa7, 0x02, 0x88, 0x02,
+ 0x71, 0x2c, 0x00, 0x00, 0x8f, 0x02, 0xa1, 0x02,
+ 0xa2, 0x02, 0x98, 0x02, 0xc0, 0x01, 0xc1, 0x01,
+ 0xc2, 0x01, 0x0a, 0xdf, 0x1e, 0xdf, 0x41, 0x04,
+ 0x40, 0x00, 0x00, 0x00, 0x00, 0x14, 0x99, 0x10,
+ 0xba, 0x10, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x10,
+ 0xba, 0x10, 0x05, 0x05, 0xa5, 0x10, 0xba, 0x10,
+ 0x05, 0x31, 0x11, 0x27, 0x11, 0x32, 0x11, 0x27,
+ 0x11, 0x55, 0x47, 0x13, 0x3e, 0x13, 0x47, 0x13,
+ 0x57, 0x13, 0x55, 0x82, 0x13, 0xc9, 0x13, 0x00,
+ 0x00, 0x00, 0x00, 0x84, 0x13, 0xbb, 0x13, 0x05,
+ 0x05, 0x8b, 0x13, 0xc2, 0x13, 0x05, 0x90, 0x13,
+ 0xc9, 0x13, 0x05, 0xc2, 0x13, 0xc2, 0x13, 0x00,
+ 0x00, 0x00, 0x00, 0xc2, 0x13, 0xb8, 0x13, 0xc2,
+ 0x13, 0xc9, 0x13, 0x05, 0x55, 0xb9, 0x14, 0xba,
+ 0x14, 0xb9, 0x14, 0xb0, 0x14, 0x00, 0x00, 0x00,
+ 0x00, 0xb9, 0x14, 0xbd, 0x14, 0x55, 0x50, 0xb8,
+ 0x15, 0xaf, 0x15, 0xb9, 0x15, 0xaf, 0x15, 0x55,
+ 0x35, 0x19, 0x30, 0x19, 0x05, 0x1e, 0x61, 0x1e,
+ 0x61, 0x1e, 0x61, 0x29, 0x61, 0x1e, 0x61, 0x1f,
+ 0x61, 0x29, 0x61, 0x1f, 0x61, 0x1e, 0x61, 0x20,
+ 0x61, 0x21, 0x61, 0x1f, 0x61, 0x22, 0x61, 0x1f,
+ 0x61, 0x21, 0x61, 0x20, 0x61, 0x55, 0x55, 0x55,
+ 0x55, 0x67, 0x6d, 0x67, 0x6d, 0x63, 0x6d, 0x67,
+ 0x6d, 0x69, 0x6d, 0x67, 0x6d, 0x55, 0x05, 0x41,
+ 0x00, 0x30, 0x00, 0x57, 0xd1, 0x65, 0xd1, 0x58,
+ 0xd1, 0x65, 0xd1, 0x5f, 0xd1, 0x6e, 0xd1, 0x5f,
+ 0xd1, 0x6f, 0xd1, 0x5f, 0xd1, 0x70, 0xd1, 0x5f,
+ 0xd1, 0x71, 0xd1, 0x5f, 0xd1, 0x72, 0xd1, 0x55,
+ 0x55, 0x55, 0x05, 0xb9, 0xd1, 0x65, 0xd1, 0xba,
+ 0xd1, 0x65, 0xd1, 0xbb, 0xd1, 0x6e, 0xd1, 0xbc,
+ 0xd1, 0x6e, 0xd1, 0xbb, 0xd1, 0x6f, 0xd1, 0xbc,
+ 0xd1, 0x6f, 0xd1, 0x55, 0x55, 0x55, 0x41, 0x00,
+ 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x69, 0x00,
+ 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x43, 0x44,
+ 0x00, 0x00, 0x47, 0x00, 0x00, 0x4a, 0x4b, 0x00,
+ 0x00, 0x4e, 0x4f, 0x50, 0x51, 0x00, 0x53, 0x54,
+ 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62,
+ 0x63, 0x64, 0x00, 0x66, 0x68, 0x00, 0x70, 0x00,
+ 0x41, 0x00, 0x61, 0x00, 0x41, 0x42, 0x00, 0x44,
+ 0x45, 0x46, 0x47, 0x4a, 0x00, 0x53, 0x00, 0x61,
+ 0x00, 0x41, 0x42, 0x00, 0x44, 0x45, 0x46, 0x47,
+ 0x00, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x00, 0x4f,
+ 0x53, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00,
+ 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00,
+ 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00,
+ 0x41, 0x00, 0x61, 0x00, 0x31, 0x01, 0x37, 0x02,
+ 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03,
+ 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x91, 0x03,
0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00,
0x1f, 0x04, 0x20, 0x05, 0x91, 0x03, 0xa3, 0x03,
0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00, 0x1f, 0x04,
0x20, 0x05, 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03,
0xd1, 0x03, 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05,
0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03,
- 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x91, 0x03,
- 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00,
- 0x1f, 0x04, 0x20, 0x05, 0x0b, 0x0c, 0x30, 0x00,
+ 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x0b, 0x0c,
0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00,
- 0x30, 0x04, 0x3a, 0x04, 0x3e, 0x04, 0x4b, 0x04,
- 0x4d, 0x04, 0x4e, 0x04, 0x89, 0xa6, 0x30, 0x04,
- 0xa9, 0x26, 0x28, 0xb9, 0x7f, 0x9f, 0x00, 0x01,
- 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0a,
- 0x0b, 0x0e, 0x0f, 0x11, 0x13, 0x14, 0x15, 0x16,
- 0x17, 0x18, 0x1a, 0x1b, 0x61, 0x26, 0x25, 0x2f,
- 0x7b, 0x51, 0xa6, 0xb1, 0x04, 0x27, 0x06, 0x00,
- 0x01, 0x05, 0x08, 0x2a, 0x06, 0x1e, 0x08, 0x03,
- 0x0d, 0x20, 0x19, 0x1a, 0x1b, 0x1c, 0x09, 0x0f,
- 0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00, 0x01, 0x04,
- 0x06, 0x0c, 0x0e, 0x10, 0x44, 0x90, 0x77, 0x45,
- 0x28, 0x06, 0x2c, 0x06, 0x00, 0x00, 0x47, 0x06,
- 0x33, 0x06, 0x17, 0x10, 0x11, 0x12, 0x13, 0x00,
- 0x06, 0x0e, 0x02, 0x0f, 0x34, 0x06, 0x2a, 0x06,
- 0x2b, 0x06, 0x2e, 0x06, 0x00, 0x00, 0x36, 0x06,
- 0x00, 0x00, 0x3a, 0x06, 0x2d, 0x06, 0x00, 0x00,
- 0x4a, 0x06, 0x00, 0x00, 0x44, 0x06, 0x00, 0x00,
- 0x46, 0x06, 0x33, 0x06, 0x39, 0x06, 0x00, 0x00,
- 0x35, 0x06, 0x42, 0x06, 0x00, 0x00, 0x34, 0x06,
- 0x00, 0x00, 0x00, 0x00, 0x2e, 0x06, 0x00, 0x00,
- 0x36, 0x06, 0x00, 0x00, 0x3a, 0x06, 0x00, 0x00,
- 0xba, 0x06, 0x00, 0x00, 0x6f, 0x06, 0x00, 0x00,
- 0x28, 0x06, 0x2c, 0x06, 0x00, 0x00, 0x47, 0x06,
- 0x00, 0x00, 0x00, 0x00, 0x2d, 0x06, 0x37, 0x06,
- 0x4a, 0x06, 0x43, 0x06, 0x00, 0x00, 0x45, 0x06,
- 0x46, 0x06, 0x33, 0x06, 0x39, 0x06, 0x41, 0x06,
- 0x35, 0x06, 0x42, 0x06, 0x00, 0x00, 0x34, 0x06,
+ 0x30, 0x00, 0x30, 0x04, 0x3a, 0x04, 0x3e, 0x04,
+ 0x4b, 0x04, 0x4d, 0x04, 0x4e, 0x04, 0x89, 0xa6,
+ 0x30, 0x04, 0xa9, 0x26, 0x28, 0xb9, 0x7f, 0x9f,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x0a, 0x0b, 0x0e, 0x0f, 0x11, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x61, 0x26,
+ 0x25, 0x2f, 0x7b, 0x51, 0xa6, 0xb1, 0x04, 0x27,
+ 0x06, 0x00, 0x01, 0x05, 0x08, 0x2a, 0x06, 0x1e,
+ 0x08, 0x03, 0x0d, 0x20, 0x19, 0x1a, 0x1b, 0x1c,
+ 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00,
+ 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, 0x44, 0x90,
+ 0x77, 0x45, 0x28, 0x06, 0x2c, 0x06, 0x00, 0x00,
+ 0x47, 0x06, 0x33, 0x06, 0x17, 0x10, 0x11, 0x12,
+ 0x13, 0x00, 0x06, 0x0e, 0x02, 0x0f, 0x34, 0x06,
0x2a, 0x06, 0x2b, 0x06, 0x2e, 0x06, 0x00, 0x00,
- 0x36, 0x06, 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,
+ 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] = {
+static const uint16_t unicode_comp_table[965] = {
0x4a01, 0x49c0, 0x4a02, 0x0280, 0x0281, 0x0282, 0x0283, 0x02c0,
0x02c2, 0x0a00, 0x0284, 0x2442, 0x0285, 0x07c0, 0x0980, 0x0982,
0x2440, 0x2280, 0x02c4, 0x2282, 0x2284, 0x2286, 0x02c6, 0x02c8,
@@ -2247,9 +2352,11 @@ static const uint16_t unicode_comp_table[945] = {
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,
+ 0x5901, 0x5902, 0x5903, 0x5940, 0x8ec0, 0x8f00, 0x8fc0, 0x8fc2,
+ 0x9000, 0x9040, 0x9041, 0x9080, 0x9081, 0x90c0, 0x90c2, 0x9100,
+ 0x9140, 0x9182, 0x9180, 0x9183, 0x91c1, 0x91c0, 0x91c3, 0x9200,
+ 0x9201, 0x9240, 0x9280, 0x9282, 0x9284, 0x9281, 0x9285, 0x9287,
+ 0x9286, 0x9283, 0x92c1, 0x92c0, 0x92c2,
};
typedef enum {
@@ -2335,7 +2442,7 @@ static const char unicode_gc_name_table[] =
"C,Other" "\0"
;
-static const uint8_t unicode_gc_table[3948] = {
+static const uint8_t unicode_gc_table[4070] = {
0xfa, 0x18, 0x17, 0x56, 0x0d, 0x56, 0x12, 0x13,
0x16, 0x0c, 0x16, 0x11, 0x36, 0xe9, 0x02, 0x36,
0x4c, 0x36, 0xe1, 0x12, 0x12, 0x16, 0x13, 0x0e,
@@ -2379,8 +2486,8 @@ static const uint8_t unicode_gc_table[3948] = {
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,
+ 0xe5, 0x10, 0x0e, 0xa5, 0x00, 0x3b, 0x80, 0xe6,
+ 0x01, 0xe5, 0x21, 0x04, 0xe6, 0x10, 0x1b, 0xe6,
0x18, 0x07, 0xe5, 0x2e, 0x06, 0x07, 0x06, 0x05,
0x47, 0xe6, 0x00, 0x67, 0x06, 0x27, 0x05, 0xc6,
0xe5, 0x02, 0x26, 0x36, 0xe9, 0x02, 0x16, 0x04,
@@ -2479,82 +2586,82 @@ static const uint8_t unicode_gc_table[3948] = {
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,
+ 0x06, 0x27, 0xe5, 0x00, 0x00, 0x36, 0xe9, 0x02,
+ 0xd6, 0xef, 0x02, 0xe6, 0x01, 0xef, 0x01, 0x56,
0x26, 0x07, 0xe5, 0x16, 0x07, 0x66, 0x27, 0x26,
0x07, 0x46, 0x25, 0xe9, 0x02, 0xe5, 0x24, 0x06,
0x07, 0x26, 0x47, 0x06, 0x07, 0x46, 0x27, 0xe0,
0x00, 0x76, 0xe5, 0x1c, 0xe7, 0x00, 0xe6, 0x00,
0x27, 0x26, 0x40, 0x96, 0xe9, 0x02, 0x40, 0x45,
0xe9, 0x02, 0xe5, 0x16, 0xa4, 0x36, 0xe2, 0x01,
- 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,
+ 0x3f, 0x80, 0xe1, 0x23, 0x20, 0x41, 0xf6, 0x00,
+ 0xe0, 0x00, 0x46, 0x16, 0xe6, 0x05, 0x07, 0xc6,
+ 0x65, 0x06, 0xa5, 0x06, 0x25, 0x07, 0x26, 0x05,
+ 0x80, 0xe2, 0x24, 0xe4, 0x37, 0xe2, 0x05, 0x04,
+ 0xe2, 0x1a, 0xe4, 0x1d, 0xe6, 0x38, 0xff, 0x80,
+ 0x0e, 0xe2, 0x00, 0xff, 0x5a, 0xe2, 0x00, 0xe1,
+ 0x00, 0xa2, 0x20, 0xa1, 0x20, 0xe2, 0x00, 0xe1,
+ 0x00, 0xe2, 0x00, 0xe1, 0x00, 0xa2, 0x20, 0xa1,
+ 0x20, 0xe2, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x3f, 0xc2, 0xe1, 0x00, 0xe2, 0x06,
+ 0x20, 0xe2, 0x00, 0xe3, 0x00, 0xe2, 0x00, 0xe3,
+ 0x00, 0xe2, 0x00, 0xe3, 0x00, 0x82, 0x00, 0x22,
+ 0x61, 0x03, 0x0e, 0x02, 0x4e, 0x42, 0x00, 0x22,
+ 0x61, 0x03, 0x4e, 0x62, 0x20, 0x22, 0x61, 0x00,
+ 0x4e, 0xe2, 0x00, 0x81, 0x4e, 0x20, 0x42, 0x00,
+ 0x22, 0x61, 0x03, 0x2e, 0x00, 0xf7, 0x03, 0x9b,
+ 0xb1, 0x36, 0x14, 0x15, 0x12, 0x34, 0x15, 0x12,
+ 0x14, 0xf6, 0x00, 0x18, 0x19, 0x9b, 0x17, 0xf6,
+ 0x01, 0x14, 0x15, 0x76, 0x30, 0x56, 0x0c, 0x12,
+ 0x13, 0xf6, 0x03, 0x0c, 0x16, 0x10, 0xf6, 0x02,
+ 0x17, 0x9b, 0x00, 0xfb, 0x02, 0x0b, 0x04, 0x20,
+ 0xab, 0x4c, 0x12, 0x13, 0x04, 0xeb, 0x02, 0x4c,
+ 0x12, 0x13, 0x00, 0xe4, 0x05, 0x40, 0xed, 0x19,
+ 0xe0, 0x07, 0xe6, 0x05, 0x68, 0x06, 0x48, 0xe6,
+ 0x04, 0xe0, 0x07, 0x2f, 0x01, 0x6f, 0x01, 0x2f,
+ 0x02, 0x41, 0x22, 0x41, 0x02, 0x0f, 0x01, 0x2f,
+ 0x0c, 0x81, 0xaf, 0x01, 0x0f, 0x01, 0x0f, 0x01,
+ 0x0f, 0x61, 0x0f, 0x02, 0x61, 0x02, 0x65, 0x02,
+ 0x2f, 0x22, 0x21, 0x8c, 0x3f, 0x42, 0x0f, 0x0c,
+ 0x2f, 0x02, 0x0f, 0xeb, 0x08, 0xea, 0x1b, 0x3f,
+ 0x6a, 0x0b, 0x2f, 0x60, 0x8c, 0x8f, 0x2c, 0x6f,
+ 0x0c, 0x2f, 0x0c, 0x2f, 0x0c, 0xcf, 0x0c, 0xef,
+ 0x17, 0x2c, 0x2f, 0x0c, 0x0f, 0x0c, 0xef, 0x17,
+ 0xec, 0x80, 0x84, 0xef, 0x00, 0x12, 0x13, 0x12,
+ 0x13, 0xef, 0x0c, 0x2c, 0xcf, 0x12, 0x13, 0xef,
+ 0x49, 0x0c, 0xef, 0x16, 0xec, 0x11, 0xef, 0x20,
+ 0xac, 0xef, 0x40, 0xe0, 0x0e, 0xef, 0x03, 0xe0,
+ 0x0d, 0xeb, 0x34, 0xef, 0x46, 0xeb, 0x0e, 0xef,
+ 0x80, 0x2f, 0x0c, 0xef, 0x01, 0x0c, 0xef, 0x2e,
+ 0xec, 0x00, 0xef, 0x67, 0x0c, 0xef, 0x80, 0x70,
0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
- 0xec, 0x08, 0xef, 0x80, 0x78, 0xec, 0x7b, 0x12,
- 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12,
+ 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, 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,
+ 0x13, 0xec, 0x08, 0xef, 0x80, 0x78, 0xec, 0x7b,
+ 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
+ 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
+ 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0xec, 0x37,
+ 0x12, 0x13, 0x12, 0x13, 0xec, 0x18, 0x12, 0x13,
+ 0xec, 0x80, 0x7a, 0xef, 0x28, 0xec, 0x0d, 0x2f,
+ 0xac, 0xef, 0x1f, 0x20, 0xef, 0x18, 0x00, 0xef,
+ 0x61, 0xe1, 0x28, 0xe2, 0x28, 0x5f, 0x21, 0x22,
+ 0xdf, 0x41, 0x02, 0x3f, 0x02, 0x3f, 0x82, 0x24,
+ 0x41, 0x02, 0xff, 0x5a, 0x02, 0xaf, 0x7f, 0x46,
+ 0x3f, 0x80, 0x76, 0x0b, 0x36, 0xe2, 0x1e, 0x00,
+ 0x02, 0x80, 0x02, 0x20, 0xe5, 0x30, 0xc0, 0x04,
+ 0x16, 0xe0, 0x06, 0x06, 0xe5, 0x0f, 0xe0, 0x01,
+ 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00,
+ 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00,
+ 0xe6, 0x18, 0x36, 0x14, 0x15, 0x14, 0x15, 0x56,
+ 0x14, 0x15, 0x16, 0x14, 0x15, 0xf6, 0x01, 0x11,
+ 0x36, 0x11, 0x16, 0x14, 0x15, 0x36, 0x14, 0x15,
+ 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
+ 0x96, 0x04, 0xf6, 0x02, 0x31, 0x76, 0x11, 0x16,
+ 0x12, 0xf6, 0x05, 0x2f, 0x56, 0x12, 0x13, 0x12,
+ 0x13, 0x12, 0x13, 0x12, 0x13, 0x11, 0xe0, 0x1a,
+ 0xef, 0x12, 0x00, 0xef, 0x51, 0xe0, 0x04, 0xef,
+ 0x80, 0x4e, 0xe0, 0x12, 0xef, 0x08, 0x17, 0x56,
0x0f, 0x04, 0x05, 0x0a, 0x12, 0x13, 0x12, 0x13,
0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x2f, 0x12,
0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x11,
@@ -2563,146 +2670,154 @@ static const uint8_t unicode_gc_table[3948] = {
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,
+ 0xe5, 0x18, 0xef, 0x1e, 0xe0, 0x01, 0x0f, 0xe5,
+ 0x08, 0xef, 0x17, 0x00, 0xeb, 0x02, 0xef, 0x16,
+ 0xeb, 0x00, 0x0f, 0xeb, 0x07, 0xef, 0x18, 0xeb,
+ 0x02, 0xef, 0x1f, 0xeb, 0x07, 0xef, 0x80, 0xb8,
+ 0xe5, 0x99, 0x38, 0xef, 0x38, 0xe5, 0xc0, 0x11,
+ 0x8d, 0x04, 0xe5, 0x83, 0xef, 0x40, 0xef, 0x2f,
+ 0xe0, 0x01, 0xe5, 0x20, 0xa4, 0x36, 0xe5, 0x80,
+ 0x84, 0x04, 0x56, 0xe5, 0x08, 0xe9, 0x02, 0x25,
+ 0xe0, 0x0c, 0xff, 0x26, 0x05, 0x06, 0x48, 0x16,
+ 0xe6, 0x02, 0x16, 0x04, 0xff, 0x14, 0x24, 0x26,
+ 0xe5, 0x3e, 0xea, 0x02, 0x26, 0xb6, 0xe0, 0x00,
+ 0xee, 0x0f, 0xe4, 0x01, 0x2e, 0xff, 0x06, 0x22,
+ 0xff, 0x36, 0x04, 0xe2, 0x00, 0x9f, 0xff, 0x02,
+ 0x04, 0x2e, 0x7f, 0x05, 0x7f, 0x22, 0xff, 0x0d,
+ 0x61, 0x02, 0x81, 0x02, 0xff, 0x07, 0x41, 0x02,
+ 0x5f, 0x3f, 0x20, 0x3f, 0x00, 0x02, 0x00, 0x02,
+ 0xdf, 0xe0, 0x0d, 0x44, 0x3f, 0x05, 0x24, 0x02,
+ 0xc5, 0x06, 0x45, 0x06, 0x65, 0x06, 0xe5, 0x0f,
+ 0x27, 0x26, 0x07, 0x6f, 0x06, 0x40, 0xab, 0x2f,
+ 0x0d, 0x0f, 0xa0, 0xe5, 0x2c, 0x76, 0xe0, 0x00,
+ 0x27, 0xe5, 0x2a, 0xe7, 0x08, 0x26, 0xe0, 0x00,
+ 0x36, 0xe9, 0x02, 0xa0, 0xe6, 0x0a, 0xa5, 0x56,
+ 0x05, 0x16, 0x25, 0x06, 0xe9, 0x02, 0xe5, 0x14,
+ 0xe6, 0x00, 0x36, 0xe5, 0x0f, 0xe6, 0x03, 0x27,
+ 0xe0, 0x03, 0x16, 0xe5, 0x15, 0x40, 0x46, 0x07,
+ 0xe5, 0x27, 0x06, 0x27, 0x66, 0x27, 0x26, 0x47,
+ 0xf6, 0x05, 0x00, 0x04, 0xe9, 0x02, 0x60, 0x36,
+ 0x85, 0x06, 0x04, 0xe5, 0x01, 0xe9, 0x02, 0x85,
+ 0x00, 0xe5, 0x21, 0xa6, 0x27, 0x26, 0x27, 0x26,
+ 0xe0, 0x01, 0x45, 0x06, 0xe5, 0x00, 0x06, 0x07,
+ 0x20, 0xe9, 0x02, 0x20, 0x76, 0xe5, 0x08, 0x04,
+ 0xa5, 0x4f, 0x05, 0x07, 0x06, 0x07, 0xe5, 0x2a,
+ 0x06, 0x05, 0x46, 0x25, 0x26, 0x85, 0x26, 0x05,
+ 0x06, 0x05, 0xe0, 0x10, 0x25, 0x04, 0x36, 0xe5,
+ 0x03, 0x07, 0x26, 0x27, 0x36, 0x05, 0x24, 0x07,
+ 0x06, 0xe0, 0x02, 0xa5, 0x20, 0xa5, 0x20, 0xa5,
+ 0xe0, 0x01, 0xc5, 0x00, 0xc5, 0x00, 0xe2, 0x23,
+ 0x0e, 0x64, 0xe2, 0x01, 0x04, 0x2e, 0x60, 0xe2,
+ 0x48, 0xe5, 0x1b, 0x27, 0x06, 0x27, 0x06, 0x27,
+ 0x16, 0x07, 0x06, 0x20, 0xe9, 0x02, 0xa0, 0xe5,
+ 0xab, 0x1c, 0xe0, 0x04, 0xe5, 0x0f, 0x60, 0xe5,
+ 0x29, 0x60, 0xfc, 0x87, 0x78, 0xfd, 0x98, 0x78,
+ 0xe5, 0x80, 0xe6, 0x20, 0xe5, 0x62, 0xe0, 0x1e,
+ 0xc2, 0xe0, 0x04, 0x82, 0x80, 0x05, 0x06, 0xe5,
+ 0x02, 0x0c, 0xe5, 0x05, 0x00, 0x85, 0x00, 0x05,
+ 0x00, 0x25, 0x00, 0x25, 0x00, 0xe5, 0x64, 0xee,
+ 0x09, 0xe0, 0x08, 0xe5, 0x80, 0xe3, 0x13, 0x12,
+ 0xef, 0x08, 0xe5, 0x38, 0x20, 0xe5, 0x2e, 0xc0,
+ 0x0f, 0xe0, 0x18, 0xe5, 0x04, 0x0d, 0x4f, 0xe6,
+ 0x08, 0xd6, 0x12, 0x13, 0x16, 0xa0, 0xe6, 0x08,
+ 0x16, 0x31, 0x30, 0x12, 0x13, 0x12, 0x13, 0x12,
0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12,
- 0x13, 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, 0x43,
- 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, 0x25, 0x06, 0xe0,
- 0x36, 0xc5, 0x00, 0x05, 0x00, 0x65, 0x00, 0xe5,
- 0x07, 0x00, 0xe5, 0x02, 0x16, 0xa0, 0xe5, 0x27,
- 0x06, 0x47, 0xe6, 0x00, 0x80, 0xe9, 0x02, 0xa0,
- 0x26, 0x27, 0x00, 0xe5, 0x00, 0x20, 0x25, 0x20,
- 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00, 0x85,
- 0x00, 0x26, 0x05, 0x27, 0x06, 0x67, 0x20, 0x27,
- 0x20, 0x47, 0x20, 0x05, 0xa0, 0x07, 0x80, 0x85,
- 0x27, 0x20, 0xc6, 0x40, 0x86, 0xe0, 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,
+ 0x13, 0x12, 0x13, 0x36, 0x12, 0x13, 0x76, 0x50,
+ 0x56, 0x00, 0x76, 0x11, 0x12, 0x13, 0x12, 0x13,
+ 0x12, 0x13, 0x56, 0x0c, 0x11, 0x4c, 0x00, 0x16,
+ 0x0d, 0x36, 0x60, 0x85, 0x00, 0xe5, 0x7f, 0x20,
+ 0x1b, 0x00, 0x56, 0x0d, 0x56, 0x12, 0x13, 0x16,
+ 0x0c, 0x16, 0x11, 0x36, 0xe9, 0x02, 0x36, 0x4c,
+ 0x36, 0xe1, 0x12, 0x12, 0x16, 0x13, 0x0e, 0x10,
+ 0x0e, 0xe2, 0x12, 0x12, 0x0c, 0x13, 0x0c, 0x12,
+ 0x13, 0x16, 0x12, 0x13, 0x36, 0xe5, 0x02, 0x04,
+ 0xe5, 0x25, 0x24, 0xe5, 0x17, 0x40, 0xa5, 0x20,
+ 0xa5, 0x20, 0xa5, 0x20, 0x45, 0x40, 0x2d, 0x0c,
+ 0x0e, 0x0f, 0x2d, 0x00, 0x0f, 0x6c, 0x2f, 0xe0,
+ 0x02, 0x5b, 0x2f, 0x20, 0xe5, 0x04, 0x00, 0xe5,
+ 0x12, 0x00, 0xe5, 0x0b, 0x00, 0x25, 0x00, 0xe5,
+ 0x07, 0x20, 0xe5, 0x06, 0xe0, 0x1a, 0xe5, 0x73,
+ 0x80, 0x56, 0x60, 0xeb, 0x25, 0x40, 0xef, 0x01,
+ 0xea, 0x2d, 0x6b, 0xef, 0x09, 0x2b, 0x4f, 0x00,
+ 0xef, 0x05, 0x40, 0x0f, 0xe0, 0x27, 0xef, 0x25,
+ 0x06, 0xe0, 0x7a, 0xe5, 0x15, 0x40, 0xe5, 0x29,
+ 0xe0, 0x07, 0x06, 0xeb, 0x13, 0x60, 0xe5, 0x18,
+ 0x6b, 0xe0, 0x01, 0xe5, 0x0c, 0x0a, 0xe5, 0x00,
+ 0x0a, 0x80, 0xe5, 0x1e, 0x86, 0x80, 0xe5, 0x16,
+ 0x00, 0x16, 0xe5, 0x1c, 0x60, 0xe5, 0x00, 0x16,
+ 0x8a, 0xe0, 0x22, 0xe1, 0x20, 0xe2, 0x20, 0xe5,
+ 0x46, 0x20, 0xe9, 0x02, 0xa0, 0xe1, 0x1c, 0x60,
+ 0xe2, 0x1c, 0x60, 0xe5, 0x20, 0xe0, 0x00, 0xe5,
+ 0x2c, 0xe0, 0x03, 0x16, 0xe1, 0x03, 0x00, 0xe1,
+ 0x07, 0x00, 0xc1, 0x00, 0x21, 0x00, 0xe2, 0x03,
+ 0x00, 0xe2, 0x07, 0x00, 0xc2, 0x00, 0x22, 0x40,
+ 0xe5, 0x2c, 0xe0, 0x04, 0xe5, 0x80, 0xaf, 0xe0,
+ 0x01, 0xe5, 0x0e, 0xe0, 0x02, 0xe5, 0x00, 0xe0,
+ 0x10, 0xa4, 0x00, 0xe4, 0x22, 0x00, 0xe4, 0x01,
+ 0xe0, 0x3d, 0xa5, 0x20, 0x05, 0x00, 0xe5, 0x24,
+ 0x00, 0x25, 0x40, 0x05, 0x20, 0xe5, 0x0f, 0x00,
+ 0x16, 0xeb, 0x00, 0xe5, 0x0f, 0x2f, 0xcb, 0xe5,
+ 0x17, 0xe0, 0x00, 0xeb, 0x01, 0xe0, 0x28, 0xe5,
+ 0x0b, 0x00, 0x25, 0x80, 0x8b, 0xe5, 0x0e, 0xab,
+ 0x40, 0x16, 0xe5, 0x12, 0x80, 0x16, 0xe0, 0x38,
+ 0xe5, 0x30, 0x60, 0x2b, 0x25, 0xeb, 0x08, 0x20,
+ 0xeb, 0x26, 0x05, 0x46, 0x00, 0x26, 0x80, 0x66,
+ 0x65, 0x00, 0x45, 0x00, 0xe5, 0x15, 0x20, 0x46,
+ 0x60, 0x06, 0xeb, 0x01, 0xc0, 0xf6, 0x01, 0xc0,
+ 0xe5, 0x15, 0x2b, 0x16, 0xe5, 0x15, 0x4b, 0xe0,
+ 0x18, 0xe5, 0x00, 0x0f, 0xe5, 0x14, 0x26, 0x60,
+ 0x8b, 0xd6, 0xe0, 0x01, 0xe5, 0x2e, 0x40, 0xd6,
+ 0xe5, 0x0e, 0x20, 0xeb, 0x00, 0xe5, 0x0b, 0x80,
+ 0xeb, 0x00, 0xe5, 0x0a, 0xc0, 0x76, 0xe0, 0x04,
+ 0xcb, 0xe0, 0x48, 0xe5, 0x41, 0xe0, 0x2f, 0xe1,
+ 0x2b, 0xe0, 0x05, 0xe2, 0x2b, 0xc0, 0xab, 0xe5,
+ 0x1c, 0x66, 0xe0, 0x00, 0xe9, 0x02, 0xa0, 0xe9,
+ 0x02, 0x65, 0x04, 0x05, 0xe1, 0x0e, 0x40, 0x86,
+ 0x11, 0x04, 0xe2, 0x0e, 0xe0, 0x00, 0x2c, 0xe0,
+ 0x80, 0x48, 0xeb, 0x17, 0x00, 0xe5, 0x22, 0x00,
+ 0x26, 0x11, 0x20, 0x25, 0xe0, 0x08, 0x45, 0xe0,
+ 0x2f, 0x66, 0xe5, 0x15, 0xeb, 0x02, 0x05, 0xe0,
+ 0x00, 0xe5, 0x0e, 0xe6, 0x03, 0x6b, 0x96, 0xe0,
+ 0x0e, 0xe5, 0x0a, 0x66, 0x76, 0xe0, 0x1e, 0xe5,
+ 0x0d, 0xcb, 0xe0, 0x0c, 0xe5, 0x0f, 0xe0, 0x01,
+ 0x07, 0x06, 0x07, 0xe5, 0x2d, 0xe6, 0x07, 0xd6,
+ 0x60, 0xeb, 0x0c, 0xe9, 0x02, 0x06, 0x25, 0x26,
+ 0x05, 0xe0, 0x01, 0x46, 0x07, 0xe5, 0x25, 0x47,
+ 0x66, 0x27, 0x26, 0x36, 0x1b, 0x76, 0x06, 0xe0,
+ 0x02, 0x1b, 0x20, 0xe5, 0x11, 0xc0, 0xe9, 0x02,
+ 0xa0, 0x46, 0xe5, 0x1c, 0x86, 0x07, 0xe6, 0x00,
+ 0x00, 0xe9, 0x02, 0x76, 0x05, 0x27, 0x05, 0xe0,
+ 0x00, 0xe5, 0x1b, 0x06, 0x36, 0x05, 0xe0, 0x01,
+ 0x26, 0x07, 0xe5, 0x28, 0x47, 0xe6, 0x01, 0x27,
+ 0x65, 0x76, 0x66, 0x16, 0x07, 0x06, 0xe9, 0x02,
+ 0x05, 0x16, 0x05, 0x56, 0x00, 0xeb, 0x0c, 0xe0,
+ 0x03, 0xe5, 0x0a, 0x00, 0xe5, 0x11, 0x47, 0x46,
+ 0x27, 0x06, 0x07, 0x26, 0xb6, 0x06, 0x25, 0x06,
+ 0xe0, 0x36, 0xc5, 0x00, 0x05, 0x00, 0x65, 0x00,
+ 0xe5, 0x07, 0x00, 0xe5, 0x02, 0x16, 0xa0, 0xe5,
+ 0x27, 0x06, 0x47, 0xe6, 0x00, 0x80, 0xe9, 0x02,
+ 0xa0, 0x26, 0x27, 0x00, 0xe5, 0x00, 0x20, 0x25,
+ 0x20, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00,
+ 0x85, 0x00, 0x26, 0x05, 0x27, 0x06, 0x67, 0x20,
+ 0x27, 0x20, 0x47, 0x20, 0x05, 0xa0, 0x07, 0x80,
+ 0x85, 0x27, 0x20, 0xc6, 0x40, 0x86, 0xe0, 0x03,
+ 0xe5, 0x02, 0x00, 0x05, 0x20, 0x05, 0x00, 0xe5,
+ 0x1e, 0x00, 0x05, 0x47, 0xa6, 0x00, 0x07, 0x20,
+ 0x07, 0x00, 0x67, 0x00, 0x27, 0x06, 0x07, 0x06,
+ 0x05, 0x06, 0x05, 0x36, 0x00, 0x36, 0xe0, 0x00,
+ 0x26, 0xe0, 0x15, 0xe5, 0x2d, 0x47, 0xe6, 0x00,
+ 0x27, 0x46, 0x07, 0x06, 0x65, 0x96, 0xe9, 0x02,
+ 0x36, 0x00, 0x16, 0x06, 0x45, 0xe0, 0x16, 0xe5,
+ 0x28, 0x47, 0xa6, 0x07, 0x06, 0x67, 0x26, 0x07,
+ 0x26, 0x25, 0x16, 0x05, 0xe0, 0x00, 0xe9, 0x02,
+ 0xe0, 0x80, 0x1e, 0xe5, 0x27, 0x47, 0x66, 0x20,
+ 0x67, 0x26, 0x07, 0x26, 0xf6, 0x0f, 0x65, 0x26,
+ 0xe0, 0x1a, 0xe5, 0x28, 0x47, 0xe6, 0x00, 0x27,
+ 0x06, 0x07, 0x26, 0x56, 0x05, 0xe0, 0x03, 0xe9,
+ 0x02, 0xa0, 0xf6, 0x05, 0xe0, 0x0b, 0xe5, 0x23,
+ 0x06, 0x07, 0x06, 0x27, 0xa6, 0x07, 0x06, 0x05,
+ 0x16, 0xa0, 0xe9, 0x02, 0xa0, 0xe9, 0x0c, 0xe0,
+ 0x14, 0xe5, 0x13, 0x20, 0x06, 0x07, 0x06, 0x27,
0x66, 0x07, 0x86, 0x60, 0xe9, 0x02, 0x2b, 0x56,
0x0f, 0xc5, 0xe0, 0x80, 0x31, 0xe5, 0x24, 0x47,
0xe6, 0x01, 0x07, 0x26, 0x16, 0xe0, 0x5c, 0xe1,
@@ -2717,7 +2832,8 @@ static const uint8_t unicode_gc_table[3948] = {
0x05, 0x66, 0xf6, 0x00, 0x06, 0xe0, 0x00, 0x05,
0xa6, 0x27, 0x46, 0xe5, 0x26, 0xe6, 0x05, 0x07,
0x26, 0x56, 0x05, 0x96, 0xe0, 0x05, 0xe5, 0x41,
- 0xc0, 0xf6, 0x02, 0xe0, 0x80, 0x6e, 0xe5, 0x01,
+ 0xc0, 0xf6, 0x02, 0xe0, 0x80, 0x2e, 0xe5, 0x19,
+ 0x16, 0xe0, 0x06, 0xe9, 0x02, 0xa0, 0xe5, 0x01,
0x00, 0xe5, 0x1d, 0x07, 0xc6, 0x00, 0xa6, 0x07,
0x06, 0x05, 0x96, 0xe0, 0x02, 0xe9, 0x02, 0xeb,
0x0b, 0x40, 0x36, 0xe5, 0x16, 0x20, 0xe6, 0x0e,
@@ -2730,106 +2846,112 @@ static const uint8_t unicode_gc_table[3948] = {
0x80, 0xae, 0xe5, 0x0b, 0x26, 0x27, 0x36, 0xc0,
0x26, 0x05, 0x07, 0xe5, 0x05, 0x00, 0xe5, 0x1a,
0x27, 0x86, 0x40, 0x27, 0x06, 0x07, 0x06, 0xf6,
- 0x05, 0xe9, 0x02, 0xe0, 0x4e, 0x05, 0xe0, 0x07,
- 0xeb, 0x0d, 0xef, 0x00, 0x6d, 0xef, 0x09, 0xe0,
- 0x05, 0x16, 0xe5, 0x83, 0x12, 0xe0, 0x5e, 0xea,
- 0x67, 0x00, 0x96, 0xe0, 0x03, 0xe5, 0x80, 0x3c,
- 0xe0, 0x89, 0xc4, 0xe5, 0x59, 0x36, 0xe0, 0x05,
- 0xe5, 0x83, 0xa8, 0xfb, 0x08, 0x06, 0xa5, 0xe6,
- 0x07, 0xe0, 0x8f, 0x22, 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, 0x07, 0x05, 0xe0, 0x15, 0x45, 0x20, 0x05,
- 0xe0, 0x06, 0x65, 0xe0, 0x00, 0xe5, 0x81, 0x04,
- 0xe0, 0x88, 0x7c, 0xe5, 0x63, 0x80, 0xe5, 0x05,
- 0x40, 0xe5, 0x01, 0xc0, 0xe5, 0x02, 0x20, 0x0f,
- 0x26, 0x16, 0x7b, 0xe0, 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, 0x72, 0xeb, 0x0c, 0xe0, 0x04, 0xeb, 0x0c,
- 0xe0, 0x04, 0xef, 0x4f, 0xe0, 0x01, 0xeb, 0x11,
- 0xe0, 0x7f, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12,
- 0xc2, 0x00, 0xe2, 0x0a, 0xe1, 0x12, 0xe2, 0x12,
- 0x01, 0x00, 0x21, 0x20, 0x01, 0x20, 0x21, 0x20,
- 0x61, 0x00, 0xe1, 0x00, 0x62, 0x00, 0x02, 0x00,
- 0xc2, 0x00, 0xe2, 0x03, 0xe1, 0x12, 0xe2, 0x12,
- 0x21, 0x00, 0x61, 0x20, 0xe1, 0x00, 0x00, 0xc1,
- 0x00, 0xe2, 0x12, 0x21, 0x00, 0x61, 0x00, 0x81,
- 0x00, 0x01, 0x40, 0xc1, 0x00, 0xe2, 0x12, 0xe1,
+ 0x05, 0xe9, 0x02, 0x06, 0xe0, 0x4d, 0x05, 0xe0,
+ 0x07, 0xeb, 0x0d, 0xef, 0x00, 0x6d, 0xef, 0x09,
+ 0xe0, 0x05, 0x16, 0xe5, 0x83, 0x12, 0xe0, 0x5e,
+ 0xea, 0x67, 0x00, 0x96, 0xe0, 0x03, 0xe5, 0x80,
+ 0x3c, 0xe0, 0x89, 0xc4, 0xe5, 0x59, 0x36, 0xe0,
+ 0x05, 0xe5, 0x83, 0xa8, 0xfb, 0x08, 0x06, 0xa5,
+ 0xe6, 0x07, 0xe0, 0x02, 0xe5, 0x8f, 0x13, 0x80,
+ 0xe5, 0x81, 0xbf, 0xe0, 0x9a, 0x31, 0xe5, 0x16,
+ 0xe6, 0x04, 0x47, 0x46, 0xe9, 0x02, 0xe0, 0x86,
+ 0x3e, 0xe5, 0x81, 0xb1, 0xc0, 0xe5, 0x17, 0x00,
+ 0xe9, 0x02, 0x60, 0x36, 0xe5, 0x47, 0x00, 0xe9,
+ 0x02, 0xa0, 0xe5, 0x16, 0x20, 0x86, 0x16, 0xe0,
+ 0x02, 0xe5, 0x28, 0xc6, 0x96, 0x6f, 0x64, 0x16,
+ 0x0f, 0xe0, 0x02, 0xe9, 0x02, 0x00, 0xcb, 0x00,
+ 0xe5, 0x0d, 0x80, 0xe5, 0x0b, 0xe0, 0x81, 0x28,
+ 0x44, 0xe5, 0x20, 0x24, 0x56, 0xe9, 0x02, 0xe0,
+ 0x80, 0x3e, 0xe1, 0x18, 0xe2, 0x18, 0xeb, 0x0f,
+ 0x76, 0xe0, 0x5d, 0xe5, 0x43, 0x60, 0x06, 0x05,
+ 0xe7, 0x2f, 0xc0, 0x66, 0xe4, 0x05, 0xe0, 0x38,
+ 0x24, 0x16, 0x04, 0x06, 0xe0, 0x03, 0x27, 0xe0,
+ 0x06, 0xe5, 0x97, 0x70, 0xe0, 0x00, 0xe5, 0x84,
+ 0x4e, 0xe0, 0x21, 0xe5, 0x02, 0xe0, 0xa2, 0x5f,
+ 0x64, 0x00, 0xc4, 0x00, 0x24, 0x00, 0xe5, 0x80,
+ 0x9b, 0xe0, 0x07, 0x05, 0xe0, 0x15, 0x45, 0x20,
+ 0x05, 0xe0, 0x06, 0x65, 0xe0, 0x00, 0xe5, 0x81,
+ 0x04, 0xe0, 0x88, 0x7c, 0xe5, 0x63, 0x80, 0xe5,
+ 0x05, 0x40, 0xe5, 0x01, 0xc0, 0xe5, 0x02, 0x20,
+ 0x0f, 0x26, 0x16, 0x7b, 0xe0, 0x8e, 0xd4, 0xef,
+ 0x80, 0x68, 0xe9, 0x02, 0xa0, 0xef, 0x81, 0x2c,
+ 0xe0, 0x44, 0xe6, 0x26, 0x20, 0xe6, 0x0f, 0xe0,
+ 0x01, 0xef, 0x6c, 0xe0, 0x34, 0xef, 0x80, 0x6e,
+ 0xe0, 0x02, 0xef, 0x1f, 0x20, 0xef, 0x34, 0x27,
+ 0x46, 0x4f, 0xa7, 0xfb, 0x00, 0xe6, 0x00, 0x2f,
+ 0xc6, 0xef, 0x16, 0x66, 0xef, 0x35, 0xe0, 0x0d,
+ 0xef, 0x3a, 0x46, 0x0f, 0xe0, 0x72, 0xeb, 0x0c,
+ 0xe0, 0x04, 0xeb, 0x0c, 0xe0, 0x04, 0xef, 0x4f,
+ 0xe0, 0x01, 0xeb, 0x11, 0xe0, 0x7f, 0xe1, 0x12,
+ 0xe2, 0x12, 0xe1, 0x12, 0xc2, 0x00, 0xe2, 0x0a,
+ 0xe1, 0x12, 0xe2, 0x12, 0x01, 0x00, 0x21, 0x20,
+ 0x01, 0x20, 0x21, 0x20, 0x61, 0x00, 0xe1, 0x00,
+ 0x62, 0x00, 0x02, 0x00, 0xc2, 0x00, 0xe2, 0x03,
+ 0xe1, 0x12, 0xe2, 0x12, 0x21, 0x00, 0x61, 0x20,
+ 0xe1, 0x00, 0x00, 0xc1, 0x00, 0xe2, 0x12, 0x21,
+ 0x00, 0x61, 0x00, 0x81, 0x00, 0x01, 0x40, 0xc1,
+ 0x00, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1,
0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1,
0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1,
- 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x14, 0x20,
- 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1,
- 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11,
- 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c,
- 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2,
- 0x11, 0x0c, 0xa2, 0x3f, 0x20, 0xe9, 0x2a, 0xef,
- 0x81, 0x78, 0xe6, 0x2f, 0x6f, 0xe6, 0x2a, 0xef,
- 0x00, 0x06, 0xef, 0x06, 0x06, 0x2f, 0x96, 0xe0,
- 0x07, 0x86, 0x00, 0xe6, 0x07, 0xe0, 0x83, 0xc8,
- 0xe2, 0x02, 0x05, 0xe2, 0x0c, 0xa0, 0xa2, 0xe0,
- 0x80, 0x4d, 0xc6, 0x00, 0xe6, 0x09, 0x20, 0xc6,
- 0x00, 0x26, 0x00, 0x86, 0x80, 0xe4, 0x36, 0xe0,
- 0x19, 0x06, 0xe0, 0x68, 0xe5, 0x25, 0x40, 0xc6,
- 0xc4, 0x20, 0xe9, 0x02, 0x60, 0x05, 0x0f, 0xe0,
- 0x80, 0xb8, 0xe5, 0x16, 0x06, 0xe0, 0x09, 0xe5,
- 0x24, 0x66, 0xe9, 0x02, 0x80, 0x0d, 0xe0, 0x81,
- 0x48, 0xe5, 0x13, 0x04, 0x66, 0xe9, 0x02, 0xe0,
- 0x82, 0x5e, 0xc5, 0x00, 0x65, 0x00, 0x25, 0x00,
- 0xe5, 0x07, 0x00, 0xe5, 0x80, 0x3d, 0x20, 0xeb,
- 0x01, 0xc6, 0xe0, 0x21, 0xe1, 0x1a, 0xe2, 0x1a,
- 0xc6, 0x04, 0x60, 0xe9, 0x02, 0x60, 0x36, 0xe0,
- 0x82, 0x89, 0xeb, 0x33, 0x0f, 0x4b, 0x0d, 0x6b,
- 0xe0, 0x44, 0xeb, 0x25, 0x0f, 0xeb, 0x07, 0xe0,
- 0x80, 0x3a, 0x65, 0x00, 0xe5, 0x13, 0x00, 0x25,
- 0x00, 0x05, 0x20, 0x05, 0x00, 0xe5, 0x02, 0x00,
- 0x65, 0x00, 0x05, 0x00, 0x05, 0xa0, 0x05, 0x60,
- 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x45, 0x00,
- 0x25, 0x00, 0x05, 0x20, 0x05, 0x00, 0x05, 0x00,
- 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x25, 0x00,
- 0x05, 0x20, 0x65, 0x00, 0xc5, 0x00, 0x65, 0x00,
- 0x65, 0x00, 0x05, 0x00, 0xe5, 0x02, 0x00, 0xe5,
- 0x09, 0x80, 0x45, 0x00, 0x85, 0x00, 0xe5, 0x09,
- 0xe0, 0x2c, 0x2c, 0xe0, 0x80, 0x86, 0xef, 0x24,
- 0x60, 0xef, 0x5c, 0xe0, 0x04, 0xef, 0x07, 0x20,
- 0xef, 0x07, 0x00, 0xef, 0x07, 0x00, 0xef, 0x1d,
- 0xe0, 0x02, 0xeb, 0x05, 0xef, 0x80, 0x19, 0xe0,
- 0x30, 0xef, 0x15, 0xe0, 0x05, 0xef, 0x24, 0x60,
- 0xef, 0x01, 0xc0, 0x2f, 0xe0, 0x06, 0xaf, 0xe0,
- 0x80, 0x12, 0xef, 0x80, 0x73, 0x8e, 0xef, 0x82,
- 0x50, 0x60, 0xef, 0x09, 0x40, 0xef, 0x05, 0x40,
- 0xef, 0x6f, 0x60, 0xef, 0x57, 0xa0, 0xef, 0x04,
- 0x60, 0x0f, 0xe0, 0x07, 0xef, 0x04, 0x60, 0xef,
- 0x30, 0xe0, 0x00, 0xef, 0x02, 0xa0, 0xef, 0x20,
- 0xe0, 0x00, 0xef, 0x16, 0x20, 0x2f, 0xe0, 0x46,
- 0xef, 0x80, 0xcc, 0xe0, 0x04, 0xef, 0x06, 0x20,
- 0xef, 0x05, 0x40, 0xef, 0x01, 0xc0, 0xef, 0x26,
- 0x00, 0xcf, 0xe0, 0x00, 0xef, 0x06, 0x60, 0xef,
- 0x01, 0xc0, 0xef, 0x01, 0xc0, 0xef, 0x80, 0x0b,
- 0x00, 0xef, 0x2f, 0xe0, 0x1d, 0xe9, 0x02, 0xe0,
- 0x83, 0x7e, 0xe5, 0xc0, 0x66, 0x58, 0xe0, 0x18,
- 0xe5, 0x8f, 0xb2, 0xa0, 0xe5, 0x80, 0x56, 0x20,
- 0xe5, 0x95, 0xfa, 0xe0, 0x06, 0xe5, 0x9c, 0xa9,
- 0xe0, 0x8b, 0x97, 0xe5, 0x81, 0x96, 0xe0, 0x85,
- 0x5a, 0xe5, 0x92, 0xc3, 0x80, 0xe5, 0x8f, 0xd8,
- 0xe0, 0xca, 0x9b, 0xc9, 0x1b, 0xe0, 0x16, 0xfb,
- 0x58, 0xe0, 0x78, 0xe6, 0x80, 0x68, 0xe0, 0xc0,
- 0xbd, 0x88, 0xfd, 0xc0, 0xbf, 0x76, 0x20, 0xfd,
- 0xc0, 0xbf, 0x76, 0x20,
+ 0x12, 0xe2, 0x14, 0x20, 0xe1, 0x11, 0x0c, 0xe2,
+ 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11,
+ 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c,
+ 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2,
+ 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0x3f,
+ 0x20, 0xe9, 0x2a, 0xef, 0x81, 0x78, 0xe6, 0x2f,
+ 0x6f, 0xe6, 0x2a, 0xef, 0x00, 0x06, 0xef, 0x06,
+ 0x06, 0x2f, 0x96, 0xe0, 0x07, 0x86, 0x00, 0xe6,
+ 0x07, 0xe0, 0x83, 0xc8, 0xe2, 0x02, 0x05, 0xe2,
+ 0x0c, 0xa0, 0xa2, 0xe0, 0x80, 0x4d, 0xc6, 0x00,
+ 0xe6, 0x09, 0x20, 0xc6, 0x00, 0x26, 0x00, 0x86,
+ 0x80, 0xe4, 0x36, 0xe0, 0x19, 0x06, 0xe0, 0x68,
+ 0xe5, 0x25, 0x40, 0xc6, 0xc4, 0x20, 0xe9, 0x02,
+ 0x60, 0x05, 0x0f, 0xe0, 0x80, 0xb8, 0xe5, 0x16,
+ 0x06, 0xe0, 0x09, 0xe5, 0x24, 0x66, 0xe9, 0x02,
+ 0x80, 0x0d, 0xe0, 0x81, 0x48, 0xe5, 0x13, 0x04,
+ 0x66, 0xe9, 0x02, 0xe0, 0x80, 0x4e, 0xe5, 0x16,
+ 0x26, 0x05, 0xe9, 0x02, 0x60, 0x16, 0xe0, 0x81,
+ 0x58, 0xc5, 0x00, 0x65, 0x00, 0x25, 0x00, 0xe5,
+ 0x07, 0x00, 0xe5, 0x80, 0x3d, 0x20, 0xeb, 0x01,
+ 0xc6, 0xe0, 0x21, 0xe1, 0x1a, 0xe2, 0x1a, 0xc6,
+ 0x04, 0x60, 0xe9, 0x02, 0x60, 0x36, 0xe0, 0x82,
+ 0x89, 0xeb, 0x33, 0x0f, 0x4b, 0x0d, 0x6b, 0xe0,
+ 0x44, 0xeb, 0x25, 0x0f, 0xeb, 0x07, 0xe0, 0x80,
+ 0x3a, 0x65, 0x00, 0xe5, 0x13, 0x00, 0x25, 0x00,
+ 0x05, 0x20, 0x05, 0x00, 0xe5, 0x02, 0x00, 0x65,
+ 0x00, 0x05, 0x00, 0x05, 0xa0, 0x05, 0x60, 0x05,
+ 0x00, 0x05, 0x00, 0x05, 0x00, 0x45, 0x00, 0x25,
+ 0x00, 0x05, 0x20, 0x05, 0x00, 0x05, 0x00, 0x05,
+ 0x00, 0x05, 0x00, 0x05, 0x00, 0x25, 0x00, 0x05,
+ 0x20, 0x65, 0x00, 0xc5, 0x00, 0x65, 0x00, 0x65,
+ 0x00, 0x05, 0x00, 0xe5, 0x02, 0x00, 0xe5, 0x09,
+ 0x80, 0x45, 0x00, 0x85, 0x00, 0xe5, 0x09, 0xe0,
+ 0x2c, 0x2c, 0xe0, 0x80, 0x86, 0xef, 0x24, 0x60,
+ 0xef, 0x5c, 0xe0, 0x04, 0xef, 0x07, 0x20, 0xef,
+ 0x07, 0x00, 0xef, 0x07, 0x00, 0xef, 0x1d, 0xe0,
+ 0x02, 0xeb, 0x05, 0xef, 0x80, 0x19, 0xe0, 0x30,
+ 0xef, 0x15, 0xe0, 0x05, 0xef, 0x24, 0x60, 0xef,
+ 0x01, 0xc0, 0x2f, 0xe0, 0x06, 0xaf, 0xe0, 0x80,
+ 0x12, 0xef, 0x80, 0x73, 0x8e, 0xef, 0x82, 0x50,
+ 0x60, 0xef, 0x09, 0x40, 0xef, 0x05, 0x40, 0xef,
+ 0x6f, 0x60, 0xef, 0x57, 0xa0, 0xef, 0x04, 0x60,
+ 0x0f, 0xe0, 0x07, 0xef, 0x04, 0x60, 0xef, 0x30,
+ 0xe0, 0x00, 0xef, 0x02, 0xa0, 0xef, 0x20, 0xe0,
+ 0x00, 0xef, 0x16, 0x20, 0xef, 0x04, 0x60, 0x2f,
+ 0xe0, 0x36, 0xef, 0x80, 0xcc, 0xe0, 0x04, 0xef,
+ 0x06, 0x20, 0xef, 0x05, 0x40, 0xef, 0x02, 0x80,
+ 0xef, 0x30, 0xc0, 0xef, 0x07, 0x20, 0xef, 0x03,
+ 0xa0, 0xef, 0x01, 0xc0, 0xef, 0x80, 0x0b, 0x00,
+ 0xef, 0x54, 0xe9, 0x02, 0xe0, 0x83, 0x7e, 0xe5,
+ 0xc0, 0x66, 0x58, 0xe0, 0x18, 0xe5, 0x8f, 0xb2,
+ 0xa0, 0xe5, 0x80, 0x56, 0x20, 0xe5, 0x95, 0xfa,
+ 0xe0, 0x06, 0xe5, 0x9c, 0xa9, 0xe0, 0x07, 0xe5,
+ 0x81, 0xe6, 0xe0, 0x89, 0x1a, 0xe5, 0x81, 0x96,
+ 0xe0, 0x85, 0x5a, 0xe5, 0x92, 0xc3, 0x80, 0xe5,
+ 0x8f, 0xd8, 0xe0, 0xca, 0x9b, 0xc9, 0x1b, 0xe0,
+ 0x16, 0xfb, 0x58, 0xe0, 0x78, 0xe6, 0x80, 0x68,
+ 0xe0, 0xc0, 0xbd, 0x88, 0xfd, 0xc0, 0xbf, 0x76,
+ 0x20, 0xfd, 0xc0, 0xbf, 0x76, 0x20,
};
typedef enum {
@@ -2873,6 +2995,7 @@ typedef enum {
UNICODE_SCRIPT_Elbasan,
UNICODE_SCRIPT_Elymaic,
UNICODE_SCRIPT_Ethiopic,
+ UNICODE_SCRIPT_Garay,
UNICODE_SCRIPT_Georgian,
UNICODE_SCRIPT_Glagolitic,
UNICODE_SCRIPT_Gothic,
@@ -2881,6 +3004,7 @@ typedef enum {
UNICODE_SCRIPT_Gujarati,
UNICODE_SCRIPT_Gunjala_Gondi,
UNICODE_SCRIPT_Gurmukhi,
+ UNICODE_SCRIPT_Gurung_Khema,
UNICODE_SCRIPT_Han,
UNICODE_SCRIPT_Hangul,
UNICODE_SCRIPT_Hanifi_Rohingya,
@@ -2903,6 +3027,7 @@ typedef enum {
UNICODE_SCRIPT_Khojki,
UNICODE_SCRIPT_Khitan_Small_Script,
UNICODE_SCRIPT_Khudawadi,
+ UNICODE_SCRIPT_Kirat_Rai,
UNICODE_SCRIPT_Lao,
UNICODE_SCRIPT_Latin,
UNICODE_SCRIPT_Lepcha,
@@ -2940,6 +3065,7 @@ typedef enum {
UNICODE_SCRIPT_Nyiakeng_Puachue_Hmong,
UNICODE_SCRIPT_Ogham,
UNICODE_SCRIPT_Ol_Chiki,
+ UNICODE_SCRIPT_Ol_Onal,
UNICODE_SCRIPT_Old_Hungarian,
UNICODE_SCRIPT_Old_Italic,
UNICODE_SCRIPT_Old_North_Arabian,
@@ -2971,6 +3097,7 @@ typedef enum {
UNICODE_SCRIPT_Sora_Sompeng,
UNICODE_SCRIPT_Soyombo,
UNICODE_SCRIPT_Sundanese,
+ UNICODE_SCRIPT_Sunuwar,
UNICODE_SCRIPT_Syloti_Nagri,
UNICODE_SCRIPT_Syriac,
UNICODE_SCRIPT_Tagalog,
@@ -2988,7 +3115,9 @@ typedef enum {
UNICODE_SCRIPT_Tifinagh,
UNICODE_SCRIPT_Tirhuta,
UNICODE_SCRIPT_Tangsa,
+ UNICODE_SCRIPT_Todhri,
UNICODE_SCRIPT_Toto,
+ UNICODE_SCRIPT_Tulu_Tigalari,
UNICODE_SCRIPT_Ugaritic,
UNICODE_SCRIPT_Vai,
UNICODE_SCRIPT_Vithkuqi,
@@ -3001,6 +3130,7 @@ typedef enum {
} UnicodeScriptEnum;
static const char unicode_script_name_table[] =
+ "Unknown,Zzzz" "\0"
"Adlam,Adlm" "\0"
"Ahom,Ahom" "\0"
"Anatolian_Hieroglyphs,Hluw" "\0"
@@ -3040,6 +3170,7 @@ static const char unicode_script_name_table[] =
"Elbasan,Elba" "\0"
"Elymaic,Elym" "\0"
"Ethiopic,Ethi" "\0"
+ "Garay,Gara" "\0"
"Georgian,Geor" "\0"
"Glagolitic,Glag" "\0"
"Gothic,Goth" "\0"
@@ -3048,6 +3179,7 @@ static const char unicode_script_name_table[] =
"Gujarati,Gujr" "\0"
"Gunjala_Gondi,Gong" "\0"
"Gurmukhi,Guru" "\0"
+ "Gurung_Khema,Gukh" "\0"
"Han,Hani" "\0"
"Hangul,Hang" "\0"
"Hanifi_Rohingya,Rohg" "\0"
@@ -3070,6 +3202,7 @@ static const char unicode_script_name_table[] =
"Khojki,Khoj" "\0"
"Khitan_Small_Script,Kits" "\0"
"Khudawadi,Sind" "\0"
+ "Kirat_Rai,Krai" "\0"
"Lao,Laoo" "\0"
"Latin,Latn" "\0"
"Lepcha,Lepc" "\0"
@@ -3107,6 +3240,7 @@ static const char unicode_script_name_table[] =
"Nyiakeng_Puachue_Hmong,Hmnp" "\0"
"Ogham,Ogam" "\0"
"Ol_Chiki,Olck" "\0"
+ "Ol_Onal,Onao" "\0"
"Old_Hungarian,Hung" "\0"
"Old_Italic,Ital" "\0"
"Old_North_Arabian,Narb" "\0"
@@ -3138,6 +3272,7 @@ static const char unicode_script_name_table[] =
"Sora_Sompeng,Sora" "\0"
"Soyombo,Soyo" "\0"
"Sundanese,Sund" "\0"
+ "Sunuwar,Sunu" "\0"
"Syloti_Nagri,Sylo" "\0"
"Syriac,Syrc" "\0"
"Tagalog,Tglg" "\0"
@@ -3155,7 +3290,9 @@ static const char unicode_script_name_table[] =
"Tifinagh,Tfng" "\0"
"Tirhuta,Tirh" "\0"
"Tangsa,Tnsa" "\0"
+ "Todhri,Todr" "\0"
"Toto,Toto" "\0"
+ "Tulu_Tigalari,Tutg" "\0"
"Ugaritic,Ugar" "\0"
"Vai,Vaii" "\0"
"Vithkuqi,Vith" "\0"
@@ -3166,87 +3303,87 @@ static const char unicode_script_name_table[] =
"Zanabazar_Square,Zanb" "\0"
;
-static const uint8_t unicode_script_table[2720] = {
- 0xc0, 0x19, 0x99, 0x47, 0x85, 0x19, 0x99, 0x47,
- 0xae, 0x19, 0x80, 0x47, 0x8e, 0x19, 0x80, 0x47,
- 0x84, 0x19, 0x96, 0x47, 0x80, 0x19, 0x9e, 0x47,
- 0x80, 0x19, 0xe1, 0x60, 0x47, 0xa6, 0x19, 0x84,
- 0x47, 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,
+static const uint8_t unicode_script_table[2803] = {
+ 0xc0, 0x19, 0x99, 0x4a, 0x85, 0x19, 0x99, 0x4a,
+ 0xae, 0x19, 0x80, 0x4a, 0x8e, 0x19, 0x80, 0x4a,
+ 0x84, 0x19, 0x96, 0x4a, 0x80, 0x19, 0x9e, 0x4a,
+ 0x80, 0x19, 0xe1, 0x60, 0x4a, 0xa6, 0x19, 0x84,
+ 0x4a, 0x84, 0x19, 0x81, 0x0d, 0x93, 0x19, 0xe0,
+ 0x0f, 0x3a, 0x83, 0x2d, 0x80, 0x19, 0x82, 0x2d,
+ 0x01, 0x83, 0x2d, 0x80, 0x19, 0x80, 0x2d, 0x03,
+ 0x80, 0x2d, 0x80, 0x19, 0x80, 0x2d, 0x80, 0x19,
+ 0x82, 0x2d, 0x00, 0x80, 0x2d, 0x00, 0x93, 0x2d,
+ 0x00, 0xbe, 0x2d, 0x8d, 0x1a, 0x8f, 0x2d, 0xe0,
+ 0x24, 0x1d, 0x81, 0x3a, 0xe0, 0x48, 0x1d, 0x00,
0xa5, 0x05, 0x01, 0xb1, 0x05, 0x01, 0x82, 0x05,
- 0x00, 0xb6, 0x35, 0x07, 0x9a, 0x35, 0x03, 0x85,
- 0x35, 0x0a, 0x84, 0x04, 0x80, 0x19, 0x85, 0x04,
+ 0x00, 0xb6, 0x37, 0x07, 0x9a, 0x37, 0x03, 0x85,
+ 0x37, 0x0a, 0x84, 0x04, 0x80, 0x19, 0x85, 0x04,
0x80, 0x19, 0x8d, 0x04, 0x80, 0x19, 0x82, 0x04,
0x80, 0x19, 0x9f, 0x04, 0x80, 0x19, 0x89, 0x04,
- 0x8a, 0x38, 0x99, 0x04, 0x80, 0x38, 0xe0, 0x0b,
- 0x04, 0x80, 0x19, 0xa1, 0x04, 0x8d, 0x8b, 0x00,
- 0xbb, 0x8b, 0x01, 0x82, 0x8b, 0xaf, 0x04, 0xb1,
- 0x95, 0x0d, 0xba, 0x66, 0x01, 0x82, 0x66, 0xad,
- 0x7f, 0x01, 0x8e, 0x7f, 0x00, 0x9b, 0x52, 0x01,
- 0x80, 0x52, 0x00, 0x8a, 0x8b, 0x04, 0x9e, 0x04,
- 0x00, 0x81, 0x04, 0x05, 0xc9, 0x04, 0x80, 0x19,
- 0x9c, 0x04, 0xd0, 0x20, 0x83, 0x38, 0x8e, 0x20,
+ 0x8a, 0x3a, 0x99, 0x04, 0x80, 0x3a, 0xe0, 0x0b,
+ 0x04, 0x80, 0x19, 0xa1, 0x04, 0x8d, 0x90, 0x00,
+ 0xbb, 0x90, 0x01, 0x82, 0x90, 0xaf, 0x04, 0xb1,
+ 0x9a, 0x0d, 0xba, 0x69, 0x01, 0x82, 0x69, 0xad,
+ 0x83, 0x01, 0x8e, 0x83, 0x00, 0x9b, 0x55, 0x01,
+ 0x80, 0x55, 0x00, 0x8a, 0x90, 0x04, 0x9e, 0x04,
+ 0x00, 0x81, 0x04, 0x04, 0xca, 0x04, 0x80, 0x19,
+ 0x9c, 0x04, 0xd0, 0x20, 0x83, 0x3a, 0x8e, 0x20,
0x81, 0x19, 0x99, 0x20, 0x83, 0x0b, 0x00, 0x87,
0x0b, 0x01, 0x81, 0x0b, 0x01, 0x95, 0x0b, 0x00,
0x86, 0x0b, 0x00, 0x80, 0x0b, 0x02, 0x83, 0x0b,
0x01, 0x88, 0x0b, 0x01, 0x81, 0x0b, 0x01, 0x83,
0x0b, 0x07, 0x80, 0x0b, 0x03, 0x81, 0x0b, 0x00,
- 0x84, 0x0b, 0x01, 0x98, 0x0b, 0x01, 0x82, 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, 0x74, 0x00, 0x87, 0x74, 0x01, 0x81, 0x74,
- 0x01, 0x95, 0x74, 0x00, 0x86, 0x74, 0x00, 0x81,
- 0x74, 0x00, 0x84, 0x74, 0x01, 0x88, 0x74, 0x01,
- 0x81, 0x74, 0x01, 0x82, 0x74, 0x06, 0x82, 0x74,
- 0x03, 0x81, 0x74, 0x00, 0x84, 0x74, 0x01, 0x91,
- 0x74, 0x09, 0x81, 0x92, 0x00, 0x85, 0x92, 0x02,
- 0x82, 0x92, 0x00, 0x83, 0x92, 0x02, 0x81, 0x92,
- 0x00, 0x80, 0x92, 0x00, 0x81, 0x92, 0x02, 0x81,
- 0x92, 0x02, 0x82, 0x92, 0x02, 0x8b, 0x92, 0x03,
- 0x84, 0x92, 0x02, 0x82, 0x92, 0x00, 0x83, 0x92,
- 0x01, 0x80, 0x92, 0x05, 0x80, 0x92, 0x0d, 0x94,
- 0x92, 0x04, 0x8c, 0x94, 0x00, 0x82, 0x94, 0x00,
- 0x96, 0x94, 0x00, 0x8f, 0x94, 0x01, 0x88, 0x94,
- 0x00, 0x82, 0x94, 0x00, 0x83, 0x94, 0x06, 0x81,
- 0x94, 0x00, 0x82, 0x94, 0x01, 0x80, 0x94, 0x01,
- 0x83, 0x94, 0x01, 0x89, 0x94, 0x06, 0x88, 0x94,
- 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, 0x82, 0x3d, 0x0b, 0x8c,
- 0x51, 0x00, 0x82, 0x51, 0x00, 0xb2, 0x51, 0x00,
- 0x82, 0x51, 0x00, 0x85, 0x51, 0x03, 0x8f, 0x51,
- 0x01, 0x99, 0x51, 0x00, 0x82, 0x85, 0x00, 0x91,
- 0x85, 0x02, 0x97, 0x85, 0x00, 0x88, 0x85, 0x00,
- 0x80, 0x85, 0x01, 0x86, 0x85, 0x02, 0x80, 0x85,
- 0x03, 0x85, 0x85, 0x00, 0x80, 0x85, 0x00, 0x87,
- 0x85, 0x05, 0x89, 0x85, 0x01, 0x82, 0x85, 0x0b,
- 0xb9, 0x96, 0x03, 0x80, 0x19, 0x9b, 0x96, 0x24,
- 0x81, 0x46, 0x00, 0x80, 0x46, 0x00, 0x84, 0x46,
- 0x00, 0x97, 0x46, 0x00, 0x80, 0x46, 0x00, 0x96,
- 0x46, 0x01, 0x84, 0x46, 0x00, 0x80, 0x46, 0x00,
- 0x86, 0x46, 0x00, 0x89, 0x46, 0x01, 0x83, 0x46,
- 0x1f, 0xc7, 0x97, 0x00, 0xa3, 0x97, 0x03, 0xa6,
- 0x97, 0x00, 0xa3, 0x97, 0x00, 0x8e, 0x97, 0x00,
- 0x86, 0x97, 0x83, 0x19, 0x81, 0x97, 0x24, 0xe0,
- 0x3f, 0x60, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04,
- 0x80, 0x28, 0x01, 0xaa, 0x28, 0x80, 0x19, 0x83,
- 0x28, 0xe0, 0x9f, 0x31, 0xc8, 0x27, 0x00, 0x83,
+ 0x84, 0x0b, 0x01, 0x98, 0x0b, 0x01, 0x82, 0x30,
+ 0x00, 0x85, 0x30, 0x03, 0x81, 0x30, 0x01, 0x95,
+ 0x30, 0x00, 0x86, 0x30, 0x00, 0x81, 0x30, 0x00,
+ 0x81, 0x30, 0x00, 0x81, 0x30, 0x01, 0x80, 0x30,
+ 0x00, 0x84, 0x30, 0x03, 0x81, 0x30, 0x01, 0x82,
+ 0x30, 0x02, 0x80, 0x30, 0x06, 0x83, 0x30, 0x00,
+ 0x80, 0x30, 0x06, 0x90, 0x30, 0x09, 0x82, 0x2e,
+ 0x00, 0x88, 0x2e, 0x00, 0x82, 0x2e, 0x00, 0x95,
+ 0x2e, 0x00, 0x86, 0x2e, 0x00, 0x81, 0x2e, 0x00,
+ 0x84, 0x2e, 0x01, 0x89, 0x2e, 0x00, 0x82, 0x2e,
+ 0x00, 0x82, 0x2e, 0x01, 0x80, 0x2e, 0x0e, 0x83,
+ 0x2e, 0x01, 0x8b, 0x2e, 0x06, 0x86, 0x2e, 0x00,
+ 0x82, 0x78, 0x00, 0x87, 0x78, 0x01, 0x81, 0x78,
+ 0x01, 0x95, 0x78, 0x00, 0x86, 0x78, 0x00, 0x81,
+ 0x78, 0x00, 0x84, 0x78, 0x01, 0x88, 0x78, 0x01,
+ 0x81, 0x78, 0x01, 0x82, 0x78, 0x06, 0x82, 0x78,
+ 0x03, 0x81, 0x78, 0x00, 0x84, 0x78, 0x01, 0x91,
+ 0x78, 0x09, 0x81, 0x97, 0x00, 0x85, 0x97, 0x02,
+ 0x82, 0x97, 0x00, 0x83, 0x97, 0x02, 0x81, 0x97,
+ 0x00, 0x80, 0x97, 0x00, 0x81, 0x97, 0x02, 0x81,
+ 0x97, 0x02, 0x82, 0x97, 0x02, 0x8b, 0x97, 0x03,
+ 0x84, 0x97, 0x02, 0x82, 0x97, 0x00, 0x83, 0x97,
+ 0x01, 0x80, 0x97, 0x05, 0x80, 0x97, 0x0d, 0x94,
+ 0x97, 0x04, 0x8c, 0x99, 0x00, 0x82, 0x99, 0x00,
+ 0x96, 0x99, 0x00, 0x8f, 0x99, 0x01, 0x88, 0x99,
+ 0x00, 0x82, 0x99, 0x00, 0x83, 0x99, 0x06, 0x81,
+ 0x99, 0x00, 0x82, 0x99, 0x01, 0x80, 0x99, 0x01,
+ 0x83, 0x99, 0x01, 0x89, 0x99, 0x06, 0x88, 0x99,
+ 0x8c, 0x3f, 0x00, 0x82, 0x3f, 0x00, 0x96, 0x3f,
+ 0x00, 0x89, 0x3f, 0x00, 0x84, 0x3f, 0x01, 0x88,
+ 0x3f, 0x00, 0x82, 0x3f, 0x00, 0x83, 0x3f, 0x06,
+ 0x81, 0x3f, 0x05, 0x81, 0x3f, 0x00, 0x83, 0x3f,
+ 0x01, 0x89, 0x3f, 0x00, 0x82, 0x3f, 0x0b, 0x8c,
+ 0x54, 0x00, 0x82, 0x54, 0x00, 0xb2, 0x54, 0x00,
+ 0x82, 0x54, 0x00, 0x85, 0x54, 0x03, 0x8f, 0x54,
+ 0x01, 0x99, 0x54, 0x00, 0x82, 0x89, 0x00, 0x91,
+ 0x89, 0x02, 0x97, 0x89, 0x00, 0x88, 0x89, 0x00,
+ 0x80, 0x89, 0x01, 0x86, 0x89, 0x02, 0x80, 0x89,
+ 0x03, 0x85, 0x89, 0x00, 0x80, 0x89, 0x00, 0x87,
+ 0x89, 0x05, 0x89, 0x89, 0x01, 0x82, 0x89, 0x0b,
+ 0xb9, 0x9b, 0x03, 0x80, 0x19, 0x9b, 0x9b, 0x24,
+ 0x81, 0x49, 0x00, 0x80, 0x49, 0x00, 0x84, 0x49,
+ 0x00, 0x97, 0x49, 0x00, 0x80, 0x49, 0x00, 0x96,
+ 0x49, 0x01, 0x84, 0x49, 0x00, 0x80, 0x49, 0x00,
+ 0x86, 0x49, 0x00, 0x89, 0x49, 0x01, 0x83, 0x49,
+ 0x1f, 0xc7, 0x9c, 0x00, 0xa3, 0x9c, 0x03, 0xa6,
+ 0x9c, 0x00, 0xa3, 0x9c, 0x00, 0x8e, 0x9c, 0x00,
+ 0x86, 0x9c, 0x83, 0x19, 0x81, 0x9c, 0x24, 0xe0,
+ 0x3f, 0x63, 0xa5, 0x29, 0x00, 0x80, 0x29, 0x04,
+ 0x80, 0x29, 0x01, 0xaa, 0x29, 0x80, 0x19, 0x83,
+ 0x29, 0xe0, 0x9f, 0x33, 0xc8, 0x27, 0x00, 0x83,
0x27, 0x01, 0x86, 0x27, 0x00, 0x80, 0x27, 0x00,
0x83, 0x27, 0x01, 0xa8, 0x27, 0x00, 0x83, 0x27,
0x01, 0xa0, 0x27, 0x00, 0x83, 0x27, 0x01, 0x86,
@@ -3254,366 +3391,430 @@ static const uint8_t unicode_script_table[2720] = {
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, 0x69, 0x02, 0xca, 0x7e,
- 0x82, 0x19, 0x8a, 0x7e, 0x06, 0x95, 0x8c, 0x08,
- 0x80, 0x8c, 0x94, 0x33, 0x81, 0x19, 0x08, 0x93,
- 0x11, 0x0b, 0x8c, 0x8d, 0x00, 0x82, 0x8d, 0x00,
- 0x81, 0x8d, 0x0b, 0xdd, 0x42, 0x01, 0x89, 0x42,
- 0x05, 0x89, 0x42, 0x05, 0x81, 0x5d, 0x81, 0x19,
- 0x80, 0x5d, 0x80, 0x19, 0x93, 0x5d, 0x05, 0xd8,
- 0x5d, 0x06, 0xaa, 0x5d, 0x04, 0xc5, 0x12, 0x09,
- 0x9e, 0x49, 0x00, 0x8b, 0x49, 0x03, 0x8b, 0x49,
- 0x03, 0x80, 0x49, 0x02, 0x8b, 0x49, 0x9d, 0x8e,
- 0x01, 0x84, 0x8e, 0x0a, 0xab, 0x64, 0x03, 0x99,
- 0x64, 0x05, 0x8a, 0x64, 0x02, 0x81, 0x64, 0x9f,
- 0x42, 0x9b, 0x10, 0x01, 0x81, 0x10, 0xbe, 0x8f,
- 0x00, 0x9c, 0x8f, 0x01, 0x8a, 0x8f, 0x05, 0x89,
- 0x8f, 0x05, 0x8d, 0x8f, 0x01, 0x9e, 0x38, 0x30,
- 0xcc, 0x07, 0x02, 0xae, 0x07, 0x00, 0xbf, 0x89,
- 0xb3, 0x0a, 0x07, 0x83, 0x0a, 0xb7, 0x48, 0x02,
- 0x8e, 0x48, 0x02, 0x82, 0x48, 0xaf, 0x6a, 0x88,
- 0x1d, 0x06, 0xaa, 0x28, 0x01, 0x82, 0x28, 0x87,
- 0x89, 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, 0x47, 0x84, 0x2c, 0x80,
- 0x1d, 0xb0, 0x47, 0x84, 0x2c, 0x83, 0x47, 0x84,
- 0x2c, 0x8c, 0x47, 0x80, 0x1d, 0xc5, 0x47, 0x80,
- 0x2c, 0xbf, 0x38, 0xe0, 0x9f, 0x47, 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,
- 0x47, 0x01, 0x8a, 0x19, 0x80, 0x47, 0x8e, 0x19,
- 0x00, 0x8c, 0x47, 0x02, 0xa0, 0x19, 0x0e, 0xa0,
- 0x38, 0x0e, 0xa5, 0x19, 0x80, 0x2c, 0x82, 0x19,
- 0x81, 0x47, 0x85, 0x19, 0x80, 0x47, 0x9a, 0x19,
- 0x80, 0x47, 0x90, 0x19, 0xa8, 0x47, 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, 0x47, 0xe0, 0x13, 0x1a, 0x04,
- 0x86, 0x1a, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04,
- 0x80, 0x28, 0x01, 0xb7, 0x98, 0x06, 0x81, 0x98,
- 0x0d, 0x80, 0x98, 0x96, 0x27, 0x08, 0x86, 0x27,
+ 0xe2, 0x1f, 0x12, 0x9c, 0x6c, 0x02, 0xca, 0x82,
+ 0x82, 0x19, 0x8a, 0x82, 0x06, 0x95, 0x91, 0x08,
+ 0x80, 0x91, 0x94, 0x35, 0x81, 0x19, 0x08, 0x93,
+ 0x11, 0x0b, 0x8c, 0x92, 0x00, 0x82, 0x92, 0x00,
+ 0x81, 0x92, 0x0b, 0xdd, 0x44, 0x01, 0x89, 0x44,
+ 0x05, 0x89, 0x44, 0x05, 0x81, 0x60, 0x81, 0x19,
+ 0x80, 0x60, 0x80, 0x19, 0x93, 0x60, 0x05, 0xd8,
+ 0x60, 0x06, 0xaa, 0x60, 0x04, 0xc5, 0x12, 0x09,
+ 0x9e, 0x4c, 0x00, 0x8b, 0x4c, 0x03, 0x8b, 0x4c,
+ 0x03, 0x80, 0x4c, 0x02, 0x8b, 0x4c, 0x9d, 0x93,
+ 0x01, 0x84, 0x93, 0x0a, 0xab, 0x67, 0x03, 0x99,
+ 0x67, 0x05, 0x8a, 0x67, 0x02, 0x81, 0x67, 0x9f,
+ 0x44, 0x9b, 0x10, 0x01, 0x81, 0x10, 0xbe, 0x94,
+ 0x00, 0x9c, 0x94, 0x01, 0x8a, 0x94, 0x05, 0x89,
+ 0x94, 0x05, 0x8d, 0x94, 0x01, 0x9e, 0x3a, 0x30,
+ 0xcc, 0x07, 0x00, 0xb1, 0x07, 0xbf, 0x8d, 0xb3,
+ 0x0a, 0x07, 0x83, 0x0a, 0xb7, 0x4b, 0x02, 0x8e,
+ 0x4b, 0x02, 0x82, 0x4b, 0xaf, 0x6d, 0x8a, 0x1d,
+ 0x04, 0xaa, 0x29, 0x01, 0x82, 0x29, 0x87, 0x8d,
+ 0x07, 0x82, 0x3a, 0x80, 0x19, 0x8c, 0x3a, 0x80,
+ 0x19, 0x86, 0x3a, 0x83, 0x19, 0x80, 0x3a, 0x85,
+ 0x19, 0x80, 0x3a, 0x82, 0x19, 0x81, 0x3a, 0x80,
+ 0x19, 0x04, 0xa5, 0x4a, 0x84, 0x2d, 0x80, 0x1d,
+ 0xb0, 0x4a, 0x84, 0x2d, 0x83, 0x4a, 0x84, 0x2d,
+ 0x8c, 0x4a, 0x80, 0x1d, 0xc5, 0x4a, 0x80, 0x2d,
+ 0xbf, 0x3a, 0xe0, 0x9f, 0x4a, 0x95, 0x2d, 0x01,
+ 0x85, 0x2d, 0x01, 0xa5, 0x2d, 0x01, 0x85, 0x2d,
+ 0x01, 0x87, 0x2d, 0x00, 0x80, 0x2d, 0x00, 0x80,
+ 0x2d, 0x00, 0x80, 0x2d, 0x00, 0x9e, 0x2d, 0x01,
+ 0xb4, 0x2d, 0x00, 0x8e, 0x2d, 0x00, 0x8d, 0x2d,
+ 0x01, 0x85, 0x2d, 0x00, 0x92, 0x2d, 0x01, 0x82,
+ 0x2d, 0x00, 0x88, 0x2d, 0x00, 0x8b, 0x19, 0x81,
+ 0x3a, 0xd6, 0x19, 0x00, 0x8a, 0x19, 0x80, 0x4a,
+ 0x01, 0x8a, 0x19, 0x80, 0x4a, 0x8e, 0x19, 0x00,
+ 0x8c, 0x4a, 0x02, 0xa0, 0x19, 0x0e, 0xa0, 0x3a,
+ 0x0e, 0xa5, 0x19, 0x80, 0x2d, 0x82, 0x19, 0x81,
+ 0x4a, 0x85, 0x19, 0x80, 0x4a, 0x9a, 0x19, 0x80,
+ 0x4a, 0x90, 0x19, 0xa8, 0x4a, 0x82, 0x19, 0x03,
+ 0xe2, 0x39, 0x19, 0x15, 0x8a, 0x19, 0x14, 0xe3,
+ 0x3f, 0x19, 0xe0, 0x9f, 0x0f, 0xe2, 0x13, 0x19,
+ 0x01, 0x9f, 0x19, 0x00, 0xe0, 0x08, 0x19, 0xdf,
+ 0x2a, 0x9f, 0x4a, 0xe0, 0x13, 0x1a, 0x04, 0x86,
+ 0x1a, 0xa5, 0x29, 0x00, 0x80, 0x29, 0x04, 0x80,
+ 0x29, 0x01, 0xb7, 0x9d, 0x06, 0x81, 0x9d, 0x0d,
+ 0x80, 0x9d, 0x96, 0x27, 0x08, 0x86, 0x27, 0x00,
+ 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86, 0x27,
0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86,
- 0x27, 0x00, 0x86, 0x27, 0x00, 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, 0xa2, 0x02,
- 0xb6, 0xa2, 0x08, 0xaf, 0x4c, 0xe0, 0xcb, 0x9d,
- 0x13, 0xdf, 0x1d, 0xd7, 0x08, 0x07, 0xa1, 0x19,
- 0xe0, 0x05, 0x47, 0x82, 0x19, 0xbf, 0x47, 0x04,
- 0x81, 0x47, 0x00, 0x80, 0x47, 0x00, 0x84, 0x47,
- 0x17, 0x8d, 0x47, 0xac, 0x8a, 0x02, 0x89, 0x19,
- 0x05, 0xb7, 0x7a, 0x07, 0xc5, 0x80, 0x07, 0x8b,
- 0x80, 0x05, 0x9f, 0x20, 0xad, 0x40, 0x80, 0x19,
- 0x80, 0x40, 0xa3, 0x7d, 0x0a, 0x80, 0x7d, 0x9c,
- 0x31, 0x02, 0xcd, 0x3b, 0x00, 0x80, 0x19, 0x89,
- 0x3b, 0x03, 0x81, 0x3b, 0x9e, 0x60, 0x00, 0xb6,
- 0x16, 0x08, 0x8d, 0x16, 0x01, 0x89, 0x16, 0x01,
- 0x83, 0x16, 0x9f, 0x60, 0xc2, 0x90, 0x17, 0x84,
- 0x90, 0x96, 0x57, 0x09, 0x85, 0x27, 0x01, 0x85,
- 0x27, 0x01, 0x85, 0x27, 0x08, 0x86, 0x27, 0x00,
- 0x86, 0x27, 0x00, 0xaa, 0x47, 0x80, 0x19, 0x88,
- 0x47, 0x80, 0x2c, 0x83, 0x47, 0x81, 0x19, 0x03,
- 0xcf, 0x17, 0xad, 0x57, 0x01, 0x89, 0x57, 0x05,
- 0xf0, 0x1b, 0x43, 0x31, 0x0b, 0x96, 0x31, 0x03,
- 0xb0, 0x31, 0x70, 0x10, 0xa3, 0xe1, 0x0d, 0x30,
- 0x01, 0xe0, 0x09, 0x30, 0x25, 0x86, 0x47, 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, 0x47,
- 0x85, 0x19, 0x99, 0x47, 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, 0x4b,
- 0x00, 0x99, 0x4b, 0x00, 0x92, 0x4b, 0x00, 0x81,
- 0x4b, 0x00, 0x8e, 0x4b, 0x01, 0x8d, 0x4b, 0x21,
- 0xe0, 0x1a, 0x4b, 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, 0x4d, 0x02, 0xb0, 0x13,
- 0x0e, 0x80, 0x38, 0x9a, 0x19, 0x03, 0xa3, 0x6c,
- 0x08, 0x82, 0x6c, 0x9a, 0x2a, 0x04, 0xaa, 0x6e,
- 0x04, 0x9d, 0x9c, 0x00, 0x80, 0x9c, 0xa3, 0x6f,
- 0x03, 0x8d, 0x6f, 0x29, 0xcf, 0x1f, 0xaf, 0x82,
- 0x9d, 0x76, 0x01, 0x89, 0x76, 0x05, 0xa3, 0x75,
- 0x03, 0xa3, 0x75, 0x03, 0xa7, 0x25, 0x07, 0xb3,
- 0x14, 0x0a, 0x80, 0x14, 0x8a, 0x9e, 0x00, 0x8e,
- 0x9e, 0x00, 0x86, 0x9e, 0x00, 0x81, 0x9e, 0x00,
- 0x8a, 0x9e, 0x00, 0x8e, 0x9e, 0x00, 0x86, 0x9e,
- 0x00, 0x81, 0x9e, 0x42, 0xe0, 0xd6, 0x4a, 0x08,
- 0x95, 0x4a, 0x09, 0x87, 0x4a, 0x17, 0x85, 0x47,
- 0x00, 0xa9, 0x47, 0x00, 0x88, 0x47, 0x44, 0x85,
- 0x1c, 0x01, 0x80, 0x1c, 0x00, 0xab, 0x1c, 0x00,
- 0x81, 0x1c, 0x02, 0x80, 0x1c, 0x01, 0x80, 0x1c,
- 0x95, 0x37, 0x00, 0x88, 0x37, 0x9f, 0x78, 0x9e,
- 0x61, 0x07, 0x88, 0x61, 0x2f, 0x92, 0x34, 0x00,
- 0x81, 0x34, 0x04, 0x84, 0x34, 0x9b, 0x7b, 0x02,
- 0x80, 0x7b, 0x99, 0x4e, 0x04, 0x80, 0x4e, 0x3f,
- 0x9f, 0x5a, 0x97, 0x59, 0x03, 0x93, 0x59, 0x01,
- 0xad, 0x59, 0x83, 0x41, 0x00, 0x81, 0x41, 0x04,
- 0x87, 0x41, 0x00, 0x82, 0x41, 0x00, 0x9c, 0x41,
- 0x01, 0x82, 0x41, 0x03, 0x89, 0x41, 0x06, 0x88,
- 0x41, 0x06, 0x9f, 0x71, 0x9f, 0x6d, 0x1f, 0xa6,
- 0x53, 0x03, 0x8b, 0x53, 0x08, 0xb5, 0x06, 0x02,
- 0x86, 0x06, 0x95, 0x3a, 0x01, 0x87, 0x3a, 0x92,
- 0x39, 0x04, 0x87, 0x39, 0x91, 0x7c, 0x06, 0x83,
- 0x7c, 0x0b, 0x86, 0x7c, 0x4f, 0xc8, 0x72, 0x36,
- 0xb2, 0x6b, 0x0c, 0xb2, 0x6b, 0x06, 0x85, 0x6b,
- 0xa7, 0x32, 0x07, 0x89, 0x32, 0x60, 0xc5, 0x9e,
- 0x04, 0x00, 0xa9, 0xa1, 0x00, 0x82, 0xa1, 0x01,
- 0x81, 0xa1, 0x4a, 0x82, 0x04, 0xa7, 0x70, 0x07,
- 0xa9, 0x86, 0x15, 0x99, 0x73, 0x25, 0x9b, 0x18,
- 0x13, 0x96, 0x26, 0x08, 0xcd, 0x0e, 0x03, 0xa3,
- 0x0e, 0x08, 0x80, 0x0e, 0xc2, 0x3c, 0x09, 0x80,
- 0x3c, 0x01, 0x98, 0x87, 0x06, 0x89, 0x87, 0x05,
- 0xb4, 0x15, 0x00, 0x91, 0x15, 0x07, 0xa6, 0x50,
- 0x08, 0xdf, 0x81, 0x00, 0x93, 0x85, 0x0a, 0x91,
- 0x43, 0x00, 0xae, 0x43, 0x3d, 0x86, 0x5f, 0x00,
- 0x80, 0x5f, 0x00, 0x83, 0x5f, 0x00, 0x8e, 0x5f,
- 0x00, 0x8a, 0x5f, 0x05, 0xba, 0x45, 0x04, 0x89,
- 0x45, 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, 0x65, 0x00, 0x84, 0x65, 0x1d,
- 0xc7, 0x99, 0x07, 0x89, 0x99, 0x60, 0x45, 0xb5,
- 0x83, 0x01, 0xa5, 0x83, 0x21, 0xc4, 0x5c, 0x0a,
- 0x89, 0x5c, 0x05, 0x8c, 0x5d, 0x12, 0xb9, 0x91,
- 0x05, 0x89, 0x91, 0x35, 0x9a, 0x02, 0x01, 0x8e,
+ 0x27, 0x00, 0x86, 0x27, 0x00, 0x9f, 0x1d, 0xdd,
+ 0x19, 0x21, 0x99, 0x32, 0x00, 0xd8, 0x32, 0x0b,
+ 0xe0, 0x75, 0x32, 0x19, 0x94, 0x19, 0x80, 0x32,
+ 0x80, 0x19, 0x80, 0x32, 0x98, 0x19, 0x88, 0x32,
+ 0x83, 0x3a, 0x81, 0x33, 0x87, 0x19, 0x83, 0x32,
+ 0x83, 0x19, 0x00, 0xd5, 0x38, 0x01, 0x81, 0x3a,
+ 0x81, 0x19, 0x82, 0x38, 0x80, 0x19, 0xd9, 0x40,
+ 0x81, 0x19, 0x82, 0x40, 0x04, 0xaa, 0x0d, 0x00,
+ 0xdd, 0x33, 0x00, 0x8f, 0x19, 0x9f, 0x0d, 0xa5,
+ 0x19, 0x08, 0x80, 0x19, 0x8f, 0x40, 0x9e, 0x33,
+ 0x00, 0xbf, 0x19, 0x9e, 0x33, 0xd0, 0x19, 0xae,
+ 0x40, 0x80, 0x19, 0xd7, 0x40, 0xe0, 0x47, 0x19,
+ 0xf0, 0x09, 0x5f, 0x32, 0xbf, 0x19, 0xf0, 0x41,
+ 0x9f, 0x32, 0xe4, 0x2c, 0xa9, 0x02, 0xb6, 0xa9,
+ 0x08, 0xaf, 0x4f, 0xe0, 0xcb, 0xa4, 0x13, 0xdf,
+ 0x1d, 0xd7, 0x08, 0x07, 0xa1, 0x19, 0xe0, 0x05,
+ 0x4a, 0x82, 0x19, 0xc2, 0x4a, 0x01, 0x81, 0x4a,
+ 0x00, 0x80, 0x4a, 0x00, 0x87, 0x4a, 0x14, 0x8d,
+ 0x4a, 0xac, 0x8f, 0x02, 0x89, 0x19, 0x05, 0xb7,
+ 0x7e, 0x07, 0xc5, 0x84, 0x07, 0x8b, 0x84, 0x05,
+ 0x9f, 0x20, 0xad, 0x42, 0x80, 0x19, 0x80, 0x42,
+ 0xa3, 0x81, 0x0a, 0x80, 0x81, 0x9c, 0x33, 0x02,
+ 0xcd, 0x3d, 0x00, 0x80, 0x19, 0x89, 0x3d, 0x03,
+ 0x81, 0x3d, 0x9e, 0x63, 0x00, 0xb6, 0x16, 0x08,
+ 0x8d, 0x16, 0x01, 0x89, 0x16, 0x01, 0x83, 0x16,
+ 0x9f, 0x63, 0xc2, 0x95, 0x17, 0x84, 0x95, 0x96,
+ 0x5a, 0x09, 0x85, 0x27, 0x01, 0x85, 0x27, 0x01,
+ 0x85, 0x27, 0x08, 0x86, 0x27, 0x00, 0x86, 0x27,
+ 0x00, 0xaa, 0x4a, 0x80, 0x19, 0x88, 0x4a, 0x80,
+ 0x2d, 0x83, 0x4a, 0x81, 0x19, 0x03, 0xcf, 0x17,
+ 0xad, 0x5a, 0x01, 0x89, 0x5a, 0x05, 0xf0, 0x1b,
+ 0x43, 0x33, 0x0b, 0x96, 0x33, 0x03, 0xb0, 0x33,
+ 0x70, 0x10, 0xa3, 0xe1, 0x0d, 0x32, 0x01, 0xe0,
+ 0x09, 0x32, 0x25, 0x86, 0x4a, 0x0b, 0x84, 0x05,
+ 0x04, 0x99, 0x37, 0x00, 0x84, 0x37, 0x00, 0x80,
+ 0x37, 0x00, 0x81, 0x37, 0x00, 0x81, 0x37, 0x00,
+ 0x89, 0x37, 0xe0, 0x12, 0x04, 0x0f, 0xe1, 0x0a,
+ 0x04, 0x81, 0x19, 0xcf, 0x04, 0x01, 0xb5, 0x04,
+ 0x06, 0x80, 0x04, 0x1f, 0x8f, 0x04, 0x8f, 0x3a,
+ 0x89, 0x19, 0x05, 0x8d, 0x3a, 0x81, 0x1d, 0xa2,
+ 0x19, 0x00, 0x92, 0x19, 0x00, 0x83, 0x19, 0x03,
+ 0x84, 0x04, 0x00, 0xe0, 0x26, 0x04, 0x01, 0x80,
+ 0x19, 0x00, 0x9f, 0x19, 0x99, 0x4a, 0x85, 0x19,
+ 0x99, 0x4a, 0x8a, 0x19, 0x89, 0x40, 0x80, 0x19,
+ 0xac, 0x40, 0x81, 0x19, 0x9e, 0x33, 0x02, 0x85,
+ 0x33, 0x01, 0x85, 0x33, 0x01, 0x85, 0x33, 0x01,
+ 0x82, 0x33, 0x02, 0x86, 0x19, 0x00, 0x86, 0x19,
+ 0x09, 0x84, 0x19, 0x01, 0x8b, 0x4e, 0x00, 0x99,
+ 0x4e, 0x00, 0x92, 0x4e, 0x00, 0x81, 0x4e, 0x00,
+ 0x8e, 0x4e, 0x01, 0x8d, 0x4e, 0x21, 0xe0, 0x1a,
+ 0x4e, 0x04, 0x82, 0x19, 0x03, 0xac, 0x19, 0x02,
+ 0x88, 0x19, 0xce, 0x2d, 0x00, 0x8c, 0x19, 0x02,
+ 0x80, 0x2d, 0x2e, 0xac, 0x19, 0x80, 0x3a, 0x60,
+ 0x21, 0x9c, 0x50, 0x02, 0xb0, 0x13, 0x0e, 0x80,
+ 0x3a, 0x9a, 0x19, 0x03, 0xa3, 0x70, 0x08, 0x82,
+ 0x70, 0x9a, 0x2b, 0x04, 0xaa, 0x72, 0x04, 0x9d,
+ 0xa3, 0x00, 0x80, 0xa3, 0xa3, 0x73, 0x03, 0x8d,
+ 0x73, 0x29, 0xcf, 0x1f, 0xaf, 0x86, 0x9d, 0x7a,
+ 0x01, 0x89, 0x7a, 0x05, 0xa3, 0x79, 0x03, 0xa3,
+ 0x79, 0x03, 0xa7, 0x25, 0x07, 0xb3, 0x14, 0x0a,
+ 0x80, 0x14, 0x8a, 0xa5, 0x00, 0x8e, 0xa5, 0x00,
+ 0x86, 0xa5, 0x00, 0x81, 0xa5, 0x00, 0x8a, 0xa5,
+ 0x00, 0x8e, 0xa5, 0x00, 0x86, 0xa5, 0x00, 0x81,
+ 0xa5, 0x02, 0xb3, 0xa0, 0x0b, 0xe0, 0xd6, 0x4d,
+ 0x08, 0x95, 0x4d, 0x09, 0x87, 0x4d, 0x17, 0x85,
+ 0x4a, 0x00, 0xa9, 0x4a, 0x00, 0x88, 0x4a, 0x44,
+ 0x85, 0x1c, 0x01, 0x80, 0x1c, 0x00, 0xab, 0x1c,
+ 0x00, 0x81, 0x1c, 0x02, 0x80, 0x1c, 0x01, 0x80,
+ 0x1c, 0x95, 0x39, 0x00, 0x88, 0x39, 0x9f, 0x7c,
+ 0x9e, 0x64, 0x07, 0x88, 0x64, 0x2f, 0x92, 0x36,
+ 0x00, 0x81, 0x36, 0x04, 0x84, 0x36, 0x9b, 0x7f,
+ 0x02, 0x80, 0x7f, 0x99, 0x51, 0x04, 0x80, 0x51,
+ 0x3f, 0x9f, 0x5d, 0x97, 0x5c, 0x03, 0x93, 0x5c,
+ 0x01, 0xad, 0x5c, 0x83, 0x43, 0x00, 0x81, 0x43,
+ 0x04, 0x87, 0x43, 0x00, 0x82, 0x43, 0x00, 0x9c,
+ 0x43, 0x01, 0x82, 0x43, 0x03, 0x89, 0x43, 0x06,
+ 0x88, 0x43, 0x06, 0x9f, 0x75, 0x9f, 0x71, 0x1f,
+ 0xa6, 0x56, 0x03, 0x8b, 0x56, 0x08, 0xb5, 0x06,
+ 0x02, 0x86, 0x06, 0x95, 0x3c, 0x01, 0x87, 0x3c,
+ 0x92, 0x3b, 0x04, 0x87, 0x3b, 0x91, 0x80, 0x06,
+ 0x83, 0x80, 0x0b, 0x86, 0x80, 0x4f, 0xc8, 0x76,
+ 0x36, 0xb2, 0x6f, 0x0c, 0xb2, 0x6f, 0x06, 0x85,
+ 0x6f, 0xa7, 0x34, 0x07, 0x89, 0x34, 0x05, 0xa5,
+ 0x28, 0x02, 0x9c, 0x28, 0x07, 0x81, 0x28, 0x60,
+ 0x6f, 0x9e, 0x04, 0x00, 0xa9, 0xa8, 0x00, 0x82,
+ 0xa8, 0x01, 0x81, 0xa8, 0x0f, 0x82, 0x04, 0x36,
+ 0x83, 0x04, 0xa7, 0x74, 0x07, 0xa9, 0x8a, 0x15,
+ 0x99, 0x77, 0x25, 0x9b, 0x18, 0x13, 0x96, 0x26,
+ 0x08, 0xcd, 0x0e, 0x03, 0xa3, 0x0e, 0x08, 0x80,
+ 0x0e, 0xc2, 0x3e, 0x09, 0x80, 0x3e, 0x01, 0x98,
+ 0x8b, 0x06, 0x89, 0x8b, 0x05, 0xb4, 0x15, 0x00,
+ 0x91, 0x15, 0x07, 0xa6, 0x53, 0x08, 0xdf, 0x85,
+ 0x00, 0x93, 0x89, 0x0a, 0x91, 0x45, 0x00, 0xae,
+ 0x45, 0x3d, 0x86, 0x62, 0x00, 0x80, 0x62, 0x00,
+ 0x83, 0x62, 0x00, 0x8e, 0x62, 0x00, 0x8a, 0x62,
+ 0x05, 0xba, 0x47, 0x04, 0x89, 0x47, 0x05, 0x83,
+ 0x2c, 0x00, 0x87, 0x2c, 0x01, 0x81, 0x2c, 0x01,
+ 0x95, 0x2c, 0x00, 0x86, 0x2c, 0x00, 0x81, 0x2c,
+ 0x00, 0x84, 0x2c, 0x00, 0x80, 0x3a, 0x88, 0x2c,
+ 0x01, 0x81, 0x2c, 0x01, 0x82, 0x2c, 0x01, 0x80,
+ 0x2c, 0x05, 0x80, 0x2c, 0x04, 0x86, 0x2c, 0x01,
+ 0x86, 0x2c, 0x02, 0x84, 0x2c, 0x0a, 0x89, 0xa2,
+ 0x00, 0x80, 0xa2, 0x01, 0x80, 0xa2, 0x00, 0xa5,
+ 0xa2, 0x00, 0x89, 0xa2, 0x00, 0x80, 0xa2, 0x01,
+ 0x80, 0xa2, 0x00, 0x83, 0xa2, 0x00, 0x89, 0xa2,
+ 0x00, 0x81, 0xa2, 0x07, 0x81, 0xa2, 0x1c, 0xdb,
+ 0x68, 0x00, 0x84, 0x68, 0x1d, 0xc7, 0x9e, 0x07,
+ 0x89, 0x9e, 0x60, 0x45, 0xb5, 0x87, 0x01, 0xa5,
+ 0x87, 0x21, 0xc4, 0x5f, 0x0a, 0x89, 0x5f, 0x05,
+ 0x8c, 0x60, 0x12, 0xb9, 0x96, 0x05, 0x89, 0x96,
+ 0x05, 0x93, 0x63, 0x1b, 0x9a, 0x02, 0x01, 0x8e,
0x02, 0x03, 0x96, 0x02, 0x60, 0x58, 0xbb, 0x22,
- 0x60, 0x03, 0xd2, 0xa0, 0x0b, 0x80, 0xa0, 0x86,
+ 0x60, 0x03, 0xd2, 0xa7, 0x0b, 0x80, 0xa7, 0x86,
0x21, 0x01, 0x80, 0x21, 0x01, 0x87, 0x21, 0x00,
0x81, 0x21, 0x00, 0x9d, 0x21, 0x00, 0x81, 0x21,
0x01, 0x8b, 0x21, 0x08, 0x89, 0x21, 0x45, 0x87,
- 0x63, 0x01, 0xad, 0x63, 0x01, 0x8a, 0x63, 0x1a,
- 0xc7, 0xa3, 0x07, 0xd2, 0x88, 0x0c, 0x8f, 0x12,
- 0xb8, 0x79, 0x06, 0x89, 0x20, 0x60, 0x95, 0x88,
- 0x0c, 0x00, 0xac, 0x0c, 0x00, 0x8d, 0x0c, 0x09,
- 0x9c, 0x0c, 0x02, 0x9f, 0x54, 0x01, 0x95, 0x54,
- 0x00, 0x8d, 0x54, 0x48, 0x86, 0x55, 0x00, 0x81,
- 0x55, 0x00, 0xab, 0x55, 0x02, 0x80, 0x55, 0x00,
- 0x81, 0x55, 0x00, 0x88, 0x55, 0x07, 0x89, 0x55,
- 0x05, 0x85, 0x2e, 0x00, 0x81, 0x2e, 0x00, 0xa4,
- 0x2e, 0x00, 0x81, 0x2e, 0x00, 0x85, 0x2e, 0x06,
- 0x89, 0x2e, 0x60, 0xd5, 0x98, 0x4f, 0x06, 0x90,
- 0x3f, 0x00, 0xa8, 0x3f, 0x02, 0x9b, 0x3f, 0x55,
- 0x80, 0x4c, 0x0e, 0xb1, 0x92, 0x0c, 0x80, 0x92,
- 0xe3, 0x39, 0x1b, 0x60, 0x05, 0xe0, 0x0e, 0x1b,
- 0x00, 0x84, 0x1b, 0x0a, 0xe0, 0x63, 0x1b, 0x69,
- 0xeb, 0xe0, 0x02, 0x1e, 0x0c, 0xe3, 0xf5, 0x24,
- 0x6f, 0x49, 0xe1, 0xe6, 0x03, 0x70, 0x11, 0x58,
- 0xe1, 0xd8, 0x08, 0x06, 0x9e, 0x5e, 0x00, 0x89,
- 0x5e, 0x03, 0x81, 0x5e, 0xce, 0x9a, 0x00, 0x89,
- 0x9a, 0x05, 0x9d, 0x09, 0x01, 0x85, 0x09, 0x09,
- 0xc5, 0x77, 0x09, 0x89, 0x77, 0x00, 0x86, 0x77,
- 0x00, 0x94, 0x77, 0x04, 0x92, 0x77, 0x62, 0x4f,
- 0xda, 0x56, 0x60, 0x04, 0xca, 0x5b, 0x03, 0xb8,
- 0x5b, 0x06, 0x90, 0x5b, 0x3f, 0x80, 0x93, 0x80,
- 0x67, 0x81, 0x30, 0x80, 0x44, 0x0a, 0x81, 0x30,
- 0x0d, 0xf0, 0x07, 0x97, 0x93, 0x07, 0xe2, 0x9f,
- 0x93, 0xe1, 0x75, 0x44, 0x29, 0x88, 0x93, 0x70,
- 0x12, 0x86, 0x83, 0x3e, 0x00, 0x86, 0x3e, 0x00,
- 0x81, 0x3e, 0x00, 0x80, 0x3e, 0xe0, 0xbe, 0x36,
- 0x82, 0x3e, 0x0e, 0x80, 0x36, 0x1c, 0x82, 0x36,
- 0x01, 0x80, 0x3e, 0x0d, 0x83, 0x3e, 0x07, 0xe1,
- 0x2b, 0x67, 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, 0x19,
- 0x93, 0x19, 0x0b, 0x93, 0x19, 0x0b, 0xd6, 0x19,
- 0x08, 0x98, 0x19, 0x60, 0x26, 0xd4, 0x19, 0x00,
- 0xc6, 0x19, 0x00, 0x81, 0x19, 0x01, 0x80, 0x19,
- 0x01, 0x81, 0x19, 0x01, 0x83, 0x19, 0x00, 0x8b,
- 0x19, 0x00, 0x80, 0x19, 0x00, 0x86, 0x19, 0x00,
- 0xc0, 0x19, 0x00, 0x83, 0x19, 0x01, 0x87, 0x19,
- 0x00, 0x86, 0x19, 0x00, 0x9b, 0x19, 0x00, 0x83,
- 0x19, 0x00, 0x84, 0x19, 0x00, 0x80, 0x19, 0x02,
- 0x86, 0x19, 0x00, 0xe0, 0xf3, 0x19, 0x01, 0xe0,
- 0xc3, 0x19, 0x01, 0xb1, 0x19, 0xe2, 0x2b, 0x84,
- 0x0e, 0x84, 0x84, 0x00, 0x8e, 0x84, 0x63, 0xef,
- 0x9e, 0x47, 0x05, 0x85, 0x47, 0x60, 0x74, 0x86,
- 0x29, 0x00, 0x90, 0x29, 0x01, 0x86, 0x29, 0x00,
- 0x81, 0x29, 0x00, 0x84, 0x29, 0x04, 0xbd, 0x1d,
- 0x20, 0x80, 0x1d, 0x60, 0x0f, 0xac, 0x68, 0x02,
- 0x8d, 0x68, 0x01, 0x89, 0x68, 0x03, 0x81, 0x68,
- 0x60, 0xdf, 0x9e, 0x9b, 0x10, 0xb9, 0x9f, 0x04,
- 0x80, 0x9f, 0x61, 0x6f, 0xa9, 0x62, 0x62, 0x85,
- 0x86, 0x27, 0x00, 0x83, 0x27, 0x00, 0x81, 0x27,
- 0x00, 0x8e, 0x27, 0x00, 0xe0, 0x64, 0x58, 0x01,
- 0x8f, 0x58, 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, 0x03, 0x90, 0x19, 0x02, 0x8c, 0x19, 0x02,
- 0xe0, 0x16, 0x19, 0x03, 0xde, 0x19, 0x05, 0x8b,
- 0x19, 0x03, 0x80, 0x19, 0x0e, 0x8b, 0x19, 0x03,
- 0xb7, 0x19, 0x07, 0x89, 0x19, 0x05, 0xa7, 0x19,
- 0x07, 0x9d, 0x19, 0x01, 0x81, 0x19, 0x4d, 0xe0,
- 0xf3, 0x19, 0x0b, 0x8d, 0x19, 0x01, 0x8c, 0x19,
- 0x02, 0x88, 0x19, 0x06, 0xad, 0x19, 0x00, 0x86,
- 0x19, 0x07, 0x8d, 0x19, 0x03, 0x88, 0x19, 0x06,
- 0x88, 0x19, 0x06, 0xe0, 0x32, 0x19, 0x00, 0xb6,
- 0x19, 0x24, 0x89, 0x19, 0x63, 0xa5, 0xf0, 0x96,
- 0x7f, 0x30, 0x1f, 0xef, 0xd9, 0x30, 0x05, 0xe0,
- 0x7d, 0x30, 0x01, 0xf0, 0x06, 0x21, 0x30, 0x0d,
- 0xf0, 0x0c, 0xd0, 0x30, 0x6b, 0xbe, 0xe1, 0xbd,
- 0x30, 0x65, 0x81, 0xf0, 0x02, 0xea, 0x30, 0x04,
- 0xef, 0xff, 0x30, 0x7a, 0xcb, 0xf0, 0x80, 0x19,
- 0x1d, 0xdf, 0x19, 0x60, 0x1f, 0xe0, 0x8f, 0x38,
+ 0x66, 0x01, 0xad, 0x66, 0x01, 0x8a, 0x66, 0x1a,
+ 0xc7, 0xaa, 0x07, 0xd2, 0x8c, 0x0c, 0x8f, 0x12,
+ 0xb8, 0x7d, 0x06, 0x89, 0x20, 0x60, 0x55, 0xa1,
+ 0x8e, 0x0d, 0x89, 0x8e, 0x05, 0x88, 0x0c, 0x00,
+ 0xac, 0x0c, 0x00, 0x8d, 0x0c, 0x09, 0x9c, 0x0c,
+ 0x02, 0x9f, 0x57, 0x01, 0x95, 0x57, 0x00, 0x8d,
+ 0x57, 0x48, 0x86, 0x58, 0x00, 0x81, 0x58, 0x00,
+ 0xab, 0x58, 0x02, 0x80, 0x58, 0x00, 0x81, 0x58,
+ 0x00, 0x88, 0x58, 0x07, 0x89, 0x58, 0x05, 0x85,
+ 0x2f, 0x00, 0x81, 0x2f, 0x00, 0xa4, 0x2f, 0x00,
+ 0x81, 0x2f, 0x00, 0x85, 0x2f, 0x06, 0x89, 0x2f,
+ 0x60, 0xd5, 0x98, 0x52, 0x06, 0x90, 0x41, 0x00,
+ 0xa8, 0x41, 0x02, 0x9c, 0x41, 0x54, 0x80, 0x4f,
+ 0x0e, 0xb1, 0x97, 0x0c, 0x80, 0x97, 0xe3, 0x39,
+ 0x1b, 0x60, 0x05, 0xe0, 0x0e, 0x1b, 0x00, 0x84,
+ 0x1b, 0x0a, 0xe0, 0x63, 0x1b, 0x69, 0xeb, 0xe0,
+ 0x02, 0x1e, 0x0c, 0xe3, 0xf5, 0x24, 0x09, 0xef,
+ 0x3a, 0x24, 0x04, 0xe1, 0xe6, 0x03, 0x70, 0x0a,
+ 0x58, 0xb9, 0x31, 0x66, 0x65, 0xe1, 0xd8, 0x08,
+ 0x06, 0x9e, 0x61, 0x00, 0x89, 0x61, 0x03, 0x81,
+ 0x61, 0xce, 0x9f, 0x00, 0x89, 0x9f, 0x05, 0x9d,
+ 0x09, 0x01, 0x85, 0x09, 0x09, 0xc5, 0x7b, 0x09,
+ 0x89, 0x7b, 0x00, 0x86, 0x7b, 0x00, 0x94, 0x7b,
+ 0x04, 0x92, 0x7b, 0x61, 0x4f, 0xb9, 0x48, 0x60,
+ 0x65, 0xda, 0x59, 0x60, 0x04, 0xca, 0x5e, 0x03,
+ 0xb8, 0x5e, 0x06, 0x90, 0x5e, 0x3f, 0x80, 0x98,
+ 0x80, 0x6a, 0x81, 0x32, 0x80, 0x46, 0x0a, 0x81,
+ 0x32, 0x0d, 0xf0, 0x07, 0x97, 0x98, 0x07, 0xe2,
+ 0x9f, 0x98, 0xe1, 0x75, 0x46, 0x28, 0x80, 0x46,
+ 0x88, 0x98, 0x70, 0x12, 0x86, 0x83, 0x40, 0x00,
+ 0x86, 0x40, 0x00, 0x81, 0x40, 0x00, 0x80, 0x40,
+ 0xe0, 0xbe, 0x38, 0x82, 0x40, 0x0e, 0x80, 0x38,
+ 0x1c, 0x82, 0x38, 0x01, 0x80, 0x40, 0x0d, 0x83,
+ 0x40, 0x07, 0xe1, 0x2b, 0x6a, 0x68, 0xa3, 0xe0,
+ 0x0a, 0x23, 0x04, 0x8c, 0x23, 0x02, 0x88, 0x23,
+ 0x06, 0x89, 0x23, 0x01, 0x83, 0x23, 0x83, 0x19,
+ 0x6e, 0xfb, 0xe0, 0x99, 0x19, 0x05, 0xe1, 0x53,
+ 0x19, 0x4b, 0xad, 0x3a, 0x01, 0x96, 0x3a, 0x08,
+ 0xe0, 0x13, 0x19, 0x3b, 0xe0, 0x95, 0x19, 0x09,
+ 0xa6, 0x19, 0x01, 0xbd, 0x19, 0x82, 0x3a, 0x90,
+ 0x19, 0x87, 0x3a, 0x81, 0x19, 0x86, 0x3a, 0x9d,
+ 0x19, 0x83, 0x3a, 0xbc, 0x19, 0x14, 0xc5, 0x2d,
+ 0x60, 0x19, 0x93, 0x19, 0x0b, 0x93, 0x19, 0x0b,
+ 0xd6, 0x19, 0x08, 0x98, 0x19, 0x60, 0x26, 0xd4,
+ 0x19, 0x00, 0xc6, 0x19, 0x00, 0x81, 0x19, 0x01,
+ 0x80, 0x19, 0x01, 0x81, 0x19, 0x01, 0x83, 0x19,
+ 0x00, 0x8b, 0x19, 0x00, 0x80, 0x19, 0x00, 0x86,
+ 0x19, 0x00, 0xc0, 0x19, 0x00, 0x83, 0x19, 0x01,
+ 0x87, 0x19, 0x00, 0x86, 0x19, 0x00, 0x9b, 0x19,
+ 0x00, 0x83, 0x19, 0x00, 0x84, 0x19, 0x00, 0x80,
+ 0x19, 0x02, 0x86, 0x19, 0x00, 0xe0, 0xf3, 0x19,
+ 0x01, 0xe0, 0xc3, 0x19, 0x01, 0xb1, 0x19, 0xe2,
+ 0x2b, 0x88, 0x0e, 0x84, 0x88, 0x00, 0x8e, 0x88,
+ 0x63, 0xef, 0x9e, 0x4a, 0x05, 0x85, 0x4a, 0x60,
+ 0x74, 0x86, 0x2a, 0x00, 0x90, 0x2a, 0x01, 0x86,
+ 0x2a, 0x00, 0x81, 0x2a, 0x00, 0x84, 0x2a, 0x04,
+ 0xbd, 0x1d, 0x20, 0x80, 0x1d, 0x60, 0x0f, 0xac,
+ 0x6b, 0x02, 0x8d, 0x6b, 0x01, 0x89, 0x6b, 0x03,
+ 0x81, 0x6b, 0x60, 0xdf, 0x9e, 0xa1, 0x10, 0xb9,
+ 0xa6, 0x04, 0x80, 0xa6, 0x61, 0x6f, 0xa9, 0x65,
+ 0x60, 0x75, 0xaa, 0x6e, 0x03, 0x80, 0x6e, 0x61,
+ 0x7f, 0x86, 0x27, 0x00, 0x83, 0x27, 0x00, 0x81,
+ 0x27, 0x00, 0x8e, 0x27, 0x00, 0xe0, 0x64, 0x5b,
+ 0x01, 0x8f, 0x5b, 0x28, 0xcb, 0x01, 0x03, 0x89,
+ 0x01, 0x03, 0x81, 0x01, 0x62, 0xb0, 0xc3, 0x19,
+ 0x4b, 0xbc, 0x19, 0x60, 0x61, 0x83, 0x04, 0x00,
+ 0x9a, 0x04, 0x00, 0x81, 0x04, 0x00, 0x80, 0x04,
+ 0x01, 0x80, 0x04, 0x00, 0x89, 0x04, 0x00, 0x83,
+ 0x04, 0x00, 0x80, 0x04, 0x00, 0x80, 0x04, 0x05,
+ 0x80, 0x04, 0x03, 0x80, 0x04, 0x00, 0x80, 0x04,
+ 0x00, 0x80, 0x04, 0x00, 0x82, 0x04, 0x00, 0x81,
+ 0x04, 0x00, 0x80, 0x04, 0x01, 0x80, 0x04, 0x00,
+ 0x80, 0x04, 0x00, 0x80, 0x04, 0x00, 0x80, 0x04,
+ 0x00, 0x80, 0x04, 0x00, 0x81, 0x04, 0x00, 0x80,
+ 0x04, 0x01, 0x83, 0x04, 0x00, 0x86, 0x04, 0x00,
+ 0x83, 0x04, 0x00, 0x83, 0x04, 0x00, 0x80, 0x04,
+ 0x00, 0x89, 0x04, 0x00, 0x90, 0x04, 0x04, 0x82,
+ 0x04, 0x00, 0x84, 0x04, 0x00, 0x90, 0x04, 0x33,
+ 0x81, 0x04, 0x60, 0xad, 0xab, 0x19, 0x03, 0xe0,
+ 0x03, 0x19, 0x0b, 0x8e, 0x19, 0x01, 0x8e, 0x19,
+ 0x00, 0x8e, 0x19, 0x00, 0xa4, 0x19, 0x09, 0xe0,
+ 0x4d, 0x19, 0x37, 0x99, 0x19, 0x80, 0x38, 0x81,
+ 0x19, 0x0c, 0xab, 0x19, 0x03, 0x88, 0x19, 0x06,
+ 0x81, 0x19, 0x0d, 0x85, 0x19, 0x60, 0x39, 0xe3,
+ 0x77, 0x19, 0x03, 0x90, 0x19, 0x02, 0x8c, 0x19,
+ 0x02, 0xe0, 0x16, 0x19, 0x03, 0xde, 0x19, 0x05,
+ 0x8b, 0x19, 0x03, 0x80, 0x19, 0x0e, 0x8b, 0x19,
+ 0x03, 0xb7, 0x19, 0x07, 0x89, 0x19, 0x05, 0xa7,
+ 0x19, 0x07, 0x9d, 0x19, 0x01, 0x8b, 0x19, 0x03,
+ 0x81, 0x19, 0x3d, 0xe0, 0xf3, 0x19, 0x0b, 0x8d,
+ 0x19, 0x01, 0x8c, 0x19, 0x02, 0x89, 0x19, 0x04,
+ 0xb7, 0x19, 0x06, 0x8e, 0x19, 0x01, 0x8a, 0x19,
+ 0x05, 0x88, 0x19, 0x06, 0xe0, 0x32, 0x19, 0x00,
+ 0xe0, 0x05, 0x19, 0x63, 0xa5, 0xf0, 0x96, 0x7f,
+ 0x32, 0x1f, 0xef, 0xd9, 0x32, 0x05, 0xe0, 0x7d,
+ 0x32, 0x01, 0xf0, 0x06, 0x21, 0x32, 0x0d, 0xf0,
+ 0x0c, 0xd0, 0x32, 0x0e, 0xe2, 0x0d, 0x32, 0x69,
+ 0x41, 0xe1, 0xbd, 0x32, 0x65, 0x81, 0xf0, 0x02,
+ 0xea, 0x32, 0x04, 0xef, 0xff, 0x32, 0x7a, 0xcb,
+ 0xf0, 0x80, 0x19, 0x1d, 0xdf, 0x19, 0x60, 0x1f,
+ 0xe0, 0x8f, 0x3a,
};
-static const uint8_t unicode_script_ext_table[828] = {
- 0x82, 0xc1, 0x00, 0x00, 0x01, 0x2c, 0x01, 0x00,
- 0x00, 0x01, 0x2c, 0x1c, 0x00, 0x0c, 0x01, 0x47,
- 0x80, 0x92, 0x00, 0x00, 0x02, 0x1d, 0x6e, 0x00,
- 0x02, 0x1d, 0x29, 0x01, 0x02, 0x1d, 0x47, 0x00,
- 0x02, 0x1d, 0x29, 0x81, 0x03, 0x00, 0x00, 0x06,
- 0x04, 0x66, 0x32, 0x8b, 0x95, 0xa1, 0x0d, 0x00,
- 0x00, 0x06, 0x04, 0x66, 0x32, 0x8b, 0x95, 0xa1,
- 0x00, 0x03, 0x04, 0x8b, 0x95, 0x01, 0x00, 0x00,
- 0x07, 0x01, 0x04, 0x66, 0x32, 0x8b, 0x95, 0xa1,
- 0x1f, 0x00, 0x00, 0x09, 0x01, 0x04, 0x52, 0x53,
- 0x73, 0x7c, 0x32, 0x86, 0x8b, 0x09, 0x00, 0x0a,
- 0x02, 0x04, 0x8b, 0x09, 0x00, 0x09, 0x03, 0x04,
- 0x95, 0xa1, 0x05, 0x00, 0x00, 0x02, 0x04, 0x8b,
- 0x62, 0x00, 0x00, 0x02, 0x04, 0x32, 0x81, 0xfb,
- 0x00, 0x00, 0x0d, 0x0b, 0x20, 0x2b, 0x2d, 0x2f,
- 0x3d, 0x47, 0x51, 0x74, 0x81, 0x92, 0x94, 0x99,
- 0x00, 0x0c, 0x0b, 0x20, 0x2b, 0x2d, 0x2f, 0x3d,
- 0x47, 0x51, 0x74, 0x92, 0x94, 0x99, 0x10, 0x00,
- 0x00, 0x14, 0x0b, 0x20, 0x22, 0x2e, 0x55, 0x2b,
- 0x2d, 0x2f, 0x3d, 0x50, 0x51, 0x63, 0x74, 0x45,
- 0x85, 0x8a, 0x91, 0x92, 0x94, 0x99, 0x00, 0x15,
- 0x0b, 0x20, 0x22, 0x2e, 0x55, 0x2b, 0x2d, 0x2f,
- 0x3d, 0x49, 0x50, 0x51, 0x63, 0x74, 0x45, 0x85,
- 0x8a, 0x91, 0x92, 0x94, 0x99, 0x09, 0x04, 0x20,
- 0x22, 0x3c, 0x50, 0x75, 0x00, 0x09, 0x03, 0x0b,
- 0x15, 0x8a, 0x75, 0x00, 0x09, 0x02, 0x2f, 0x5f,
- 0x75, 0x00, 0x09, 0x02, 0x2d, 0x43, 0x80, 0x75,
- 0x00, 0x0d, 0x02, 0x2b, 0x92, 0x80, 0x71, 0x00,
- 0x09, 0x02, 0x3d, 0x63, 0x82, 0xcf, 0x00, 0x09,
- 0x03, 0x15, 0x60, 0x8e, 0x80, 0x30, 0x00, 0x00,
- 0x02, 0x28, 0x47, 0x85, 0xb8, 0x00, 0x01, 0x04,
- 0x11, 0x33, 0x8d, 0x8c, 0x80, 0x4a, 0x00, 0x01,
- 0x02, 0x5d, 0x7a, 0x00, 0x00, 0x00, 0x02, 0x5d,
- 0x7a, 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, 0x81, 0x00, 0x02, 0x0b, 0x20, 0x00, 0x02,
- 0x20, 0x81, 0x00, 0x06, 0x20, 0x3d, 0x51, 0x74,
- 0x92, 0x94, 0x00, 0x01, 0x20, 0x01, 0x02, 0x20,
- 0x81, 0x01, 0x01, 0x20, 0x00, 0x02, 0x20, 0x81,
- 0x00, 0x02, 0x0b, 0x20, 0x06, 0x01, 0x20, 0x00,
- 0x02, 0x20, 0x63, 0x00, 0x02, 0x0b, 0x20, 0x01,
- 0x01, 0x20, 0x00, 0x02, 0x0b, 0x20, 0x03, 0x01,
- 0x20, 0x00, 0x08, 0x0b, 0x20, 0x2b, 0x3d, 0x63,
- 0x74, 0x94, 0x99, 0x00, 0x02, 0x20, 0x2b, 0x00,
- 0x03, 0x20, 0x2b, 0x3d, 0x01, 0x02, 0x0b, 0x20,
- 0x00, 0x01, 0x0b, 0x01, 0x02, 0x20, 0x2b, 0x00,
- 0x01, 0x63, 0x80, 0x44, 0x00, 0x01, 0x01, 0x2c,
- 0x35, 0x00, 0x00, 0x02, 0x1d, 0x8b, 0x00, 0x00,
- 0x00, 0x01, 0x8b, 0x81, 0xb3, 0x00, 0x00, 0x02,
- 0x47, 0x5d, 0x80, 0x3f, 0x00, 0x00, 0x03, 0x20,
- 0x2b, 0x47, 0x8c, 0xd1, 0x00, 0x00, 0x02, 0x1d,
- 0x29, 0x81, 0x3c, 0x00, 0x01, 0x06, 0x0d, 0x31,
- 0x30, 0x36, 0x3e, 0xa2, 0x00, 0x05, 0x0d, 0x31,
- 0x30, 0x36, 0x3e, 0x01, 0x00, 0x00, 0x01, 0x30,
- 0x00, 0x00, 0x09, 0x06, 0x0d, 0x31, 0x30, 0x36,
- 0x3e, 0xa2, 0x00, 0x00, 0x00, 0x05, 0x0d, 0x31,
- 0x30, 0x36, 0x3e, 0x07, 0x06, 0x0d, 0x31, 0x30,
- 0x36, 0x3e, 0xa2, 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, 0xa2, 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, 0x47, 0x80,
- 0xa7, 0x00, 0x02, 0x0e, 0x20, 0x22, 0x2d, 0x2f,
- 0x43, 0x3d, 0x3c, 0x50, 0x51, 0x5c, 0x63, 0x45,
- 0x91, 0x99, 0x02, 0x0d, 0x20, 0x22, 0x2d, 0x2f,
- 0x43, 0x3d, 0x3c, 0x50, 0x5c, 0x63, 0x45, 0x91,
- 0x99, 0x03, 0x0b, 0x20, 0x22, 0x2d, 0x2f, 0x43,
- 0x3c, 0x50, 0x5c, 0x45, 0x91, 0x99, 0x80, 0x36,
- 0x00, 0x00, 0x02, 0x0b, 0x20, 0x00, 0x00, 0x00,
- 0x02, 0x20, 0x92, 0x39, 0x00, 0x00, 0x03, 0x40,
- 0x47, 0x60, 0x80, 0x1f, 0x00, 0x00, 0x02, 0x10,
- 0x3b, 0xc0, 0x12, 0xed, 0x00, 0x01, 0x02, 0x04,
- 0x66, 0x80, 0x31, 0x00, 0x00, 0x02, 0x04, 0x95,
- 0x09, 0x00, 0x00, 0x02, 0x04, 0x95, 0x46, 0x00,
- 0x01, 0x05, 0x0d, 0x31, 0x30, 0x36, 0x3e, 0x80,
- 0x99, 0x00, 0x04, 0x06, 0x0d, 0x31, 0x30, 0x36,
- 0x3e, 0xa2, 0x09, 0x00, 0x00, 0x02, 0x36, 0x3e,
- 0x2c, 0x00, 0x01, 0x02, 0x36, 0x3e, 0x80, 0xdf,
- 0x00, 0x01, 0x03, 0x1e, 0x1c, 0x4b, 0x00, 0x02,
- 0x1c, 0x4b, 0x03, 0x00, 0x2c, 0x03, 0x1c, 0x4a,
- 0x4b, 0x02, 0x00, 0x08, 0x02, 0x1c, 0x4b, 0x81,
- 0x1f, 0x00, 0x1b, 0x02, 0x04, 0x1a, 0x87, 0x75,
- 0x00, 0x00, 0x02, 0x53, 0x73, 0x87, 0x8d, 0x00,
- 0x00, 0x02, 0x2b, 0x92, 0x00, 0x00, 0x00, 0x02,
- 0x2b, 0x92, 0x36, 0x00, 0x01, 0x02, 0x2b, 0x92,
- 0x8c, 0x12, 0x00, 0x01, 0x02, 0x2b, 0x92, 0x00,
- 0x00, 0x00, 0x02, 0x2b, 0x92, 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_script_ext_table[1253] = {
+ 0x80, 0x36, 0x00, 0x00, 0x10, 0x06, 0x13, 0x1a,
+ 0x23, 0x25, 0x29, 0x2a, 0x2f, 0x2b, 0x2d, 0x32,
+ 0x4a, 0x51, 0x53, 0x72, 0x86, 0x81, 0x83, 0x00,
+ 0x00, 0x07, 0x0b, 0x1d, 0x20, 0x4a, 0x4f, 0x9b,
+ 0xa1, 0x09, 0x00, 0x00, 0x02, 0x0d, 0x4a, 0x00,
+ 0x00, 0x02, 0x02, 0x0d, 0x4a, 0x00, 0x00, 0x00,
+ 0x02, 0x4a, 0x4f, 0x08, 0x00, 0x00, 0x02, 0x4a,
+ 0x9b, 0x00, 0x00, 0x00, 0x02, 0x0d, 0x4a, 0x25,
+ 0x00, 0x00, 0x08, 0x17, 0x1a, 0x1d, 0x2d, 0x4a,
+ 0x72, 0x8e, 0x93, 0x00, 0x08, 0x17, 0x1d, 0x2d,
+ 0x4a, 0x79, 0x8e, 0x93, 0xa0, 0x00, 0x04, 0x17,
+ 0x1d, 0x4a, 0x9d, 0x00, 0x05, 0x2a, 0x4a, 0x8e,
+ 0x90, 0x9b, 0x00, 0x0b, 0x14, 0x17, 0x1a, 0x1d,
+ 0x2b, 0x2d, 0x4a, 0x79, 0x90, 0x9d, 0xa0, 0x00,
+ 0x06, 0x1a, 0x25, 0x2a, 0x2b, 0x40, 0x4a, 0x00,
+ 0x04, 0x1d, 0x2d, 0x4a, 0x72, 0x00, 0x09, 0x1a,
+ 0x23, 0x37, 0x4a, 0x72, 0x90, 0x93, 0x9d, 0xa0,
+ 0x00, 0x0a, 0x05, 0x1d, 0x23, 0x2b, 0x2d, 0x37,
+ 0x4a, 0x72, 0x90, 0x93, 0x00, 0x02, 0x4a, 0x9d,
+ 0x00, 0x03, 0x23, 0x4a, 0x90, 0x00, 0x04, 0x17,
+ 0x1d, 0x4a, 0x79, 0x00, 0x03, 0x17, 0x4a, 0x93,
+ 0x00, 0x02, 0x4a, 0x8e, 0x00, 0x02, 0x27, 0x4a,
+ 0x00, 0x00, 0x00, 0x02, 0x4a, 0x8e, 0x00, 0x03,
+ 0x1d, 0x4a, 0xa0, 0x00, 0x00, 0x00, 0x04, 0x2d,
+ 0x4a, 0x72, 0xa0, 0x0b, 0x00, 0x00, 0x02, 0x4a,
+ 0x90, 0x01, 0x00, 0x00, 0x05, 0x17, 0x23, 0x40,
+ 0x4a, 0x90, 0x00, 0x04, 0x17, 0x23, 0x4a, 0x90,
+ 0x00, 0x02, 0x4a, 0x90, 0x06, 0x00, 0x00, 0x03,
+ 0x4a, 0x8e, 0x90, 0x00, 0x02, 0x4a, 0x90, 0x00,
+ 0x00, 0x00, 0x03, 0x17, 0x4a, 0x90, 0x00, 0x06,
+ 0x14, 0x17, 0x2b, 0x4a, 0x8e, 0x9b, 0x0f, 0x00,
+ 0x00, 0x01, 0x2d, 0x01, 0x00, 0x00, 0x01, 0x2d,
+ 0x11, 0x00, 0x00, 0x02, 0x4a, 0x79, 0x04, 0x00,
+ 0x00, 0x03, 0x14, 0x4a, 0xa0, 0x03, 0x00, 0x0c,
+ 0x01, 0x4a, 0x03, 0x00, 0x01, 0x02, 0x1a, 0x2d,
+ 0x80, 0x8c, 0x00, 0x00, 0x02, 0x1d, 0x72, 0x00,
+ 0x02, 0x1d, 0x2a, 0x01, 0x02, 0x1d, 0x4a, 0x00,
+ 0x02, 0x1d, 0x2a, 0x80, 0x80, 0x00, 0x00, 0x03,
+ 0x05, 0x29, 0x2a, 0x80, 0x01, 0x00, 0x00, 0x07,
+ 0x04, 0x28, 0x69, 0x34, 0x90, 0x9a, 0xa8, 0x0d,
+ 0x00, 0x00, 0x07, 0x04, 0x28, 0x69, 0x34, 0x90,
+ 0x9a, 0xa8, 0x00, 0x03, 0x04, 0x90, 0x9a, 0x01,
+ 0x00, 0x00, 0x08, 0x01, 0x04, 0x28, 0x69, 0x34,
+ 0x90, 0x9a, 0xa8, 0x1f, 0x00, 0x00, 0x09, 0x01,
+ 0x04, 0x55, 0x56, 0x77, 0x80, 0x34, 0x8a, 0x90,
+ 0x09, 0x00, 0x0a, 0x02, 0x04, 0x90, 0x09, 0x00,
+ 0x09, 0x03, 0x04, 0x9a, 0xa8, 0x05, 0x00, 0x00,
+ 0x02, 0x04, 0x90, 0x62, 0x00, 0x00, 0x02, 0x04,
+ 0x34, 0x81, 0xfb, 0x00, 0x00, 0x0d, 0x0b, 0x20,
+ 0x2c, 0x2e, 0x30, 0x3f, 0x4a, 0x54, 0x78, 0x85,
+ 0x97, 0x99, 0x9e, 0x00, 0x0c, 0x0b, 0x20, 0x2c,
+ 0x2e, 0x30, 0x3f, 0x4a, 0x54, 0x78, 0x97, 0x99,
+ 0x9e, 0x10, 0x00, 0x00, 0x15, 0x0b, 0x20, 0x22,
+ 0x2f, 0x58, 0x2c, 0x2e, 0x30, 0x3f, 0x53, 0x54,
+ 0x66, 0x6e, 0x78, 0x47, 0x89, 0x8f, 0x96, 0x97,
+ 0x99, 0x9e, 0x00, 0x17, 0x0b, 0x20, 0x22, 0x2f,
+ 0x58, 0x2c, 0x2e, 0x31, 0x30, 0x3f, 0x4c, 0x53,
+ 0x54, 0x66, 0x6e, 0x78, 0x47, 0x89, 0x8f, 0x96,
+ 0x97, 0x99, 0x9e, 0x09, 0x04, 0x20, 0x22, 0x3e,
+ 0x53, 0x75, 0x00, 0x09, 0x03, 0x0b, 0x15, 0x8f,
+ 0x75, 0x00, 0x09, 0x02, 0x30, 0x62, 0x75, 0x00,
+ 0x09, 0x02, 0x2e, 0x45, 0x80, 0x75, 0x00, 0x0d,
+ 0x02, 0x2c, 0x97, 0x80, 0x71, 0x00, 0x09, 0x03,
+ 0x3f, 0x66, 0xa2, 0x82, 0xcf, 0x00, 0x09, 0x03,
+ 0x15, 0x63, 0x93, 0x80, 0x30, 0x00, 0x00, 0x03,
+ 0x29, 0x2a, 0x4a, 0x85, 0x6e, 0x00, 0x02, 0x01,
+ 0x82, 0x46, 0x00, 0x01, 0x04, 0x11, 0x35, 0x92,
+ 0x91, 0x80, 0x4a, 0x00, 0x01, 0x02, 0x60, 0x7e,
+ 0x00, 0x00, 0x00, 0x02, 0x60, 0x7e, 0x84, 0x49,
+ 0x00, 0x00, 0x04, 0x0b, 0x20, 0x2c, 0x3f, 0x00,
+ 0x01, 0x20, 0x00, 0x04, 0x0b, 0x20, 0x2c, 0x3f,
+ 0x00, 0x03, 0x20, 0x2c, 0x3f, 0x00, 0x01, 0x20,
+ 0x01, 0x02, 0x0b, 0x20, 0x00, 0x02, 0x20, 0x85,
+ 0x00, 0x02, 0x0b, 0x20, 0x00, 0x02, 0x20, 0x85,
+ 0x00, 0x06, 0x20, 0x3f, 0x54, 0x78, 0x97, 0x99,
+ 0x00, 0x01, 0x20, 0x01, 0x02, 0x20, 0x85, 0x01,
+ 0x01, 0x20, 0x00, 0x02, 0x20, 0x85, 0x00, 0x02,
+ 0x0b, 0x20, 0x06, 0x01, 0x20, 0x00, 0x02, 0x20,
+ 0x66, 0x00, 0x02, 0x0b, 0x20, 0x01, 0x01, 0x20,
+ 0x00, 0x02, 0x0b, 0x20, 0x03, 0x01, 0x20, 0x00,
+ 0x0b, 0x0b, 0x20, 0x2c, 0x3f, 0x54, 0x66, 0x78,
+ 0x89, 0x99, 0x9e, 0xa2, 0x00, 0x02, 0x20, 0x2c,
+ 0x00, 0x04, 0x20, 0x2c, 0x3f, 0xa2, 0x01, 0x02,
+ 0x0b, 0x20, 0x00, 0x01, 0x0b, 0x01, 0x02, 0x20,
+ 0x2c, 0x00, 0x01, 0x66, 0x80, 0x44, 0x00, 0x01,
+ 0x01, 0x2d, 0x35, 0x00, 0x00, 0x03, 0x1d, 0x4a,
+ 0x90, 0x00, 0x00, 0x00, 0x01, 0x90, 0x81, 0xb3,
+ 0x00, 0x00, 0x03, 0x4a, 0x60, 0x7e, 0x1e, 0x00,
+ 0x00, 0x02, 0x01, 0x04, 0x09, 0x00, 0x00, 0x06,
+ 0x13, 0x29, 0x2a, 0x6f, 0x50, 0x76, 0x01, 0x00,
+ 0x00, 0x04, 0x13, 0x2d, 0x6f, 0x5d, 0x80, 0x11,
+ 0x00, 0x00, 0x03, 0x20, 0x2c, 0x4a, 0x8c, 0xa5,
+ 0x00, 0x00, 0x02, 0x1a, 0x4a, 0x17, 0x00, 0x00,
+ 0x02, 0x06, 0x76, 0x00, 0x07, 0x06, 0x13, 0x29,
+ 0x6f, 0x3e, 0x51, 0x83, 0x09, 0x00, 0x00, 0x01,
+ 0x23, 0x03, 0x00, 0x00, 0x03, 0x01, 0x04, 0x6f,
+ 0x00, 0x00, 0x00, 0x02, 0x1d, 0x2a, 0x81, 0x2b,
+ 0x00, 0x0f, 0x02, 0x32, 0x98, 0x00, 0x00, 0x00,
+ 0x07, 0x0d, 0x33, 0x32, 0x38, 0x40, 0x60, 0xa9,
+ 0x00, 0x08, 0x0d, 0x33, 0x32, 0x38, 0x40, 0x60,
+ 0x7e, 0xa9, 0x00, 0x05, 0x0d, 0x33, 0x32, 0x38,
+ 0x40, 0x01, 0x00, 0x00, 0x01, 0x32, 0x00, 0x00,
+ 0x01, 0x08, 0x0d, 0x33, 0x32, 0x38, 0x40, 0x60,
+ 0x9c, 0xa9, 0x01, 0x09, 0x0d, 0x33, 0x32, 0x38,
+ 0x40, 0x4f, 0x60, 0x9c, 0xa9, 0x05, 0x06, 0x0d,
+ 0x33, 0x32, 0x38, 0x40, 0xa9, 0x00, 0x00, 0x00,
+ 0x05, 0x0d, 0x33, 0x32, 0x38, 0x40, 0x07, 0x06,
+ 0x0d, 0x33, 0x32, 0x38, 0x40, 0xa9, 0x03, 0x05,
+ 0x0d, 0x33, 0x32, 0x38, 0x40, 0x09, 0x00, 0x03,
+ 0x02, 0x0d, 0x32, 0x01, 0x00, 0x00, 0x05, 0x0d,
+ 0x33, 0x32, 0x38, 0x40, 0x04, 0x02, 0x38, 0x40,
+ 0x00, 0x00, 0x00, 0x05, 0x0d, 0x33, 0x32, 0x38,
+ 0x40, 0x03, 0x00, 0x01, 0x03, 0x32, 0x38, 0x40,
+ 0x01, 0x01, 0x32, 0x58, 0x00, 0x03, 0x02, 0x38,
+ 0x40, 0x02, 0x00, 0x00, 0x02, 0x38, 0x40, 0x59,
+ 0x00, 0x00, 0x06, 0x0d, 0x33, 0x32, 0x38, 0x40,
+ 0xa9, 0x00, 0x02, 0x38, 0x40, 0x80, 0x12, 0x00,
+ 0x0f, 0x01, 0x32, 0x1f, 0x00, 0x25, 0x01, 0x32,
+ 0x08, 0x00, 0x00, 0x02, 0x32, 0x98, 0x2f, 0x00,
+ 0x27, 0x01, 0x32, 0x37, 0x00, 0x30, 0x01, 0x32,
+ 0x0e, 0x00, 0x0b, 0x01, 0x32, 0x32, 0x00, 0x00,
+ 0x01, 0x32, 0x57, 0x00, 0x18, 0x01, 0x32, 0x09,
+ 0x00, 0x04, 0x01, 0x32, 0x5f, 0x00, 0x1e, 0x01,
+ 0x32, 0xc0, 0x31, 0xef, 0x00, 0x00, 0x02, 0x1d,
+ 0x2a, 0x80, 0x0f, 0x00, 0x07, 0x02, 0x32, 0x4a,
+ 0x80, 0xa7, 0x00, 0x02, 0x10, 0x20, 0x22, 0x2e,
+ 0x30, 0x45, 0x3f, 0x3e, 0x53, 0x54, 0x5f, 0x66,
+ 0x85, 0x47, 0x96, 0x9e, 0xa2, 0x02, 0x0f, 0x20,
+ 0x22, 0x2e, 0x30, 0x45, 0x3f, 0x3e, 0x53, 0x5f,
+ 0x66, 0x85, 0x47, 0x96, 0x9e, 0xa2, 0x01, 0x0b,
+ 0x20, 0x22, 0x2e, 0x30, 0x45, 0x3e, 0x53, 0x5f,
+ 0x47, 0x96, 0x9e, 0x00, 0x0c, 0x20, 0x22, 0x2e,
+ 0x30, 0x45, 0x3e, 0x53, 0x5f, 0x85, 0x47, 0x96,
+ 0x9e, 0x00, 0x0b, 0x20, 0x22, 0x2e, 0x30, 0x45,
+ 0x3e, 0x53, 0x5f, 0x47, 0x96, 0x9e, 0x80, 0x36,
+ 0x00, 0x00, 0x03, 0x0b, 0x20, 0xa2, 0x00, 0x00,
+ 0x00, 0x02, 0x20, 0x97, 0x39, 0x00, 0x00, 0x03,
+ 0x42, 0x4a, 0x63, 0x80, 0x1f, 0x00, 0x00, 0x02,
+ 0x10, 0x3d, 0xc0, 0x12, 0xed, 0x00, 0x01, 0x02,
+ 0x04, 0x69, 0x80, 0x31, 0x00, 0x00, 0x02, 0x04,
+ 0x9a, 0x09, 0x00, 0x00, 0x02, 0x04, 0x9a, 0x46,
+ 0x00, 0x01, 0x05, 0x0d, 0x33, 0x32, 0x38, 0x40,
+ 0x80, 0x99, 0x00, 0x04, 0x06, 0x0d, 0x33, 0x32,
+ 0x38, 0x40, 0xa9, 0x09, 0x00, 0x00, 0x02, 0x38,
+ 0x40, 0x2c, 0x00, 0x01, 0x02, 0x38, 0x40, 0x80,
+ 0xdf, 0x00, 0x01, 0x03, 0x1e, 0x1c, 0x4e, 0x00,
+ 0x02, 0x1c, 0x4e, 0x03, 0x00, 0x2c, 0x03, 0x1c,
+ 0x4d, 0x4e, 0x02, 0x00, 0x08, 0x02, 0x1c, 0x4e,
+ 0x81, 0x1f, 0x00, 0x1b, 0x02, 0x04, 0x1a, 0x87,
+ 0x75, 0x00, 0x00, 0x02, 0x56, 0x77, 0x87, 0x8d,
+ 0x00, 0x00, 0x02, 0x2c, 0x97, 0x00, 0x00, 0x00,
+ 0x02, 0x2c, 0x97, 0x36, 0x00, 0x01, 0x02, 0x2c,
+ 0x97, 0x8c, 0x12, 0x00, 0x01, 0x02, 0x2c, 0x97,
+ 0x00, 0x00, 0x00, 0x02, 0x2c, 0x97, 0xc0, 0x5c,
+ 0x4b, 0x00, 0x03, 0x01, 0x23, 0x96, 0x3b, 0x00,
+ 0x11, 0x01, 0x32, 0x9e, 0x5d, 0x00, 0x01, 0x01,
+ 0x32, 0xce, 0xcd, 0x2d, 0x00,
};
static const uint8_t unicode_prop_Hyphen_table[28] = {
@@ -3651,61 +3852,63 @@ static const uint8_t unicode_prop_Other_Math_table[200] = {
0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90,
};
-static const uint8_t unicode_prop_Other_Alphabetic_table[428] = {
- 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, 0x84, 0xb8,
- 0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x9c, 0x82,
- 0xb9, 0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x8e,
- 0x80, 0x8b, 0x83, 0xb9, 0x30, 0x10, 0x82, 0x89,
- 0x80, 0x89, 0x81, 0x9c, 0x82, 0xca, 0x28, 0x00,
- 0x87, 0x91, 0x81, 0xbc, 0x01, 0x86, 0x91, 0x80,
- 0xe2, 0x01, 0x28, 0x81, 0x8f, 0x80, 0x40, 0xa2,
- 0x92, 0x88, 0x8a, 0x80, 0xa3, 0xed, 0x8b, 0x00,
- 0x0b, 0x96, 0x1b, 0x10, 0x11, 0x32, 0x83, 0x8c,
- 0x8b, 0x00, 0x89, 0x83, 0x46, 0x73, 0x81, 0x9d,
- 0x81, 0x9d, 0x81, 0x9d, 0x81, 0xc1, 0x92, 0x40,
- 0xbb, 0x81, 0xa1, 0x80, 0xf5, 0x8b, 0x83, 0x88,
- 0x40, 0xdd, 0x84, 0xb8, 0x89, 0x81, 0x93, 0xc9,
- 0x81, 0x8a, 0x82, 0xb0, 0x84, 0xaf, 0x8e, 0xbb,
- 0x82, 0x9d, 0x88, 0x09, 0xb8, 0x8a, 0xb1, 0x92,
- 0x41, 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, 0x8a, 0x82, 0xac, 0x88, 0x88, 0x80, 0xbc,
- 0x82, 0xa3, 0x8b, 0x91, 0x81, 0xb8, 0x82, 0xaf,
- 0x8c, 0x8d, 0x81, 0xdb, 0x88, 0x08, 0x28, 0x08,
- 0x40, 0x9c, 0x89, 0x96, 0x83, 0xb9, 0x31, 0x09,
- 0x81, 0x89, 0x80, 0x89, 0x81, 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, 0x88, 0x08,
- 0x80, 0xaf, 0x32, 0x82, 0x60, 0x50, 0x0d, 0x00,
- 0xb6, 0x33, 0xdc, 0x81, 0x60, 0x4c, 0xab, 0x80,
- 0x60, 0x23, 0x60, 0x30, 0x90, 0x0e, 0x01, 0x04,
- 0xe3, 0x80, 0x48, 0xb6, 0x80, 0x47, 0xe7, 0x99,
- 0x85, 0x99, 0x85, 0x99,
+static const uint8_t unicode_prop_Other_Alphabetic_table[443] = {
+ 0x43, 0x44, 0x80, 0x9c, 0x8c, 0x42, 0x3f, 0x8d,
+ 0x00, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xaf, 0x8c,
+ 0x06, 0x8f, 0x80, 0xe4, 0x33, 0x19, 0x0b, 0x80,
+ 0xa2, 0x80, 0x9d, 0x8f, 0xe5, 0x8a, 0xe4, 0x0a,
+ 0x88, 0x02, 0x03, 0xe9, 0x80, 0xbb, 0x8b, 0x16,
+ 0x85, 0x93, 0xb5, 0x09, 0x8e, 0x01, 0x22, 0x89,
+ 0x81, 0x9c, 0x82, 0xb9, 0x31, 0x09, 0x81, 0x89,
+ 0x80, 0x89, 0x81, 0x9c, 0x82, 0xb9, 0x23, 0x09,
+ 0x0b, 0x80, 0x9d, 0x0a, 0x80, 0x8a, 0x82, 0xb9,
+ 0x38, 0x10, 0x81, 0x94, 0x81, 0x95, 0x13, 0x82,
+ 0xb9, 0x31, 0x09, 0x81, 0x88, 0x81, 0x89, 0x81,
+ 0x9d, 0x80, 0xba, 0x22, 0x10, 0x82, 0x89, 0x80,
+ 0xa7, 0x84, 0xb8, 0x30, 0x10, 0x17, 0x81, 0x8a,
+ 0x81, 0x9c, 0x82, 0xb9, 0x30, 0x10, 0x17, 0x81,
+ 0x8a, 0x81, 0x8e, 0x80, 0x8b, 0x83, 0xb9, 0x30,
+ 0x10, 0x82, 0x89, 0x80, 0x89, 0x81, 0x9c, 0x82,
+ 0xca, 0x28, 0x00, 0x87, 0x91, 0x81, 0xbc, 0x01,
+ 0x86, 0x91, 0x80, 0xe2, 0x01, 0x28, 0x81, 0x8f,
+ 0x80, 0x40, 0xa2, 0x92, 0x88, 0x8a, 0x80, 0xa3,
+ 0xed, 0x8b, 0x00, 0x0b, 0x96, 0x1b, 0x10, 0x11,
+ 0x32, 0x83, 0x8c, 0x8b, 0x00, 0x89, 0x83, 0x46,
+ 0x73, 0x81, 0x9d, 0x81, 0x9d, 0x81, 0x9d, 0x81,
+ 0xc1, 0x92, 0x40, 0xbb, 0x81, 0xa1, 0x80, 0xf5,
+ 0x8b, 0x83, 0x88, 0x40, 0xdd, 0x84, 0xb8, 0x89,
+ 0x81, 0x93, 0xc9, 0x81, 0x8a, 0x82, 0xb0, 0x84,
+ 0xaf, 0x8e, 0xbb, 0x82, 0x9d, 0x88, 0x09, 0xb8,
+ 0x8a, 0xb1, 0x92, 0x41, 0x9b, 0xa1, 0x46, 0xc0,
+ 0xb3, 0x48, 0xf5, 0x9f, 0x60, 0x78, 0x73, 0x87,
+ 0xa1, 0x81, 0x41, 0x61, 0x07, 0x80, 0x96, 0x84,
+ 0xd7, 0x81, 0xb1, 0x8f, 0x00, 0xb8, 0x80, 0xa5,
+ 0x84, 0x9b, 0x8b, 0xac, 0x83, 0xaf, 0x8b, 0xa4,
+ 0x80, 0xc2, 0x8d, 0x8b, 0x07, 0x81, 0xac, 0x82,
+ 0xb1, 0x00, 0x11, 0x0c, 0x80, 0xab, 0x24, 0x80,
+ 0x40, 0xec, 0x87, 0x60, 0x4f, 0x32, 0x80, 0x48,
+ 0x56, 0x84, 0x46, 0x85, 0x10, 0x0c, 0x83, 0x43,
+ 0x13, 0x83, 0xc0, 0x80, 0x41, 0x40, 0x81, 0xce,
+ 0x80, 0x41, 0x02, 0x82, 0xb4, 0x8d, 0xac, 0x81,
+ 0x8a, 0x82, 0xac, 0x88, 0x88, 0x80, 0xbc, 0x82,
+ 0xa3, 0x8b, 0x91, 0x81, 0xb8, 0x82, 0xaf, 0x8c,
+ 0x8d, 0x81, 0xdb, 0x88, 0x08, 0x28, 0x08, 0x40,
+ 0x9c, 0x89, 0x96, 0x83, 0xb9, 0x31, 0x09, 0x81,
+ 0x89, 0x80, 0x89, 0x81, 0xd3, 0x88, 0x00, 0x08,
+ 0x03, 0x01, 0xe6, 0x8c, 0x02, 0xe9, 0x91, 0x40,
+ 0xec, 0x31, 0x86, 0x9c, 0x81, 0xd1, 0x8e, 0x00,
+ 0xe9, 0x8a, 0xe6, 0x8d, 0x41, 0x00, 0x8c, 0x40,
+ 0xf6, 0x28, 0x09, 0x0a, 0x00, 0x80, 0x40, 0x8d,
+ 0x31, 0x2b, 0x80, 0x9b, 0x89, 0xa9, 0x20, 0x83,
+ 0x91, 0x8a, 0xad, 0x8d, 0x41, 0x96, 0x38, 0x86,
+ 0xd2, 0x95, 0x80, 0x8d, 0xf9, 0x2a, 0x00, 0x08,
+ 0x10, 0x02, 0x80, 0xc1, 0x20, 0x08, 0x83, 0x41,
+ 0x5b, 0x83, 0x88, 0x08, 0x80, 0xaf, 0x32, 0x82,
+ 0x60, 0x41, 0xdc, 0x90, 0x4e, 0x1f, 0x00, 0xb6,
+ 0x33, 0xdc, 0x81, 0x60, 0x4c, 0xab, 0x80, 0x60,
+ 0x23, 0x60, 0x30, 0x90, 0x0e, 0x01, 0x04, 0xe3,
+ 0x80, 0x48, 0xb6, 0x80, 0x47, 0xe7, 0x99, 0x85,
+ 0x99, 0x85, 0x99,
};
static const uint8_t unicode_prop_Other_Lowercase_table[69] = {
@@ -3725,16 +3928,21 @@ static const uint8_t unicode_prop_Other_Uppercase_table[15] = {
0xcc, 0x5f, 0x99, 0x85, 0x99, 0x85, 0x99,
};
-static const uint8_t unicode_prop_Other_Grapheme_Extend_table[65] = {
+static const uint8_t unicode_prop_Other_Grapheme_Extend_table[112] = {
0x49, 0xbd, 0x80, 0x97, 0x80, 0x41, 0x65, 0x80,
- 0x97, 0x80, 0xe5, 0x80, 0x97, 0x80, 0x40, 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,
+ 0x97, 0x80, 0xe5, 0x80, 0x97, 0x80, 0x40, 0xe7,
+ 0x00, 0x03, 0x08, 0x81, 0x88, 0x81, 0xe6, 0x80,
+ 0x97, 0x80, 0xf6, 0x80, 0x8e, 0x80, 0x49, 0x34,
+ 0x80, 0x9d, 0x80, 0x43, 0xff, 0x04, 0x00, 0x04,
+ 0x81, 0xe4, 0x80, 0xc6, 0x81, 0x44, 0x17, 0x80,
+ 0x50, 0x20, 0x81, 0x60, 0x79, 0x22, 0x80, 0xeb,
+ 0x80, 0x60, 0x55, 0xdc, 0x81, 0x52, 0x1f, 0x80,
+ 0xf3, 0x80, 0x41, 0x07, 0x80, 0x8d, 0x80, 0x88,
+ 0x80, 0xdf, 0x80, 0x88, 0x01, 0x00, 0x14, 0x80,
+ 0x40, 0xdf, 0x80, 0x8b, 0x80, 0x40, 0xf0, 0x80,
+ 0x41, 0x05, 0x80, 0x42, 0x78, 0x80, 0x8b, 0x80,
+ 0x46, 0x02, 0x80, 0x60, 0x50, 0xad, 0x81, 0x60,
+ 0x61, 0x72, 0x0d, 0x85, 0x6c, 0x2e, 0xac, 0xdf,
};
static const uint8_t unicode_prop_Other_Default_Ignorable_Code_Point_table[32] = {
@@ -3749,9 +3957,10 @@ static const uint8_t unicode_prop_Other_ID_Start_table[11] = {
0x4f, 0x6b, 0x81,
};
-static const uint8_t unicode_prop_Other_ID_Continue_table[12] = {
+static const uint8_t unicode_prop_Other_ID_Continue_table[22] = {
0x40, 0xb6, 0x80, 0x42, 0xce, 0x80, 0x4f, 0xe0,
- 0x88, 0x46, 0x67, 0x80,
+ 0x88, 0x46, 0x67, 0x80, 0x46, 0x30, 0x81, 0x50,
+ 0xec, 0x80, 0x60, 0xce, 0x68, 0x80,
};
static const uint8_t unicode_prop_Prepended_Concatenation_Mark_table[19] = {
@@ -3779,72 +3988,154 @@ static const uint8_t unicode_prop_Changes_When_Titlecased1_table[22] = {
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_Casefolded1_table[29] = {
+ 0x41, 0xef, 0x80, 0x41, 0x9e, 0x80, 0x9e, 0x80,
+ 0x5a, 0xe4, 0x83, 0x40, 0xb5, 0x00, 0x00, 0x00,
+ 0x80, 0xde, 0x06, 0x06, 0x80, 0x8a, 0x09, 0x81,
+ 0x89, 0x10, 0x81, 0x8d, 0x80,
};
-static const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[451] = {
+static const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[450] = {
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, 0x48, 0x2f, 0xbd, 0x4d, 0x91, 0x18,
- 0x9a, 0x01, 0x00, 0x08, 0x80, 0x89, 0x03, 0x00,
- 0x00, 0x28, 0x18, 0x00, 0x00, 0x02, 0x01, 0x00,
- 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0b,
- 0x06, 0x03, 0x03, 0x00, 0x80, 0x89, 0x80, 0x90,
- 0x22, 0x04, 0x80, 0x90, 0x42, 0x43, 0x8a, 0x84,
- 0x9e, 0x80, 0x9f, 0x99, 0x82, 0xa2, 0x80, 0xee,
- 0x82, 0x8c, 0xab, 0x83, 0x88, 0x31, 0x49, 0x9d,
- 0x89, 0x60, 0xfc, 0x05, 0x42, 0x1d, 0x6b, 0x05,
- 0xe1, 0x4f, 0xff,
+ 0x10, 0x82, 0xf3, 0x80, 0x8b, 0x80, 0x40, 0x84,
+ 0x01, 0x01, 0x80, 0xa2, 0x01, 0x80, 0x40, 0xbb,
+ 0x88, 0x9e, 0x29, 0x84, 0xda, 0x08, 0x81, 0x89,
+ 0x80, 0xa3, 0x04, 0x02, 0x04, 0x08, 0x07, 0x80,
+ 0x9e, 0x80, 0xa0, 0x82, 0x9c, 0x80, 0x42, 0x28,
+ 0x80, 0xd7, 0x83, 0x42, 0xde, 0x87, 0xfb, 0x08,
+ 0x80, 0xd2, 0x01, 0x80, 0xa1, 0x11, 0x80, 0x40,
+ 0xfc, 0x81, 0x42, 0xd4, 0x80, 0xfe, 0x80, 0xa7,
+ 0x81, 0xad, 0x80, 0xb5, 0x80, 0x88, 0x03, 0x03,
+ 0x03, 0x80, 0x8b, 0x80, 0x88, 0x00, 0x26, 0x80,
+ 0x90, 0x80, 0x88, 0x03, 0x03, 0x03, 0x80, 0x8b,
+ 0x80, 0x41, 0x41, 0x80, 0xe1, 0x81, 0x46, 0x52,
+ 0x81, 0xd4, 0x84, 0x45, 0x1b, 0x10, 0x8a, 0x80,
+ 0x91, 0x80, 0x9b, 0x8c, 0x80, 0xa1, 0xa4, 0x40,
+ 0xd5, 0x83, 0x40, 0xb5, 0x00, 0x00, 0x00, 0x80,
+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0xb7, 0x05, 0x00, 0x13, 0x05, 0x11, 0x02, 0x0c,
+ 0x11, 0x00, 0x00, 0x0c, 0x15, 0x05, 0x08, 0x8f,
+ 0x00, 0x20, 0x8b, 0x12, 0x2a, 0x08, 0x0b, 0x00,
+ 0x07, 0x82, 0x8c, 0x06, 0x92, 0x81, 0x9a, 0x80,
+ 0x8c, 0x8a, 0x80, 0xd6, 0x18, 0x10, 0x8a, 0x01,
+ 0x0c, 0x0a, 0x00, 0x10, 0x11, 0x02, 0x06, 0x05,
+ 0x1c, 0x85, 0x8f, 0x8f, 0x8f, 0x88, 0x80, 0x40,
+ 0xa1, 0x08, 0x81, 0x40, 0xf7, 0x81, 0x41, 0x34,
+ 0xd5, 0x99, 0x9a, 0x45, 0x20, 0x80, 0xe6, 0x82,
+ 0xe4, 0x80, 0x41, 0x9e, 0x81, 0x40, 0xf0, 0x80,
+ 0x41, 0x2e, 0x80, 0xd2, 0x80, 0x8b, 0x40, 0xd5,
+ 0xa9, 0x80, 0xb4, 0x00, 0x82, 0xdf, 0x09, 0x80,
+ 0xde, 0x80, 0xb0, 0xdd, 0x82, 0x8d, 0xdf, 0x9e,
+ 0x80, 0xa7, 0x87, 0xae, 0x80, 0x41, 0x7f, 0x60,
+ 0x72, 0x9b, 0x81, 0x40, 0xd1, 0x80, 0x40, 0x80,
+ 0x12, 0x81, 0x43, 0x61, 0x83, 0x88, 0x80, 0x60,
+ 0x4d, 0x95, 0x41, 0x0d, 0x08, 0x00, 0x81, 0x89,
+ 0x00, 0x00, 0x09, 0x82, 0xc3, 0x81, 0xe9, 0xc2,
+ 0x00, 0x97, 0x04, 0x00, 0x01, 0x01, 0x80, 0xeb,
+ 0xa0, 0x41, 0x6a, 0x91, 0xbf, 0x81, 0xb5, 0xa7,
+ 0x8c, 0x82, 0x99, 0x95, 0x94, 0x81, 0x8b, 0x80,
+ 0x92, 0x03, 0x1a, 0x00, 0x80, 0x40, 0x86, 0x08,
+ 0x80, 0x9f, 0x99, 0x40, 0x83, 0x15, 0x0d, 0x0d,
+ 0x0a, 0x16, 0x06, 0x80, 0x88, 0x47, 0x87, 0x20,
+ 0xa9, 0x80, 0x88, 0x60, 0xb4, 0xe4, 0x83, 0x50,
+ 0x31, 0xa3, 0x44, 0x63, 0x86, 0x8d, 0x87, 0xbf,
+ 0x85, 0x42, 0x3e, 0xd4, 0x80, 0xc6, 0x01, 0x08,
+ 0x09, 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0,
+ 0x03, 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00,
+ 0x16, 0x80, 0x41, 0x53, 0x81, 0x41, 0x23, 0x81,
+ 0xb1, 0x48, 0x2f, 0xbd, 0x4d, 0x91, 0x18, 0x9a,
+ 0x01, 0x00, 0x08, 0x80, 0x89, 0x03, 0x00, 0x00,
+ 0x28, 0x18, 0x00, 0x00, 0x02, 0x01, 0x00, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x06,
+ 0x03, 0x03, 0x00, 0x80, 0x89, 0x80, 0x90, 0x22,
+ 0x04, 0x80, 0x90, 0x42, 0x43, 0x8a, 0x84, 0x9e,
+ 0x80, 0x9f, 0x99, 0x82, 0xa2, 0x80, 0xee, 0x82,
+ 0x8c, 0xab, 0x83, 0x88, 0x31, 0x49, 0x9d, 0x89,
+ 0x60, 0xfc, 0x05, 0x42, 0x1d, 0x6b, 0x05, 0xe1,
+ 0x4f, 0xff,
+};
+
+static const uint8_t unicode_prop_Basic_Emoji1_table[143] = {
+ 0x60, 0x23, 0x19, 0x81, 0x40, 0xcc, 0x1a, 0x01,
+ 0x80, 0x42, 0x08, 0x81, 0x94, 0x81, 0xb1, 0x8b,
+ 0xaa, 0x80, 0x92, 0x80, 0x8c, 0x07, 0x81, 0x90,
+ 0x0c, 0x0f, 0x04, 0x80, 0x94, 0x06, 0x08, 0x03,
+ 0x01, 0x06, 0x03, 0x81, 0x9b, 0x80, 0xa2, 0x00,
+ 0x03, 0x10, 0x80, 0xbc, 0x82, 0x97, 0x80, 0x8d,
+ 0x80, 0x43, 0x5a, 0x81, 0xb2, 0x03, 0x80, 0x61,
+ 0xc4, 0xad, 0x80, 0x40, 0xc9, 0x80, 0x40, 0xbd,
+ 0x01, 0x89, 0xe5, 0x80, 0x97, 0x80, 0x93, 0x01,
+ 0x20, 0x82, 0x94, 0x81, 0x40, 0xad, 0xa0, 0x8b,
+ 0x88, 0x80, 0xc5, 0x80, 0x95, 0x8b, 0xaa, 0x1c,
+ 0x8b, 0x90, 0x10, 0x82, 0xc6, 0x00, 0x80, 0x40,
+ 0xba, 0x81, 0xbe, 0x8c, 0x18, 0x97, 0x91, 0x80,
+ 0x99, 0x81, 0x8c, 0x80, 0xd5, 0xd4, 0xaf, 0xc5,
+ 0x28, 0x12, 0x0a, 0x1b, 0x8a, 0x0e, 0x88, 0x40,
+ 0xe2, 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, 0x89,
+ 0x80, 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x89, 0x84,
+ 0xb7, 0x86, 0x8e, 0x81, 0x8a, 0x85, 0x88,
+};
+
+static const uint8_t unicode_prop_Basic_Emoji2_table[183] = {
+ 0x40, 0xa8, 0x03, 0x80, 0x5f, 0x8c, 0x80, 0x8b,
+ 0x80, 0x40, 0xd7, 0x80, 0x95, 0x80, 0xd9, 0x85,
+ 0x8e, 0x81, 0x41, 0x7c, 0x80, 0x40, 0xa5, 0x80,
+ 0x9c, 0x10, 0x0c, 0x82, 0x40, 0xc6, 0x80, 0x40,
+ 0xe6, 0x81, 0x89, 0x80, 0x88, 0x80, 0xb9, 0x0a,
+ 0x84, 0x88, 0x01, 0x05, 0x03, 0x01, 0x00, 0x09,
+ 0x02, 0x02, 0x0f, 0x14, 0x00, 0x80, 0x9b, 0x09,
+ 0x00, 0x08, 0x80, 0x91, 0x01, 0x80, 0x92, 0x00,
+ 0x18, 0x00, 0x0a, 0x05, 0x07, 0x81, 0x95, 0x05,
+ 0x00, 0x00, 0x80, 0x94, 0x05, 0x09, 0x01, 0x17,
+ 0x04, 0x09, 0x08, 0x01, 0x00, 0x00, 0x05, 0x02,
+ 0x80, 0x90, 0x81, 0x8e, 0x01, 0x80, 0x9a, 0x81,
+ 0xbb, 0x80, 0x41, 0x91, 0x81, 0x41, 0xce, 0x82,
+ 0x45, 0x27, 0x80, 0x8b, 0x80, 0x42, 0x58, 0x00,
+ 0x80, 0x61, 0xbe, 0xd5, 0x81, 0x8b, 0x81, 0x40,
+ 0x81, 0x80, 0xb3, 0x80, 0x40, 0xe8, 0x01, 0x88,
+ 0x88, 0x80, 0xc5, 0x80, 0x97, 0x08, 0x11, 0x81,
+ 0xaa, 0x1c, 0x8b, 0x92, 0x00, 0x00, 0x80, 0xc6,
+ 0x00, 0x80, 0x40, 0xba, 0x80, 0xca, 0x81, 0xa3,
+ 0x09, 0x86, 0x8c, 0x01, 0x19, 0x80, 0x93, 0x01,
+ 0x07, 0x81, 0x88, 0x04, 0x82, 0x8b, 0x17, 0x11,
+ 0x00, 0x03, 0x05, 0x02, 0x05, 0x80, 0x40, 0xcf,
+ 0x00, 0x82, 0x8f, 0x2a, 0x05, 0x01, 0x80,
+};
+
+static const uint8_t unicode_prop_RGI_Emoji_Modifier_Sequence_table[73] = {
+ 0x60, 0x26, 0x1c, 0x80, 0x40, 0xda, 0x80, 0x8f,
+ 0x83, 0x61, 0xcc, 0x76, 0x80, 0xbb, 0x11, 0x01,
+ 0x82, 0xf4, 0x09, 0x8a, 0x94, 0x18, 0x18, 0x88,
+ 0x10, 0x1a, 0x02, 0x30, 0x00, 0x97, 0x80, 0x40,
+ 0xc8, 0x0b, 0x80, 0x94, 0x03, 0x81, 0x40, 0xad,
+ 0x12, 0x84, 0xd2, 0x80, 0x8f, 0x82, 0x88, 0x80,
+ 0x8a, 0x80, 0x42, 0x3e, 0x01, 0x07, 0x3d, 0x80,
+ 0x88, 0x89, 0x11, 0xb7, 0x80, 0xbc, 0x08, 0x08,
+ 0x80, 0x90, 0x10, 0x8c, 0x40, 0xe4, 0x82, 0xa9,
+ 0x88,
+};
+
+static const uint8_t unicode_prop_RGI_Emoji_Flag_Sequence_table[128] = {
+ 0x0c, 0x00, 0x09, 0x00, 0x04, 0x01, 0x02, 0x06,
+ 0x03, 0x03, 0x01, 0x02, 0x01, 0x03, 0x07, 0x0d,
+ 0x18, 0x00, 0x09, 0x00, 0x00, 0x89, 0x08, 0x00,
+ 0x00, 0x81, 0x88, 0x83, 0x8c, 0x10, 0x00, 0x01,
+ 0x07, 0x08, 0x29, 0x10, 0x28, 0x00, 0x80, 0x8a,
+ 0x00, 0x0a, 0x00, 0x0e, 0x15, 0x18, 0x83, 0x89,
+ 0x06, 0x00, 0x81, 0x8d, 0x00, 0x12, 0x08, 0x00,
+ 0x03, 0x00, 0x24, 0x00, 0x05, 0x21, 0x00, 0x00,
+ 0x29, 0x90, 0x00, 0x02, 0x00, 0x08, 0x09, 0x00,
+ 0x08, 0x18, 0x8b, 0x80, 0x8c, 0x02, 0x19, 0x1a,
+ 0x11, 0x00, 0x00, 0x80, 0x9c, 0x80, 0x88, 0x02,
+ 0x00, 0x00, 0x02, 0x20, 0x88, 0x0a, 0x00, 0x03,
+ 0x01, 0x02, 0x05, 0x08, 0x00, 0x01, 0x09, 0x20,
+ 0x21, 0x18, 0x22, 0x00, 0x00, 0x00, 0x00, 0x18,
+ 0x28, 0x89, 0x80, 0x8b, 0x80, 0x90, 0x80, 0x92,
+ 0x80, 0x8d, 0x05, 0x80, 0x8a, 0x80, 0x88, 0x80,
+};
+
+static const uint8_t unicode_prop_Emoji_Keycap_Sequence_table[4] = {
+ 0xa2, 0x05, 0x04, 0x89,
};
static const uint8_t unicode_prop_ASCII_Hex_Digit_table[5] = {
@@ -3856,14 +4147,15 @@ static const uint8_t unicode_prop_Bidi_Control_table[10] = {
0xb6, 0x83,
};
-static const uint8_t unicode_prop_Dash_table[55] = {
+static const uint8_t unicode_prop_Dash_table[58] = {
0xac, 0x80, 0x45, 0x5b, 0x80, 0xb2, 0x80, 0x4e,
0x40, 0x80, 0x44, 0x04, 0x80, 0x48, 0x08, 0x85,
0xbc, 0x80, 0xa6, 0x80, 0x8e, 0x80, 0x41, 0x85,
0x80, 0x4c, 0x03, 0x01, 0x80, 0x9e, 0x0b, 0x80,
0x9b, 0x80, 0x41, 0xbd, 0x80, 0x92, 0x80, 0xee,
0x80, 0x60, 0xcd, 0x8f, 0x81, 0xa4, 0x80, 0x89,
- 0x80, 0x40, 0xa8, 0x80, 0x4f, 0x9e, 0x80,
+ 0x80, 0x40, 0xa8, 0x80, 0x4e, 0x5f, 0x80, 0x41,
+ 0x3d, 0x80,
};
static const uint8_t unicode_prop_Deprecated_table[23] = {
@@ -3872,7 +4164,7 @@ static const uint8_t unicode_prop_Deprecated_table[23] = {
0x42, 0xb8, 0x81, 0x6d, 0xdc, 0xd5, 0x80,
};
-static const uint8_t unicode_prop_Diacritic_table[399] = {
+static const uint8_t unicode_prop_Diacritic_table[438] = {
0xdd, 0x00, 0x80, 0xc6, 0x05, 0x03, 0x01, 0x81,
0x41, 0xf6, 0x40, 0x9e, 0x07, 0x25, 0x90, 0x0b,
0x80, 0x88, 0x81, 0x40, 0xfc, 0x84, 0x40, 0xd0,
@@ -3885,59 +4177,66 @@ static const uint8_t unicode_prop_Diacritic_table[399] = {
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, 0x41, 0xd4, 0x82, 0xc5, 0x8a,
- 0xb0, 0x83, 0x40, 0xbf, 0x80, 0xa8, 0x80, 0xc7,
- 0x81, 0xf7, 0x81, 0xbd, 0x80, 0xcb, 0x80, 0x88,
- 0x82, 0xe7, 0x81, 0x40, 0xb1, 0x81, 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, 0x56, 0xae, 0x8e,
- 0x60, 0x36, 0x99, 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, 0x4e, 0x81,
- 0xbd, 0x40, 0xc1, 0x86, 0x41, 0x76, 0x80, 0xbc,
- 0x83, 0x45, 0xdf, 0x86, 0xec, 0x10, 0x82,
+ 0x80, 0xee, 0x80, 0x8b, 0x28, 0x80, 0xea, 0x80,
+ 0x8c, 0x84, 0xca, 0x81, 0x9a, 0x00, 0x00, 0x03,
+ 0x81, 0xc1, 0x10, 0x81, 0xbd, 0x80, 0xef, 0x00,
+ 0x81, 0xa7, 0x0b, 0x84, 0x98, 0x30, 0x80, 0x89,
+ 0x81, 0x42, 0xc0, 0x82, 0x43, 0xb3, 0x81, 0x9d,
+ 0x80, 0x40, 0x93, 0x8a, 0x88, 0x80, 0x41, 0x5a,
+ 0x82, 0x41, 0x23, 0x80, 0x93, 0x39, 0x80, 0xaf,
+ 0x8e, 0x81, 0x8a, 0xe7, 0x80, 0x8e, 0x80, 0xa5,
+ 0x88, 0xb5, 0x81, 0xb9, 0x80, 0x8a, 0x81, 0xc1,
+ 0x81, 0xbf, 0x85, 0xd1, 0x98, 0x18, 0x28, 0x0a,
+ 0xb1, 0xbe, 0xd8, 0x8b, 0xa4, 0x8a, 0x41, 0xbc,
+ 0x00, 0x82, 0x8a, 0x82, 0x8c, 0x82, 0x8c, 0x82,
+ 0x8c, 0x81, 0x4c, 0xef, 0x82, 0x41, 0x3c, 0x80,
+ 0x41, 0xf9, 0x85, 0xe8, 0x83, 0xde, 0x80, 0x60,
+ 0x75, 0x71, 0x80, 0x8b, 0x08, 0x80, 0x9b, 0x81,
+ 0xd1, 0x81, 0x8d, 0xa1, 0xe5, 0x82, 0xec, 0x81,
+ 0x8b, 0x80, 0xa4, 0x80, 0x40, 0x96, 0x80, 0x9a,
+ 0x91, 0xb8, 0x83, 0xa3, 0x80, 0xde, 0x80, 0x8b,
+ 0x80, 0xa3, 0x80, 0x40, 0x94, 0x82, 0xc0, 0x83,
+ 0xb2, 0x80, 0xe3, 0x84, 0x88, 0x82, 0xff, 0x81,
+ 0x60, 0x4f, 0x2f, 0x80, 0x43, 0x00, 0x8f, 0x41,
+ 0x0d, 0x00, 0x80, 0xae, 0x80, 0xac, 0x81, 0xc2,
+ 0x80, 0x42, 0xfb, 0x80, 0x44, 0x9e, 0x28, 0xa9,
+ 0x80, 0x88, 0x42, 0x7c, 0x13, 0x80, 0x40, 0xa4,
+ 0x81, 0x42, 0x3a, 0x85, 0xa5, 0x80, 0x99, 0x84,
+ 0x41, 0x8e, 0x82, 0xc5, 0x8a, 0xb0, 0x83, 0x40,
+ 0xbf, 0x80, 0xa8, 0x80, 0xc7, 0x81, 0xf7, 0x81,
+ 0xbd, 0x80, 0xcb, 0x80, 0x88, 0x82, 0xe7, 0x81,
+ 0x40, 0xb1, 0x81, 0xcf, 0x81, 0x8f, 0x80, 0x97,
+ 0x32, 0x84, 0xd8, 0x10, 0x81, 0x8c, 0x81, 0xde,
+ 0x02, 0x80, 0xfa, 0x81, 0x40, 0xfa, 0x81, 0xfd,
+ 0x80, 0xf5, 0x81, 0xf2, 0x80, 0x41, 0x0c, 0x81,
+ 0x41, 0x01, 0x0b, 0x80, 0x40, 0x9b, 0x80, 0xd2,
+ 0x80, 0x91, 0x80, 0xd0, 0x80, 0x41, 0xa4, 0x80,
+ 0x41, 0x01, 0x00, 0x81, 0xd0, 0x80, 0x41, 0xa8,
+ 0x81, 0x96, 0x80, 0x54, 0xeb, 0x8e, 0x60, 0x2c,
+ 0xd8, 0x80, 0x49, 0xbf, 0x84, 0xba, 0x86, 0x42,
+ 0x33, 0x81, 0x42, 0x21, 0x90, 0xcf, 0x81, 0x60,
+ 0x3f, 0xfd, 0x18, 0x30, 0x81, 0x5f, 0x00, 0xad,
+ 0x81, 0x96, 0x42, 0x1f, 0x12, 0x2f, 0x39, 0x86,
+ 0x9d, 0x83, 0x4e, 0x81, 0xbd, 0x40, 0xc1, 0x86,
+ 0x41, 0x76, 0x80, 0xbc, 0x83, 0x42, 0xfd, 0x81,
+ 0x42, 0xdf, 0x86, 0xec, 0x10, 0x82,
};
-static const uint8_t unicode_prop_Extender_table[92] = {
+static const uint8_t unicode_prop_Extender_table[111] = {
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,
+ 0x80, 0x41, 0xb8, 0x80, 0x42, 0x75, 0x80, 0x40,
+ 0x88, 0x80, 0xd8, 0x80, 0x42, 0xef, 0x80, 0xfe,
+ 0x80, 0x49, 0x42, 0x80, 0xb7, 0x80, 0x42, 0x62,
+ 0x80, 0x41, 0x8d, 0x80, 0xc3, 0x80, 0x53, 0x88,
+ 0x80, 0xaa, 0x84, 0xe6, 0x81, 0xdc, 0x82, 0x60,
+ 0x6f, 0x15, 0x80, 0x45, 0xf5, 0x80, 0x43, 0xc1,
+ 0x80, 0x95, 0x80, 0x40, 0x88, 0x80, 0xeb, 0x80,
+ 0x94, 0x81, 0x60, 0x54, 0x7a, 0x80, 0x48, 0x0f,
+ 0x81, 0x45, 0xca, 0x80, 0x9a, 0x03, 0x80, 0x44,
+ 0xc6, 0x80, 0x41, 0x24, 0x80, 0xf3, 0x81, 0x41,
+ 0xf1, 0x82, 0x44, 0xce, 0x80, 0x60, 0x50, 0xa8,
0x81, 0x44, 0x9b, 0x08, 0x80, 0x60, 0x71, 0x57,
- 0x81, 0x48, 0x05, 0x82,
+ 0x81, 0x44, 0xb0, 0x80, 0x43, 0x53, 0x82,
};
static const uint8_t unicode_prop_Hex_Digit_table[12] = {
@@ -3945,24 +4244,28 @@ static const uint8_t unicode_prop_Hex_Digit_table[12] = {
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_Unary_Operator_table[4] = {
+ 0x60, 0x2f, 0xfd, 0x81,
+};
+
+static const uint8_t unicode_prop_IDS_Binary_Operator_table[8] = {
+ 0x60, 0x2f, 0xef, 0x09, 0x89, 0x41, 0xf0, 0x80,
};
static const uint8_t unicode_prop_IDS_Trinary_Operator_table[4] = {
0x60, 0x2f, 0xf1, 0x81,
};
-static const uint8_t unicode_prop_Ideographic_table[69] = {
+static const uint8_t unicode_prop_Ideographic_table[72] = {
0x60, 0x30, 0x05, 0x81, 0x98, 0x88, 0x8d, 0x82,
0x43, 0xc4, 0x59, 0xbf, 0xbf, 0x60, 0x51, 0xff,
0x60, 0x58, 0xff, 0x41, 0x6d, 0x81, 0xe9, 0x60,
0x75, 0x09, 0x80, 0x9a, 0x57, 0xf7, 0x87, 0x44,
- 0xd5, 0xa9, 0x88, 0x60, 0x24, 0x66, 0x41, 0x8b,
+ 0xd5, 0xa8, 0x89, 0x60, 0x24, 0x66, 0x41, 0x8b,
0x60, 0x4d, 0x03, 0x60, 0xa6, 0xdf, 0x9f, 0x50,
0x39, 0x85, 0x40, 0xdd, 0x81, 0x56, 0x81, 0x8d,
- 0x5d, 0x30, 0x4c, 0x1e, 0x42, 0x1d, 0x45, 0xe1,
- 0x53, 0x4a, 0x84, 0x50, 0x5f,
+ 0x5d, 0x30, 0x8e, 0x42, 0x6d, 0x49, 0xa1, 0x42,
+ 0x1d, 0x45, 0xe1, 0x53, 0x4a, 0x84, 0x50, 0x5f,
};
static const uint8_t unicode_prop_Join_Control_table[4] = {
@@ -3974,6 +4277,11 @@ static const uint8_t unicode_prop_Logical_Order_Exception_table[15] = {
0x80, 0x60, 0x90, 0xf9, 0x09, 0x00, 0x81,
};
+static const uint8_t unicode_prop_Modifier_Combining_Mark_table[16] = {
+ 0x46, 0x53, 0x09, 0x80, 0x40, 0x82, 0x05, 0x02,
+ 0x81, 0x41, 0xe0, 0x08, 0x12, 0x80, 0x9e, 0x80,
+};
+
static const uint8_t unicode_prop_Noncharacter_Code_Point_table[71] = {
0x60, 0xfd, 0xcf, 0x9f, 0x42, 0x0d, 0x81, 0x60,
0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
@@ -4018,32 +4326,34 @@ static const uint8_t unicode_prop_Regional_Indicator_table[4] = {
0x61, 0xf1, 0xe5, 0x99,
};
-static const uint8_t unicode_prop_Sentence_Terminal_table[196] = {
+static const uint8_t unicode_prop_Sentence_Terminal_table[213] = {
0xa0, 0x80, 0x8b, 0x80, 0x8f, 0x80, 0x45, 0x48,
0x80, 0x40, 0x92, 0x82, 0x40, 0xb3, 0x80, 0xaa,
0x82, 0x40, 0xf5, 0x80, 0xbc, 0x00, 0x02, 0x81,
0x41, 0x24, 0x81, 0x46, 0xe3, 0x81, 0x43, 0x15,
0x03, 0x81, 0x43, 0x04, 0x80, 0x40, 0xc5, 0x81,
- 0x40, 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, 0xc9, 0x81, 0x60,
- 0x4b, 0x28, 0x81, 0x40, 0x84, 0x80, 0xc0, 0x81,
- 0x8a, 0x80, 0x43, 0x52, 0x80, 0x60, 0x4e, 0x05,
- 0x80, 0x5d, 0xe7, 0x80,
+ 0x40, 0x9c, 0x81, 0xac, 0x04, 0x80, 0x41, 0x39,
+ 0x81, 0x41, 0x61, 0x83, 0x40, 0xa1, 0x81, 0x89,
+ 0x09, 0x81, 0x9c, 0x82, 0x40, 0xba, 0x81, 0xc0,
+ 0x81, 0x43, 0xa3, 0x80, 0x96, 0x81, 0x88, 0x82,
+ 0x4c, 0xae, 0x82, 0x41, 0x31, 0x80, 0x8c, 0x80,
+ 0x95, 0x81, 0x41, 0xac, 0x80, 0x60, 0x74, 0xfb,
+ 0x80, 0x41, 0x0d, 0x81, 0x40, 0xe2, 0x02, 0x80,
+ 0x41, 0x7d, 0x81, 0xd5, 0x81, 0xde, 0x80, 0x40,
+ 0x97, 0x81, 0x40, 0x92, 0x82, 0x40, 0x8f, 0x81,
+ 0x40, 0xf8, 0x80, 0x60, 0x52, 0x25, 0x01, 0x81,
+ 0xba, 0x02, 0x81, 0x40, 0xa8, 0x80, 0x8b, 0x80,
+ 0x8f, 0x80, 0xc0, 0x80, 0x4a, 0xf3, 0x81, 0x44,
+ 0xfc, 0x84, 0xab, 0x83, 0x40, 0xbc, 0x81, 0xf4,
+ 0x83, 0xfe, 0x82, 0x40, 0x80, 0x0d, 0x80, 0x8f,
+ 0x81, 0xd7, 0x08, 0x81, 0xeb, 0x80, 0x41, 0x29,
+ 0x81, 0xf4, 0x81, 0x41, 0x74, 0x0c, 0x8e, 0xe8,
+ 0x81, 0x40, 0xf8, 0x82, 0x42, 0x04, 0x00, 0x80,
+ 0x40, 0xfa, 0x81, 0xd6, 0x81, 0x41, 0xa3, 0x81,
+ 0x42, 0xb3, 0x81, 0xc9, 0x81, 0x60, 0x4b, 0x28,
+ 0x81, 0x40, 0x84, 0x80, 0xc0, 0x81, 0x8a, 0x80,
+ 0x42, 0x28, 0x81, 0x41, 0x27, 0x80, 0x60, 0x4e,
+ 0x05, 0x80, 0x5d, 0xe7, 0x80,
};
static const uint8_t unicode_prop_Soft_Dotted_table[79] = {
@@ -4059,47 +4369,49 @@ static const uint8_t unicode_prop_Soft_Dotted_table[79] = {
0x85, 0x80, 0x41, 0x30, 0x81, 0x99, 0x80,
};
-static const uint8_t unicode_prop_Terminal_Punctuation_table[248] = {
+static const uint8_t unicode_prop_Terminal_Punctuation_table[264] = {
0xa0, 0x80, 0x89, 0x00, 0x80, 0x8a, 0x0a, 0x80,
0x43, 0x3d, 0x07, 0x80, 0x42, 0x00, 0x80, 0xb8,
0x80, 0xc7, 0x80, 0x8d, 0x00, 0x82, 0x40, 0xb3,
0x80, 0xaa, 0x8a, 0x00, 0x40, 0xea, 0x81, 0xb5,
- 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,
+ 0x28, 0x87, 0x9e, 0x80, 0x41, 0x04, 0x81, 0x44,
+ 0xf3, 0x81, 0x40, 0xab, 0x03, 0x85, 0x41, 0x36,
+ 0x81, 0x43, 0x14, 0x87, 0x43, 0x04, 0x80, 0xfb,
+ 0x82, 0xc6, 0x81, 0x40, 0x9c, 0x12, 0x80, 0xa6,
+ 0x19, 0x81, 0x41, 0x39, 0x81, 0x41, 0x61, 0x83,
+ 0x40, 0xa1, 0x81, 0x89, 0x08, 0x82, 0x9c, 0x82,
+ 0x40, 0xba, 0x84, 0xbd, 0x81, 0x43, 0xa3, 0x80,
+ 0x96, 0x81, 0x88, 0x82, 0x4c, 0xae, 0x82, 0x41,
+ 0x31, 0x80, 0x8c, 0x03, 0x80, 0x89, 0x00, 0x0a,
0x81, 0x41, 0xab, 0x81, 0x60, 0x74, 0xfa, 0x81,
0x41, 0x0c, 0x82, 0x40, 0xe2, 0x84, 0x41, 0x7d,
0x81, 0xd5, 0x81, 0xde, 0x80, 0x40, 0x96, 0x82,
0x40, 0x92, 0x82, 0xfe, 0x80, 0x8f, 0x81, 0x40,
- 0xf8, 0x80, 0x60, 0x52, 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, 0xc9, 0x81,
- 0x45, 0x2a, 0x84, 0x60, 0x45, 0xf8, 0x81, 0x40,
- 0x84, 0x80, 0xc0, 0x82, 0x89, 0x80, 0x43, 0x51,
+ 0xf8, 0x80, 0x60, 0x52, 0x25, 0x01, 0x81, 0xb8,
+ 0x10, 0x83, 0x40, 0xa8, 0x80, 0x89, 0x00, 0x80,
+ 0x8a, 0x0a, 0x80, 0xc0, 0x01, 0x80, 0x44, 0x39,
+ 0x80, 0xaf, 0x80, 0x44, 0x85, 0x80, 0x40, 0xc6,
+ 0x80, 0x41, 0x35, 0x81, 0x40, 0x97, 0x85, 0xc3,
+ 0x85, 0xd8, 0x83, 0x43, 0xb7, 0x84, 0xab, 0x83,
+ 0x40, 0xbc, 0x86, 0xef, 0x83, 0xfe, 0x82, 0x40,
+ 0x80, 0x0d, 0x80, 0x8f, 0x81, 0xd7, 0x84, 0xeb,
+ 0x80, 0x41, 0x29, 0x81, 0xf4, 0x82, 0x8b, 0x81,
+ 0x41, 0x65, 0x1a, 0x8e, 0xe8, 0x81, 0x40, 0xf8,
+ 0x82, 0x42, 0x04, 0x00, 0x80, 0x40, 0xfa, 0x81,
+ 0xd6, 0x0b, 0x81, 0x41, 0x9d, 0x82, 0xac, 0x80,
+ 0x42, 0x84, 0x81, 0xc9, 0x81, 0x45, 0x2a, 0x84,
+ 0x60, 0x45, 0xf8, 0x81, 0x40, 0x84, 0x80, 0xc0,
+ 0x82, 0x89, 0x80, 0x42, 0x28, 0x81, 0x41, 0x26,
0x81, 0x60, 0x4e, 0x05, 0x80, 0x5d, 0xe6, 0x83,
};
-static const uint8_t unicode_prop_Unified_Ideograph_table[45] = {
+static const uint8_t unicode_prop_Unified_Ideograph_table[48] = {
0x60, 0x33, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x51,
0xff, 0x60, 0x5a, 0x0d, 0x08, 0x00, 0x81, 0x89,
0x00, 0x00, 0x09, 0x82, 0x61, 0x05, 0xd5, 0x60,
0xa6, 0xdf, 0x9f, 0x50, 0x39, 0x85, 0x40, 0xdd,
- 0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x54, 0x1e,
- 0x53, 0x4a, 0x84, 0x50, 0x5f,
+ 0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x8e, 0x42,
+ 0x6d, 0x51, 0xa1, 0x53, 0x4a, 0x84, 0x50, 0x5f,
};
static const uint8_t unicode_prop_Variation_Selector_table[13] = {
@@ -4120,7 +4432,7 @@ static const uint8_t unicode_prop_Bidi_Mirrored_table[173] = {
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,
+ 0x88, 0x08, 0x00, 0x38, 0x9f, 0x0b, 0x20, 0x88,
0x09, 0x92, 0x21, 0x88, 0x21, 0x0b, 0x97, 0x81,
0x8f, 0x3b, 0x93, 0x0e, 0x81, 0x44, 0x3c, 0x8d,
0xc9, 0x01, 0x18, 0x08, 0x14, 0x1c, 0x12, 0x8d,
@@ -4138,7 +4450,7 @@ static const uint8_t unicode_prop_Bidi_Mirrored_table[173] = {
0x80, 0xb8, 0x80, 0xb8, 0x80,
};
-static const uint8_t unicode_prop_Emoji_table[239] = {
+static const uint8_t unicode_prop_Emoji_table[238] = {
0xa2, 0x05, 0x04, 0x89, 0xee, 0x03, 0x80, 0x5f,
0x8c, 0x80, 0x8b, 0x80, 0x40, 0xd7, 0x80, 0x95,
0x80, 0xd9, 0x85, 0x8e, 0x81, 0x41, 0x6e, 0x81,
@@ -4167,8 +4479,8 @@ static const uint8_t unicode_prop_Emoji_table[239] = {
0x02, 0x05, 0xd5, 0xaf, 0xc5, 0x27, 0x0a, 0x83,
0x89, 0x10, 0x01, 0x10, 0x81, 0x89, 0x40, 0xe2,
0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, 0x89, 0x80,
- 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x88, 0x86, 0xad,
- 0x06, 0x87, 0x8d, 0x83, 0x88, 0x86, 0x88,
+ 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x89, 0x84, 0xb7,
+ 0x86, 0x8e, 0x81, 0x8a, 0x85, 0x88,
};
static const uint8_t unicode_prop_Emoji_Component_table[28] = {
@@ -4194,7 +4506,7 @@ static const uint8_t unicode_prop_Emoji_Modifier_Base_table[71] = {
0x10, 0x8c, 0x40, 0xe4, 0x82, 0xa9, 0x88,
};
-static const uint8_t unicode_prop_Emoji_Presentation_table[145] = {
+static const uint8_t unicode_prop_Emoji_Presentation_table[144] = {
0x60, 0x23, 0x19, 0x81, 0x40, 0xcc, 0x1a, 0x01,
0x80, 0x42, 0x08, 0x81, 0x94, 0x81, 0xb1, 0x8b,
0xaa, 0x80, 0x92, 0x80, 0x8c, 0x07, 0x81, 0x90,
@@ -4211,9 +4523,8 @@ static const uint8_t unicode_prop_Emoji_Presentation_table[145] = {
0x80, 0x99, 0x81, 0x8c, 0x80, 0xd5, 0xd4, 0xaf,
0xc5, 0x28, 0x12, 0x0a, 0x1b, 0x8a, 0x0e, 0x88,
0x40, 0xe2, 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80,
- 0x89, 0x80, 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x88,
- 0x86, 0xad, 0x06, 0x87, 0x8d, 0x83, 0x88, 0x86,
- 0x88,
+ 0x89, 0x80, 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x89,
+ 0x84, 0xb7, 0x86, 0x8e, 0x81, 0x8a, 0x85, 0x88,
};
static const uint8_t unicode_prop_Extended_Pictographic_table[156] = {
@@ -4266,6 +4577,11 @@ typedef enum {
UNICODE_PROP_Changes_When_Titlecased1,
UNICODE_PROP_Changes_When_Casefolded1,
UNICODE_PROP_Changes_When_NFKC_Casefolded1,
+ UNICODE_PROP_Basic_Emoji1,
+ UNICODE_PROP_Basic_Emoji2,
+ UNICODE_PROP_RGI_Emoji_Modifier_Sequence,
+ UNICODE_PROP_RGI_Emoji_Flag_Sequence,
+ UNICODE_PROP_Emoji_Keycap_Sequence,
UNICODE_PROP_ASCII_Hex_Digit,
UNICODE_PROP_Bidi_Control,
UNICODE_PROP_Dash,
@@ -4273,11 +4589,13 @@ typedef enum {
UNICODE_PROP_Diacritic,
UNICODE_PROP_Extender,
UNICODE_PROP_Hex_Digit,
+ UNICODE_PROP_IDS_Unary_Operator,
UNICODE_PROP_IDS_Binary_Operator,
UNICODE_PROP_IDS_Trinary_Operator,
UNICODE_PROP_Ideographic,
UNICODE_PROP_Join_Control,
UNICODE_PROP_Logical_Order_Exception,
+ UNICODE_PROP_Modifier_Combining_Mark,
UNICODE_PROP_Noncharacter_Code_Point,
UNICODE_PROP_Pattern_Syntax,
UNICODE_PROP_Pattern_White_Space,
@@ -4314,6 +4632,9 @@ typedef enum {
UNICODE_PROP_Grapheme_Base,
UNICODE_PROP_Grapheme_Extend,
UNICODE_PROP_ID_Continue,
+ UNICODE_PROP_ID_Compat_Math_Start,
+ UNICODE_PROP_ID_Compat_Math_Continue,
+ UNICODE_PROP_InCB,
UNICODE_PROP_Lowercase,
UNICODE_PROP_Math,
UNICODE_PROP_Uppercase,
@@ -4331,11 +4652,13 @@ static const char unicode_prop_name_table[] =
"Diacritic,Dia" "\0"
"Extender,Ext" "\0"
"Hex_Digit,Hex" "\0"
+ "IDS_Unary_Operator,IDSU" "\0"
"IDS_Binary_Operator,IDSB" "\0"
"IDS_Trinary_Operator,IDST" "\0"
"Ideographic,Ideo" "\0"
"Join_Control,Join_C" "\0"
"Logical_Order_Exception,LOE" "\0"
+ "Modifier_Combining_Mark,MCM" "\0"
"Noncharacter_Code_Point,NChar" "\0"
"Pattern_Syntax,Pat_Syn" "\0"
"Pattern_White_Space,Pat_WS" "\0"
@@ -4372,6 +4695,9 @@ static const char unicode_prop_name_table[] =
"Grapheme_Base,Gr_Base" "\0"
"Grapheme_Extend,Gr_Ext" "\0"
"ID_Continue,IDC" "\0"
+ "ID_Compat_Math_Start" "\0"
+ "ID_Compat_Math_Continue" "\0"
+ "InCB" "\0"
"Lowercase,Lower" "\0"
"Math" "\0"
"Uppercase,Upper" "\0"
@@ -4396,6 +4722,11 @@ static const uint8_t * const unicode_prop_table[] = {
unicode_prop_Changes_When_Titlecased1_table,
unicode_prop_Changes_When_Casefolded1_table,
unicode_prop_Changes_When_NFKC_Casefolded1_table,
+ unicode_prop_Basic_Emoji1_table,
+ unicode_prop_Basic_Emoji2_table,
+ unicode_prop_RGI_Emoji_Modifier_Sequence_table,
+ unicode_prop_RGI_Emoji_Flag_Sequence_table,
+ unicode_prop_Emoji_Keycap_Sequence_table,
unicode_prop_ASCII_Hex_Digit_table,
unicode_prop_Bidi_Control_table,
unicode_prop_Dash_table,
@@ -4403,11 +4734,13 @@ static const uint8_t * const unicode_prop_table[] = {
unicode_prop_Diacritic_table,
unicode_prop_Extender_table,
unicode_prop_Hex_Digit_table,
+ unicode_prop_IDS_Unary_Operator_table,
unicode_prop_IDS_Binary_Operator_table,
unicode_prop_IDS_Trinary_Operator_table,
unicode_prop_Ideographic_table,
unicode_prop_Join_Control_table,
unicode_prop_Logical_Order_Exception_table,
+ unicode_prop_Modifier_Combining_Mark_table,
unicode_prop_Noncharacter_Code_Point_table,
unicode_prop_Pattern_Syntax_table,
unicode_prop_Pattern_White_Space_table,
@@ -4449,6 +4782,11 @@ static const uint16_t unicode_prop_len_table[] = {
countof(unicode_prop_Changes_When_Titlecased1_table),
countof(unicode_prop_Changes_When_Casefolded1_table),
countof(unicode_prop_Changes_When_NFKC_Casefolded1_table),
+ countof(unicode_prop_Basic_Emoji1_table),
+ countof(unicode_prop_Basic_Emoji2_table),
+ countof(unicode_prop_RGI_Emoji_Modifier_Sequence_table),
+ countof(unicode_prop_RGI_Emoji_Flag_Sequence_table),
+ countof(unicode_prop_Emoji_Keycap_Sequence_table),
countof(unicode_prop_ASCII_Hex_Digit_table),
countof(unicode_prop_Bidi_Control_table),
countof(unicode_prop_Dash_table),
@@ -4456,11 +4794,13 @@ static const uint16_t unicode_prop_len_table[] = {
countof(unicode_prop_Diacritic_table),
countof(unicode_prop_Extender_table),
countof(unicode_prop_Hex_Digit_table),
+ countof(unicode_prop_IDS_Unary_Operator_table),
countof(unicode_prop_IDS_Binary_Operator_table),
countof(unicode_prop_IDS_Trinary_Operator_table),
countof(unicode_prop_Ideographic_table),
countof(unicode_prop_Join_Control_table),
countof(unicode_prop_Logical_Order_Exception_table),
+ countof(unicode_prop_Modifier_Combining_Mark_table),
countof(unicode_prop_Noncharacter_Code_Point_table),
countof(unicode_prop_Pattern_Syntax_table),
countof(unicode_prop_Pattern_White_Space_table),
@@ -4485,4 +4825,325 @@ static const uint16_t unicode_prop_len_table[] = {
countof(unicode_prop_Case_Ignorable_table),
};
+typedef enum {
+ UNICODE_SEQUENCE_PROP_Basic_Emoji,
+ UNICODE_SEQUENCE_PROP_Emoji_Keycap_Sequence,
+ UNICODE_SEQUENCE_PROP_RGI_Emoji_Modifier_Sequence,
+ UNICODE_SEQUENCE_PROP_RGI_Emoji_Flag_Sequence,
+ UNICODE_SEQUENCE_PROP_RGI_Emoji_Tag_Sequence,
+ UNICODE_SEQUENCE_PROP_RGI_Emoji_ZWJ_Sequence,
+ UNICODE_SEQUENCE_PROP_RGI_Emoji,
+ UNICODE_SEQUENCE_PROP_COUNT,
+} UnicodeSequencePropertyEnum;
+
+static const char unicode_sequence_prop_name_table[] =
+ "Basic_Emoji" "\0"
+ "Emoji_Keycap_Sequence" "\0"
+ "RGI_Emoji_Modifier_Sequence" "\0"
+ "RGI_Emoji_Flag_Sequence" "\0"
+ "RGI_Emoji_Tag_Sequence" "\0"
+ "RGI_Emoji_ZWJ_Sequence" "\0"
+ "RGI_Emoji" "\0"
+;
+
+static const uint8_t unicode_rgi_emoji_tag_sequence[18] = {
+ 0x67, 0x62, 0x65, 0x6e, 0x67, 0x00, 0x67, 0x62,
+ 0x73, 0x63, 0x74, 0x00, 0x67, 0x62, 0x77, 0x6c,
+ 0x73, 0x00,
+};
+
+static const uint8_t unicode_rgi_emoji_zwj_sequence[2320] = {
+ 0x02, 0xb8, 0x19, 0x40, 0x86, 0x02, 0xd1, 0x39,
+ 0xb0, 0x19, 0x02, 0x26, 0x39, 0x42, 0x86, 0x02,
+ 0xb4, 0x36, 0x42, 0x86, 0x03, 0x68, 0x54, 0x64,
+ 0x87, 0x68, 0x54, 0x02, 0xdc, 0x39, 0x42, 0x86,
+ 0x02, 0xd1, 0x39, 0x73, 0x13, 0x02, 0x39, 0x39,
+ 0x40, 0x86, 0x02, 0x69, 0x34, 0xbd, 0x19, 0x03,
+ 0xb6, 0x36, 0x40, 0x86, 0xa1, 0x87, 0x03, 0x68,
+ 0x74, 0x1d, 0x19, 0x68, 0x74, 0x03, 0x68, 0x34,
+ 0xbd, 0x19, 0xa1, 0x87, 0x02, 0xf1, 0x7a, 0xf2,
+ 0x7a, 0x02, 0xca, 0x33, 0x42, 0x86, 0x02, 0x69,
+ 0x34, 0xb0, 0x19, 0x04, 0x68, 0x14, 0x68, 0x14,
+ 0x67, 0x14, 0x66, 0x14, 0x02, 0xf9, 0x26, 0x42,
+ 0x86, 0x03, 0x69, 0x74, 0x1d, 0x19, 0x69, 0x74,
+ 0x03, 0xd1, 0x19, 0xbc, 0x19, 0xa1, 0x87, 0x02,
+ 0x3c, 0x19, 0x40, 0x86, 0x02, 0x68, 0x34, 0xeb,
+ 0x13, 0x02, 0xc3, 0x33, 0xa1, 0x87, 0x02, 0x70,
+ 0x34, 0x40, 0x86, 0x02, 0xd4, 0x39, 0x42, 0x86,
+ 0x02, 0xcf, 0x39, 0x42, 0x86, 0x02, 0x47, 0x36,
+ 0x40, 0x86, 0x02, 0x39, 0x39, 0x42, 0x86, 0x04,
+ 0xd1, 0x79, 0x64, 0x87, 0x8b, 0x14, 0xd1, 0x79,
+ 0x02, 0xd1, 0x39, 0x95, 0x86, 0x02, 0x68, 0x34,
+ 0x93, 0x13, 0x02, 0x69, 0x34, 0xed, 0x13, 0x02,
+ 0xda, 0x39, 0x40, 0x86, 0x03, 0x69, 0x34, 0xaf,
+ 0x19, 0xa1, 0x87, 0x02, 0xd1, 0x39, 0x93, 0x13,
+ 0x03, 0xce, 0x39, 0x42, 0x86, 0xa1, 0x87, 0x03,
+ 0xd1, 0x79, 0x64, 0x87, 0xd1, 0x79, 0x03, 0xc3,
+ 0x33, 0x42, 0x86, 0xa1, 0x87, 0x03, 0x69, 0x74,
+ 0x1d, 0x19, 0x68, 0x74, 0x02, 0x69, 0x34, 0x92,
+ 0x16, 0x02, 0xd1, 0x39, 0x96, 0x86, 0x04, 0x69,
+ 0x14, 0x64, 0x87, 0x8b, 0x14, 0x68, 0x14, 0x02,
+ 0x68, 0x34, 0x7c, 0x13, 0x02, 0x47, 0x36, 0x42,
+ 0x86, 0x02, 0x86, 0x34, 0x42, 0x86, 0x02, 0xd1,
+ 0x39, 0x7c, 0x13, 0x02, 0x69, 0x14, 0xa4, 0x13,
+ 0x02, 0xda, 0x39, 0x42, 0x86, 0x02, 0x37, 0x39,
+ 0x40, 0x86, 0x02, 0xd1, 0x39, 0x08, 0x87, 0x04,
+ 0x68, 0x54, 0x64, 0x87, 0x8b, 0x14, 0x68, 0x54,
+ 0x02, 0x4d, 0x36, 0x40, 0x86, 0x02, 0x68, 0x34,
+ 0x2c, 0x15, 0x02, 0x69, 0x34, 0xaf, 0x19, 0x02,
+ 0x6e, 0x34, 0x40, 0x86, 0x02, 0xcd, 0x39, 0x42,
+ 0x86, 0x02, 0xd1, 0x39, 0x2c, 0x15, 0x02, 0x6f,
+ 0x14, 0x40, 0x86, 0x03, 0xd1, 0x39, 0xbc, 0x19,
+ 0xa1, 0x87, 0x02, 0x68, 0x34, 0xa8, 0x13, 0x02,
+ 0x69, 0x34, 0x73, 0x13, 0x04, 0x69, 0x54, 0x64,
+ 0x87, 0x8b, 0x14, 0x68, 0x54, 0x02, 0x71, 0x34,
+ 0x42, 0x86, 0x02, 0xd1, 0x39, 0xa8, 0x13, 0x02,
+ 0x45, 0x36, 0x40, 0x86, 0x03, 0x69, 0x54, 0x64,
+ 0x87, 0x68, 0x54, 0x03, 0x69, 0x54, 0x64, 0x87,
+ 0x69, 0x54, 0x03, 0xce, 0x39, 0x40, 0x86, 0xa1,
+ 0x87, 0x02, 0xd8, 0x39, 0x40, 0x86, 0x03, 0xc3,
+ 0x33, 0x40, 0x86, 0xa1, 0x87, 0x02, 0x4d, 0x36,
+ 0x42, 0x86, 0x02, 0xd1, 0x19, 0x92, 0x16, 0x02,
+ 0xd1, 0x39, 0xeb, 0x13, 0x02, 0x68, 0x34, 0xbc,
+ 0x14, 0x02, 0xd1, 0x39, 0xbc, 0x14, 0x02, 0x3d,
+ 0x39, 0x40, 0x86, 0x02, 0xb8, 0x39, 0x42, 0x86,
+ 0x02, 0xa3, 0x36, 0x40, 0x86, 0x02, 0x75, 0x35,
+ 0x40, 0x86, 0x02, 0xd8, 0x39, 0x42, 0x86, 0x02,
+ 0x69, 0x34, 0x93, 0x13, 0x02, 0x35, 0x39, 0x40,
+ 0x86, 0x02, 0x4b, 0x36, 0x40, 0x86, 0x02, 0x3d,
+ 0x39, 0x42, 0x86, 0x02, 0x38, 0x39, 0x42, 0x86,
+ 0x02, 0xa3, 0x36, 0x42, 0x86, 0x03, 0x69, 0x14,
+ 0x67, 0x14, 0x67, 0x14, 0x02, 0xb6, 0x36, 0x40,
+ 0x86, 0x02, 0x69, 0x34, 0x7c, 0x13, 0x02, 0x75,
+ 0x35, 0x42, 0x86, 0x02, 0xcc, 0x93, 0x40, 0x86,
+ 0x02, 0xcc, 0x33, 0x40, 0x86, 0x03, 0xd1, 0x39,
+ 0xbd, 0x19, 0xa1, 0x87, 0x02, 0x82, 0x34, 0x40,
+ 0x86, 0x02, 0x87, 0x34, 0x40, 0x86, 0x02, 0x69,
+ 0x14, 0x3e, 0x13, 0x02, 0xd6, 0x39, 0x40, 0x86,
+ 0x02, 0x68, 0x14, 0xbd, 0x19, 0x02, 0x46, 0x36,
+ 0x42, 0x86, 0x02, 0x4b, 0x36, 0x42, 0x86, 0x02,
+ 0x69, 0x34, 0x2c, 0x15, 0x03, 0xb6, 0x36, 0x42,
+ 0x86, 0xa1, 0x87, 0x02, 0xc4, 0x33, 0x40, 0x86,
+ 0x02, 0x26, 0x19, 0x40, 0x86, 0x02, 0x69, 0x14,
+ 0xb0, 0x19, 0x02, 0xde, 0x19, 0x42, 0x86, 0x02,
+ 0x69, 0x34, 0xa8, 0x13, 0x02, 0xcc, 0x33, 0x42,
+ 0x86, 0x02, 0x82, 0x34, 0x42, 0x86, 0x02, 0xd1,
+ 0x19, 0x93, 0x13, 0x02, 0x81, 0x14, 0x42, 0x86,
+ 0x02, 0x69, 0x34, 0x95, 0x86, 0x02, 0x68, 0x34,
+ 0xbb, 0x14, 0x02, 0xd1, 0x39, 0xbb, 0x14, 0x02,
+ 0x69, 0x34, 0xeb, 0x13, 0x02, 0xd1, 0x39, 0x84,
+ 0x13, 0x02, 0x69, 0x34, 0xbc, 0x14, 0x04, 0x69,
+ 0x54, 0x64, 0x87, 0x8b, 0x14, 0x69, 0x54, 0x02,
+ 0x26, 0x39, 0x40, 0x86, 0x02, 0xb4, 0x36, 0x40,
+ 0x86, 0x02, 0x47, 0x16, 0x42, 0x86, 0x02, 0xdc,
+ 0x39, 0x40, 0x86, 0x02, 0xca, 0x33, 0x40, 0x86,
+ 0x02, 0xf9, 0x26, 0x40, 0x86, 0x02, 0x69, 0x34,
+ 0x08, 0x87, 0x03, 0x69, 0x14, 0x69, 0x14, 0x66,
+ 0x14, 0x03, 0xd1, 0x59, 0x1d, 0x19, 0xd1, 0x59,
+ 0x02, 0xd4, 0x39, 0x40, 0x86, 0x02, 0xcf, 0x39,
+ 0x40, 0x86, 0x02, 0x68, 0x34, 0xa4, 0x13, 0x02,
+ 0xd1, 0x39, 0xa4, 0x13, 0x02, 0xd1, 0x19, 0xa8,
+ 0x13, 0x02, 0xd7, 0x39, 0x42, 0x86, 0x03, 0x69,
+ 0x34, 0xbc, 0x19, 0xa1, 0x87, 0x02, 0x68, 0x14,
+ 0xb0, 0x19, 0x02, 0x68, 0x14, 0x73, 0x13, 0x04,
+ 0x69, 0x14, 0x69, 0x14, 0x66, 0x14, 0x66, 0x14,
+ 0x03, 0x68, 0x34, 0xaf, 0x19, 0xa1, 0x87, 0x02,
+ 0x68, 0x34, 0x80, 0x16, 0x02, 0x73, 0x34, 0x42,
+ 0x86, 0x02, 0xd1, 0x39, 0x80, 0x16, 0x02, 0x68,
+ 0x34, 0xb0, 0x19, 0x02, 0x86, 0x34, 0x40, 0x86,
+ 0x02, 0x38, 0x19, 0x42, 0x86, 0x02, 0x69, 0x34,
+ 0xbb, 0x14, 0x02, 0xb5, 0x36, 0x42, 0x86, 0x02,
+ 0xcd, 0x39, 0x40, 0x86, 0x02, 0x68, 0x34, 0x95,
+ 0x86, 0x02, 0x68, 0x34, 0x27, 0x15, 0x03, 0x68,
+ 0x14, 0x68, 0x14, 0x66, 0x14, 0x02, 0x71, 0x34,
+ 0x40, 0x86, 0x02, 0xd1, 0x39, 0x27, 0x15, 0x02,
+ 0x2e, 0x16, 0xa8, 0x14, 0x02, 0xc3, 0x33, 0x42,
+ 0x86, 0x02, 0x69, 0x14, 0x66, 0x14, 0x02, 0x68,
+ 0x34, 0x96, 0x86, 0x02, 0x69, 0x34, 0xa4, 0x13,
+ 0x03, 0x69, 0x14, 0x64, 0x87, 0x68, 0x14, 0x02,
+ 0xb8, 0x39, 0x40, 0x86, 0x02, 0x68, 0x34, 0x3e,
+ 0x13, 0x03, 0xd1, 0x19, 0xaf, 0x19, 0xa1, 0x87,
+ 0x02, 0xd1, 0x39, 0x3e, 0x13, 0x02, 0x68, 0x34,
+ 0xbd, 0x19, 0x02, 0xd1, 0x19, 0xbb, 0x14, 0x02,
+ 0xd1, 0x19, 0x95, 0x86, 0x02, 0xdb, 0x39, 0x42,
+ 0x86, 0x02, 0x38, 0x39, 0x40, 0x86, 0x02, 0x69,
+ 0x34, 0x80, 0x16, 0x02, 0x69, 0x14, 0xeb, 0x13,
+ 0x04, 0x68, 0x14, 0x69, 0x14, 0x67, 0x14, 0x67,
+ 0x14, 0x02, 0x77, 0x34, 0x42, 0x86, 0x02, 0x46,
+ 0x36, 0x40, 0x86, 0x02, 0x68, 0x34, 0x92, 0x16,
+ 0x02, 0x4e, 0x36, 0x42, 0x86, 0x03, 0x69, 0x14,
+ 0xbd, 0x19, 0xa1, 0x87, 0x02, 0xde, 0x19, 0x40,
+ 0x86, 0x02, 0x69, 0x34, 0x27, 0x15, 0x03, 0xc3,
+ 0x13, 0x40, 0x86, 0xa1, 0x87, 0x02, 0x81, 0x14,
+ 0x40, 0x86, 0x03, 0xd1, 0x39, 0xaf, 0x19, 0xa1,
+ 0x87, 0x02, 0x68, 0x34, 0xbc, 0x19, 0x02, 0xd1,
+ 0x19, 0x80, 0x16, 0x02, 0xd9, 0x39, 0x42, 0x86,
+ 0x02, 0xd1, 0x39, 0xbc, 0x19, 0x02, 0xdc, 0x19,
+ 0x42, 0x86, 0x02, 0x68, 0x34, 0x73, 0x13, 0x02,
+ 0x69, 0x34, 0x3e, 0x13, 0x02, 0x47, 0x16, 0x40,
+ 0x86, 0x02, 0xd1, 0x39, 0xbd, 0x19, 0x02, 0x3e,
+ 0x39, 0x42, 0x86, 0x02, 0x69, 0x14, 0x95, 0x86,
+ 0x02, 0x68, 0x14, 0x96, 0x86, 0x03, 0x69, 0x34,
+ 0xbd, 0x19, 0xa1, 0x87, 0x02, 0xd7, 0x39, 0x40,
+ 0x86, 0x02, 0x45, 0x16, 0x42, 0x86, 0x02, 0x68,
+ 0x34, 0xed, 0x13, 0x03, 0x68, 0x34, 0xbc, 0x19,
+ 0xa1, 0x87, 0x02, 0xd1, 0x39, 0xed, 0x13, 0x02,
+ 0xd1, 0x39, 0x92, 0x16, 0x02, 0x73, 0x34, 0x40,
+ 0x86, 0x02, 0x38, 0x19, 0x40, 0x86, 0x02, 0xb5,
+ 0x36, 0x40, 0x86, 0x02, 0x68, 0x34, 0xaf, 0x19,
+ 0x02, 0xd1, 0x39, 0xaf, 0x19, 0x02, 0x69, 0x34,
+ 0xbc, 0x19, 0x02, 0xb6, 0x16, 0x42, 0x86, 0x02,
+ 0x26, 0x14, 0x25, 0x15, 0x02, 0xc3, 0x33, 0x40,
+ 0x86, 0x02, 0xdd, 0x39, 0x42, 0x86, 0x02, 0xcb,
+ 0x93, 0x42, 0x86, 0x02, 0xcb, 0x33, 0x42, 0x86,
+ 0x02, 0x81, 0x34, 0x42, 0x86, 0x02, 0xce, 0x39,
+ 0xa1, 0x87, 0x02, 0xdb, 0x39, 0x40, 0x86, 0x02,
+ 0x68, 0x34, 0x08, 0x87, 0x02, 0xd1, 0x19, 0xb0,
+ 0x19, 0x02, 0x77, 0x34, 0x40, 0x86, 0x02, 0x4e,
+ 0x36, 0x40, 0x86, 0x02, 0xce, 0x39, 0x42, 0x86,
+ 0x02, 0x4e, 0x16, 0x42, 0x86, 0x02, 0xd9, 0x39,
+ 0x40, 0x86, 0x02, 0xdc, 0x19, 0x40, 0x86, 0x02,
+ 0x3e, 0x39, 0x40, 0x86, 0x02, 0xb9, 0x39, 0x42,
+ 0x86, 0x02, 0xda, 0x19, 0x42, 0x86, 0x02, 0x42,
+ 0x16, 0x94, 0x81, 0x02, 0x45, 0x16, 0x40, 0x86,
+ 0x02, 0x69, 0x14, 0xbd, 0x19, 0x02, 0x70, 0x34,
+ 0x42, 0x86, 0x02, 0xce, 0x19, 0xa1, 0x87, 0x02,
+ 0xc3, 0x13, 0x42, 0x86, 0x02, 0x68, 0x14, 0x08,
+ 0x87, 0x02, 0xd1, 0x19, 0x7c, 0x13, 0x02, 0x68,
+ 0x14, 0x92, 0x16, 0x02, 0xb6, 0x16, 0x40, 0x86,
+ 0x02, 0x37, 0x39, 0x42, 0x86, 0x03, 0xce, 0x19,
+ 0x42, 0x86, 0xa1, 0x87, 0x03, 0x68, 0x14, 0x67,
+ 0x14, 0x67, 0x14, 0x02, 0xdd, 0x39, 0x40, 0x86,
+ 0x02, 0xcf, 0x19, 0x42, 0x86, 0x02, 0xd1, 0x19,
+ 0x2c, 0x15, 0x02, 0x4b, 0x13, 0xe9, 0x17, 0x02,
+ 0x68, 0x14, 0x67, 0x14, 0x02, 0xcb, 0x93, 0x40,
+ 0x86, 0x02, 0x6e, 0x34, 0x42, 0x86, 0x02, 0xcb,
+ 0x33, 0x40, 0x86, 0x02, 0x81, 0x34, 0x40, 0x86,
+ 0x02, 0xb6, 0x36, 0xa1, 0x87, 0x02, 0x45, 0x36,
+ 0x42, 0x86, 0x02, 0xb4, 0x16, 0x42, 0x86, 0x02,
+ 0x69, 0x14, 0x73, 0x13, 0x04, 0x69, 0x14, 0x69,
+ 0x14, 0x67, 0x14, 0x66, 0x14, 0x02, 0x35, 0x39,
+ 0x42, 0x86, 0x02, 0x68, 0x14, 0x93, 0x13, 0x02,
+ 0xb6, 0x36, 0x42, 0x86, 0x03, 0x68, 0x14, 0x69,
+ 0x14, 0x66, 0x14, 0x02, 0xce, 0x39, 0x40, 0x86,
+ 0x02, 0x4e, 0x16, 0x40, 0x86, 0x02, 0x87, 0x34,
+ 0x42, 0x86, 0x02, 0x86, 0x14, 0x42, 0x86, 0x02,
+ 0xd6, 0x39, 0x42, 0x86, 0x02, 0xc4, 0x33, 0x42,
+ 0x86, 0x02, 0x69, 0x34, 0x96, 0x86, 0x02, 0xb9,
+ 0x39, 0x40, 0x86, 0x02, 0x68, 0x14, 0xa8, 0x13,
+ 0x02, 0xd1, 0x19, 0x84, 0x13, 0x02, 0xda, 0x19,
+ 0x40, 0x86, 0x02, 0xd8, 0x19, 0x42, 0x86, 0x02,
+ 0xc3, 0x13, 0x40, 0x86, 0x02, 0xb9, 0x19, 0x42,
+ 0x86, 0x02, 0x3d, 0x19, 0x42, 0x86, 0x02, 0xcf,
+ 0x19, 0x40, 0x86, 0x04, 0x68, 0x14, 0x68, 0x14,
+ 0x67, 0x14, 0x67, 0x14, 0x03, 0xd1, 0x19, 0xd1,
+ 0x19, 0xd2, 0x19, 0x02, 0x68, 0x14, 0xbb, 0x14,
+ 0x02, 0x3b, 0x14, 0x44, 0x87, 0x02, 0xd1, 0x19,
+ 0x27, 0x15, 0x02, 0xb4, 0x16, 0x40, 0x86, 0x02,
+ 0xcd, 0x19, 0x42, 0x86, 0x02, 0xd3, 0x86, 0xa5,
+ 0x14, 0x02, 0x70, 0x14, 0x42, 0x86, 0x03, 0xb6,
+ 0x16, 0x42, 0x86, 0xa1, 0x87, 0x04, 0x69, 0x14,
+ 0x64, 0x87, 0x8b, 0x14, 0x69, 0x14, 0x02, 0x36,
+ 0x16, 0x2b, 0x93, 0x02, 0x68, 0x14, 0x80, 0x16,
+ 0x02, 0x86, 0x14, 0x40, 0x86, 0x02, 0x08, 0x14,
+ 0x1b, 0x0b, 0x02, 0xd1, 0x19, 0xbc, 0x19, 0x02,
+ 0xca, 0x13, 0x42, 0x86, 0x02, 0x41, 0x94, 0xe8,
+ 0x95, 0x02, 0xd8, 0x19, 0x40, 0x86, 0x02, 0xb9,
+ 0x19, 0x40, 0x86, 0x02, 0xd1, 0x19, 0xed, 0x13,
+ 0x02, 0xf9, 0x86, 0x42, 0x86, 0x03, 0xd1, 0x19,
+ 0xbd, 0x19, 0xa1, 0x87, 0x02, 0x3d, 0x19, 0x40,
+ 0x86, 0x02, 0xd6, 0x19, 0x42, 0x86, 0x03, 0x69,
+ 0x14, 0x66, 0x14, 0x66, 0x14, 0x02, 0xd1, 0x19,
+ 0xaf, 0x19, 0x03, 0x69, 0x14, 0x69, 0x14, 0x67,
+ 0x14, 0x02, 0xcd, 0x19, 0x40, 0x86, 0x02, 0x70,
+ 0x14, 0x40, 0x86, 0x03, 0x68, 0x14, 0xbc, 0x19,
+ 0xa1, 0x87, 0x02, 0x6e, 0x14, 0x42, 0x86, 0x02,
+ 0x69, 0x14, 0x92, 0x16, 0x03, 0x68, 0x14, 0x68,
+ 0x14, 0x67, 0x14, 0x02, 0x69, 0x14, 0x67, 0x14,
+ 0x02, 0x75, 0x95, 0x42, 0x86, 0x03, 0x69, 0x14,
+ 0x64, 0x87, 0x69, 0x14, 0x02, 0xd1, 0x19, 0xbc,
+ 0x14, 0x02, 0xdf, 0x19, 0x42, 0x86, 0x02, 0xca,
+ 0x13, 0x40, 0x86, 0x02, 0x82, 0x14, 0x42, 0x86,
+ 0x02, 0x69, 0x14, 0x93, 0x13, 0x02, 0x68, 0x14,
+ 0x7c, 0x13, 0x02, 0xf9, 0x86, 0x40, 0x86, 0x02,
+ 0xd6, 0x19, 0x40, 0x86, 0x02, 0x68, 0x14, 0x2c,
+ 0x15, 0x02, 0x69, 0x14, 0xa8, 0x13, 0x02, 0xd4,
+ 0x19, 0x42, 0x86, 0x04, 0x68, 0x14, 0x69, 0x14,
+ 0x66, 0x14, 0x66, 0x14, 0x02, 0x77, 0x14, 0x42,
+ 0x86, 0x02, 0x39, 0x19, 0x42, 0x86, 0x02, 0xd1,
+ 0x19, 0xa4, 0x13, 0x02, 0x6e, 0x14, 0x40, 0x86,
+ 0x03, 0xd1, 0x19, 0xd2, 0x19, 0xd2, 0x19, 0x02,
+ 0x69, 0x14, 0xbb, 0x14, 0x02, 0xd1, 0x19, 0x96,
+ 0x86, 0x02, 0x75, 0x95, 0x40, 0x86, 0x04, 0x68,
+ 0x14, 0x64, 0x87, 0x8b, 0x14, 0x68, 0x14, 0x02,
+ 0xd1, 0x19, 0x3e, 0x13, 0x02, 0xdf, 0x19, 0x40,
+ 0x86, 0x02, 0x82, 0x14, 0x40, 0x86, 0x02, 0x44,
+ 0x13, 0xeb, 0x17, 0x02, 0xdd, 0x19, 0x42, 0x86,
+ 0x02, 0x69, 0x14, 0x80, 0x16, 0x03, 0x68, 0x14,
+ 0xaf, 0x19, 0xa1, 0x87, 0x02, 0xa3, 0x16, 0x42,
+ 0x86, 0x02, 0x69, 0x14, 0x96, 0x86, 0x02, 0x46,
+ 0x16, 0x42, 0x86, 0x02, 0xb6, 0x16, 0xa1, 0x87,
+ 0x02, 0x68, 0x14, 0x27, 0x15, 0x02, 0x26, 0x14,
+ 0x1b, 0x0b, 0x02, 0xd4, 0x19, 0x40, 0x86, 0x02,
+ 0x77, 0x14, 0x40, 0x86, 0x02, 0x39, 0x19, 0x40,
+ 0x86, 0x02, 0x37, 0x19, 0x42, 0x86, 0x03, 0x69,
+ 0x14, 0x67, 0x14, 0x66, 0x14, 0x03, 0xc3, 0x13,
+ 0x42, 0x86, 0xa1, 0x87, 0x02, 0x68, 0x14, 0xbc,
+ 0x19, 0x02, 0xd1, 0x19, 0xeb, 0x13, 0x04, 0x69,
+ 0x14, 0x69, 0x14, 0x67, 0x14, 0x67, 0x14, 0x02,
+ 0xd1, 0x19, 0x08, 0x87, 0x02, 0x68, 0x14, 0xed,
+ 0x13, 0x03, 0x69, 0x14, 0xbc, 0x19, 0xa1, 0x87,
+ 0x02, 0xdd, 0x19, 0x40, 0x86, 0x02, 0xc3, 0x13,
+ 0xa1, 0x87, 0x03, 0x68, 0x14, 0x66, 0x14, 0x66,
+ 0x14, 0x03, 0x68, 0x14, 0x69, 0x14, 0x67, 0x14,
+ 0x02, 0xa3, 0x16, 0x40, 0x86, 0x02, 0xdb, 0x19,
+ 0x42, 0x86, 0x02, 0x68, 0x14, 0xaf, 0x19, 0x02,
+ 0x46, 0x16, 0x40, 0x86, 0x02, 0x35, 0x16, 0xab,
+ 0x14, 0x02, 0x68, 0x14, 0x95, 0x86, 0x02, 0x42,
+ 0x16, 0x95, 0x81, 0x02, 0xc4, 0x13, 0x42, 0x86,
+ 0x02, 0x15, 0x14, 0xba, 0x19, 0x02, 0x69, 0x14,
+ 0x08, 0x87, 0x03, 0xd1, 0x19, 0x1d, 0x19, 0xd1,
+ 0x19, 0x02, 0x69, 0x14, 0x7c, 0x13, 0x02, 0x37,
+ 0x19, 0x40, 0x86, 0x02, 0x73, 0x14, 0x42, 0x86,
+ 0x02, 0x69, 0x14, 0x2c, 0x15, 0x02, 0xb5, 0x16,
+ 0x42, 0x86, 0x02, 0x35, 0x19, 0x42, 0x86, 0x04,
+ 0x68, 0x14, 0x69, 0x14, 0x67, 0x14, 0x66, 0x14,
+ 0x02, 0x64, 0x87, 0x25, 0x15, 0x02, 0x64, 0x87,
+ 0x79, 0x1a, 0x02, 0x68, 0x14, 0xbc, 0x14, 0x03,
+ 0xce, 0x19, 0x40, 0x86, 0xa1, 0x87, 0x02, 0x87,
+ 0x14, 0x42, 0x86, 0x02, 0x4d, 0x16, 0x42, 0x86,
+ 0x04, 0x68, 0x14, 0x68, 0x14, 0x66, 0x14, 0x66,
+ 0x14, 0x02, 0xdb, 0x19, 0x40, 0x86, 0x02, 0xd9,
+ 0x19, 0x42, 0x86, 0x02, 0xc4, 0x13, 0x40, 0x86,
+ 0x02, 0xd1, 0x19, 0xbd, 0x19, 0x02, 0x68, 0x14,
+ 0xa4, 0x13, 0x02, 0x3e, 0x19, 0x42, 0x86, 0x02,
+ 0xf3, 0x93, 0xa7, 0x86, 0x03, 0x69, 0x14, 0xaf,
+ 0x19, 0xa1, 0x87, 0x02, 0xf3, 0x93, 0x08, 0x13,
+ 0x02, 0xd1, 0x19, 0xd2, 0x19, 0x02, 0x73, 0x14,
+ 0x40, 0x86, 0x02, 0xb5, 0x16, 0x40, 0x86, 0x02,
+ 0x35, 0x19, 0x40, 0x86, 0x02, 0x69, 0x14, 0x27,
+ 0x15, 0x02, 0xce, 0x19, 0x42, 0x86, 0x02, 0x71,
+ 0x14, 0x42, 0x86, 0x02, 0xd1, 0x19, 0x73, 0x13,
+ 0x02, 0x68, 0x14, 0x3e, 0x13, 0x02, 0xf4, 0x13,
+ 0x20, 0x86, 0x02, 0x87, 0x14, 0x40, 0x86, 0x03,
+ 0xb6, 0x16, 0x40, 0x86, 0xa1, 0x87, 0x02, 0x4d,
+ 0x16, 0x40, 0x86, 0x02, 0x69, 0x14, 0xbc, 0x19,
+ 0x02, 0x4b, 0x16, 0x42, 0x86, 0x02, 0xd9, 0x19,
+ 0x40, 0x86, 0x02, 0x3e, 0x19, 0x40, 0x86, 0x02,
+ 0x69, 0x14, 0xed, 0x13, 0x02, 0xd7, 0x19, 0x42,
+ 0x86, 0x02, 0xb8, 0x19, 0x42, 0x86, 0x03, 0x68,
+ 0x14, 0x67, 0x14, 0x66, 0x14, 0x02, 0x3c, 0x19,
+ 0x42, 0x86, 0x02, 0x68, 0x14, 0x66, 0x14, 0x03,
+ 0x68, 0x14, 0x64, 0x87, 0x68, 0x14, 0x02, 0x69,
+ 0x14, 0xaf, 0x19, 0x02, 0xce, 0x19, 0x40, 0x86,
+ 0x02, 0x71, 0x14, 0x40, 0x86, 0x02, 0x68, 0x14,
+ 0xeb, 0x13, 0x03, 0x68, 0x14, 0xbd, 0x19, 0xa1,
+ 0x87, 0x02, 0x6f, 0x14, 0x42, 0x86, 0x04, 0xd1,
+ 0x19, 0xd1, 0x19, 0xd2, 0x19, 0xd2, 0x19, 0x02,
+ 0x69, 0x14, 0xbc, 0x14, 0x02, 0xcc, 0x93, 0x42,
+ 0x86, 0x02, 0x4b, 0x16, 0x40, 0x86, 0x02, 0x26,
+ 0x19, 0x42, 0x86, 0x02, 0xd7, 0x19, 0x40, 0x86,
+};
+
#endif /* CONFIG_ALL_UNICODE */
+/* 71 tables / 36311 bytes, 5 index / 351 bytes */
diff --git a/quickjs/libunicode.c b/quickjs/libunicode.c
index 63c12a0771..3791523d6a 100644
--- a/quickjs/libunicode.c
+++ b/quickjs/libunicode.c
@@ -1,6 +1,6 @@
/*
* Unicode utilities
- *
+ *
* Copyright (c) 2017-2018 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -43,15 +43,115 @@ enum {
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,
+ RUN_TYPE_UF_EXT2,
+ RUN_TYPE_LF_EXT2,
+ RUN_TYPE_UF_EXT3,
};
+static int lre_case_conv1(uint32_t c, int conv_type)
+{
+ uint32_t res[LRE_CC_RES_LEN_MAX];
+ lre_case_conv(res, c, conv_type);
+ return res[0];
+}
+
+/* case conversion using the table entry 'idx' with value 'v' */
+static int lre_case_conv_entry(uint32_t *res, uint32_t c, int conv_type, uint32_t idx, uint32_t v)
+{
+ uint32_t code, data, type, a, is_lower;
+ is_lower = (conv_type != 0);
+ type = (v >> (32 - 17 - 7 - 4)) & 0xf;
+ data = ((v & 0xf) << 8) | case_conv_table2[idx];
+ code = v >> (32 - 17);
+ switch(type) {
+ case RUN_TYPE_U:
+ case RUN_TYPE_L:
+ case RUN_TYPE_UF:
+ case RUN_TYPE_LF:
+ if (conv_type == (type & 1) ||
+ (type >= RUN_TYPE_UF && conv_type == 2)) {
+ c = c - code + (case_conv_table1[data] >> (32 - 17));
+ }
+ break;
+ case RUN_TYPE_UL:
+ a = c - code;
+ if ((a & 1) != (1 - is_lower))
+ break;
+ c = (a ^ 1) + code;
+ break;
+ case RUN_TYPE_LSU:
+ a = c - code;
+ if (a == 1) {
+ c += 2 * is_lower - 1;
+ } else if (a == (1 - is_lower) * 2) {
+ c += (2 * is_lower - 1) * 2;
+ }
+ break;
+ case RUN_TYPE_U2L_399_EXT2:
+ if (!is_lower) {
+ res[0] = c - code + case_conv_ext[data >> 6];
+ res[1] = 0x399;
+ return 2;
+ } else {
+ c = c - code + case_conv_ext[data & 0x3f];
+ }
+ break;
+ case RUN_TYPE_UF_D20:
+ if (conv_type == 1)
+ break;
+ c = data + (conv_type == 2) * 0x20;
+ break;
+ case RUN_TYPE_UF_D1_EXT:
+ if (conv_type == 1)
+ break;
+ c = case_conv_ext[data] + (conv_type == 2);
+ break;
+ case RUN_TYPE_U_EXT:
+ case RUN_TYPE_LF_EXT:
+ if (is_lower != (type - RUN_TYPE_U_EXT))
+ break;
+ c = case_conv_ext[data];
+ break;
+ case RUN_TYPE_LF_EXT2:
+ if (!is_lower)
+ break;
+ res[0] = c - code + case_conv_ext[data >> 6];
+ res[1] = case_conv_ext[data & 0x3f];
+ return 2;
+ case RUN_TYPE_UF_EXT2:
+ if (conv_type == 1)
+ break;
+ res[0] = c - code + case_conv_ext[data >> 6];
+ res[1] = case_conv_ext[data & 0x3f];
+ if (conv_type == 2) {
+ /* convert to lower */
+ res[0] = lre_case_conv1(res[0], 1);
+ res[1] = lre_case_conv1(res[1], 1);
+ }
+ return 2;
+ default:
+ case RUN_TYPE_UF_EXT3:
+ if (conv_type == 1)
+ break;
+ res[0] = case_conv_ext[data >> 8];
+ res[1] = case_conv_ext[(data >> 4) & 0xf];
+ res[2] = case_conv_ext[data & 0xf];
+ if (conv_type == 2) {
+ /* convert to lower */
+ res[0] = lre_case_conv1(res[0], 1);
+ res[1] = lre_case_conv1(res[1], 1);
+ res[2] = lre_case_conv1(res[2], 1);
+ }
+ return 3;
+ }
+ res[0] = c;
+ return 1;
+}
+
/* conv_type:
- 0 = to upper
+ 0 = to upper
1 = to lower
- 2 = case folding (= to lower with modifications)
+ 2 = case folding (= to lower with modifications)
*/
int lre_case_conv(uint32_t *res, uint32_t c, int conv_type)
{
@@ -66,10 +166,9 @@ int lre_case_conv(uint32_t *res, uint32_t c, int conv_type)
}
}
} else {
- uint32_t v, code, data, type, len, a, is_lower;
+ uint32_t v, code, len;
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) {
@@ -82,74 +181,7 @@ int lre_case_conv(uint32_t *res, uint32_t c, int conv_type)
} 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;
+ return lre_case_conv_entry(res, c, conv_type, idx, v);
}
}
}
@@ -157,13 +189,80 @@ int lre_case_conv(uint32_t *res, uint32_t c, int conv_type)
return 1;
}
+static int lre_case_folding_entry(uint32_t c, uint32_t idx, uint32_t v, BOOL is_unicode)
+{
+ uint32_t res[LRE_CC_RES_LEN_MAX];
+ int len;
+
+ if (is_unicode) {
+ len = lre_case_conv_entry(res, c, 2, idx, v);
+ if (len == 1) {
+ c = res[0];
+ } else {
+ /* handle the few specific multi-character cases (see
+ unicode_gen.c:dump_case_folding_special_cases()) */
+ if (c == 0xfb06) {
+ c = 0xfb05;
+ } else if (c == 0x01fd3) {
+ c = 0x390;
+ } else if (c == 0x01fe3) {
+ c = 0x3b0;
+ }
+ }
+ } else {
+ if (likely(c < 128)) {
+ if (c >= 'a' && c <= 'z')
+ c = c - 'a' + 'A';
+ } else {
+ /* legacy regexp: to upper case if single char >= 128 */
+ len = lre_case_conv_entry(res, c, FALSE, idx, v);
+ if (len == 1 && res[0] >= 128)
+ c = res[0];
+ }
+ }
+ return c;
+}
+
+/* JS regexp specific rules for case folding */
+int lre_canonicalize(uint32_t c, BOOL is_unicode)
+{
+ if (c < 128) {
+ /* fast case */
+ if (is_unicode) {
+ if (c >= 'A' && c <= 'Z') {
+ c = c - 'A' + 'a';
+ }
+ } else {
+ if (c >= 'a' && c <= 'z') {
+ c = c - 'a' + 'A';
+ }
+ }
+ } else {
+ uint32_t v, code, len;
+ int idx, idx_min, idx_max;
+
+ idx_min = 0;
+ idx_max = countof(case_conv_table1) - 1;
+ while (idx_min <= idx_max) {
+ idx = (unsigned)(idx_max + idx_min) / 2;
+ v = case_conv_table1[idx];
+ code = v >> (32 - 17);
+ len = (v >> (32 - 17 - 7)) & 0x7f;
+ if (c < code) {
+ idx_max = idx - 1;
+ } else if (c >= code + len) {
+ idx_min = idx + 1;
+ } else {
+ return lre_case_folding_entry(c, idx, v, is_unicode);
+ }
+ }
+ }
+ return c;
+}
+
static uint32_t get_le24(const uint8_t *ptr)
{
-#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
@@ -208,12 +307,20 @@ static BOOL lre_is_in_table(uint32_t c, const uint8_t *table,
uint32_t code, b, bit;
int pos;
const uint8_t *p;
-
+
pos = get_index_pos(&code, c, index_table, index_table_len);
if (pos < 0)
return FALSE; /* outside the table */
p = table + pos;
bit = 0;
+ /* Compressed run length encoding:
+ 00..3F: 2 packed lengths: 3-bit + 3-bit
+ 40..5F: 5-bits plus extra byte for length
+ 60..7F: 5-bits plus 2 extra bytes for length
+ 80..FF: 7-bit length
+ lengths must be incremented to get character count
+ Ranges alternate between false and true return value.
+ */
for(;;) {
b = *p++;
if (b < 64) {
@@ -241,7 +348,7 @@ 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) {
@@ -300,7 +407,7 @@ 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,
@@ -327,7 +434,7 @@ static void cr_compress(CharRange *cr)
{
int i, j, k, len;
uint32_t *pt;
-
+
pt = cr->points;
len = cr->len;
i = 0;
@@ -357,7 +464,7 @@ int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,
{
int a_idx, b_idx, is_in;
uint32_t v;
-
+
a_idx = 0;
b_idx = 0;
for(;;) {
@@ -392,6 +499,9 @@ int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,
case CR_OP_XOR:
is_in = (a_idx & 1) ^ (b_idx & 1);
break;
+ case CR_OP_SUB:
+ is_in = (a_idx & 1) & ((b_idx & 1) ^ 1);
+ break;
default:
abort();
}
@@ -404,14 +514,14 @@ int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,
return 0;
}
-int cr_union1(CharRange *cr, const uint32_t *b_pt, int b_len)
+int cr_op1(CharRange *cr, const uint32_t *b_pt, int b_len, int op)
{
CharRange a = *cr;
int ret;
cr->len = 0;
cr->size = 0;
cr->points = NULL;
- ret = cr_op(cr, a.points, a.len, b_pt, b_len, CR_OP_UNION);
+ ret = cr_op(cr, a.points, a.len, b_pt, b_len, op);
cr_free(&a);
return ret;
}
@@ -430,6 +540,207 @@ int cr_invert(CharRange *cr)
return 0;
}
+#define CASE_U (1 << 0)
+#define CASE_L (1 << 1)
+#define CASE_F (1 << 2)
+
+/* use the case conversion table to generate range of characters.
+ CASE_U: set char if modified by uppercasing,
+ CASE_L: set char if modified by lowercasing,
+ CASE_F: set char if modified by case folding,
+ */
+static int unicode_case1(CharRange *cr, int case_mask)
+{
+#define MR(x) (1 << RUN_TYPE_ ## x)
+ const uint32_t tab_run_mask[3] = {
+ MR(U) | MR(UF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(UF_D20) |
+ MR(UF_D1_EXT) | MR(U_EXT) | MR(UF_EXT2) | MR(UF_EXT3),
+
+ MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2),
+
+ MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT) | MR(UF_EXT2) | MR(UF_EXT3),
+ };
+#undef MR
+ uint32_t mask, v, code, type, len, i, idx;
+
+ if (case_mask == 0)
+ return 0;
+ mask = 0;
+ for(i = 0; i < 3; i++) {
+ if ((case_mask >> i) & 1)
+ mask |= tab_run_mask[i];
+ }
+ for(idx = 0; idx < countof(case_conv_table1); idx++) {
+ v = case_conv_table1[idx];
+ type = (v >> (32 - 17 - 7 - 4)) & 0xf;
+ code = v >> (32 - 17);
+ len = (v >> (32 - 17 - 7)) & 0x7f;
+ if ((mask >> type) & 1) {
+ // printf("%d: type=%d %04x %04x\n", idx, type, code, code + len - 1);
+ switch(type) {
+ case RUN_TYPE_UL:
+ if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F)))
+ goto def_case;
+ code += ((case_mask & CASE_U) != 0);
+ for(i = 0; i < len; i += 2) {
+ if (cr_add_interval(cr, code + i, code + i + 1))
+ return -1;
+ }
+ break;
+ case RUN_TYPE_LSU:
+ if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F)))
+ goto def_case;
+ if (!(case_mask & CASE_U)) {
+ if (cr_add_interval(cr, code, code + 1))
+ return -1;
+ }
+ if (cr_add_interval(cr, code + 1, code + 2))
+ return -1;
+ if (case_mask & CASE_U) {
+ if (cr_add_interval(cr, code + 2, code + 3))
+ return -1;
+ }
+ break;
+ default:
+ def_case:
+ if (cr_add_interval(cr, code, code + len))
+ return -1;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static int point_cmp(const void *p1, const void *p2, void *arg)
+{
+ uint32_t v1 = *(uint32_t *)p1;
+ uint32_t v2 = *(uint32_t *)p2;
+ return (v1 > v2) - (v1 < v2);
+}
+
+static void cr_sort_and_remove_overlap(CharRange *cr)
+{
+ uint32_t start, end, start1, end1, i, j;
+
+ /* the resulting ranges are not necessarily sorted and may overlap */
+ rqsort(cr->points, cr->len / 2, sizeof(cr->points[0]) * 2, point_cmp, NULL);
+ j = 0;
+ for(i = 0; i < cr->len; ) {
+ start = cr->points[i];
+ end = cr->points[i + 1];
+ i += 2;
+ while (i < cr->len) {
+ start1 = cr->points[i];
+ end1 = cr->points[i + 1];
+ if (start1 > end) {
+ /* |------|
+ * |-------| */
+ break;
+ } else if (end1 <= end) {
+ /* |------|
+ * |--| */
+ i += 2;
+ } else {
+ /* |------|
+ * |-------| */
+ end = end1;
+ i += 2;
+ }
+ }
+ cr->points[j] = start;
+ cr->points[j + 1] = end;
+ j += 2;
+ }
+ cr->len = j;
+}
+
+/* canonicalize a character set using the JS regex case folding rules
+ (see lre_canonicalize()) */
+int cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode)
+{
+ CharRange cr_inter, cr_mask, cr_result, cr_sub;
+ uint32_t v, code, len, i, idx, start, end, c, d_start, d_end, d;
+
+ cr_init(&cr_mask, cr->mem_opaque, cr->realloc_func);
+ cr_init(&cr_inter, cr->mem_opaque, cr->realloc_func);
+ cr_init(&cr_result, cr->mem_opaque, cr->realloc_func);
+ cr_init(&cr_sub, cr->mem_opaque, cr->realloc_func);
+
+ if (unicode_case1(&cr_mask, is_unicode ? CASE_F : CASE_U))
+ goto fail;
+ if (cr_op(&cr_inter, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER))
+ goto fail;
+
+ if (cr_invert(&cr_mask))
+ goto fail;
+ if (cr_op(&cr_sub, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER))
+ goto fail;
+
+ /* cr_inter = cr & cr_mask */
+ /* cr_sub = cr & ~cr_mask */
+
+ /* use the case conversion table to compute the result */
+ d_start = -1;
+ d_end = -1;
+ idx = 0;
+ v = case_conv_table1[idx];
+ code = v >> (32 - 17);
+ len = (v >> (32 - 17 - 7)) & 0x7f;
+ for(i = 0; i < cr_inter.len; i += 2) {
+ start = cr_inter.points[i];
+ end = cr_inter.points[i + 1];
+
+ for(c = start; c < end; c++) {
+ for(;;) {
+ if (c >= code && c < code + len)
+ break;
+ idx++;
+ assert(idx < countof(case_conv_table1));
+ v = case_conv_table1[idx];
+ code = v >> (32 - 17);
+ len = (v >> (32 - 17 - 7)) & 0x7f;
+ }
+ d = lre_case_folding_entry(c, idx, v, is_unicode);
+ /* try to merge with the current interval */
+ if (d_start == -1) {
+ d_start = d;
+ d_end = d + 1;
+ } else if (d_end == d) {
+ d_end++;
+ } else {
+ cr_add_interval(&cr_result, d_start, d_end);
+ d_start = d;
+ d_end = d + 1;
+ }
+ }
+ }
+ if (d_start != -1) {
+ if (cr_add_interval(&cr_result, d_start, d_end))
+ goto fail;
+ }
+
+ /* the resulting ranges are not necessarily sorted and may overlap */
+ cr_sort_and_remove_overlap(&cr_result);
+
+ /* or with the character not affected by the case folding */
+ cr->len = 0;
+ if (cr_op(cr, cr_result.points, cr_result.len, cr_sub.points, cr_sub.len, CR_OP_UNION))
+ goto fail;
+
+ cr_free(&cr_inter);
+ cr_free(&cr_mask);
+ cr_free(&cr_result);
+ cr_free(&cr_sub);
+ return 0;
+ fail:
+ cr_free(&cr_inter);
+ cr_free(&cr_mask);
+ cr_free(&cr_result);
+ cr_free(&cr_sub);
+ return -1;
+}
+
#ifdef CONFIG_ALL_UNICODE
BOOL lre_is_id_start(uint32_t c)
@@ -658,7 +969,7 @@ 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) {
@@ -688,7 +999,7 @@ 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) {
@@ -724,12 +1035,19 @@ static int unicode_get_cc(uint32_t c)
uint32_t code, n, type, cc, c1, b;
int pos;
const uint8_t *p;
-
+
pos = get_index_pos(&code, c,
unicode_cc_index, sizeof(unicode_cc_index) / 3);
if (pos < 0)
return 0;
p = unicode_cc_table + pos;
+ /* Compressed run length encoding:
+ - 2 high order bits are combining class type
+ - 0:0, 1:230, 2:extra byte linear progression, 3:extra byte
+ - 00..2F: range length (add 1)
+ - 30..37: 3-bit range-length + 1 extra byte
+ - 38..3F: 3-bit range-length + 2 extra byte
+ */
for(;;) {
b = *p++;
type = b >> 6;
@@ -773,7 +1091,7 @@ static int unicode_get_cc(uint32_t c)
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) {
@@ -812,7 +1130,7 @@ static void to_nfd_rec(DynBuf *dbuf,
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) {
@@ -857,7 +1175,7 @@ int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
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);
@@ -885,15 +1203,15 @@ int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
}
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) {
@@ -930,7 +1248,7 @@ 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);
@@ -963,13 +1281,11 @@ int unicode_script(CharRange *cr,
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) {
@@ -998,17 +1314,21 @@ int unicode_script(CharRange *cr,
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;
+ if (type != 0) {
+ v = *p++;
+ if (v == script_idx || script_idx == UNICODE_SCRIPT_Unknown) {
+ if (cr_add_interval(cr1, c, c1))
+ goto fail;
+ }
}
c = c1;
}
+ if (script_idx == UNICODE_SCRIPT_Unknown) {
+ /* Unknown is all the characters outside scripts */
+ if (cr_invert(cr1))
+ goto fail;
+ }
if (is_ext) {
/* add the script extensions */
@@ -1082,6 +1402,15 @@ static int unicode_general_category1(CharRange *cr, uint32_t gc_mask)
p = unicode_gc_table;
p_end = unicode_gc_table + countof(unicode_gc_table);
c = 0;
+ /* Compressed range encoding:
+ initial byte:
+ bits 0..4: category number (special case 31)
+ bits 5..7: range length (add 1)
+ special case bits 5..7 == 7: read an extra byte
+ - 00..7F: range length (add 7 + 1)
+ - 80..BF: 6-bits plus extra byte for range length (add 7 + 128)
+ - C0..FF: 6-bits plus 2 extra bytes for range length (add 7 + 128 + 16384)
+ */
while (p < p_end) {
b = *p++;
n = b >> 5;
@@ -1135,6 +1464,14 @@ static int unicode_prop1(CharRange *cr, int prop_idx)
p_end = p + unicode_prop_len_table[prop_idx];
c = 0;
bit = 0;
+ /* Compressed range encoding:
+ 00..3F: 2 packed lengths: 3-bit + 3-bit
+ 40..5F: 5-bits plus extra byte for length
+ 60..7F: 5-bits plus 2 extra bytes for length
+ 80..FF: 7-bit length
+ lengths must be incremented to get character count
+ Ranges alternate between false and true return value.
+ */
while (p < p_end) {
c0 = c;
b = *p++;
@@ -1165,78 +1502,6 @@ static int unicode_prop1(CharRange *cr, int prop_idx)
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,
@@ -1256,7 +1521,7 @@ static int unicode_prop_ops(CharRange *cr, ...)
CharRange stack[POP_STACK_LEN_MAX];
int stack_len, op, ret, i;
uint32_t a;
-
+
va_start(ap, cr);
stack_len = 0;
for(;;) {
@@ -1294,6 +1559,7 @@ static int unicode_prop_ops(CharRange *cr, ...)
cr2 = &stack[stack_len - 1];
cr3 = &stack[stack_len++];
cr_init(cr3, cr->mem_opaque, cr->realloc_func);
+ /* CR_OP_XOR may be used here */
if (cr_op(cr3, cr1->points, cr1->len,
cr2->points, cr2->len, op - POP_UNION + CR_OP_UNION))
goto fail;
@@ -1342,7 +1608,7 @@ 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;
@@ -1360,7 +1626,7 @@ int unicode_general_category(CharRange *cr, const char *gc_name)
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;
@@ -1554,3 +1820,304 @@ int unicode_prop(CharRange *cr, const char *prop_name)
}
#endif /* CONFIG_ALL_UNICODE */
+
+/*---- lre codepoint categorizing functions ----*/
+
+#define S UNICODE_C_SPACE
+#define D UNICODE_C_DIGIT
+#define X UNICODE_C_XDIGIT
+#define U UNICODE_C_UPPER
+#define L UNICODE_C_LOWER
+#define _ UNICODE_C_UNDER
+#define d UNICODE_C_DOLLAR
+
+uint8_t const lre_ctype_bits[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, S, S, S, S, S, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ S, 0, 0, 0, d, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ X|D, X|D, X|D, X|D, X|D, X|D, X|D, X|D,
+ X|D, X|D, 0, 0, 0, 0, 0, 0,
+
+ 0, X|U, X|U, X|U, X|U, X|U, X|U, U,
+ U, U, U, U, U, U, U, U,
+ U, U, U, U, U, U, U, U,
+ U, U, U, 0, 0, 0, 0, _,
+
+ 0, X|L, X|L, X|L, X|L, X|L, X|L, L,
+ L, L, L, L, L, L, L, L,
+ L, L, L, L, L, L, L, L,
+ L, L, L, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ S, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+#undef S
+#undef D
+#undef X
+#undef U
+#undef L
+#undef _
+#undef d
+
+/* code point ranges for Zs,Zl or Zp property */
+static const uint16_t char_range_s[] = {
+ 10,
+ 0x0009, 0x000D + 1,
+ 0x0020, 0x0020 + 1,
+ 0x00A0, 0x00A0 + 1,
+ 0x1680, 0x1680 + 1,
+ 0x2000, 0x200A + 1,
+ /* 2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; */
+ /* 2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; */
+ 0x2028, 0x2029 + 1,
+ 0x202F, 0x202F + 1,
+ 0x205F, 0x205F + 1,
+ 0x3000, 0x3000 + 1,
+ /* FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; */
+ 0xFEFF, 0xFEFF + 1,
+};
+
+BOOL lre_is_space_non_ascii(uint32_t c)
+{
+ size_t i, n;
+
+ n = countof(char_range_s);
+ for(i = 5; i < n; i += 2) {
+ uint32_t low = char_range_s[i];
+ uint32_t high = char_range_s[i + 1];
+ if (c < low)
+ return FALSE;
+ if (c < high)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#define SEQ_MAX_LEN 16
+
+static int unicode_sequence_prop1(int seq_prop_idx, UnicodeSequencePropCB *cb, void *opaque,
+ CharRange *cr)
+{
+ int i, c, j;
+ uint32_t seq[SEQ_MAX_LEN];
+
+ switch(seq_prop_idx) {
+ case UNICODE_SEQUENCE_PROP_Basic_Emoji:
+ if (unicode_prop1(cr, UNICODE_PROP_Basic_Emoji1) < 0)
+ return -1;
+ for(i = 0; i < cr->len; i += 2) {
+ for(c = cr->points[i]; c < cr->points[i + 1]; c++) {
+ seq[0] = c;
+ cb(opaque, seq, 1);
+ }
+ }
+
+ cr->len = 0;
+
+ if (unicode_prop1(cr, UNICODE_PROP_Basic_Emoji2) < 0)
+ return -1;
+ for(i = 0; i < cr->len; i += 2) {
+ for(c = cr->points[i]; c < cr->points[i + 1]; c++) {
+ seq[0] = c;
+ seq[1] = 0xfe0f;
+ cb(opaque, seq, 2);
+ }
+ }
+
+ break;
+ case UNICODE_SEQUENCE_PROP_RGI_Emoji_Modifier_Sequence:
+ if (unicode_prop1(cr, UNICODE_PROP_Emoji_Modifier_Base) < 0)
+ return -1;
+ for(i = 0; i < cr->len; i += 2) {
+ for(c = cr->points[i]; c < cr->points[i + 1]; c++) {
+ for(j = 0; j < 5; j++) {
+ seq[0] = c;
+ seq[1] = 0x1f3fb + j;
+ cb(opaque, seq, 2);
+ }
+ }
+ }
+ break;
+ case UNICODE_SEQUENCE_PROP_RGI_Emoji_Flag_Sequence:
+ if (unicode_prop1(cr, UNICODE_PROP_RGI_Emoji_Flag_Sequence) < 0)
+ return -1;
+ for(i = 0; i < cr->len; i += 2) {
+ for(c = cr->points[i]; c < cr->points[i + 1]; c++) {
+ int c0, c1;
+ c0 = c / 26;
+ c1 = c % 26;
+ seq[0] = 0x1F1E6 + c0;
+ seq[1] = 0x1F1E6 + c1;
+ cb(opaque, seq, 2);
+ }
+ }
+ break;
+ case UNICODE_SEQUENCE_PROP_RGI_Emoji_ZWJ_Sequence:
+ {
+ int len, code, pres, k, mod, mod_count, mod_pos[2], hc_pos, n_mod, n_hc, mod1;
+ int mod_idx, hc_idx, i0, i1;
+ const uint8_t *tab = unicode_rgi_emoji_zwj_sequence;
+
+ for(i = 0; i < countof(unicode_rgi_emoji_zwj_sequence);) {
+ len = tab[i++];
+ k = 0;
+ mod = 0;
+ mod_count = 0;
+ hc_pos = -1;
+ for(j = 0; j < len; j++) {
+ code = tab[i++];
+ code |= tab[i++] << 8;
+ pres = code >> 15;
+ mod1 = (code >> 13) & 3;
+ code &= 0x1fff;
+ if (code < 0x1000) {
+ c = code + 0x2000;
+ } else {
+ c = 0x1f000 + (code - 0x1000);
+ }
+ if (c == 0x1f9b0)
+ hc_pos = k;
+ seq[k++] = c;
+ if (mod1 != 0) {
+ assert(mod_count < 2);
+ mod = mod1;
+ mod_pos[mod_count++] = k;
+ seq[k++] = 0; /* will be filled later */
+ }
+ if (pres) {
+ seq[k++] = 0xfe0f;
+ }
+ if (j < len - 1) {
+ seq[k++] = 0x200d;
+ }
+ }
+
+ /* genrate all the variants */
+ switch(mod) {
+ case 1:
+ n_mod = 5;
+ break;
+ case 2:
+ n_mod = 25;
+ break;
+ case 3:
+ n_mod = 20;
+ break;
+ default:
+ n_mod = 1;
+ break;
+ }
+ if (hc_pos >= 0)
+ n_hc = 4;
+ else
+ n_hc = 1;
+ for(hc_idx = 0; hc_idx < n_hc; hc_idx++) {
+ for(mod_idx = 0; mod_idx < n_mod; mod_idx++) {
+ if (hc_pos >= 0)
+ seq[hc_pos] = 0x1f9b0 + hc_idx;
+
+ switch(mod) {
+ case 1:
+ seq[mod_pos[0]] = 0x1f3fb + mod_idx;
+ break;
+ case 2:
+ case 3:
+ i0 = mod_idx / 5;
+ i1 = mod_idx % 5;
+ /* avoid identical values */
+ if (mod == 3 && i0 >= i1)
+ i0++;
+ seq[mod_pos[0]] = 0x1f3fb + i0;
+ seq[mod_pos[1]] = 0x1f3fb + i1;
+ break;
+ default:
+ break;
+ }
+#if 0
+ for(j = 0; j < k; j++)
+ printf(" %04x", seq[j]);
+ printf("\n");
+#endif
+ cb(opaque, seq, k);
+ }
+ }
+ }
+ }
+ break;
+ case UNICODE_SEQUENCE_PROP_RGI_Emoji_Tag_Sequence:
+ {
+ for(i = 0; i < countof(unicode_rgi_emoji_tag_sequence);) {
+ j = 0;
+ seq[j++] = 0x1F3F4;
+ for(;;) {
+ c = unicode_rgi_emoji_tag_sequence[i++];
+ if (c == 0x00)
+ break;
+ seq[j++] = 0xe0000 + c;
+ }
+ seq[j++] = 0xe007f;
+ cb(opaque, seq, j);
+ }
+ }
+ break;
+ case UNICODE_SEQUENCE_PROP_Emoji_Keycap_Sequence:
+ if (unicode_prop1(cr, UNICODE_PROP_Emoji_Keycap_Sequence) < 0)
+ return -1;
+ for(i = 0; i < cr->len; i += 2) {
+ for(c = cr->points[i]; c < cr->points[i + 1]; c++) {
+ seq[0] = c;
+ seq[1] = 0xfe0f;
+ seq[2] = 0x20e3;
+ cb(opaque, seq, 3);
+ }
+ }
+ break;
+ case UNICODE_SEQUENCE_PROP_RGI_Emoji:
+ /* all prevous sequences */
+ for(i = UNICODE_SEQUENCE_PROP_Basic_Emoji; i <= UNICODE_SEQUENCE_PROP_RGI_Emoji_ZWJ_Sequence; i++) {
+ int ret;
+ ret = unicode_sequence_prop1(i, cb, opaque, cr);
+ if (ret < 0)
+ return ret;
+ cr->len = 0;
+ }
+ break;
+ default:
+ return -2;
+ }
+ return 0;
+}
+
+/* build a unicode sequence property */
+/* return -2 if not found, -1 if other error. 'cr' is used as temporary memory. */
+int unicode_sequence_prop(const char *prop_name, UnicodeSequencePropCB *cb, void *opaque,
+ CharRange *cr)
+{
+ int seq_prop_idx;
+ seq_prop_idx = unicode_find_name(unicode_sequence_prop_name_table, prop_name);
+ if (seq_prop_idx < 0)
+ return -2;
+ return unicode_sequence_prop1(seq_prop_idx, cb, opaque, cr);
+}
diff --git a/quickjs/libunicode.h b/quickjs/libunicode.h
index cfa600a50d..5d964e40f7 100644
--- a/quickjs/libunicode.h
+++ b/quickjs/libunicode.h
@@ -1,6 +1,6 @@
/*
* Unicode utilities
- *
+ *
* Copyright (c) 2017-2018 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -24,26 +24,13 @@
#ifndef LIBUNICODE_H
#define LIBUNICODE_H
-#include
-
-#define LRE_BOOL int /* for documentation purposes */
+#include
/* 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 {
@@ -58,6 +45,7 @@ typedef enum {
CR_OP_UNION,
CR_OP_INTER,
CR_OP_XOR,
+ CR_OP_SUB,
} CharRangeOpEnum;
void cr_init(CharRange *cr, void *mem_opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size));
@@ -86,25 +74,28 @@ static inline int cr_add_interval(CharRange *cr, uint32_t c1, uint32_t c2)
return 0;
}
-int cr_union1(CharRange *cr, const uint32_t *b_pt, int b_len);
+int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,
+ const uint32_t *b_pt, int b_len, int op);
+int cr_op1(CharRange *cr, const uint32_t *b_pt, int b_len, int op);
static inline int cr_union_interval(CharRange *cr, uint32_t c1, uint32_t c2)
{
uint32_t b_pt[2];
b_pt[0] = c1;
b_pt[1] = c2 + 1;
- return cr_union1(cr, b_pt, 2);
+ return cr_op1(cr, b_pt, 2, CR_OP_UNION);
}
-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
+int cr_regexp_canonicalize(CharRange *cr, int is_unicode);
-LRE_BOOL lre_is_id_start(uint32_t c);
-LRE_BOOL lre_is_id_continue(uint32_t c);
+typedef enum {
+ UNICODE_NFC,
+ UNICODE_NFD,
+ UNICODE_NFKC,
+ UNICODE_NFKD,
+} UnicodeNormalizationEnum;
int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
UnicodeNormalizationEnum n_type,
@@ -112,13 +103,84 @@ int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
/* Unicode character range functions */
-int unicode_script(CharRange *cr,
- const char *script_name, LRE_BOOL is_ext);
+int unicode_script(CharRange *cr, const char *script_name, int is_ext);
int unicode_general_category(CharRange *cr, const char *gc_name);
int unicode_prop(CharRange *cr, const char *prop_name);
-#endif /* CONFIG_ALL_UNICODE */
+typedef void UnicodeSequencePropCB(void *opaque, const uint32_t *buf, int len);
+int unicode_sequence_prop(const char *prop_name, UnicodeSequencePropCB *cb, void *opaque,
+ CharRange *cr);
+
+int lre_case_conv(uint32_t *res, uint32_t c, int conv_type);
+int lre_canonicalize(uint32_t c, int is_unicode);
+
+/* Code point type categories */
+enum {
+ UNICODE_C_SPACE = (1 << 0),
+ UNICODE_C_DIGIT = (1 << 1),
+ UNICODE_C_UPPER = (1 << 2),
+ UNICODE_C_LOWER = (1 << 3),
+ UNICODE_C_UNDER = (1 << 4),
+ UNICODE_C_DOLLAR = (1 << 5),
+ UNICODE_C_XDIGIT = (1 << 6),
+};
+extern uint8_t const lre_ctype_bits[256];
+
+/* zero or non-zero return value */
+int lre_is_cased(uint32_t c);
+int lre_is_case_ignorable(uint32_t c);
+int lre_is_id_start(uint32_t c);
+int lre_is_id_continue(uint32_t c);
+
+static inline int lre_is_space_byte(uint8_t c) {
+ return lre_ctype_bits[c] & UNICODE_C_SPACE;
+}
+
+static inline int lre_is_id_start_byte(uint8_t c) {
+ return lre_ctype_bits[c] & (UNICODE_C_UPPER | UNICODE_C_LOWER |
+ UNICODE_C_UNDER | UNICODE_C_DOLLAR);
+}
+
+static inline int lre_is_id_continue_byte(uint8_t c) {
+ return lre_ctype_bits[c] & (UNICODE_C_UPPER | UNICODE_C_LOWER |
+ UNICODE_C_UNDER | UNICODE_C_DOLLAR |
+ UNICODE_C_DIGIT);
+}
+
+int lre_is_space_non_ascii(uint32_t c);
+
+static inline int lre_is_space(uint32_t c) {
+ if (c < 256)
+ return lre_is_space_byte(c);
+ else
+ return lre_is_space_non_ascii(c);
+}
+
+static inline int lre_js_is_ident_first(uint32_t c) {
+ if (c < 128) {
+ return lre_is_id_start_byte(c);
+ } else {
+#ifdef CONFIG_ALL_UNICODE
+ return lre_is_id_start(c);
+#else
+ return !lre_is_space_non_ascii(c);
+#endif
+ }
+}
-#undef LRE_BOOL
+static inline int lre_js_is_ident_next(uint32_t c) {
+ if (c < 128) {
+ return lre_is_id_continue_byte(c);
+ } else {
+ /* ZWNJ and ZWJ are accepted in identifiers */
+ if (c >= 0x200C && c <= 0x200D)
+ return TRUE;
+#ifdef CONFIG_ALL_UNICODE
+ return lre_is_id_continue(c);
+#else
+ return !lre_is_space_non_ascii(c);
+#endif
+ }
+}
#endif /* LIBUNICODE_H */
diff --git a/quickjs/list.h b/quickjs/list.h
index 0a1bc5a493..809831115f 100644
--- a/quickjs/list.h
+++ b/quickjs/list.h
@@ -1,6 +1,6 @@
/*
* Linux klist like system
- *
+ *
* Copyright (c) 2016-2017 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -36,8 +36,7 @@ struct list_head {
#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)))
+#define list_entry(el, type, member) container_of(el, type, member)
static inline void init_list_head(struct list_head *head)
{
@@ -46,7 +45,7 @@ static inline void init_list_head(struct list_head *head)
}
/* insert 'el' between 'prev' and 'next' */
-static inline void __list_add(struct list_head *el,
+static inline void __list_add(struct list_head *el,
struct list_head *prev, struct list_head *next)
{
prev->next = el;
diff --git a/quickjs/quickjs-atom.h b/quickjs/quickjs-atom.h
index 81c65b99d8..425c2e909a 100644
--- a/quickjs/quickjs-atom.h
+++ b/quickjs/quickjs-atom.h
@@ -1,6 +1,6 @@
/*
* QuickJS atom definitions
- *
+ *
* Copyright (c) 2017-2018 Fabrice Bellard
* Copyright (c) 2017-2018 Charlie Gordon
*
@@ -81,7 +81,9 @@ DEF(empty_string, "")
DEF(length, "length")
DEF(fileName, "fileName")
DEF(lineNumber, "lineNumber")
+DEF(columnNumber, "columnNumber")
DEF(message, "message")
+DEF(cause, "cause")
DEF(errors, "errors")
DEF(stack, "stack")
DEF(name, "name")
@@ -166,22 +168,26 @@ DEF(revoke, "revoke")
DEF(async, "async")
DEF(exec, "exec")
DEF(groups, "groups")
+DEF(indices, "indices")
DEF(status, "status")
DEF(reason, "reason")
DEF(globalThis, "globalThis")
DEF(bigint, "bigint")
-#ifdef CONFIG_BIGNUM
-DEF(bigfloat, "bigfloat")
-DEF(bigdecimal, "bigdecimal")
-DEF(roundingMode, "roundingMode")
-DEF(maximumSignificantDigits, "maximumSignificantDigits")
-DEF(maximumFractionDigits, "maximumFractionDigits")
-#endif
-#ifdef CONFIG_ATOMICS
+DEF(minus_zero, "-0")
+DEF(Infinity, "Infinity")
+DEF(minus_Infinity, "-Infinity")
+DEF(NaN, "NaN")
+DEF(hasIndices, "hasIndices")
+DEF(ignoreCase, "ignoreCase")
+DEF(multiline, "multiline")
+DEF(dotAll, "dotAll")
+DEF(sticky, "sticky")
+DEF(unicodeSets, "unicodeSets")
+/* the following 3 atoms are only used with CONFIG_ATOMICS */
DEF(not_equal, "not-equal")
DEF(timed_out, "timed-out")
DEF(ok, "ok")
-#endif
+/* */
DEF(toJSON, "toJSON")
/* class names */
DEF(Object, "Object")
@@ -202,7 +208,7 @@ DEF(RegExp, "RegExp")
DEF(ArrayBuffer, "ArrayBuffer")
DEF(SharedArrayBuffer, "SharedArrayBuffer")
/* must keep same order as class IDs for typed arrays */
-DEF(Uint8ClampedArray, "Uint8ClampedArray")
+DEF(Uint8ClampedArray, "Uint8ClampedArray")
DEF(Int8Array, "Int8Array")
DEF(Uint8Array, "Uint8Array")
DEF(Int16Array, "Int16Array")
@@ -211,17 +217,13 @@ DEF(Int32Array, "Int32Array")
DEF(Uint32Array, "Uint32Array")
DEF(BigInt64Array, "BigInt64Array")
DEF(BigUint64Array, "BigUint64Array")
+DEF(Float16Array, "Float16Array")
DEF(Float32Array, "Float32Array")
DEF(Float64Array, "Float64Array")
DEF(DataView, "DataView")
DEF(BigInt, "BigInt")
-#ifdef CONFIG_BIGNUM
-DEF(BigFloat, "BigFloat")
-DEF(BigFloatEnv, "BigFloatEnv")
-DEF(BigDecimal, "BigDecimal")
-DEF(OperatorSet, "OperatorSet")
-DEF(Operators, "Operators")
-#endif
+DEF(WeakRef, "WeakRef")
+DEF(FinalizationRegistry, "FinalizationRegistry")
DEF(Map, "Map")
DEF(Set, "Set") /* Map + 1 */
DEF(WeakMap, "WeakMap") /* Map + 2 */
@@ -264,8 +266,5 @@ 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/quickjs/quickjs-libc.c b/quickjs/quickjs-libc.c
index f0c61be66f..5af9f2a922 100644
--- a/quickjs/quickjs-libc.c
+++ b/quickjs/quickjs-libc.c
@@ -1,6 +1,6 @@
/*
* QuickJS C library
- *
+ *
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
@@ -22,26 +22,38 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+#define _CRT_SECURE_NO_WARNINGS
+#define _CRT_NONSTDC_NO_DEPRECATE
#include
#include
#include
#include
#include
#include
-#include
#include
#include
-#include
#include
#include
#include
#include
-#include
#if defined(_WIN32)
#include
#include
-#include
+#include
+#include
+#include
+#include
+#include
+#include "win/dirent.h"
+#ifndef PATH_MAX
+#define PATH_MAX MAX_PATH
+#endif
+#define popen _popen
+#define pclose _pclose
#else
+#include
+#include
+#include
#include
#include
#include
@@ -55,13 +67,6 @@ typedef sig_t sighandler_t;
#endif
#endif /* __APPLE__ */
-#if defined(__FreeBSD__)
-typedef sig_t sighandler_t;
-__BEGIN_DECLS
-extern char **environ;
-__END_DECLS
-#endif /* __FreeBSD__ */
-
#endif
#if !defined(_WIN32)
@@ -78,6 +83,10 @@ __END_DECLS
#include "list.h"
#include "quickjs-libc.h"
+#if !defined(PATH_MAX)
+#define PATH_MAX 4096
+#endif
+
/* TODO:
- add socket calls
*/
@@ -96,7 +105,7 @@ typedef struct {
typedef struct {
struct list_head link;
- BOOL has_object;
+ int timer_id;
int64_t timeout;
JSValue func;
} JSOSTimer;
@@ -110,14 +119,22 @@ typedef struct {
size_t sab_tab_len;
} JSWorkerMessage;
+typedef struct JSWaker {
+#ifdef _WIN32
+ HANDLE handle;
+#else
+ int read_fd;
+ int write_fd;
+#endif
+} JSWaker;
+
typedef struct {
int ref_count;
#ifdef USE_WORKER
pthread_mutex_t mutex;
#endif
struct list_head msg_queue; /* list of JSWorkerMessage.link */
- int read_fd;
- int write_fd;
+ JSWaker waker;
} JSWorkerMessagePipe;
typedef struct {
@@ -126,12 +143,20 @@ typedef struct {
JSValue on_message_func;
} JSWorkerMessageHandler;
+typedef struct {
+ struct list_head link;
+ JSValue promise;
+ JSValue reason;
+} JSRejectedPromiseEntry;
+
typedef struct JSThreadState {
struct list_head os_rw_handlers; /* list of JSOSRWHandler.link */
struct list_head os_signal_handlers; /* list JSOSSignalHandler.link */
struct list_head os_timers; /* list of JSOSTimer.link */
struct list_head port_list; /* list of JSWorkerMessageHandler.link */
+ struct list_head rejected_promise_list; /* list of JSRejectedPromiseEntry.link */
int eval_script_recurse; /* only used in the main thread */
+ int next_timer_id; /* for setTimeout() */
/* not used in the main thread */
JSWorkerMessagePipe *recv_pipe, *send_pipe;
} JSThreadState;
@@ -149,6 +174,7 @@ static BOOL my_isdigit(int c)
return (c >= '0' && c <= '9');
}
+/* XXX: use 'o' and 'O' for object using JS_PrintValue() ? */
static JSValue js_printf_internal(JSContext *ctx,
int argc, JSValueConst *argv, FILE *fp)
{
@@ -156,7 +182,7 @@ static JSValue js_printf_internal(JSContext *ctx,
uint8_t cbuf[UTF8_CHAR_LEN_MAX+1];
JSValue res;
DynBuf dbuf;
- const char *fmt_str;
+ const char *fmt_str = NULL;
const uint8_t *fmt, *fmt_end;
const uint8_t *p;
char *q;
@@ -187,7 +213,7 @@ static JSValue js_printf_internal(JSContext *ctx,
break;
q = fmtbuf;
*q++ = *fmt++; /* copy '%' */
-
+
/* flags */
for(;;) {
c = *fmt;
@@ -241,14 +267,14 @@ static JSValue js_printf_internal(JSContext *ctx,
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)
@@ -257,7 +283,7 @@ static JSValue js_printf_internal(JSContext *ctx,
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);
+ int32_arg = unicode_from_utf8((const uint8_t *)string_arg, UTF8_CHAR_LEN_MAX, &p);
JS_FreeCString(ctx, string_arg);
} else {
if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
@@ -270,7 +296,7 @@ static JSValue js_printf_internal(JSContext *ctx,
len = unicode_to_utf8(cbuf, int32_arg);
dbuf_put(&dbuf, cbuf, len);
break;
-
+
case 'd':
case 'i':
case 'o':
@@ -315,7 +341,7 @@ static JSValue js_printf_internal(JSContext *ctx,
dbuf_printf_fun(&dbuf, fmtbuf, string_arg);
JS_FreeCString(ctx, string_arg);
break;
-
+
case 'e':
case 'f':
case 'g':
@@ -330,11 +356,11 @@ static JSValue js_printf_internal(JSContext *ctx,
goto fail;
dbuf_printf_fun(&dbuf, fmtbuf, double_arg);
break;
-
+
case '%':
dbuf_putc(&dbuf, '%');
break;
-
+
default:
/* XXX: should support an extension mechanism */
invalid:
@@ -361,6 +387,7 @@ static JSValue js_printf_internal(JSContext *ctx,
return res;
fail:
+ JS_FreeCString(ctx, fmt_str);
dbuf_free(&dbuf);
return JS_EXCEPTION;
}
@@ -371,7 +398,7 @@ uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename)
uint8_t *buf;
size_t buf_len;
long lret;
-
+
f = fopen(filename, "rb");
if (!f)
return NULL;
@@ -418,7 +445,7 @@ static JSValue js_loadScript(JSContext *ctx, JSValueConst this_val,
const char *filename;
JSValue ret;
size_t buf_len;
-
+
filename = JS_ToCString(ctx, argv[0]);
if (!filename)
return JS_EXCEPTION;
@@ -443,7 +470,7 @@ static JSValue js_std_loadFile(JSContext *ctx, JSValueConst this_val,
const char *filename;
JSValue ret;
size_t buf_len;
-
+
filename = JS_ToCString(ctx, argv[0]);
if (!filename)
return JS_EXCEPTION;
@@ -475,7 +502,7 @@ static JSModuleDef *js_module_loader_so(JSContext *ctx,
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 */
@@ -487,7 +514,7 @@ static JSModuleDef *js_module_loader_so(JSContext *ctx,
} else {
filename = (char *)module_name;
}
-
+
/* C module */
hd = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
if (filename != module_name)
@@ -526,7 +553,7 @@ int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
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);
@@ -557,7 +584,7 @@ int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
pstrcpy(buf, sizeof(buf), module_name);
}
JS_FreeCString(ctx, module_name);
-
+
meta_obj = JS_GetImportMeta(ctx, m);
if (JS_IsException(meta_obj))
return -1;
@@ -571,36 +598,138 @@ int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
return 0;
}
-JSModuleDef *js_module_loader(JSContext *ctx,
- const char *module_name, void *opaque)
+static int json_module_init(JSContext *ctx, JSModuleDef *m)
+{
+ JSValue val;
+ val = JS_GetModulePrivateValue(ctx, m);
+ JS_SetModuleExport(ctx, m, "default", val);
+ return 0;
+}
+
+static JSModuleDef *create_json_module(JSContext *ctx, const char *module_name, JSValue val)
{
JSModuleDef *m;
+ m = JS_NewCModule(ctx, module_name, json_module_init);
+ if (!m) {
+ JS_FreeValue(ctx, val);
+ return NULL;
+ }
+ /* only export the "default" symbol which will contain the JSON object */
+ JS_AddModuleExport(ctx, m, "default");
+ JS_SetModulePrivateValue(ctx, m, val);
+ return m;
+}
+
+/* in order to conform with the specification, only the keys should be
+ tested and not the associated values. */
+int js_module_check_attributes(JSContext *ctx, void *opaque,
+ JSValueConst attributes)
+{
+ JSPropertyEnum *tab;
+ uint32_t i, len;
+ int ret;
+ const char *cstr;
+ size_t cstr_len;
+
+ if (JS_GetOwnPropertyNames(ctx, &tab, &len, attributes, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK))
+ return -1;
+ ret = 0;
+ for(i = 0; i < len; i++) {
+ cstr = JS_AtomToCStringLen(ctx, &cstr_len, tab[i].atom);
+ if (!cstr) {
+ ret = -1;
+ break;
+ }
+ if (!(cstr_len == 4 && !memcmp(cstr, "type", cstr_len))) {
+ JS_ThrowTypeError(ctx, "import attribute '%s' is not supported", cstr);
+ ret = -1;
+ }
+ JS_FreeCString(ctx, cstr);
+ if (ret)
+ break;
+ }
+ JS_FreePropertyEnum(ctx, tab, len);
+ return ret;
+}
+/* return > 0 if the attributes indicate a JSON module */
+int js_module_test_json(JSContext *ctx, JSValueConst attributes)
+{
+ JSValue str;
+ const char *cstr;
+ size_t len;
+ BOOL res;
+
+ if (JS_IsUndefined(attributes))
+ return FALSE;
+ str = JS_GetPropertyStr(ctx, attributes, "type");
+ if (!JS_IsString(str))
+ return FALSE;
+ cstr = JS_ToCStringLen(ctx, &len, str);
+ JS_FreeValue(ctx, str);
+ if (!cstr)
+ return FALSE;
+ /* XXX: raise an error if unknown type ? */
+ if (len == 4 && !memcmp(cstr, "json", len)) {
+ res = 1;
+ } else if (len == 5 && !memcmp(cstr, "json5", len)) {
+ res = 2;
+ } else {
+ res = 0;
+ }
+ JS_FreeCString(ctx, cstr);
+ return res;
+}
+
+JSModuleDef *js_module_loader(JSContext *ctx,
+ const char *module_name, void *opaque,
+ JSValueConst attributes)
+{
+ JSModuleDef *m;
+ int res;
+
if (has_suffix(module_name, ".so")) {
m = js_module_loader_so(ctx, module_name);
} else {
size_t buf_len;
uint8_t *buf;
- 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);
+ res = js_module_test_json(ctx, attributes);
+ if (has_suffix(module_name, ".json") || res > 0) {
+ /* compile as JSON or JSON5 depending on "type" */
+ JSValue val;
+ int flags;
+ if (res == 2)
+ flags = JS_PARSE_JSON_EXT;
+ else
+ flags = 0;
+ val = JS_ParseJSON2(ctx, (char *)buf, buf_len, module_name, flags);
+ js_free(ctx, buf);
+ if (JS_IsException(val))
+ return NULL;
+ m = create_json_module(ctx, module_name, val);
+ if (!m)
+ return NULL;
+ } else {
+ JSValue func_val;
+ /* compile the module */
+ func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
+ JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
+ js_free(ctx, buf);
+ if (JS_IsException(func_val))
+ return NULL;
+ /* XXX: could propagate the exception */
+ js_module_set_import_meta(ctx, func_val, TRUE, FALSE);
+ /* the module is already referenced, so we must free it */
+ m = JS_VALUE_GET_PTR(func_val);
+ JS_FreeValue(ctx, func_val);
+ }
}
return m;
}
@@ -758,13 +887,17 @@ static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val,
JSValue ret;
JSValueConst options_obj;
BOOL backtrace_barrier = FALSE;
+ BOOL is_async = FALSE;
int flags;
-
+
if (argc >= 2) {
options_obj = argv[1];
if (get_bool_option(ctx, &backtrace_barrier, options_obj,
"backtrace_barrier"))
return JS_EXCEPTION;
+ if (get_bool_option(ctx, &is_async, options_obj,
+ "async"))
+ return JS_EXCEPTION;
}
str = JS_ToCStringLen(ctx, &len, argv[0]);
@@ -774,9 +907,11 @@ static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val,
/* install the interrupt handler */
JS_SetInterruptHandler(JS_GetRuntime(ctx), interrupt_handler, NULL);
}
- flags = JS_EVAL_TYPE_GLOBAL;
+ flags = JS_EVAL_TYPE_GLOBAL;
if (backtrace_barrier)
flags |= JS_EVAL_FLAG_BACKTRACE_BARRIER;
+ if (is_async)
+ flags |= JS_EVAL_FLAG_ASYNC;
ret = JS_Eval(ctx, str, len, "", flags);
JS_FreeCString(ctx, str);
if (!ts->recv_pipe && --ts->eval_script_recurse == 0) {
@@ -786,7 +921,7 @@ static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val,
/* 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);
+ JS_SetUncatchableException(ctx, FALSE);
}
return ret;
}
@@ -878,7 +1013,7 @@ static JSValue js_std_open(JSContext *ctx, JSValueConst this_val,
const char *filename, *mode = NULL;
FILE *f;
int err;
-
+
filename = JS_ToCString(ctx, argv[0]);
if (!filename)
goto fail;
@@ -914,7 +1049,7 @@ static JSValue js_std_popen(JSContext *ctx, JSValueConst this_val,
const char *filename, *mode = NULL;
FILE *f;
int err;
-
+
filename = JS_ToCString(ctx, argv[0]);
if (!filename)
goto fail;
@@ -1028,7 +1163,7 @@ static JSValue js_std_file_puts(JSContext *ctx, JSValueConst this_val,
if (!f)
return JS_EXCEPTION;
}
-
+
for(i = 0; i < argc; i++) {
str = JS_ToCStringLen(ctx, &len, argv[i]);
if (!str)
@@ -1065,6 +1200,19 @@ static JSValue js_std_file_printf(JSContext *ctx, JSValueConst this_val,
return js_printf_internal(ctx, argc, argv, f);
}
+static void js_print_value_write(void *opaque, const char *buf, size_t len)
+{
+ FILE *fo = opaque;
+ fwrite(buf, 1, len, fo);
+}
+
+static JSValue js_std_file_printObject(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JS_PrintValue(ctx, js_print_value_write, stdout, argv[0], NULL);
+ return JS_UNDEFINED;
+}
+
static JSValue js_std_file_flush(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
@@ -1082,7 +1230,7 @@ static JSValue js_std_file_tell(JSContext *ctx, JSValueConst this_val,
int64_t pos;
if (!f)
return JS_EXCEPTION;
-#if defined(__linux__)
+#if defined(__linux__) || defined(__GLIBC__)
pos = ftello(f);
#else
pos = ftell(f);
@@ -1105,7 +1253,7 @@ static JSValue js_std_file_seek(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
if (JS_ToInt32(ctx, &whence, argv[1]))
return JS_EXCEPTION;
-#if defined(__linux__)
+#if defined(__linux__) || defined(__GLIBC__)
ret = fseeko(f, pos, whence);
#else
ret = fseek(f, pos, whence);
@@ -1159,7 +1307,7 @@ static JSValue js_std_file_read_write(JSContext *ctx, JSValueConst 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]))
@@ -1186,7 +1334,7 @@ static JSValue js_std_file_getline(JSContext *ctx, JSValueConst this_val,
int c;
DynBuf dbuf;
JSValue obj;
-
+
if (!f)
return JS_EXCEPTION;
@@ -1225,7 +1373,7 @@ static JSValue js_std_file_readAsString(JSContext *ctx, JSValueConst this_val,
uint64_t max_size64;
size_t max_size;
JSValueConst max_size_val;
-
+
if (!f)
return JS_EXCEPTION;
@@ -1281,7 +1429,7 @@ static JSValue js_std_file_putByte(JSContext *ctx, JSValueConst this_val,
/* urlGet */
-#define URL_GET_PROGRAM "curl -s -i"
+#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,
@@ -1289,7 +1437,7 @@ static int http_get_header_line(FILE *f, char *buf, size_t buf_size,
{
int c;
char *p;
-
+
p = buf;
for(;;) {
c = fgetc(f);
@@ -1325,21 +1473,21 @@ static JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val,
DynBuf cmd_buf;
DynBuf data_buf_s, *data_buf = &data_buf_s;
DynBuf header_buf_s, *header_buf = &header_buf_s;
- char *buf;
+ char *buf;
size_t i, len;
- int c, status;
+ int status;
JSValue response = JS_UNDEFINED, ret_obj;
JSValueConst options_obj;
FILE *f;
BOOL binary_flag, full_flag;
-
+
url = JS_ToCString(ctx, argv[0]);
if (!url)
return JS_EXCEPTION;
-
+
binary_flag = FALSE;
full_flag = FALSE;
-
+
if (argc >= 2) {
options_obj = argv[1];
@@ -1352,18 +1500,27 @@ static JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val,
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_printf(&cmd_buf, "%s '", URL_GET_PROGRAM);
+ for(i = 0; url[i] != '\0'; i++) {
+ unsigned char c = url[i];
+ switch (c) {
+ case '\'':
+ /* shell single quoted string does not support \' */
+ dbuf_putstr(&cmd_buf, "'\\''");
+ break;
+ case '[': case ']': case '{': case '}': case '\\':
+ /* prevent interpretation by curl as range or set specification */
dbuf_putc(&cmd_buf, '\\');
- dbuf_putc(&cmd_buf, c);
+ /* FALLTHROUGH */
+ default:
+ dbuf_putc(&cmd_buf, c);
+ break;
+ }
}
JS_FreeCString(ctx, url);
- dbuf_putstr(&cmd_buf, "''");
+ dbuf_putstr(&cmd_buf, "'");
dbuf_putc(&cmd_buf, '\0');
if (dbuf_error(&cmd_buf)) {
dbuf_free(&cmd_buf);
@@ -1378,7 +1535,7 @@ static JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val,
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;
@@ -1392,7 +1549,7 @@ static JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val,
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) {
@@ -1468,7 +1625,7 @@ static JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val,
static JSClassDef js_std_file_class = {
"FILE",
.finalizer = js_std_file_finalizer,
-};
+};
static const JSCFunctionListEntry js_std_error_props[] = {
/* various errno values */
@@ -1500,7 +1657,7 @@ static const JSCFunctionListEntry js_std_funcs[] = {
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 ),
@@ -1513,8 +1670,9 @@ static const JSCFunctionListEntry js_std_funcs[] = {
JS_PROP_INT32_DEF("SEEK_CUR", SEEK_CUR, JS_PROP_CONFIGURABLE ),
JS_PROP_INT32_DEF("SEEK_END", SEEK_END, JS_PROP_CONFIGURABLE ),
JS_OBJECT_DEF("Error", js_std_error_props, countof(js_std_error_props), JS_PROP_CONFIGURABLE),
+ JS_CFUNC_DEF("__printObject", 1, js_std_file_printObject ),
};
-
+
static const JSCFunctionListEntry js_std_file_proto_funcs[] = {
JS_CFUNC_DEF("close", 0, js_std_file_close ),
JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 1 ),
@@ -1539,7 +1697,7 @@ static const JSCFunctionListEntry js_std_file_proto_funcs[] = {
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);
@@ -1620,7 +1778,7 @@ static JSValue js_os_seek(JSContext *ctx, JSValueConst this_val,
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]);
@@ -1638,14 +1796,14 @@ static JSValue js_os_seek(JSContext *ctx, JSValueConst this_val,
}
static JSValue js_os_read_write(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
+ 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]))
@@ -1670,7 +1828,7 @@ static JSValue js_os_isatty(JSContext *ctx, JSValueConst this_val,
int fd;
if (JS_ToInt32(ctx, &fd, argv[0]))
return JS_EXCEPTION;
- return JS_NewBool(ctx, (isatty(fd) != 0));
+ return JS_NewBool(ctx, isatty(fd));
}
#if defined(_WIN32)
@@ -1685,7 +1843,7 @@ static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val,
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);
@@ -1724,7 +1882,7 @@ static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val,
int fd;
struct winsize ws;
JSValue obj;
-
+
if (JS_ToInt32(ctx, &fd, argv[0]))
return JS_EXCEPTION;
if (ioctl(fd, TIOCGWINSZ, &ws) == 0 &&
@@ -1753,10 +1911,10 @@ static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val,
{
struct termios tty;
int fd;
-
+
if (JS_ToInt32(ctx, &fd, argv[0]))
return JS_EXCEPTION;
-
+
memset(&tty, 0, sizeof(tty));
tcgetattr(fd, &tty);
oldtty = tty;
@@ -1779,11 +1937,11 @@ static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val,
#endif /* !_WIN32 */
static JSValue js_os_remove(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
+ int argc, JSValueConst *argv)
{
const char *filename;
int ret;
-
+
filename = JS_ToCString(ctx, argv[0]);
if (!filename)
return JS_EXCEPTION;
@@ -1809,7 +1967,7 @@ static JSValue js_os_rename(JSContext *ctx, JSValueConst this_val,
{
const char *oldpath, *newpath;
int ret;
-
+
oldpath = JS_ToCString(ctx, argv[0]);
if (!oldpath)
return JS_EXCEPTION;
@@ -1861,7 +2019,7 @@ static JSValue js_os_setReadHandler(JSContext *ctx, JSValueConst this_val,
JSOSRWHandler *rh;
int fd;
JSValueConst func;
-
+
if (JS_ToInt32(ctx, &fd, argv[0]))
return JS_EXCEPTION;
func = argv[1];
@@ -1935,7 +2093,7 @@ static JSValue js_os_signal(JSContext *ctx, JSValueConst this_val,
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)
@@ -1977,6 +2135,13 @@ static int64_t get_time_ms(void)
clock_gettime(CLOCK_MONOTONIC, &ts);
return (uint64_t)ts.tv_sec * 1000 + (ts.tv_nsec / 1000000);
}
+
+static int64_t get_time_ns(void)
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (uint64_t)ts.tv_sec * 1000000000 + ts.tv_nsec;
+}
#else
/* more portable, but does not work if the date is updated */
static int64_t get_time_ms(void)
@@ -1985,43 +2150,28 @@ static int64_t get_time_ms(void)
gettimeofday(&tv, NULL);
return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
}
+
+static int64_t get_time_ns(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (int64_t)tv.tv_sec * 1000000000 + (tv.tv_usec * 1000);
+}
#endif
-static void unlink_timer(JSRuntime *rt, JSOSTimer *th)
+static JSValue js_os_now(JSContext *ctx, JSValue this_val,
+ int argc, JSValue *argv)
{
- if (th->link.prev) {
- list_del(&th->link);
- th->link.prev = th->link.next = NULL;
- }
+ return JS_NewFloat64(ctx, (double)get_time_ns() / 1e6);
}
static void free_timer(JSRuntime *rt, JSOSTimer *th)
{
+ list_del(&th->link);
JS_FreeValueRT(rt, th->func);
js_free_rt(rt, th);
}
-static 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)
{
@@ -2030,44 +2180,87 @@ static JSValue js_os_setTimeout(JSContext *ctx, JSValueConst this_val,
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);
+ if (!th)
return JS_EXCEPTION;
- }
- th->has_object = TRUE;
+ th->timer_id = ts->next_timer_id;
+ if (ts->next_timer_id == INT32_MAX)
+ ts->next_timer_id = 1;
+ else
+ ts->next_timer_id++;
th->timeout = get_time_ms() + delay;
th->func = JS_DupValue(ctx, func);
list_add_tail(&th->link, &ts->os_timers);
- JS_SetOpaque(obj, th);
- return obj;
+ return JS_NewInt32(ctx, th->timer_id);
+}
+
+static JSOSTimer *find_timer_by_id(JSThreadState *ts, int timer_id)
+{
+ struct list_head *el;
+ if (timer_id <= 0)
+ return NULL;
+ list_for_each(el, &ts->os_timers) {
+ JSOSTimer *th = list_entry(el, JSOSTimer, link);
+ if (th->timer_id == timer_id)
+ return th;
+ }
+ return NULL;
}
static JSValue js_os_clearTimeout(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
- JSOSTimer *th = JS_GetOpaque2(ctx, argv[0], js_os_timer_class_id);
- if (!th)
+ JSRuntime *rt = JS_GetRuntime(ctx);
+ JSThreadState *ts = JS_GetRuntimeOpaque(rt);
+ JSOSTimer *th;
+ int timer_id;
+
+ if (JS_ToInt32(ctx, &timer_id, argv[0]))
return JS_EXCEPTION;
- unlink_timer(JS_GetRuntime(ctx), th);
+ th = find_timer_by_id(ts, timer_id);
+ if (!th)
+ return JS_UNDEFINED;
+ free_timer(rt, th);
return JS_UNDEFINED;
}
-static JSClassDef js_os_timer_class = {
- "OSTimer",
- .finalizer = js_os_timer_finalizer,
- .gc_mark = js_os_timer_mark,
-};
+/* return a promise */
+static JSValue js_os_sleepAsync(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSRuntime *rt = JS_GetRuntime(ctx);
+ JSThreadState *ts = JS_GetRuntimeOpaque(rt);
+ int64_t delay;
+ JSOSTimer *th;
+ JSValue promise, resolving_funcs[2];
+
+ if (JS_ToInt64(ctx, &delay, argv[0]))
+ return JS_EXCEPTION;
+ promise = JS_NewPromiseCapability(ctx, resolving_funcs);
+ if (JS_IsException(promise))
+ return JS_EXCEPTION;
+
+ th = js_mallocz(ctx, sizeof(*th));
+ if (!th) {
+ JS_FreeValue(ctx, promise);
+ JS_FreeValue(ctx, resolving_funcs[0]);
+ JS_FreeValue(ctx, resolving_funcs[1]);
+ return JS_EXCEPTION;
+ }
+ th->timer_id = -1;
+ th->timeout = get_time_ms() + delay;
+ th->func = JS_DupValue(ctx, resolving_funcs[0]);
+ list_add_tail(&th->link, &ts->os_timers);
+ JS_FreeValue(ctx, resolving_funcs[0]);
+ JS_FreeValue(ctx, resolving_funcs[1]);
+ return promise;
+}
static void call_handler(JSContext *ctx, JSValueConst func)
{
@@ -2082,84 +2275,81 @@ static void call_handler(JSContext *ctx, JSValueConst func)
JS_FreeValue(ctx, ret);
}
-#if defined(_WIN32)
+#ifdef USE_WORKER
-static int js_os_poll(JSContext *ctx)
+#ifdef _WIN32
+
+static int js_waker_init(JSWaker *w)
{
- 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 */
+ w->handle = CreateEvent(NULL, TRUE, FALSE, NULL);
+ return w->handle ? 0 : -1;
+}
- 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;
- }
+static void js_waker_signal(JSWaker *w)
+{
+ SetEvent(w->handle);
+}
- 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;
+static void js_waker_clear(JSWaker *w)
+{
+ ResetEvent(w->handle);
+}
+
+static void js_waker_close(JSWaker *w)
+{
+ CloseHandle(w->handle);
+ w->handle = INVALID_HANDLE_VALUE;
+}
+
+#else // !_WIN32
+
+static int js_waker_init(JSWaker *w)
+{
+ int fds[2];
+
+ if (pipe(fds) < 0)
+ return -1;
+ w->read_fd = fds[0];
+ w->write_fd = fds[1];
+ return 0;
+}
+
+static void js_waker_signal(JSWaker *w)
+{
+ int ret;
+
+ for(;;) {
+ ret = write(w->write_fd, "", 1);
+ if (ret == 1)
+ break;
+ if (ret < 0 && (errno != EAGAIN || errno != EINTR))
break;
- }
}
+}
- 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);
+static void js_waker_clear(JSWaker *w)
+{
+ uint8_t buf[16];
+ int ret;
+
+ for(;;) {
+ ret = read(w->read_fd, buf, sizeof(buf));
+ if (ret >= 0)
+ break;
+ if (errno != EAGAIN && errno != EINTR)
+ break;
}
- return 0;
}
-#else
-#ifdef USE_WORKER
+static void js_waker_close(JSWaker *w)
+{
+ close(w->read_fd);
+ close(w->write_fd);
+ w->read_fd = -1;
+ w->write_fd = -1;
+}
+
+#endif // _WIN32
static void js_free_message(JSWorkerMessage *msg);
@@ -2172,7 +2362,7 @@ static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
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;
@@ -2181,17 +2371,8 @@ static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
/* 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;
- }
- }
+ if (list_empty(&ps->msg_queue))
+ js_waker_clear(&ps->waker);
pthread_mutex_unlock(&ps->mutex);
@@ -2199,7 +2380,7 @@ static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
JS_READ_OBJ_SAB | JS_READ_OBJ_REFERENCE);
js_free_message(msg);
-
+
if (JS_IsException(data_obj))
goto fail;
obj = JS_NewObject(ctx);
@@ -2234,7 +2415,104 @@ static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
{
return 0;
}
-#endif
+#endif /* !USE_WORKER */
+
+#if defined(_WIN32)
+
+static int js_os_poll(JSContext *ctx)
+{
+ JSRuntime *rt = JS_GetRuntime(ctx);
+ JSThreadState *ts = JS_GetRuntimeOpaque(rt);
+ int min_delay, count;
+ int64_t cur_time, delay;
+ JSOSRWHandler *rh;
+ struct list_head *el;
+ HANDLE handles[MAXIMUM_WAIT_OBJECTS]; // 64
+
+ /* XXX: handle signals if useful */
+
+ if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers) &&
+ list_empty(&ts->port_list)) {
+ return -1; /* no more events */
+ }
+
+ if (!list_empty(&ts->os_timers)) {
+ cur_time = get_time_ms();
+ min_delay = 10000;
+ list_for_each(el, &ts->os_timers) {
+ JSOSTimer *th = list_entry(el, JSOSTimer, link);
+ delay = th->timeout - cur_time;
+ if (delay <= 0) {
+ JSValue func;
+ /* the timer expired */
+ func = th->func;
+ th->func = JS_UNDEFINED;
+ free_timer(rt, th);
+ call_handler(ctx, func);
+ JS_FreeValue(ctx, func);
+ return 0;
+ } else if (delay < min_delay) {
+ min_delay = delay;
+ }
+ }
+ } else {
+ min_delay = -1;
+ }
+
+ count = 0;
+ list_for_each(el, &ts->os_rw_handlers) {
+ rh = list_entry(el, JSOSRWHandler, link);
+ if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {
+ handles[count++] = (HANDLE)_get_osfhandle(rh->fd); // stdin
+ if (count == (int)countof(handles))
+ break;
+ }
+ }
+
+ list_for_each(el, &ts->port_list) {
+ JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
+ if (JS_IsNull(port->on_message_func))
+ continue;
+ handles[count++] = port->recv_pipe->waker.handle;
+ if (count == (int)countof(handles))
+ break;
+ }
+
+ if (count > 0) {
+ DWORD ret, timeout = INFINITE;
+ if (min_delay != -1)
+ timeout = min_delay;
+ ret = WaitForMultipleObjects(count, handles, FALSE, timeout);
+
+ if (ret < count) {
+ list_for_each(el, &ts->os_rw_handlers) {
+ rh = list_entry(el, JSOSRWHandler, link);
+ if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {
+ call_handler(ctx, rh->rw_func[0]);
+ /* must stop because the list may have been modified */
+ goto done;
+ }
+ }
+
+ list_for_each(el, &ts->port_list) {
+ JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
+ if (!JS_IsNull(port->on_message_func)) {
+ JSWorkerMessagePipe *ps = port->recv_pipe;
+ if (ps->waker.handle == handles[ret]) {
+ if (handle_posted_message(rt, ctx, port))
+ goto done;
+ }
+ }
+ }
+ }
+ } else {
+ Sleep(min_delay);
+ }
+ done:
+ return 0;
+}
+
+#else
static int js_os_poll(JSContext *ctx)
{
@@ -2252,7 +2530,7 @@ static int js_os_poll(JSContext *ctx)
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;
@@ -2267,7 +2545,7 @@ static int js_os_poll(JSContext *ctx)
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;
@@ -2279,9 +2557,7 @@ static int js_os_poll(JSContext *ctx)
/* the timer expired */
func = th->func;
th->func = JS_UNDEFINED;
- unlink_timer(rt, th);
- if (!th->has_object)
- free_timer(rt, th);
+ free_timer(rt, th);
call_handler(ctx, func);
JS_FreeValue(ctx, func);
return 0;
@@ -2295,7 +2571,7 @@ static int js_os_poll(JSContext *ctx)
} else {
tvp = NULL;
}
-
+
FD_ZERO(&rfds);
FD_ZERO(&wfds);
fd_max = -1;
@@ -2312,8 +2588,8 @@ static int js_os_poll(JSContext *ctx)
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);
+ fd_max = max_int(fd_max, ps->waker.read_fd);
+ FD_SET(ps->waker.read_fd, &rfds);
}
}
@@ -2339,14 +2615,14 @@ static int js_os_poll(JSContext *ctx)
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 (FD_ISSET(ps->waker.read_fd, &rfds)) {
if (handle_posted_message(rt, ctx, port))
goto done;
}
}
}
}
- done:
+ done:
return 0;
}
#endif /* !_WIN32 */
@@ -2381,7 +2657,7 @@ static JSValue js_os_getcwd(JSContext *ctx, JSValueConst this_val,
{
char buf[PATH_MAX];
int err;
-
+
if (!getcwd(buf, sizeof(buf))) {
buf[0] = '\0';
err = errno;
@@ -2410,7 +2686,7 @@ static JSValue js_os_mkdir(JSContext *ctx, JSValueConst this_val,
{
int mode, ret;
const char *path;
-
+
if (argc >= 2) {
if (JS_ToInt32(ctx, &mode, argv[1]))
return JS_EXCEPTION;
@@ -2440,7 +2716,7 @@ static JSValue js_os_readdir(JSContext *ctx, JSValueConst this_val,
JSValue obj;
int err;
uint32_t len;
-
+
path = JS_ToCString(ctx, argv[0]);
if (!path)
return JS_EXCEPTION;
@@ -2501,12 +2777,14 @@ static JSValue js_os_stat(JSContext *ctx, JSValueConst this_val,
else
res = stat(path, &st);
#endif
+ if (res < 0)
+ err = errno;
+ else
+ err = 0;
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;
@@ -2588,7 +2866,7 @@ static JSValue js_os_utimes(JSContext *ctx, JSValueConst this_val,
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]))
@@ -2617,11 +2895,11 @@ static JSValue js_os_utimes(JSContext *ctx, JSValueConst this_val,
/* sleep(delay_ms) */
static JSValue js_os_sleep(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
+ int argc, JSValueConst *argv)
{
int64_t delay;
int ret;
-
+
if (JS_ToInt64(ctx, &delay, argv[0]))
return JS_EXCEPTION;
if (delay < 0)
@@ -2681,11 +2959,11 @@ static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val,
#if !defined(_WIN32)
static JSValue js_os_symlink(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
+ int argc, JSValueConst *argv)
{
const char *target, *linkpath;
int err;
-
+
target = JS_ToCString(ctx, argv[0]);
if (!target)
return JS_EXCEPTION;
@@ -2708,7 +2986,7 @@ static JSValue js_os_readlink(JSContext *ctx, JSValueConst this_val,
char buf[PATH_MAX];
int err;
ssize_t res;
-
+
path = JS_ToCString(ctx, argv[0]);
if (!path)
return JS_EXCEPTION;
@@ -2732,7 +3010,7 @@ static char **build_envp(JSContext *ctx, JSValueConst obj)
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;
@@ -2769,9 +3047,7 @@ static char **build_envp(JSContext *ctx, JSValueConst obj)
JS_FreeCString(ctx, str);
}
done:
- for(i = 0; i < len; i++)
- JS_FreeAtom(ctx, tab[i].atom);
- js_free(ctx, tab);
+ JS_FreePropertyEnum(ctx, tab, len);
return envp;
fail:
if (envp) {
@@ -2790,7 +3066,7 @@ static int my_execvpe(const char *filename, char **argv, char **envp)
char buf[PATH_MAX];
size_t filename_len, path_len;
BOOL eacces_error;
-
+
filename_len = strlen(filename);
if (filename_len == 0) {
errno = ENOENT;
@@ -2798,7 +3074,7 @@ static int my_execvpe(const char *filename, char **argv, char **envp)
}
if (strchr(filename, '/'))
return execve(filename, argv, envp);
-
+
path = getenv("PATH");
if (!path)
path = (char *)"/bin:/usr/bin";
@@ -2820,7 +3096,7 @@ static int my_execvpe(const char *filename, char **argv, char **envp)
buf[path_len] = '/';
memcpy(buf + path_len + 1, filename, filename_len);
buf[path_len + 1 + filename_len] = '\0';
-
+
execve(buf, argv, envp);
switch(errno) {
@@ -2853,7 +3129,7 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
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;
@@ -2882,7 +3158,7 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
for(i = 0; i < 3; i++)
std_fds[i] = i;
-
+
/* get the options, if any */
if (argc >= 2) {
options = argv[1];
@@ -2891,7 +3167,7 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
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;
@@ -2936,7 +3212,7 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
if (!envp)
goto exception;
}
-
+
val = JS_GetPropertyStr(ctx, options, "uid");
if (JS_IsException(val))
goto exception;
@@ -2965,7 +3241,6 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
}
if (pid == 0) {
/* child */
- int fd_max = sysconf(_SC_OPEN_MAX);
/* remap the stdin/stdout/stderr handles if necessary */
for(i = 0; i < 3; i++) {
@@ -2974,9 +3249,28 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
_exit(127);
}
}
-
- for(i = 3; i < fd_max; i++)
- close(i);
+#if defined(HAVE_CLOSEFROM)
+ /* closefrom() is available on many recent unix systems:
+ Linux with glibc 2.34+, Solaris 9+, FreeBSD 7.3+,
+ NetBSD 3.0+, OpenBSD 3.5+.
+ Linux with the musl libc and macOS don't have it.
+ */
+
+ closefrom(3);
+#else
+ {
+ /* Close the file handles manually, limit to 1024 to avoid
+ costly loop on linux Alpine where sysconf(_SC_OPEN_MAX)
+ returns a huge value 1048576.
+ Patch inspired by nicolas-duteil-nova. See also:
+ https://stackoverflow.com/questions/73229353/
+ https://stackoverflow.com/questions/899038/#918469
+ */
+ int fd_max = min_int(sysconf(_SC_OPEN_MAX), 1024);
+ for(i = 3; i < fd_max; i++)
+ close(i);
+ }
+#endif
if (cwd) {
if (chdir(cwd) < 0)
_exit(127);
@@ -3037,13 +3331,20 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
goto done;
}
+/* getpid() -> pid */
+static JSValue js_os_getpid(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ return JS_NewInt32(ctx, getpid());
+}
+
/* waitpid(pid, block) -> [pid, status] */
static JSValue js_os_waitpid(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
int pid, status, options, ret;
JSValue obj;
-
+
if (JS_ToInt32(ctx, &pid, argv[0]))
return JS_EXCEPTION;
if (JS_ToInt32(ctx, &options, argv[1]))
@@ -3063,7 +3364,7 @@ static JSValue js_os_waitpid(JSContext *ctx, JSValueConst this_val,
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,
@@ -3071,7 +3372,7 @@ static JSValue js_os_pipe(JSContext *ctx, JSValueConst this_val,
{
int pipe_fds[2], ret;
JSValue obj;
-
+
ret = pipe(pipe_fds);
if (ret < 0)
return JS_NULL;
@@ -3090,7 +3391,7 @@ 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]))
@@ -3104,7 +3405,7 @@ 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));
@@ -3116,7 +3417,7 @@ 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]))
@@ -3141,6 +3442,7 @@ typedef struct {
char *filename; /* module filename */
char *basename; /* module base name */
JSWorkerMessagePipe *recv_pipe, *send_pipe;
+ int strip_flags;
} WorkerFuncArgs;
typedef struct {
@@ -3189,22 +3491,17 @@ static void js_sab_dup(void *opaque, void *ptr)
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]);
+ if (!ps)
+ return NULL;
+ if (js_waker_init(&ps->waker)) {
+ free(ps);
return NULL;
}
ps->ref_count = 1;
init_list_head(&ps->msg_queue);
pthread_mutex_init(&ps->mutex, NULL);
- ps->read_fd = pipe_fds[0];
- ps->write_fd = pipe_fds[1];
return ps;
}
@@ -3231,10 +3528,10 @@ 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) {
@@ -3243,8 +3540,7 @@ static void js_free_message_pipe(JSWorkerMessagePipe *ps)
js_free_message(msg);
}
pthread_mutex_destroy(&ps->mutex);
- close(ps->read_fd);
- close(ps->write_fd);
+ js_waker_close(&ps->waker);
free(ps);
}
}
@@ -3273,7 +3569,7 @@ static void js_worker_finalizer(JSRuntime *rt, JSValue val)
static JSClassDef js_worker_class = {
"Worker",
.finalizer = js_worker_finalizer,
-};
+};
static void *worker_func(void *opaque)
{
@@ -3281,21 +3577,23 @@ static void *worker_func(void *opaque)
JSRuntime *rt;
JSThreadState *ts;
JSContext *ctx;
-
+ JSValue val;
+
rt = JS_NewRuntime();
if (rt == NULL) {
fprintf(stderr, "JS_NewRuntime failure");
exit(1);
- }
+ }
+ JS_SetStripInfo(rt, args->strip_flags);
js_std_init_handlers(rt);
- JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
+ JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL);
/* set the pipe to communicate with the parent */
ts = JS_GetRuntimeOpaque(rt);
ts->recv_pipe = args->recv_pipe;
ts->send_pipe = args->send_pipe;
-
+
/* function pointer to avoid linking the whole JS_NewContext() if
not needed */
ctx = js_worker_new_context_func(rt);
@@ -3307,11 +3605,14 @@ static void *worker_func(void *opaque)
js_std_add_helpers(ctx, -1, NULL);
- if (!JS_RunModule(ctx, args->basename, args->filename))
- js_std_dump_error(ctx);
+ val = JS_LoadModule(ctx, args->basename, args->filename);
free(args->filename);
free(args->basename);
free(args);
+ val = js_std_await(ctx, val);
+ if (JS_IsException(val))
+ js_std_dump_error(ctx);
+ JS_FreeValue(ctx, val);
js_std_loop(ctx);
@@ -3327,7 +3628,7 @@ static JSValue js_worker_ctor_internal(JSContext *ctx, JSValueConst new_target,
{
JSValue obj = JS_UNDEFINED, proto;
JSWorkerData *s;
-
+
/* create the object */
if (JS_IsUndefined(new_target)) {
proto = JS_GetClassProto(ctx, js_worker_class_id);
@@ -3364,7 +3665,7 @@ static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target,
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))
@@ -3380,7 +3681,7 @@ static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target,
JS_FreeAtom(ctx, basename_atom);
if (!basename)
goto fail;
-
+
/* module name */
filename = JS_ToCString(ctx, argv[0]);
if (!filename)
@@ -3401,11 +3702,13 @@ static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target,
if (!args->send_pipe)
goto oom_fail;
+ args->strip_flags = JS_GetStripInfo(rt);
+
obj = js_worker_ctor_internal(ctx, new_target,
args->send_pipe, args->recv_pipe);
if (JS_IsException(obj))
goto fail;
-
+
pthread_attr_init(&attr);
/* no join at the end */
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
@@ -3443,10 +3746,10 @@ static JSValue js_worker_postMessage(JSContext *ctx, JSValueConst this_val,
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);
@@ -3466,15 +3769,17 @@ static JSValue js_worker_postMessage(JSContext *ctx, JSValueConst this_val,
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);
+ if (sab_tab_len > 0) {
+ msg->sab_tab = malloc(sizeof(msg->sab_tab[0]) * sab_tab_len);
+ if (!msg->sab_tab)
+ goto fail;
+ memcpy(msg->sab_tab, sab_tab, sizeof(msg->sab_tab[0]) * sab_tab_len);
+ }
msg->sab_tab_len = sab_tab_len;
js_free(ctx, data);
js_free(ctx, sab_tab);
-
+
/* increment the SAB reference counts */
for(i = 0; i < msg->sab_tab_len; i++) {
js_sab_dup(NULL, msg->sab_tab[i]);
@@ -3483,17 +3788,8 @@ static JSValue js_worker_postMessage(JSContext *ctx, JSValueConst this_val,
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;
- }
- }
+ if (list_empty(&ps->msg_queue))
+ js_waker_signal(&ps->waker);
list_add_tail(&msg->link, &ps->msg_queue);
pthread_mutex_unlock(&ps->mutex);
return JS_UNDEFINED;
@@ -3506,7 +3802,7 @@ static JSValue js_worker_postMessage(JSContext *ctx, JSValueConst this_val,
js_free(ctx, data);
js_free(ctx, sab_tab);
return JS_EXCEPTION;
-
+
}
static JSValue js_worker_set_onmessage(JSContext *ctx, JSValueConst this_val,
@@ -3516,7 +3812,7 @@ static JSValue js_worker_set_onmessage(JSContext *ctx, JSValueConst this_val,
JSThreadState *ts = JS_GetRuntimeOpaque(rt);
JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id);
JSWorkerMessageHandler *port;
-
+
if (!worker)
return JS_EXCEPTION;
@@ -3628,8 +3924,10 @@ static const JSCFunctionListEntry js_os_funcs[] = {
OS_FLAG(SIGTTIN),
OS_FLAG(SIGTTOU),
#endif
+ JS_CFUNC_DEF("now", 0, js_os_now ),
JS_CFUNC_DEF("setTimeout", 2, js_os_setTimeout ),
JS_CFUNC_DEF("clearTimeout", 1, js_os_clearTimeout ),
+ JS_CFUNC_DEF("sleepAsync", 1, js_os_sleepAsync ),
JS_PROP_STRING_DEF("platform", OS_PLATFORM, 0 ),
JS_CFUNC_DEF("getcwd", 0, js_os_getcwd ),
JS_CFUNC_DEF("chdir", 0, js_os_chdir ),
@@ -3657,6 +3955,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
JS_CFUNC_DEF("symlink", 2, js_os_symlink ),
JS_CFUNC_DEF("readlink", 1, js_os_readlink ),
JS_CFUNC_DEF("exec", 1, js_os_exec ),
+ JS_CFUNC_DEF("getpid", 0, js_os_getpid ),
JS_CFUNC_DEF("waitpid", 2, js_os_waitpid ),
OS_FLAG(WNOHANG),
JS_CFUNC_DEF("pipe", 0, js_os_pipe ),
@@ -3669,10 +3968,6 @@ static const JSCFunctionListEntry js_os_funcs[] = {
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
{
@@ -3684,20 +3979,20 @@ static int js_os_init(JSContext *ctx, JSModuleDef *m)
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 */
@@ -3722,28 +4017,43 @@ JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name)
/**********************************************************/
static JSValue js_print(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
+ int argc, JSValueConst *argv)
{
int i;
- const char *str;
- size_t len;
-
+ JSValueConst v;
+
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);
+ v = argv[i];
+ if (JS_IsString(v)) {
+ const char *str;
+ size_t len;
+ str = JS_ToCStringLen(ctx, &len, v);
+ if (!str)
+ return JS_EXCEPTION;
+ fwrite(str, 1, len, stdout);
+ JS_FreeCString(ctx, str);
+ } else {
+ JS_PrintValue(ctx, js_print_value_write, stdout, v, NULL);
+ }
}
putchar('\n');
return JS_UNDEFINED;
}
+static JSValue js_console_log(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue ret;
+ ret = js_print(ctx, this_val, argc, argv);
+ fflush(stdout);
+ return ret;
+}
+
void js_std_add_helpers(JSContext *ctx, int argc, char **argv)
{
- JSValue global_obj, console, args;
+ JSValue global_obj, console, args, performance;
int i;
/* XXX: should these global definitions be enumerable? */
@@ -3751,9 +4061,14 @@ void js_std_add_helpers(JSContext *ctx, int argc, char **argv)
console = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, console, "log",
- JS_NewCFunction(ctx, js_print, "log", 1));
+ JS_NewCFunction(ctx, js_console_log, "log", 1));
JS_SetPropertyStr(ctx, global_obj, "console", console);
+ performance = JS_NewObject(ctx);
+ JS_SetPropertyStr(ctx, performance, "now",
+ JS_NewCFunction(ctx, js_os_now, "now", 0));
+ JS_SetPropertyStr(ctx, global_obj, "performance", performance);
+
/* same methods as the mozilla JS shell */
if (argc >= 0) {
args = JS_NewArray(ctx);
@@ -3762,12 +4077,12 @@ void js_std_add_helpers(JSContext *ctx, int argc, char **argv)
}
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);
}
@@ -3785,6 +4100,8 @@ void js_std_init_handlers(JSRuntime *rt)
init_list_head(&ts->os_signal_handlers);
init_list_head(&ts->os_timers);
init_list_head(&ts->port_list);
+ init_list_head(&ts->rejected_promise_list);
+ ts->next_timer_id = 1;
JS_SetRuntimeOpaque(rt, ts);
@@ -3815,12 +4132,17 @@ void js_std_free_handlers(JSRuntime *rt)
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);
+ free_timer(rt, th);
+ }
+
+ list_for_each_safe(el, el1, &ts->rejected_promise_list) {
+ JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);
+ JS_FreeValueRT(rt, rp->promise);
+ JS_FreeValueRT(rt, rp->reason);
+ free(rp);
}
#ifdef USE_WORKER
@@ -3833,51 +4155,82 @@ void js_std_free_handlers(JSRuntime *rt)
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);
- }
+ JS_PrintValue(ctx, js_print_value_write, stderr, exception_val, NULL);
+ fputc('\n', stderr);
}
void js_std_dump_error(JSContext *ctx)
{
JSValue exception_val;
-
+
exception_val = JS_GetException(ctx);
js_std_dump_error1(ctx, exception_val);
JS_FreeValue(ctx, exception_val);
}
+static JSRejectedPromiseEntry *find_rejected_promise(JSContext *ctx, JSThreadState *ts,
+ JSValueConst promise)
+{
+ struct list_head *el;
+
+ list_for_each(el, &ts->rejected_promise_list) {
+ JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);
+ if (JS_SameValue(ctx, rp->promise, promise))
+ return rp;
+ }
+ return NULL;
+}
+
void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
JSValueConst reason,
BOOL is_handled, void *opaque)
{
+ JSRuntime *rt = JS_GetRuntime(ctx);
+ JSThreadState *ts = JS_GetRuntimeOpaque(rt);
+ JSRejectedPromiseEntry *rp;
+
if (!is_handled) {
- fprintf(stderr, "Possibly unhandled promise rejection: ");
- js_std_dump_error1(ctx, reason);
+ /* add a new entry if needed */
+ rp = find_rejected_promise(ctx, ts, promise);
+ if (!rp) {
+ rp = malloc(sizeof(*rp));
+ if (rp) {
+ rp->promise = JS_DupValue(ctx, promise);
+ rp->reason = JS_DupValue(ctx, reason);
+ list_add_tail(&rp->link, &ts->rejected_promise_list);
+ }
+ }
+ } else {
+ /* the rejection is handled, so the entry can be removed if present */
+ rp = find_rejected_promise(ctx, ts, promise);
+ if (rp) {
+ JS_FreeValue(ctx, rp->promise);
+ JS_FreeValue(ctx, rp->reason);
+ list_del(&rp->link);
+ free(rp);
+ }
+ }
+}
+
+/* check if there are pending promise rejections. It must be done
+ asynchrously in case a rejected promise is handled later. Currently
+ we do it once the application is about to sleep. It could be done
+ more often if needed. */
+static void js_std_promise_rejection_check(JSContext *ctx)
+{
+ JSRuntime *rt = JS_GetRuntime(ctx);
+ JSThreadState *ts = JS_GetRuntimeOpaque(rt);
+ struct list_head *el;
+
+ if (unlikely(!list_empty(&ts->rejected_promise_list))) {
+ list_for_each(el, &ts->rejected_promise_list) {
+ JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);
+ fprintf(stderr, "Possibly unhandled promise rejection: ");
+ js_std_dump_error1(ctx, rp->reason);
+ }
+ exit(1);
}
}
@@ -3899,11 +4252,53 @@ void js_std_loop(JSContext *ctx)
}
}
+ js_std_promise_rejection_check(ctx);
+
if (!os_poll_func || os_poll_func(ctx))
break;
}
}
+/* Wait for a promise and execute pending jobs while waiting for
+ it. Return the promise result or JS_EXCEPTION in case of promise
+ rejection. */
+JSValue js_std_await(JSContext *ctx, JSValue obj)
+{
+ JSValue ret;
+ int state;
+
+ for(;;) {
+ state = JS_PromiseState(ctx, obj);
+ if (state == JS_PROMISE_FULFILLED) {
+ ret = JS_PromiseResult(ctx, obj);
+ JS_FreeValue(ctx, obj);
+ break;
+ } else if (state == JS_PROMISE_REJECTED) {
+ ret = JS_Throw(ctx, JS_PromiseResult(ctx, obj));
+ JS_FreeValue(ctx, obj);
+ break;
+ } else if (state == JS_PROMISE_PENDING) {
+ JSContext *ctx1;
+ int err;
+ err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
+ if (err < 0) {
+ js_std_dump_error(ctx1);
+ }
+ if (err == 0) {
+ js_std_promise_rejection_check(ctx);
+
+ if (os_poll_func)
+ os_poll_func(ctx);
+ }
+ } else {
+ /* not a promise */
+ ret = obj;
+ break;
+ }
+ }
+ return ret;
+}
+
void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
int load_only)
{
@@ -3922,8 +4317,11 @@ void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
goto exception;
}
js_module_set_import_meta(ctx, obj, FALSE, TRUE);
+ val = JS_EvalFunction(ctx, obj);
+ val = js_std_await(ctx, val);
+ } else {
+ val = JS_EvalFunction(ctx, obj);
}
- val = JS_EvalFunction(ctx, obj);
if (JS_IsException(val)) {
exception:
js_std_dump_error(ctx);
@@ -3932,3 +4330,22 @@ void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
JS_FreeValue(ctx, val);
}
}
+
+void js_std_eval_binary_json_module(JSContext *ctx,
+ const uint8_t *buf, size_t buf_len,
+ const char *module_name)
+{
+ JSValue obj;
+ JSModuleDef *m;
+
+ obj = JS_ReadObject(ctx, buf, buf_len, 0);
+ if (JS_IsException(obj))
+ goto exception;
+ m = create_json_module(ctx, module_name, obj);
+ if (!m) {
+ exception:
+ js_std_dump_error(ctx);
+ exit(1);
+ }
+}
+
diff --git a/quickjs/quickjs-libc.h b/quickjs/quickjs-libc.h
index fbbe5b0166..5c8301b717 100644
--- a/quickjs/quickjs-libc.h
+++ b/quickjs/quickjs-libc.h
@@ -1,6 +1,6 @@
/*
* QuickJS C library
- *
+ *
* Copyright (c) 2017-2018 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -37,21 +37,28 @@ JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name);
JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name);
void js_std_add_helpers(JSContext *ctx, int argc, char **argv);
void js_std_loop(JSContext *ctx);
+JSValue js_std_await(JSContext *ctx, JSValue obj);
void js_std_init_handlers(JSRuntime *rt);
void js_std_free_handlers(JSRuntime *rt);
void js_std_dump_error(JSContext *ctx);
uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename);
int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
JS_BOOL use_realpath, JS_BOOL is_main);
+int js_module_test_json(JSContext *ctx, JSValueConst attributes);
+int js_module_check_attributes(JSContext *ctx, void *opaque, JSValueConst attributes);
JSModuleDef *js_module_loader(JSContext *ctx,
- const char *module_name, void *opaque);
+ const char *module_name, void *opaque,
+ JSValueConst attributes);
void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
int flags);
+void js_std_eval_binary_json_module(JSContext *ctx,
+ const uint8_t *buf, size_t buf_len,
+ const char *module_name);
void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
JSValueConst reason,
JS_BOOL is_handled, void *opaque);
void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt));
-
+
#ifdef __cplusplus
} /* extern "C" { */
#endif
diff --git a/quickjs/quickjs-opcode.h b/quickjs/quickjs-opcode.h
index 15a9fce6a3..814a7cbaaa 100644
--- a/quickjs/quickjs-opcode.h
+++ b/quickjs/quickjs-opcode.h
@@ -1,6 +1,6 @@
/*
* QuickJS opcode definitions
- *
+ *
* Copyright (c) 2017-2018 Fabrice Bellard
* Copyright (c) 2017-2018 Charlie Gordon
*
@@ -110,6 +110,7 @@ DEF( return, 1, 1, 0, none)
DEF( return_undef, 1, 0, 0, none)
DEF(check_ctor_return, 1, 1, 2, none)
DEF( check_ctor, 1, 0, 0, none)
+DEF( init_ctor, 1, 0, 1, none)
DEF( check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */
DEF( add_brand, 1, 2, 0, none) /* this_obj home_obj -> */
DEF( return_async, 1, 1, 0, none)
@@ -120,7 +121,7 @@ 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( import, 1, 2, 1, none) /* dynamic module import */
DEF( check_var, 5, 0, 1, atom) /* check if a variable exists */
DEF( get_var_undef, 5, 0, 1, atom) /* push undefined if the variable does not exist */
@@ -143,6 +144,7 @@ DEF( put_private_field, 1, 3, 0, none) /* obj value prop -> */
DEF(define_private_field, 1, 3, 1, none) /* obj prop value -> obj */
DEF( get_array_el, 1, 2, 1, none)
DEF( get_array_el2, 1, 2, 2, none) /* obj prop -> obj value */
+DEF( get_array_el3, 1, 2, 3, none) /* obj prop -> obj prop1 value */
DEF( put_array_el, 1, 3, 0, none)
DEF(get_super_value, 1, 3, 1, none) /* this obj prop -> value */
DEF(put_super_value, 1, 4, 0, none) /* this obj prop value -> */
@@ -165,14 +167,15 @@ 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( 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(get_loc_checkthis, 3, 0, 1, loc)
+DEF(get_var_ref_check, 3, 0, 1, var_ref)
DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */
DEF(put_var_ref_check_init, 3, 1, 0, var_ref)
DEF( close_loc, 3, 0, 0, loc)
@@ -182,18 +185,17 @@ DEF( goto, 5, 0, 0, label) /* must come after if_true */
DEF( catch, 5, 0, 1, label)
DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */
DEF( ret, 1, 1, 0, none) /* used to return from the finally block */
+DEF( nip_catch, 1, 2, 1, none) /* catch ... a -> a */
DEF( to_object, 1, 1, 1, none)
//DEF( to_string, 1, 1, 1, none)
DEF( to_propkey, 1, 1, 1, none)
-DEF( 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)
@@ -205,10 +207,10 @@ DEF( for_of_start, 1, 1, 3, none)
DEF(for_await_of_start, 1, 1, 3, none)
DEF( for_in_next, 1, 1, 3, none)
DEF( for_of_next, 2, 3, 5, u8)
+DEF(for_await_of_next, 1, 3, 4, none) /* iter next catch_offset -> iter next catch_offset obj */
DEF(iterator_check_object, 1, 1, 1, none)
-DEF(iterator_get_value_done, 1, 1, 2, none)
+DEF(iterator_get_value_done, 1, 2, 3, none) /* catch_offset obj -> catch_offset value done */
DEF( iterator_close, 1, 3, 0, none)
-DEF(iterator_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)
@@ -256,12 +258,10 @@ 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
+DEF( private_in, 1, 2, 1, none)
+DEF(push_bigint_i32, 5, 0, 1, i32)
/* must be the last non short and non temporary opcode */
-DEF( nop, 1, 0, 0, none)
+DEF( nop, 1, 0, 0, none)
/* temporary opcodes: never emitted in the final bytecode */
@@ -270,6 +270,8 @@ def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */
+/* the following opcodes must be in the same order as the 'with_x' and
+ get_var_undef, get_var and put_var opcodes */
def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */
@@ -277,12 +279,15 @@ def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase
def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */
def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
+def(scope_get_var_checkthis, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2, only used to return 'this' in derived class constructors */
def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */
def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */
def(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */
-
+def(scope_in_private_field, 7, 1, 1, atom_u16) /* obj -> res emitted in phase 1, removed in phase 2 */
+def(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase 2 */
+def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */
def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */
-
+
def( line_num, 5, 0, 0, u32) /* emitted in phase 1, removed in phase 3 */
#if SHORT_OPCODES
diff --git a/quickjs/quickjs.c b/quickjs/quickjs.c
index f9fd091ac0..ac8401f7e3 100644
--- a/quickjs/quickjs.c
+++ b/quickjs/quickjs.c
@@ -1,8 +1,8 @@
/*
* QuickJS Javascript Engine
- *
- * Copyright (c) 2017-2021 Fabrice Bellard
- * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Copyright (c) 2017-2025 Fabrice Bellard
+ * Copyright (c) 2017-2025 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,13 +22,14 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+#define _CRT_SECURE_NO_WARNINGS
+#define _CRT_NONSTDC_NO_DEPRECATE
#include
#include
#include
#include
#include
#include
-#include
#include
#include
#include
@@ -44,11 +45,14 @@
#include "list.h"
#include "quickjs.h"
#include "libregexp.h"
-#include "libbf.h"
+#include "libunicode.h"
+#include "dtoa.h"
+
+#pragma warning(disable:4146)
#define OPTIMIZE 1
#define SHORT_OPCODES 1
-#if defined(EMSCRIPTEN)
+#if defined(EMSCRIPTEN) || defined(_MSC_VER)
#define DIRECT_DISPATCH 0
#else
#define DIRECT_DISPATCH 1
@@ -67,11 +71,11 @@
/* define to include Atomics.* operations which depend on the OS
threads */
-#if !defined(EMSCRIPTEN)
+#if !defined(EMSCRIPTEN) && !defined(_MSC_VER)
#define CONFIG_ATOMICS
#endif
-#if !defined(EMSCRIPTEN)
+#if !defined(EMSCRIPTEN) && !defined(_MSC_VER)
/* enable stack limitation */
#define CONFIG_STACK_CHECK
#endif
@@ -87,6 +91,7 @@
8: dump stdlib functions
16: dump bytecode in hex
32: dump line number table
+ 64: dump compute_stack_size
*/
//#define DUMP_BYTECODE (1)
/* dump the occurence of the automatic GC */
@@ -103,6 +108,7 @@
//#define DUMP_MODULE_RESOLVE
//#define DUMP_PROMISE
//#define DUMP_READ_OBJECT
+//#define DUMP_ROPE_REBALANCE
/* test the GC by forcing it before each object allocation */
//#define FORCE_GC_AT_MALLOC
@@ -144,16 +150,11 @@ enum {
JS_CLASS_UINT32_ARRAY, /* u.array (typed_array) */
JS_CLASS_BIG_INT64_ARRAY, /* u.array (typed_array) */
JS_CLASS_BIG_UINT64_ARRAY, /* u.array (typed_array) */
+ JS_CLASS_FLOAT16_ARRAY, /* u.array (typed_array) */
JS_CLASS_FLOAT32_ARRAY, /* u.array (typed_array) */
JS_CLASS_FLOAT64_ARRAY, /* u.array (typed_array) */
JS_CLASS_DATAVIEW, /* u.typed_array */
JS_CLASS_BIG_INT, /* u.object_data */
-#ifdef CONFIG_BIGNUM
- 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 */
@@ -174,7 +175,9 @@ enum {
JS_CLASS_ASYNC_FROM_SYNC_ITERATOR, /* u.async_from_sync_iterator_data */
JS_CLASS_ASYNC_GENERATOR_FUNCTION, /* u.func */
JS_CLASS_ASYNC_GENERATOR, /* u.async_generator_data */
-
+ JS_CLASS_WEAK_REF,
+ JS_CLASS_FINALIZATION_REGISTRY,
+
JS_CLASS_INIT_COUNT, /* last entry for predefined classes */
};
@@ -192,19 +195,34 @@ typedef enum JSErrorEnum {
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
+/* the variable and scope indexes must fit on 16 bits. The (-1) and
+ ARG_SCOPE_END values are reserved. */
+#define JS_MAX_LOCAL_VARS 65534
#define JS_STACK_SIZE_MAX 65534
#define JS_STRING_LEN_MAX ((1 << 30) - 1)
+/* strings <= this length are not concatenated using ropes. if too
+ small, the rope memory overhead becomes high. */
+#define JS_STRING_ROPE_SHORT_LEN 512
+/* specific threshold for initial rope use */
+#define JS_STRING_ROPE_SHORT2_LEN 8192
+/* rope depth at which we rebalance */
+#define JS_STRING_ROPE_MAX_DEPTH 60
+
#define __exception __attribute__((warn_unused_result))
typedef struct JSShape JSShape;
typedef struct JSString JSString;
typedef struct JSString JSAtomStruct;
+typedef struct JSObject JSObject;
+
+#define JS_VALUE_GET_OBJ(v) ((JSObject *)JS_VALUE_GET_PTR(v))
+#define JS_VALUE_GET_STRING(v) ((JSString *)JS_VALUE_GET_PTR(v))
+#define JS_VALUE_GET_STRING_ROPE(v) ((JSStringRope *)JS_VALUE_GET_PTR(v))
typedef enum {
JS_GC_PHASE_NONE,
@@ -214,24 +232,6 @@ typedef enum {
typedef enum OPCodeEnum OPCodeEnum;
-/* 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;
-
struct JSRuntime {
JSMallocFunctions mf;
JSMallocState malloc_state;
@@ -253,10 +253,11 @@ struct JSRuntime {
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 gc_zero_ref_count_list;
struct list_head tmp_obj_list; /* used during GC */
JSGCPhaseEnum gc_phase : 8;
size_t malloc_gc_threshold;
+ struct list_head weakref_list; /* list of JSWeakRefHeader.link */
#ifdef DUMP_LEAKS
struct list_head string_list; /* list of JSString.link */
#endif
@@ -264,8 +265,10 @@ struct JSRuntime {
uintptr_t stack_size; /* in bytes, 0 if no limit */
uintptr_t stack_top;
uintptr_t stack_limit; /* lower stack limit */
-
+
JSValue current_exception;
+ /* true if the current exception cannot be catched */
+ BOOL current_exception_is_uncatchable : 8;
/* true if inside an out of memory error, to avoid recursing */
BOOL in_out_of_memory : 8;
@@ -279,29 +282,31 @@ struct JSRuntime {
JSHostPromiseRejectionTracker *host_unhandled_promise_rejection_tracker;
void *host_unhandled_promise_rejection_tracker_opaque;
-
+
struct list_head job_list; /* list of JSJobEntry.link */
JSModuleNormalizeFunc *module_normalize_func;
- JSModuleLoaderFunc *module_loader_func;
+ BOOL module_loader_has_attr;
+ union {
+ JSModuleLoaderFunc *module_loader_func;
+ JSModuleLoaderFunc2 *module_loader_func2;
+ } u;
+ JSModuleCheckSupportedImportAttributes *module_check_attrs;
void *module_loader_opaque;
+ /* timestamp for internal use in module evaluation */
+ int64_t module_async_evaluation_next_timestamp;
BOOL can_block : 8; /* TRUE if Atomics.wait can block */
/* used to allocate, free and clone SharedArrayBuffers */
JSSharedArrayBufferFunctions sab_funcs;
+ /* see JS_SetStripInfo() */
+ uint8_t strip_flags;
/* Shape hash table */
int shape_hash_bits;
int shape_hash_size;
int shape_hash_count; /* number of hashed shapes */
JSShape **shape_hash;
- bf_context_t bf_ctx;
- JSNumericOperations bigint_ops;
-#ifdef CONFIG_BIGNUM
- JSNumericOperations bigfloat_ops;
- JSNumericOperations bigdecimal_ops;
- uint32_t operator_count;
-#endif
void *user_opaque;
};
@@ -316,21 +321,21 @@ struct JSClass {
};
#define JS_MODE_STRICT (1 << 0)
-#define JS_MODE_STRIP (1 << 1)
-#define JS_MODE_MATH (1 << 2)
+#define JS_MODE_ASYNC (1 << 2) /* async function */
+#define JS_MODE_BACKTRACE_BARRIER (1 << 3) /* stop backtrace before this frame */
typedef struct JSStackFrame {
struct JSStackFrame *prev_frame; /* NULL if first stack frame */
JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */
JSValue *arg_buf; /* arguments */
JSValue *var_buf; /* variables */
- struct list_head var_ref_list; /* list of JSVarRef.link */
+ struct list_head var_ref_list; /* list of JSVarRef.var_ref_link */
const uint8_t *cur_pc; /* only used in bytecode functions : PC of the
instruction after the call */
int arg_count;
- int js_mode; /* 0 or JS_MODE_MATH for C functions */
+ int js_mode; /* not supported for C functions */
/* only used in generators. Current stack pointer value. NULL if
- the function is running. */
+ the function is running. */
JSValue *cur_sp;
} JSStackFrame;
@@ -355,48 +360,76 @@ struct JSGCObjectHeader {
struct list_head link;
};
+typedef enum {
+ JS_WEAKREF_TYPE_MAP,
+ JS_WEAKREF_TYPE_WEAKREF,
+ JS_WEAKREF_TYPE_FINREC,
+} JSWeakRefHeaderTypeEnum;
+
+typedef struct {
+ struct list_head link;
+ JSWeakRefHeaderTypeEnum weakref_type;
+} JSWeakRefHeader;
+
typedef struct JSVarRef {
union {
JSGCObjectHeader header; /* must come first */
struct {
int __gc_ref_count; /* corresponds to header.ref_count */
uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
-
- /* 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 */
+ uint8_t is_detached;
};
};
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 */
+ union {
+ JSValue value; /* used when is_detached = TRUE */
+ struct {
+ struct list_head var_ref_link; /* JSStackFrame.var_ref_list list */
+ struct JSAsyncFunctionState *async_func; /* != NULL if async stack frame */
+ }; /* used when is_detached = FALSE */
+ };
} JSVarRef;
-/* 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;
+/* bigint */
-#ifdef CONFIG_BIGNUM
-typedef struct JSFloatEnv {
- limb_t prec;
- bf_flags_t flags;
- unsigned int status;
-} JSFloatEnv;
+#if JS_LIMB_BITS == 32
+
+typedef int32_t js_slimb_t;
+typedef uint32_t js_limb_t;
+typedef int64_t js_sdlimb_t;
+typedef uint64_t js_dlimb_t;
+
+#define JS_LIMB_DIGITS 9
+
+#else
+
+typedef __int128 int128_t;
+typedef unsigned __int128 uint128_t;
+typedef int64_t js_slimb_t;
+typedef uint64_t js_limb_t;
+typedef int128_t js_sdlimb_t;
+typedef uint128_t js_dlimb_t;
+
+#define JS_LIMB_DIGITS 19
-typedef struct JSBigDecimal {
- JSRefCountHeader header; /* must come first, 32-bit */
- bfdec_t num;
-} JSBigDecimal;
#endif
+typedef struct JSBigInt {
+ JSRefCountHeader header; /* must come first, 32-bit */
+ uint32_t len; /* number of limbs, >= 1 */
+ js_limb_t tab[]; /* two's complement representation, always
+ normalized so that 'len' is the minimum
+ possible length >= 1 */
+} JSBigInt;
+
+/* this bigint structure can hold a 64 bit integer */
+typedef struct {
+ js_limb_t big_int_buf[sizeof(JSBigInt) / sizeof(js_limb_t)]; /* for JSBigInt */
+ /* must come just after */
+ js_limb_t tab[(64 + JS_LIMB_BITS - 1) / JS_LIMB_BITS];
+} JSBigIntBuf;
+
typedef enum {
JS_AUTOINIT_ID_PROTOTYPE,
JS_AUTOINIT_ID_MODULE_NS,
@@ -434,15 +467,9 @@ struct JSContext {
JSValue global_var_obj; /* contains the global let/const definitions */
uint64_t random_state;
- bf_context_t *bf_ctx; /* points to rt->bf_ctx, shared by all contexts */
-#ifdef CONFIG_BIGNUM
- 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 */
@@ -469,11 +496,6 @@ enum {
JS_ATOM_TYPE_PRIVATE,
};
-enum {
- JS_ATOM_HASH_SYMBOL,
- JS_ATOM_HASH_PRIVATE,
-};
-
typedef enum {
JS_ATOM_KIND_STRING,
JS_ATOM_KIND_SYMBOL,
@@ -481,13 +503,14 @@ typedef enum {
} JSAtomKindEnum;
#define JS_ATOM_HASH_MASK ((1 << 30) - 1)
+#define JS_ATOM_HASH_PRIVATE JS_ATOM_HASH_MASK
struct JSString {
JSRefCountHeader header; /* must come first, 32-bit */
uint32_t len : 31;
uint8_t is_wide_char : 1; /* 0 = 8 bits, 1 = 16 bits characters */
- /* for JS_ATOM_TYPE_SYMBOL: hash = 0, atom_type = 3,
- for JS_ATOM_TYPE_PRIVATE: hash = 1, atom_type = 3
+ /* for JS_ATOM_TYPE_SYMBOL: hash = weakref_count, atom_type = 3,
+ for JS_ATOM_TYPE_PRIVATE: hash = JS_ATOM_HASH_PRIVATE, atom_type = 3
XXX: could change encoding to have one more bit in hash */
uint32_t hash : 30;
uint8_t atom_type : 2; /* != 0 if atom, JS_ATOM_TYPE_x */
@@ -501,6 +524,17 @@ struct JSString {
} u;
};
+typedef struct JSStringRope {
+ JSRefCountHeader header; /* must come first, 32-bit */
+ uint32_t len;
+ uint8_t is_wide_char; /* 0 = 8 bits, 1 = 16 bits characters */
+ uint8_t depth; /* max depth of the rope tree */
+ /* XXX: could reduce memory usage by using a direct pointer with
+ bit 0 to select rope or string */
+ JSValue left;
+ JSValue right; /* might be the empty string */
+} JSStringRope;
+
typedef struct JSClosureVar {
uint8_t is_local : 1;
uint8_t is_arg : 1;
@@ -543,7 +577,7 @@ typedef struct JSVarDef {
JSAtom var_name;
/* index into fd->scopes of this variable lexical scope */
int scope_level;
- /* during compilation:
+ /* 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
@@ -551,7 +585,7 @@ typedef struct JSVarDef {
index into fd->vars of the next
variable in the same or enclosing lexical scope
*/
- int scope_next;
+ int scope_next;
uint8_t is_const : 1;
uint8_t is_lexical : 1;
uint8_t is_captured : 1;
@@ -594,9 +628,9 @@ typedef struct JSFunctionBytecode {
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 is_direct_or_indirect_eval : 1; /* used by JS_GetScriptOrModuleName() */
+ /* XXX: 10 bits available */
uint8_t *byte_code_buf; /* (self pointer) */
int byte_code_len;
JSAtom func_name;
@@ -613,8 +647,7 @@ typedef struct JSFunctionBytecode {
struct {
/* debug info, move to separate structure to save memory? */
JSAtom filename;
- int line_num;
- int source_len;
+ int source_len;
int pc2line_len;
uint8_t *pc2line_buf;
char *source;
@@ -636,9 +669,11 @@ typedef enum JSIteratorKindEnum {
typedef struct JSForInIterator {
JSValue obj;
- BOOL is_array;
- uint32_t array_length;
uint32_t idx;
+ uint32_t atom_count;
+ uint8_t in_prototype_chain;
+ uint8_t is_array;
+ JSPropertyEnum *tab_atom; /* is_array = FALSE */
} JSForInIterator;
typedef struct JSRegExp {
@@ -672,21 +707,16 @@ typedef struct JSTypedArray {
} JSTypedArray;
typedef struct JSAsyncFunctionState {
- JSValue this_val; /* 'this' generator argument */
+ JSGCObjectHeader header;
+ JSValue this_val; /* 'this' argument */
int argc; /* number of function arguments */
BOOL throw_flag; /* used to throw an exception in JS_CallInternal() */
+ BOOL is_completed; /* TRUE if the function has returned. The stack
+ frame is no longer valid */
+ JSValue resolving_funcs[2]; /* only used in JS async functions */
JSStackFrame frame;
} JSAsyncFunctionState;
-/* 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,
@@ -737,6 +767,7 @@ typedef struct {
typedef struct JSReqModuleEntry {
JSAtom module_name;
JSModuleDef *module; /* used using resolution */
+ JSValue attributes; /* JS_UNDEFINED or an object contains the attributes as key/value */
} JSReqModuleEntry;
typedef enum JSExportTypeEnum {
@@ -764,10 +795,20 @@ typedef struct JSStarExportEntry {
typedef struct JSImportEntry {
int var_idx; /* closure variable index */
+ BOOL is_star; /* import_name = '*' is a valid import name, so need a flag */
JSAtom import_name;
int req_module_idx; /* in req_module_entries */
} JSImportEntry;
+typedef enum {
+ JS_MODULE_STATUS_UNLINKED,
+ JS_MODULE_STATUS_LINKING,
+ JS_MODULE_STATUS_LINKED,
+ JS_MODULE_STATUS_EVALUATING,
+ JS_MODULE_STATUS_EVALUATING_ASYNC,
+ JS_MODULE_STATUS_EVALUATED,
+} JSModuleStatus;
+
struct JSModuleDef {
JSRefCountHeader header; /* must come first, 32-bit */
JSAtom module_name;
@@ -792,16 +833,30 @@ struct JSModuleDef {
JSValue module_ns;
JSValue func_obj; /* only used for JS modules */
JSModuleInitFunc *init_func; /* only used for C modules */
+ BOOL has_tla : 8; /* true if func_obj contains await */
BOOL resolved : 8;
BOOL func_created : 8;
- BOOL instantiated : 8;
- BOOL evaluated : 8;
- BOOL eval_mark : 8; /* temporary use during js_evaluate_module() */
+ JSModuleStatus status : 8;
+ /* temp use during js_module_link() & js_module_evaluate() */
+ int dfs_index, dfs_ancestor_index;
+ JSModuleDef *stack_prev;
+ /* temp use during js_module_evaluate() */
+ JSModuleDef **async_parent_modules;
+ int async_parent_modules_count;
+ int async_parent_modules_size;
+ int pending_async_dependencies;
+ BOOL async_evaluation;
+ int64_t async_evaluation_timestamp;
+ JSModuleDef *cycle_root;
+ JSValue promise; /* corresponds to spec field: capability */
+ JSValue resolving_funcs[2]; /* corresponds to spec field: capability */
+
/* true if evaluation yielded an exception. It is saved in
eval_exception */
- BOOL eval_has_exception : 8;
+ BOOL eval_has_exception : 8;
JSValue eval_exception;
JSValue meta_obj; /* for import.meta */
+ JSValue private_value; /* private value for C modules */
};
typedef struct JSJobEntry {
@@ -867,24 +922,24 @@ struct JSObject {
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 has_immutable_prototype : 1; /* cannot modify the prototype */
uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */
uint8_t is_HTMLDDA : 1; /* specific annex B IsHtmlDDA behavior */
uint16_t class_id; /* see JS_CLASS_x */
};
};
- /* byte offsets: 16/24 */
+ /* count the number of weak references to this object. The object
+ structure is freed only if header.ref_count = 0 and
+ weakref_count = 0 */
+ uint32_t weakref_count;
JSShape *shape; /* prototype and property names + flag */
JSProperty *prop; /* array of properties */
- /* 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 */
@@ -892,10 +947,6 @@ struct JSObject {
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 */
@@ -904,7 +955,7 @@ struct JSObject {
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 JSAsyncFunctionState *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */
struct JSAsyncFromSyncIteratorData *async_from_sync_iterator_data; /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */
struct JSAsyncGeneratorData *async_generator_data; /* JS_CLASS_ASYNC_GENERATOR */
struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */
@@ -927,7 +978,7 @@ struct JSObject {
struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
} u1;
union {
- JSValue *values; /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */
+ 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 */
@@ -937,6 +988,7 @@ struct JSObject {
uint32_t *uint32_ptr; /* JS_CLASS_UINT32_ARRAY */
int64_t *int64_ptr; /* JS_CLASS_INT64_ARRAY */
uint64_t *uint64_ptr; /* JS_CLASS_UINT64_ARRAY */
+ uint16_t *fp16_ptr; /* JS_CLASS_FLOAT16_ARRAY */
float *float_ptr; /* JS_CLASS_FLOAT32_ARRAY */
double *double_ptr; /* JS_CLASS_FLOAT64_ARRAY */
} u;
@@ -945,8 +997,29 @@ struct JSObject {
JSRegExp regexp; /* JS_CLASS_REGEXP: 8/16 bytes */
JSValue object_data; /* for JS_SetObjectData(): 8/16/16 bytes */
} u;
- /* byte sizes: 40/48/72 */
};
+
+typedef struct JSMapRecord {
+ int ref_count; /* used during enumeration to avoid freeing the record */
+ BOOL empty : 8; /* TRUE if the record is deleted */
+ struct list_head link;
+ struct JSMapRecord *hash_next;
+ JSValue key;
+ JSValue value;
+} JSMapRecord;
+
+typedef struct JSMapState {
+ BOOL is_weak; /* TRUE if WeakSet/WeakMap */
+ struct list_head records; /* list of JSMapRecord.link */
+ uint32_t record_count;
+ JSMapRecord **hash_table;
+ int hash_bits;
+ uint32_t hash_size; /* = 2 ^ hash_bits */
+ uint32_t record_count_threshold; /* count at which a hash table
+ resize is needed */
+ JSWeakRefHeader weakref_header; /* only used if is_weak = TRUE */
+} JSMapState;
+
enum {
__JS_ATOM_NULL = JS_ATOM_NULL,
#define DEF(name, str) JS_ATOM_ ## name,
@@ -1021,29 +1094,22 @@ static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
JSValueConst val, int flags, int scope_idx);
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...);
static __maybe_unused void JS_DumpAtoms(JSRuntime *rt);
-static __maybe_unused void JS_DumpString(JSRuntime *rt,
- const JSString *p);
+static __maybe_unused void JS_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_DumpValueRT(JSRuntime *rt, const char *str, JSValueConst val);
+static __maybe_unused void JS_DumpValue(JSContext *ctx, const char *str, JSValueConst val);
static __maybe_unused void JS_DumpShapes(JSRuntime *rt);
+static void js_dump_value_write(void *opaque, const char *buf, size_t len);
static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic);
static void js_array_finalizer(JSRuntime *rt, JSValue val);
-static void js_array_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
+static void js_array_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
static void js_object_data_finalizer(JSRuntime *rt, JSValue val);
-static void js_object_data_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
+static void js_object_data_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
static void js_c_function_finalizer(JSRuntime *rt, JSValue val);
-static void js_c_function_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
+static void js_c_function_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val);
static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
JS_MarkFunc *mark_func);
@@ -1082,16 +1148,18 @@ static void js_promise_mark(JSRuntime *rt, JSValueConst val,
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
+
+#define HINT_STRING 0
+#define HINT_NUMBER 1
+#define HINT_NONE 2
+#define HINT_FORCE_ORDINARY (1 << 4) // don't try Symbol.toPrimitive
+static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint);
static JSValue JS_ToStringFree(JSContext *ctx, JSValue val);
static int JS_ToBoolFree(JSContext *ctx, JSValue val);
static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val);
static int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val);
static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val);
+static JSValue js_new_string8_len(JSContext *ctx, const char *buf, int len);
static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
JSValueConst flags);
static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor,
@@ -1108,58 +1176,24 @@ typedef enum JSStrictEqModeEnum {
static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
JSStrictEqModeEnum eq_mode);
-static BOOL js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2);
+static BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2);
static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2);
static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2);
static JSValue JS_ToObject(JSContext *ctx, JSValueConst val);
static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val);
static JSProperty *add_property(JSContext *ctx,
JSObject *p, JSAtom prop, int prop_flags);
-static JSValue JS_NewBigInt(JSContext *ctx);
-static inline bf_t *JS_GetBigInt(JSValueConst val)
-{
- JSBigFloat *p = JS_VALUE_GET_PTR(val);
- return &p->num;
-}
-static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
- BOOL convert_to_safe_integer);
-static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val);
static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val);
-static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val);
-static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf);
-#ifdef CONFIG_BIGNUM
-static void js_float_env_finalizer(JSRuntime *rt, JSValue val);
-static JSValue JS_NewBigFloat(JSContext *ctx);
-static inline bf_t *JS_GetBigFloat(JSValueConst val)
-{
- JSBigFloat *p = JS_VALUE_GET_PTR(val);
- return &p->num;
-}
-static JSValue JS_NewBigDecimal(JSContext *ctx);
-static inline bfdec_t *JS_GetBigDecimal(JSValueConst val)
-{
- JSBigDecimal *p = JS_VALUE_GET_PTR(val);
- return &p->num;
-}
-static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val);
-static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
- BOOL allow_null_or_undefined);
-static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val);
-#endif
JSValue JS_ThrowOutOfMemory(JSContext *ctx);
static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx);
-static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj);
-static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
- JSValueConst proto_val, BOOL throw_flag);
-static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj);
-static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj);
-static int js_proxy_isArray(JSContext *ctx, JSValueConst obj);
+
+static int js_resolve_proxy(JSContext *ctx, JSValueConst *pval, int throw_exception);
static int JS_CreateProperty(JSContext *ctx, JSObject *p,
JSAtom prop, JSValueConst val,
JSValueConst getter, JSValueConst setter,
int flags);
-static int js_string_memcmp(const JSString *p1, const JSString *p2, int len);
-static void reset_weak_ref(JSRuntime *rt, JSObject *p);
+static int js_string_memcmp(const JSString *p1, int pos1, const JSString *p2,
+ int pos2, int len);
static JSValue js_array_buffer_constructor3(JSContext *ctx,
JSValueConst new_target,
uint64_t len, JSClassID class_id,
@@ -1171,11 +1205,17 @@ static JSValue js_typed_array_constructor(JSContext *ctx,
JSValueConst this_val,
int argc, JSValueConst *argv,
int classid);
+static JSValue js_typed_array_constructor_ta(JSContext *ctx,
+ JSValueConst new_target,
+ JSValueConst src_obj,
+ int classid);
static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p);
static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p);
static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx);
static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx,
BOOL is_arg);
+static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s);
+static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s);
static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
JSValueConst this_obj,
int argc, JSValueConst *argv,
@@ -1190,7 +1230,7 @@ static void js_free_module_def(JSContext *ctx, JSModuleDef *m);
static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
JS_MarkFunc *mark_func);
static JSValue js_import_meta(JSContext *ctx);
-static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier);
+static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier, JSValueConst options);
static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref);
static JSValue js_new_promise_capability(JSContext *ctx,
JSValue *resolving_funcs,
@@ -1201,6 +1241,8 @@ static __exception int perform_promise_then(JSContext *ctx,
JSValueConst *cap_resolving_funcs);
static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic);
+static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
static int js_string_compare(JSContext *ctx,
const JSString *p1, const JSString *p2);
static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val);
@@ -1212,8 +1254,6 @@ static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val);
static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,
JSObject *p, JSAtom prop);
static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc);
-static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s,
- JS_MarkFunc *mark_func);
static void JS_AddIntrinsicBasicObjects(JSContext *ctx);
static void js_free_shape(JSRuntime *rt, JSShape *sh);
static void js_free_shape_null(JSRuntime *rt, JSShape *sh);
@@ -1241,13 +1281,26 @@ static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val);
static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
JSGCObjectTypeEnum type);
static void remove_gc_object(JSGCObjectHeader *h);
-static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s);
static 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 JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int is_map);
+static void map_delete_weakrefs(JSRuntime *rt, JSWeakRefHeader *wh);
+static void weakref_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh);
+static void finrec_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh);
+static void JS_RunGCInternal(JSRuntime *rt, BOOL remove_weak_objects);
+static JSValue js_array_from_iterator(JSContext *ctx, uint32_t *plen,
+ JSValueConst obj, JSValueConst method);
+static int js_string_find_invalid_codepoint(JSString *p);
+static JSValue js_regexp_toString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
+static JSValue get_date_string(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int magic);
+static JSValue js_error_toString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
static const JSClassExoticMethods js_arguments_exotic_methods;
static const JSClassExoticMethods js_string_exotic_methods;
@@ -1309,13 +1362,6 @@ void *js_mallocz_rt(JSRuntime *rt, size_t size)
return memset(ptr, 0, size);
}
-/* 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);
-}
-
/* Throw out of memory in case of error */
void *js_malloc(JSContext *ctx, size_t size)
{
@@ -1431,6 +1477,10 @@ static inline int is_digit(int c) {
return c >= '0' && c <= '9';
}
+static inline int string_get(const JSString *p, int idx) {
+ return p->is_wide_char ? p->u.str16[idx] : p->u.str8[idx];
+}
+
typedef struct JSClassShortDef {
JSAtom class_name;
JSClassFinalizer *finalizer;
@@ -1467,16 +1517,11 @@ static JSClassShortDef const js_std_class_def[] = {
{ JS_ATOM_Uint32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT32_ARRAY */
{ JS_ATOM_BigInt64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_BIG_INT64_ARRAY */
{ JS_ATOM_BigUint64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_BIG_UINT64_ARRAY */
+ { JS_ATOM_Float16Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT16_ARRAY */
{ JS_ATOM_Float32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT32_ARRAY */
{ JS_ATOM_Float64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT64_ARRAY */
{ JS_ATOM_DataView, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_DATAVIEW */
{ JS_ATOM_BigInt, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_INT */
-#ifdef CONFIG_BIGNUM
- { 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 */
@@ -1506,61 +1551,6 @@ static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab,
return 0;
}
-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;
-}
-
#if !defined(CONFIG_STACK_CHECK)
/* no stack limitation */
static inline uintptr_t js_get_stack_pointer(void)
@@ -1608,18 +1598,12 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
rt->malloc_state = ms;
rt->malloc_gc_threshold = 256 * 1024;
- bf_context_init(&rt->bf_ctx, js_bf_realloc, rt);
- set_dummy_numeric_ops(&rt->bigint_ops);
-#ifdef CONFIG_BIGNUM
- 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;
-
+ init_list_head(&rt->weakref_list);
+
#ifdef DUMP_LEAKS
init_list_head(&rt->string_list);
#endif
@@ -1646,7 +1630,7 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
rt->stack_size = JS_DEFAULT_STACK_SIZE;
JS_UpdateStackTop(rt);
- rt->current_exception = JS_NULL;
+ rt->current_exception = JS_UNINITIALIZED;
return rt;
fail:
@@ -1665,19 +1649,19 @@ void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque)
}
/* default memory allocation functions with memory limitation */
-static inline size_t js_def_malloc_usable_size(void *ptr)
+static size_t js_def_malloc_usable_size(const void *ptr)
{
#if defined(__APPLE__)
return malloc_size(ptr);
#elif defined(_WIN32)
- return _msize(ptr);
+ return _msize((void *)ptr);
#elif defined(EMSCRIPTEN)
return 0;
-#elif defined(__linux__)
- return malloc_usable_size(ptr);
+#elif defined(__linux__) || defined(__GLIBC__)
+ return malloc_usable_size((void *)ptr);
#else
/* change this to `return 0;` if compilation fails */
- return malloc_usable_size(ptr);
+ return malloc_usable_size((void *)ptr);
#endif
}
@@ -1741,18 +1725,7 @@ 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__)
- (size_t (*)(const void *))malloc_usable_size,
-#else
- /* change this to `NULL,` if compilation fails */
- malloc_usable_size,
-#endif
+ js_def_malloc_usable_size,
};
JSRuntime *JS_NewRuntime(void)
@@ -1792,6 +1765,16 @@ void JS_SetSharedArrayBufferFunctions(JSRuntime *rt,
rt->sab_funcs = *sf;
}
+void JS_SetStripInfo(JSRuntime *rt, int flags)
+{
+ rt->strip_flags = flags;
+}
+
+int JS_GetStripInfo(JSRuntime *rt)
+{
+ return rt->strip_flags;
+}
+
/* return 0 if OK, < 0 if exception */
int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func,
int argc, JSValueConst *argv)
@@ -1930,7 +1913,9 @@ void JS_FreeRuntime(JSRuntime *rt)
}
init_list_head(&rt->job_list);
- JS_RunGC(rt);
+ /* don't remove the weak objects to avoid create new jobs with
+ FinalizationRegistry */
+ JS_RunGCInternal(rt, FALSE);
#ifdef DUMP_LEAKS
/* leaking objects */
@@ -1972,6 +1957,7 @@ void JS_FreeRuntime(JSRuntime *rt)
}
#endif
assert(list_empty(&rt->gc_obj_list));
+ assert(list_empty(&rt->weakref_list));
/* free the classes */
for(i = 0; i < rt->class_count; i++) {
@@ -1982,8 +1968,6 @@ void JS_FreeRuntime(JSRuntime *rt)
}
js_free_rt(rt, rt->class_array);
- bf_context_end(&rt->bf_ctx);
-
#ifdef DUMP_LEAKS
/* only the atoms defined in JS_InitAtoms() should be left */
{
@@ -2018,7 +2002,7 @@ void JS_FreeRuntime(JSRuntime *rt)
printf(")");
break;
case JS_ATOM_TYPE_SYMBOL:
- if (p->hash == JS_ATOM_HASH_SYMBOL) {
+ if (p->hash != JS_ATOM_HASH_PRIVATE) {
printf("Symbol(");
JS_DumpString(rt, p);
printf(")");
@@ -2120,11 +2104,6 @@ JSContext *JS_NewContextRaw(JSRuntime *rt)
}
ctx->rt = rt;
list_add_tail(&ctx->link, &rt->context_list);
- ctx->bf_ctx = &rt->bf_ctx;
-#ifdef CONFIG_BIGNUM
- 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;
@@ -2154,7 +2133,7 @@ JSContext *JS_NewContext(JSRuntime *rt)
JS_AddIntrinsicMapSet(ctx);
JS_AddIntrinsicTypedArrays(ctx);
JS_AddIntrinsicPromise(ctx);
- JS_AddIntrinsicBigInt(ctx);
+ JS_AddIntrinsicWeakRef(ctx);
return ctx;
}
@@ -2195,7 +2174,6 @@ JSValue JS_GetClassProto(JSContext *ctx, JSClassID 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 */
@@ -2205,8 +2183,7 @@ static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag)
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)) {
+ (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved)) {
js_free_module_def(ctx, m);
}
}
@@ -2265,7 +2242,7 @@ void JS_FreeContext(JSContext *ctx)
if (--ctx->header.ref_count > 0)
return;
assert(ctx->header.ref_count == 0);
-
+
#ifdef DUMP_ATOMS
JS_DumpAtoms(ctx->rt);
#endif
@@ -2356,19 +2333,6 @@ static inline BOOL is_strict_mode(JSContext *ctx)
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));
-}
-#else
-static inline BOOL is_math_mode(JSContext *ctx)
-{
- return FALSE;
-}
-#endif
-
/* JSAtom support */
#define JS_ATOM_TAG_INT (1U << 31)
@@ -2417,10 +2381,7 @@ static inline BOOL is_num_string(uint32_t *pval, const JSString *p)
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];
+ c = string_get(p, 0);
if (is_num(c)) {
if (c == '0') {
if (len != 1)
@@ -2429,10 +2390,7 @@ static inline BOOL is_num_string(uint32_t *pval, const JSString *p)
} 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];
+ c = string_get(p, i);
if (!is_num(c))
return FALSE;
n64 = (uint64_t)n * 10 + (c - '0');
@@ -2477,10 +2435,35 @@ static uint32_t hash_string(const JSString *str, uint32_t h)
return h;
}
-static __maybe_unused void JS_DumpString(JSRuntime *rt,
- const JSString *p)
+static uint32_t hash_string_rope(JSValueConst val, uint32_t h)
+{
+ if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
+ return hash_string(JS_VALUE_GET_STRING(val), h);
+ } else {
+ JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val);
+ h = hash_string_rope(r->left, h);
+ return hash_string_rope(r->right, h);
+ }
+}
+
+static __maybe_unused void JS_DumpChar(FILE *fo, int c, int sep)
+{
+ if (c == sep || c == '\\') {
+ fputc('\\', fo);
+ fputc(c, fo);
+ } else if (c >= ' ' && c <= 126) {
+ fputc(c, fo);
+ } else if (c == '\n') {
+ fputc('\\', fo);
+ fputc('n', fo);
+ } else {
+ fprintf(fo, "\\u%04x", c);
+ }
+}
+
+static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p)
{
- int i, c, sep;
+ int i, sep;
if (p == NULL) {
printf("");
@@ -2490,21 +2473,7 @@ static __maybe_unused void JS_DumpString(JSRuntime *rt,
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);
- }
+ JS_DumpChar(stdout, string_get(p, i), sep);
}
putchar(sep);
}
@@ -2642,14 +2611,10 @@ static JSAtomKindEnum JS_AtomGetKind(JSContext *ctx, JSAtom v)
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:
+ if (p->hash == JS_ATOM_HASH_PRIVATE)
return JS_ATOM_KIND_PRIVATE;
- default:
- abort();
- }
+ else
+ return JS_ATOM_KIND_SYMBOL;
default:
abort();
}
@@ -2709,7 +2674,7 @@ static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type)
if (p->hash == h &&
p->atom_type == atom_type &&
p->len == len &&
- js_string_memcmp(p, str, len) == 0) {
+ js_string_memcmp(p, 0, str, 0, len) == 0) {
if (!__JS_AtomIsConst(i))
p->header.ref_count++;
goto done;
@@ -2719,7 +2684,7 @@ static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type)
} else {
h1 = 0; /* avoid warning */
if (atom_type == JS_ATOM_TYPE_SYMBOL) {
- h = JS_ATOM_HASH_SYMBOL;
+ h = 0;
} else {
h = JS_ATOM_HASH_PRIVATE;
atom_type = JS_ATOM_TYPE_SYMBOL;
@@ -2847,6 +2812,7 @@ static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
return __JS_NewAtom(rt, p, atom_type);
}
+/* Warning: str must be ASCII only */
static JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len,
int atom_type)
{
@@ -2911,7 +2877,13 @@ static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p)
#ifdef DUMP_LEAKS
list_del(&p->link);
#endif
- js_free_rt(rt, p);
+ if (p->atom_type == JS_ATOM_TYPE_SYMBOL &&
+ p->hash != JS_ATOM_HASH_PRIVATE && p->hash != 0) {
+ /* live weak references are still present on this object: keep
+ it */
+ } else {
+ js_free_rt(rt, p);
+ }
rt->atom_count--;
assert(rt->atom_count >= 0);
}
@@ -2941,11 +2913,25 @@ static JSAtom JS_NewAtomStr(JSContext *ctx, JSString *p)
return __JS_NewAtom(rt, p, JS_ATOM_TYPE_STRING);
}
+/* XXX: optimize */
+static size_t count_ascii(const uint8_t *buf, size_t len)
+{
+ const uint8_t *p, *p_end;
+ p = buf;
+ p_end = buf + len;
+ while (p < p_end && *p < 128)
+ p++;
+ return p - buf;
+}
+
+/* str is UTF-8 encoded */
JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len)
{
JSValue val;
- if (len == 0 || !is_digit(*str)) {
+ if (len == 0 ||
+ (!is_digit(*str) &&
+ count_ascii((const uint8_t *)str, len) == len)) {
JSAtom atom = __JS_FindAtom(ctx->rt, str, len, JS_ATOM_TYPE_STRING);
if (atom)
return atom;
@@ -2968,8 +2954,9 @@ JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n)
} else {
char buf[11];
JSValue val;
- snprintf(buf, sizeof(buf), "%u", n);
- val = JS_NewString(ctx, buf);
+ size_t len;
+ len = u32toa(buf, n);
+ val = js_new_string8_len(ctx, buf, len);
if (JS_IsException(val))
return JS_ATOM_NULL;
return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
@@ -2984,8 +2971,9 @@ static JSAtom JS_NewAtomInt64(JSContext *ctx, int64_t n)
} else {
char buf[24];
JSValue val;
- snprintf(buf, sizeof(buf), "%" PRId64 , n);
- val = JS_NewString(ctx, buf);
+ size_t len;
+ len = i64toa(buf, n);
+ val = js_new_string8_len(ctx, buf, len);
if (JS_IsException(val))
return JS_ATOM_NULL;
return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
@@ -3051,10 +3039,7 @@ static const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size,
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];
+ c = string_get(str, i);
if ((q - buf) >= buf_size - UTF8_CHAR_LEN_MAX)
break;
if (c < 128) {
@@ -3080,8 +3065,8 @@ 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);
+ size_t len = u32toa(buf, __JS_AtomToUInt32(atom));
+ return js_new_string8_len(ctx, buf, len);
} else {
JSRuntime *rt = ctx->rt;
JSAtomStruct *p;
@@ -3145,7 +3130,7 @@ static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom)
JSRuntime *rt = ctx->rt;
JSAtomStruct *p1;
JSString *p;
- int c, len, ret;
+ int c, ret;
JSValue num, str;
if (__JS_AtomIsTaggedInt(atom))
@@ -3154,54 +3139,24 @@ static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom)
p1 = rt->atom_array[atom];
if (p1->atom_type != JS_ATOM_TYPE_STRING)
return JS_UNDEFINED;
+ switch(atom) {
+ case JS_ATOM_minus_zero:
+ return __JS_NewFloat64(ctx, -0.0);
+ case JS_ATOM_Infinity:
+ return __JS_NewFloat64(ctx, INFINITY);
+ case JS_ATOM_minus_Infinity:
+ return __JS_NewFloat64(ctx, -INFINITY);
+ case JS_ATOM_NaN:
+ return __JS_NewFloat64(ctx, NAN);
+ default:
+ break;
+ }
p = p1;
- len = p->len;
- if (p->is_wide_char) {
- const uint16_t *r = p->u.str16, *r_end = p->u.str16 + len;
- if (r >= r_end)
- return JS_UNDEFINED;
- c = *r;
- if (c == '-') {
- if (r >= r_end)
- return JS_UNDEFINED;
- r++;
- c = *r;
- /* -0 case is specific */
- if (c == '0' && len == 2)
- goto minus_zero;
- }
- /* XXX: should test NaN, but the tests do not check it */
- if (!is_num(c)) {
- /* XXX: String should be normalized, therefore 8-bit only */
- const uint16_t nfinity16[7] = { 'n', 'f', 'i', 'n', 'i', 't', 'y' };
- if (!(c =='I' && (r_end - r) == 8 &&
- !memcmp(r + 1, nfinity16, sizeof(nfinity16))))
- return JS_UNDEFINED;
- }
- } else {
- const uint8_t *r = p->u.str8, *r_end = p->u.str8 + len;
- if (r >= r_end)
- return JS_UNDEFINED;
- c = *r;
- if (c == '-') {
- if (r >= r_end)
- return JS_UNDEFINED;
- r++;
- c = *r;
- /* -0 case is specific */
- if (c == '0' && len == 2) {
- minus_zero:
- return __JS_NewFloat64(ctx, -0.0);
- }
- }
- if (!is_num(c)) {
- if (!(c =='I' && (r_end - r) == 8 &&
- !memcmp(r + 1, "nfinity", 7)))
- return JS_UNDEFINED;
- }
- }
- /* XXX: bignum: would be better to only accept integer to avoid
- relying on current floating point precision */
+ if (p->len == 0)
+ return JS_UNDEFINED;
+ c = string_get(p, 0);
+ if (!is_num(c) && c != '-')
+ return JS_UNDEFINED;
/* this is ECMA CanonicalNumericIndexString primitive */
num = JS_ToNumber(ctx, JS_MKPTR(JS_TAG_STRING, p));
if (JS_IsException(num))
@@ -3257,59 +3212,24 @@ static BOOL JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v)
return FALSE;
p = rt->atom_array[v];
return (((p->atom_type == JS_ATOM_TYPE_SYMBOL &&
- p->hash == JS_ATOM_HASH_SYMBOL) ||
+ p->hash != JS_ATOM_HASH_PRIVATE) ||
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)
+const char *JS_AtomToCStringLen(JSContext *ctx, size_t *plen, JSAtom atom)
{
JSValue str;
const char *cstr;
str = JS_AtomToString(ctx, atom);
- if (JS_IsException(str))
+ if (JS_IsException(str)) {
+ if (plen)
+ *plen = 0;
return NULL;
- cstr = JS_ToCString(ctx, str);
+ }
+ cstr = JS_ToCStringLen(ctx, plen, str);
JS_FreeValue(ctx, str);
return cstr;
}
@@ -3322,7 +3242,7 @@ static JSAtom js_atom_concat_str(JSContext *ctx, JSAtom name, const char *str1)
const char *cstr;
char *cstr2;
size_t len, len1;
-
+
str = JS_AtomToString(ctx, name);
if (JS_IsException(str))
return JS_ATOM_NULL;
@@ -3350,7 +3270,9 @@ static JSAtom js_atom_concat_str(JSContext *ctx, JSAtom name, const char *str1)
static JSAtom js_atom_concat_num(JSContext *ctx, JSAtom name, uint32_t n)
{
char buf[16];
- snprintf(buf, sizeof(buf), "%u", n);
+ size_t len;
+ len = u32toa(buf, n);
+ buf[len] = '\0';
return js_atom_concat_str(ctx, name, buf);
}
@@ -3361,19 +3283,37 @@ static inline BOOL JS_IsEmptyString(JSValueConst v)
/* JSClass support */
+#ifdef CONFIG_ATOMICS
+static pthread_mutex_t js_class_id_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
/* a new class ID is allocated if *pclass_id != 0 */
JSClassID JS_NewClassID(JSClassID *pclass_id)
{
JSClassID class_id;
- /* XXX: make it thread safe */
+#ifdef CONFIG_ATOMICS
+ pthread_mutex_lock(&js_class_id_mutex);
+#endif
class_id = *pclass_id;
if (class_id == 0) {
class_id = js_class_id_alloc++;
*pclass_id = class_id;
}
+#ifdef CONFIG_ATOMICS
+ pthread_mutex_unlock(&js_class_id_mutex);
+#endif
return class_id;
}
+JSClassID JS_GetClassID(JSValue v)
+{
+ JSObject *p;
+ if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT)
+ return JS_INVALID_CLASS_ID;
+ p = JS_VALUE_GET_OBJ(v);
+ return p->class_id;
+}
+
BOOL JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id)
{
return (class_id < rt->class_count &&
@@ -3448,7 +3388,7 @@ int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def)
return ret;
}
-static JSValue js_new_string8(JSContext *ctx, const uint8_t *buf, int len)
+static JSValue js_new_string8_len(JSContext *ctx, const char *buf, int len)
{
JSString *str;
@@ -3463,7 +3403,12 @@ static JSValue js_new_string8(JSContext *ctx, const uint8_t *buf, int len)
return JS_MKPTR(JS_TAG_STRING, str);
}
-static JSValue js_new_string16(JSContext *ctx, const uint16_t *buf, int len)
+static JSValue js_new_string8(JSContext *ctx, const char *buf)
+{
+ return js_new_string8_len(ctx, buf, strlen(buf));
+}
+
+static JSValue js_new_string16_len(JSContext *ctx, const uint16_t *buf, int len)
{
JSString *str;
str = js_alloc_string(ctx, len, 1);
@@ -3477,10 +3422,10 @@ static JSValue js_new_string_char(JSContext *ctx, uint16_t c)
{
if (c < 0x100) {
uint8_t ch8 = c;
- return js_new_string8(ctx, &ch8, 1);
+ return js_new_string8_len(ctx, (const char *)&ch8, 1);
} else {
uint16_t ch16 = c;
- return js_new_string16(ctx, &ch16, 1);
+ return js_new_string16_len(ctx, &ch16, 1);
}
}
@@ -3498,7 +3443,7 @@ static JSValue js_sub_string(JSContext *ctx, JSString *p, int start, int end)
c |= p->u.str16[i];
}
if (c > 0xFF)
- return js_new_string16(ctx, p->u.str16 + start, len);
+ return js_new_string16_len(ctx, p->u.str16 + start, len);
str = js_alloc_string(ctx, len, 0);
if (!str)
@@ -3509,7 +3454,7 @@ static JSValue js_sub_string(JSContext *ctx, JSString *p, int start, int end)
str->u.str8[len] = '\0';
return JS_MKPTR(JS_TAG_STRING, str);
} else {
- return js_new_string8(ctx, p->u.str8 + start, len);
+ return js_new_string8_len(ctx, (const char *)(p->u.str8 + start), len);
}
}
@@ -3668,28 +3613,23 @@ static int string_buffer_putc(StringBuffer *s, uint32_t c)
{
if (unlikely(c >= 0x10000)) {
/* surrogate pair */
- c -= 0x10000;
- if (string_buffer_putc16(s, (c >> 10) + 0xd800))
+ if (string_buffer_putc16(s, get_hi_surrogate(c)))
return -1;
- c = (c & 0x3ff) + 0xdc00;
+ c = get_lo_surrogate(c);
}
return string_buffer_putc16(s, c);
}
-static int string_get(const JSString *p, int idx) {
- return p->is_wide_char ? p->u.str16[idx] : p->u.str8[idx];
-}
-
static int string_getc(const JSString *p, int *pidx)
{
int idx, c, c1;
idx = *pidx;
if (p->is_wide_char) {
c = p->u.str16[idx++];
- if (c >= 0xd800 && c < 0xdc00 && idx < p->len) {
+ if (is_hi_surrogate(c) && idx < p->len) {
c1 = p->u.str16[idx];
- if (c1 >= 0xdc00 && c1 < 0xe000) {
- c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
+ if (is_lo_surrogate(c1)) {
+ c = from_surrogate(c, c1);
idx++;
}
}
@@ -3774,13 +3714,21 @@ static int string_buffer_concat_value(StringBuffer *s, JSValueConst v)
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;
+ if (JS_VALUE_GET_TAG(v) == JS_TAG_STRING_ROPE) {
+ JSStringRope *r = JS_VALUE_GET_STRING_ROPE(v);
+ /* recursion is acceptable because the rope depth is bounded */
+ if (string_buffer_concat_value(s, r->left))
+ return -1;
+ return string_buffer_concat_value(s, r->right);
+ } else {
+ v1 = JS_ToString(s->ctx, v);
+ if (JS_IsException(v1))
+ return string_buffer_set_error(s);
+ p = JS_VALUE_GET_STRING(v1);
+ res = string_buffer_concat(s, p, 0, p->len);
+ JS_FreeValue(s->ctx, v1);
+ return res;
+ }
}
p = JS_VALUE_GET_STRING(v);
return string_buffer_concat(s, p, 0, p->len);
@@ -3860,18 +3808,16 @@ JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len)
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;
+ len1 = count_ascii(p_start, buf_len);
+ p = p_start + len1;
if (len1 > JS_STRING_LEN_MAX)
return JS_ThrowInternalError(ctx, "string too long");
if (p == p_end) {
/* ASCII string */
- return js_new_string8(ctx, (const uint8_t *)buf, buf_len);
+ return js_new_string8_len(ctx, buf, buf_len);
} else {
if (string_buffer_init(ctx, b, buf_len))
goto fail;
@@ -3887,9 +3833,8 @@ JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len)
} else if (c <= 0x10FFFF) {
p = p_next;
/* surrogate pair */
- c -= 0x10000;
- string_buffer_putc16(b, (c >> 10) + 0xd800);
- c = (c & 0x3ff) + 0xdc00;
+ string_buffer_putc16(b, get_hi_surrogate(c));
+ c = get_lo_surrogate(c);
} else {
/* invalid char */
c = 0xfffd;
@@ -3945,11 +3890,6 @@ static JSValue JS_ConcatString3(JSContext *ctx, const char *str1,
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);
@@ -4027,13 +3967,12 @@ const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, BO
if (c < 0x80) {
*q++ = c;
} else {
- if (c >= 0xd800 && c < 0xdc00) {
+ if (is_hi_surrogate(c)) {
if (pos < len && !cesu8) {
c1 = src[pos];
- if (c1 >= 0xdc00 && c1 < 0xe000) {
+ if (is_lo_surrogate(c1)) {
pos++;
- /* surrogate pair */
- c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
+ c = from_surrogate(c, c1);
} else {
/* Keep unmatched surrogate code points */
/* c = 0xfffd; */ /* error */
@@ -4066,7 +4005,7 @@ void JS_FreeCString(JSContext *ctx, const char *ptr)
if (!ptr)
return;
/* purposely removing constness */
- p = (JSString *)(void *)(ptr - offsetof(JSString, u));
+ p = container_of(ptr, JSString, u);
JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
}
@@ -4092,20 +4031,21 @@ static int memcmp16(const uint16_t *src1, const uint16_t *src2, int len)
return 0;
}
-static int js_string_memcmp(const JSString *p1, const JSString *p2, int len)
+static int js_string_memcmp(const JSString *p1, int pos1, const JSString *p2,
+ int pos2, int len)
{
int res;
if (likely(!p1->is_wide_char)) {
if (likely(!p2->is_wide_char))
- res = memcmp(p1->u.str8, p2->u.str8, len);
+ res = memcmp(p1->u.str8 + pos1, p2->u.str8 + pos2, len);
else
- res = -memcmp16_8(p2->u.str16, p1->u.str8, len);
+ res = -memcmp16_8(p2->u.str16 + pos2, p1->u.str8 + pos1, len);
} else {
if (!p2->is_wide_char)
- res = memcmp16_8(p1->u.str16, p2->u.str8, len);
+ res = memcmp16_8(p1->u.str16 + pos1, p2->u.str8 + pos2, len);
else
- res = memcmp16(p1->u.str16, p2->u.str16, len);
+ res = memcmp16(p1->u.str16 + pos1, p2->u.str16 + pos2, len);
}
return res;
}
@@ -4116,7 +4056,7 @@ static int js_string_compare(JSContext *ctx,
{
int res, len;
len = min_int(p1->len, p2->len);
- res = js_string_memcmp(p1, p2, len);
+ res = js_string_memcmp(p1, 0, p2, 0, len);
if (res == 0) {
if (p1->len == p2->len)
res = 0;
@@ -4166,53 +4106,452 @@ static JSValue JS_ConcatString1(JSContext *ctx,
return JS_MKPTR(JS_TAG_STRING, p);
}
-/* op1 and op2 are converted to strings. For convience, op1 or op2 =
+static BOOL JS_ConcatStringInPlace(JSContext *ctx, JSString *p1, JSValueConst op2) {
+ if (JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {
+ JSString *p2 = JS_VALUE_GET_STRING(op2);
+ size_t size1;
+
+ if (p2->len == 0)
+ return TRUE;
+ if (p1->header.ref_count != 1)
+ return FALSE;
+ size1 = js_malloc_usable_size(ctx, p1);
+ if (p1->is_wide_char) {
+ if (size1 >= sizeof(*p1) + ((p1->len + p2->len) << 1)) {
+ if (p2->is_wide_char) {
+ memcpy(p1->u.str16 + p1->len, p2->u.str16, p2->len << 1);
+ p1->len += p2->len;
+ return TRUE;
+ } else {
+ size_t i;
+ for (i = 0; i < p2->len; i++) {
+ p1->u.str16[p1->len++] = p2->u.str8[i];
+ }
+ return TRUE;
+ }
+ }
+ } else if (!p2->is_wide_char) {
+ if (size1 >= sizeof(*p1) + p1->len + p2->len + 1) {
+ memcpy(p1->u.str8 + p1->len, p2->u.str8, p2->len);
+ p1->len += p2->len;
+ p1->u.str8[p1->len] = '\0';
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+static JSValue JS_ConcatString2(JSContext *ctx, JSValue op1, JSValue op2)
+{
+ JSValue ret;
+ JSString *p1, *p2;
+ p1 = JS_VALUE_GET_STRING(op1);
+ if (JS_ConcatStringInPlace(ctx, p1, op2)) {
+ JS_FreeValue(ctx, op2);
+ return op1;
+ }
+ p2 = JS_VALUE_GET_STRING(op2);
+ ret = JS_ConcatString1(ctx, p1, p2);
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ return ret;
+}
+
+/* Return the character at position 'idx'. 'val' must be a string or rope */
+static int string_rope_get(JSValueConst val, uint32_t idx)
+{
+ if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
+ return string_get(JS_VALUE_GET_STRING(val), idx);
+ } else {
+ JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val);
+ uint32_t len;
+ if (JS_VALUE_GET_TAG(r->left) == JS_TAG_STRING)
+ len = JS_VALUE_GET_STRING(r->left)->len;
+ else
+ len = JS_VALUE_GET_STRING_ROPE(r->left)->len;
+ if (idx < len)
+ return string_rope_get(r->left, idx);
+ else
+ return string_rope_get(r->right, idx - len);
+ }
+}
+
+typedef struct {
+ JSValueConst stack[JS_STRING_ROPE_MAX_DEPTH];
+ int stack_len;
+} JSStringRopeIter;
+
+static void string_rope_iter_init(JSStringRopeIter *s, JSValueConst val)
+{
+ s->stack_len = 0;
+ s->stack[s->stack_len++] = val;
+}
+
+/* iterate thru a rope and return the strings in order */
+static JSString *string_rope_iter_next(JSStringRopeIter *s)
+{
+ JSValueConst val;
+ JSStringRope *r;
+
+ if (s->stack_len == 0)
+ return NULL;
+ val = s->stack[--s->stack_len];
+ for(;;) {
+ if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING)
+ return JS_VALUE_GET_STRING(val);
+ r = JS_VALUE_GET_STRING_ROPE(val);
+ assert(s->stack_len < JS_STRING_ROPE_MAX_DEPTH);
+ s->stack[s->stack_len++] = r->right;
+ val = r->left;
+ }
+}
+
+static uint32_t string_rope_get_len(JSValueConst val)
+{
+ if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING)
+ return JS_VALUE_GET_STRING(val)->len;
+ else
+ return JS_VALUE_GET_STRING_ROPE(val)->len;
+}
+
+static int js_string_rope_compare(JSContext *ctx, JSValueConst op1,
+ JSValueConst op2, BOOL eq_only)
+{
+ uint32_t len1, len2, len, pos1, pos2, l;
+ int res;
+ JSStringRopeIter it1, it2;
+ JSString *p1, *p2;
+
+ len1 = string_rope_get_len(op1);
+ len2 = string_rope_get_len(op2);
+ /* no need to go further for equality test if
+ different length */
+ if (eq_only && len1 != len2)
+ return 1;
+ len = min_uint32(len1, len2);
+ string_rope_iter_init(&it1, op1);
+ string_rope_iter_init(&it2, op2);
+ p1 = string_rope_iter_next(&it1);
+ p2 = string_rope_iter_next(&it2);
+ pos1 = 0;
+ pos2 = 0;
+ while (len != 0) {
+ l = min_uint32(p1->len - pos1, p2->len - pos2);
+ l = min_uint32(l, len);
+ res = js_string_memcmp(p1, pos1, p2, pos2, l);
+ if (res != 0)
+ return res;
+ len -= l;
+ pos1 += l;
+ if (pos1 >= p1->len) {
+ p1 = string_rope_iter_next(&it1);
+ pos1 = 0;
+ }
+ pos2 += l;
+ if (pos2 >= p2->len) {
+ p2 = string_rope_iter_next(&it2);
+ pos2 = 0;
+ }
+ }
+
+ if (len1 == len2)
+ res = 0;
+ else if (len1 < len2)
+ res = -1;
+ else
+ res = 1;
+ return res;
+}
+
+/* 'rope' must be a rope. return a string and modify the rope so that
+ it won't need to be linearized again. */
+static JSValue js_linearize_string_rope(JSContext *ctx, JSValue rope)
+{
+ StringBuffer b_s, *b = &b_s;
+ JSStringRope *r;
+ JSValue ret;
+
+ r = JS_VALUE_GET_STRING_ROPE(rope);
+
+ /* check whether it is already linearized */
+ if (JS_VALUE_GET_TAG(r->right) == JS_TAG_STRING &&
+ JS_VALUE_GET_STRING(r->right)->len == 0) {
+ ret = JS_DupValue(ctx, r->left);
+ JS_FreeValue(ctx, rope);
+ return ret;
+ }
+ if (string_buffer_init2(ctx, b, r->len, r->is_wide_char))
+ goto fail;
+ if (string_buffer_concat_value(b, rope))
+ goto fail;
+ ret = string_buffer_end(b);
+ if (r->header.ref_count > 1) {
+ /* update the rope so that it won't need to be linearized again */
+ JS_FreeValue(ctx, r->left);
+ JS_FreeValue(ctx, r->right);
+ r->left = JS_DupValue(ctx, ret);
+ r->right = JS_AtomToString(ctx, JS_ATOM_empty_string);
+ }
+ JS_FreeValue(ctx, rope);
+ return ret;
+ fail:
+ JS_FreeValue(ctx, rope);
+ return JS_EXCEPTION;
+}
+
+static JSValue js_rebalancee_string_rope(JSContext *ctx, JSValueConst rope);
+
+/* op1 and op2 must be strings or string ropes */
+static JSValue js_new_string_rope(JSContext *ctx, JSValue op1, JSValue op2)
+{
+ uint32_t len;
+ int is_wide_char, depth;
+ JSStringRope *r;
+ JSValue res;
+
+ if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING) {
+ JSString *p1 = JS_VALUE_GET_STRING(op1);
+ len = p1->len;
+ is_wide_char = p1->is_wide_char;
+ depth = 0;
+ } else {
+ JSStringRope *r1 = JS_VALUE_GET_STRING_ROPE(op1);
+ len = r1->len;
+ is_wide_char = r1->is_wide_char;
+ depth = r1->depth;
+ }
+
+ if (JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {
+ JSString *p2 = JS_VALUE_GET_STRING(op2);
+ len += p2->len;
+ is_wide_char |= p2->is_wide_char;
+ } else {
+ JSStringRope *r2 = JS_VALUE_GET_STRING_ROPE(op2);
+ len += r2->len;
+ is_wide_char |= r2->is_wide_char;
+ depth = max_int(depth, r2->depth);
+ }
+ if (len > JS_STRING_LEN_MAX) {
+ JS_ThrowInternalError(ctx, "string too long");
+ goto fail;
+ }
+ r = js_malloc(ctx, sizeof(*r));
+ if (!r)
+ goto fail;
+ r->header.ref_count = 1;
+ r->len = len;
+ r->is_wide_char = is_wide_char;
+ r->depth = depth + 1;
+ r->left = op1;
+ r->right = op2;
+ res = JS_MKPTR(JS_TAG_STRING_ROPE, r);
+ if (r->depth > JS_STRING_ROPE_MAX_DEPTH) {
+ JSValue res2;
+#ifdef DUMP_ROPE_REBALANCE
+ printf("rebalance: initial depth=%d\n", r->depth);
+#endif
+ res2 = js_rebalancee_string_rope(ctx, res);
+#ifdef DUMP_ROPE_REBALANCE
+ if (JS_VALUE_GET_TAG(res2) == JS_TAG_STRING_ROPE)
+ printf("rebalance: final depth=%d\n", JS_VALUE_GET_STRING_ROPE(res2)->depth);
+#endif
+ JS_FreeValue(ctx, res);
+ return res2;
+ } else {
+ return res;
+ }
+ fail:
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ return JS_EXCEPTION;
+}
+
+#define ROPE_N_BUCKETS 44
+
+/* Fibonacii numbers starting from F_2 */
+static const uint32_t rope_bucket_len[ROPE_N_BUCKETS] = {
+ 1, 2, 3, 5,
+ 8, 13, 21, 34,
+ 55, 89, 144, 233,
+ 377, 610, 987, 1597,
+ 2584, 4181, 6765, 10946,
+ 17711, 28657, 46368, 75025,
+ 121393, 196418, 317811, 514229,
+ 832040, 1346269, 2178309, 3524578,
+ 5702887, 9227465, 14930352, 24157817,
+ 39088169, 63245986, 102334155, 165580141,
+ 267914296, 433494437, 701408733, 1134903170, /* > JS_STRING_LEN_MAX */
+};
+
+static int js_rebalancee_string_rope_rec(JSContext *ctx, JSValue *buckets,
+ JSValueConst val)
+{
+ if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
+ JSString *p = JS_VALUE_GET_STRING(val);
+ uint32_t len, i;
+ JSValue a, b;
+
+ len = p->len;
+ if (len == 0)
+ return 0; /* nothing to do */
+ /* find the bucket i so that rope_bucket_len[i] <= len <
+ rope_bucket_len[i + 1] and concatenate the ropes in the
+ buckets before */
+ a = JS_NULL;
+ i = 0;
+ while (len >= rope_bucket_len[i + 1]) {
+ b = buckets[i];
+ if (!JS_IsNull(b)) {
+ buckets[i] = JS_NULL;
+ if (JS_IsNull(a)) {
+ a = b;
+ } else {
+ a = js_new_string_rope(ctx, b, a);
+ if (JS_IsException(a))
+ return -1;
+ }
+ }
+ i++;
+ }
+ if (!JS_IsNull(a)) {
+ a = js_new_string_rope(ctx, a, JS_DupValue(ctx, val));
+ if (JS_IsException(a))
+ return -1;
+ } else {
+ a = JS_DupValue(ctx, val);
+ }
+ while (!JS_IsNull(buckets[i])) {
+ a = js_new_string_rope(ctx, buckets[i], a);
+ buckets[i] = JS_NULL;
+ if (JS_IsException(a))
+ return -1;
+ i++;
+ }
+ buckets[i] = a;
+ } else {
+ JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val);
+ js_rebalancee_string_rope_rec(ctx, buckets, r->left);
+ js_rebalancee_string_rope_rec(ctx, buckets, r->right);
+ }
+ return 0;
+}
+
+/* Return a new rope which is balanced. Algorithm from "Ropes: an
+ Alternative to Strings", Hans-J. Boehm, Russ Atkinson and Michael
+ Plass. */
+static JSValue js_rebalancee_string_rope(JSContext *ctx, JSValueConst rope)
+{
+ JSValue buckets[ROPE_N_BUCKETS], a, b;
+ int i;
+
+ for(i = 0; i < ROPE_N_BUCKETS; i++)
+ buckets[i] = JS_NULL;
+ if (js_rebalancee_string_rope_rec(ctx, buckets, rope))
+ goto fail;
+ a = JS_NULL;
+ for(i = 0; i < ROPE_N_BUCKETS; i++) {
+ b = buckets[i];
+ if (!JS_IsNull(b)) {
+ buckets[i] = JS_NULL;
+ if (JS_IsNull(a)) {
+ a = b;
+ } else {
+ a = js_new_string_rope(ctx, b, a);
+ if (JS_IsException(a))
+ goto fail;
+ }
+ }
+ }
+ /* fail safe */
+ if (JS_IsNull(a))
+ return JS_AtomToString(ctx, JS_ATOM_empty_string);
+ else
+ return a;
+ fail:
+ for(i = 0; i < ROPE_N_BUCKETS; i++) {
+ JS_FreeValue(ctx, buckets[i]);
+ }
+ return JS_EXCEPTION;
+}
+
+/* op1 and op2 are converted to strings. For convenience, op1 or op2 =
JS_EXCEPTION are accepted and return JS_EXCEPTION. */
static JSValue JS_ConcatString(JSContext *ctx, JSValue op1, JSValue op2)
{
- JSValue ret;
JSString *p1, *p2;
- if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_STRING)) {
+ if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_STRING &&
+ JS_VALUE_GET_TAG(op1) != JS_TAG_STRING_ROPE)) {
op1 = JS_ToStringFree(ctx, op1);
if (JS_IsException(op1)) {
JS_FreeValue(ctx, op2);
return JS_EXCEPTION;
}
}
- if (unlikely(JS_VALUE_GET_TAG(op2) != JS_TAG_STRING)) {
+ if (unlikely(JS_VALUE_GET_TAG(op2) != JS_TAG_STRING &&
+ JS_VALUE_GET_TAG(op2) != JS_TAG_STRING_ROPE)) {
op2 = JS_ToStringFree(ctx, op2);
if (JS_IsException(op2)) {
JS_FreeValue(ctx, op1);
return JS_EXCEPTION;
}
}
- 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';
+ /* normal concatenation for short strings */
+ if (JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {
+ p2 = JS_VALUE_GET_STRING(op2);
+ if (p2->len == 0) {
+ JS_FreeValue(ctx, op2);
+ return op1;
+ }
+ if (p2->len <= JS_STRING_ROPE_SHORT_LEN) {
+ if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING) {
+ p1 = JS_VALUE_GET_STRING(op1);
+ if (p1->len <= JS_STRING_ROPE_SHORT2_LEN) {
+ return JS_ConcatString2(ctx, op1, op2);
+ } else {
+ return js_new_string_rope(ctx, op1, op2);
+ }
+ } else {
+ JSStringRope *r1;
+ r1 = JS_VALUE_GET_STRING_ROPE(op1);
+ if (JS_VALUE_GET_TAG(r1->right) == JS_TAG_STRING &&
+ JS_VALUE_GET_STRING(r1->right)->len <= JS_STRING_ROPE_SHORT_LEN) {
+ JSValue val, ret;
+ val = JS_ConcatString2(ctx, JS_DupValue(ctx, r1->right), op2);
+ if (JS_IsException(val)) {
+ JS_FreeValue(ctx, op1);
+ return JS_EXCEPTION;
+ }
+ ret = js_new_string_rope(ctx, JS_DupValue(ctx, r1->left), val);
+ JS_FreeValue(ctx, op1);
+ return ret;
+ }
+ }
+ }
+ } else if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING) {
+ JSStringRope *r2;
+ p1 = JS_VALUE_GET_STRING(op1);
+ if (p1->len == 0) {
+ JS_FreeValue(ctx, op1);
+ return op2;
+ }
+ r2 = JS_VALUE_GET_STRING_ROPE(op2);
+ if (JS_VALUE_GET_TAG(r2->left) == JS_TAG_STRING &&
+ JS_VALUE_GET_STRING(r2->left)->len <= JS_STRING_ROPE_SHORT_LEN) {
+ JSValue val, ret;
+ val = JS_ConcatString2(ctx, op1, JS_DupValue(ctx, r2->left));
+ if (JS_IsException(val)) {
+ JS_FreeValue(ctx, op2);
+ return JS_EXCEPTION;
+ }
+ ret = js_new_string_rope(ctx, val, JS_DupValue(ctx, r2->right));
+ JS_FreeValue(ctx, op2);
+ return ret;
}
- ret_op1:
- JS_FreeValue(ctx, op2);
- return op1;
}
- ret = JS_ConcatString1(ctx, p1, p2);
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- return ret;
+ return js_new_string_rope(ctx, op1, op2);
}
/* Shape support */
@@ -4352,7 +4691,7 @@ static no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto,
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;
@@ -4445,6 +4784,7 @@ static no_inline int resize_properties(JSContext *ctx, JSShape **psh,
JSShapeProperty *pr;
void *sh_alloc;
intptr_t h;
+ JSShape *old_sh;
sh = *psh;
new_size = max_int(count, sh->prop_size * 3 / 2);
@@ -4460,19 +4800,21 @@ static no_inline int resize_properties(JSContext *ctx, JSShape **psh,
new_hash_size = sh->prop_hash_mask + 1;
while (new_hash_size < new_size)
new_hash_size = 2 * new_hash_size;
+ /* resize the property shapes. Using js_realloc() is not possible in
+ case the GC runs during the allocation */
+ old_sh = sh;
+ sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
+ if (!sh_alloc)
+ return -1;
+ sh = get_shape_from_alloc(sh_alloc, new_hash_size);
+ list_del(&old_sh->header.link);
+ /* copy all the shape properties */
+ memcpy(sh, old_sh,
+ sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count);
+ list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
+
if (new_hash_size != (sh->prop_hash_mask + 1)) {
- JSShape *old_sh;
/* resize the hash table and the properties */
- old_sh = sh;
- sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
- if (!sh_alloc)
- return -1;
- sh = get_shape_from_alloc(sh_alloc, new_hash_size);
- list_del(&old_sh->header.link);
- /* copy all the fields and the properties */
- memcpy(sh, old_sh,
- sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count);
- list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
new_hash_mask = new_hash_size - 1;
sh->prop_hash_mask = new_hash_mask;
memset(prop_hash_end(sh) - new_hash_size, 0,
@@ -4484,20 +4826,12 @@ static no_inline int resize_properties(JSContext *ctx, JSShape **psh,
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);
+ /* just copy the previous hash table */
+ memcpy(prop_hash_end(sh) - new_hash_size, prop_hash_end(old_sh) - new_hash_size,
+ sizeof(prop_hash_end(sh)[0]) * new_hash_size);
}
+ js_free(ctx, get_alloc_from_shape(old_sh));
*psh = sh;
sh->prop_size = new_size;
return 0;
@@ -4512,7 +4846,7 @@ static int compact_properties(JSContext *ctx, JSObject *p)
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);
@@ -4534,7 +4868,7 @@ static int compact_properties(JSContext *ctx, JSObject *p)
list_del(&old_sh->header.link);
memcpy(sh, old_sh, sizeof(JSShape));
list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
-
+
memset(prop_hash_end(sh) - new_hash_size, 0,
sizeof(prop_hash_end(sh)[0]) * new_hash_size);
@@ -4563,7 +4897,7 @@ static int compact_properties(JSContext *ctx, JSObject *p)
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)
@@ -4690,7 +5024,7 @@ static __maybe_unused void JS_DumpShapes(JSRuntime *rt)
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++) {
@@ -4726,10 +5060,10 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas
p->is_exotic = 0;
p->fast_array = 0;
p->is_constructor = 0;
- p->is_uncatchable_error = 0;
+ p->has_immutable_prototype = 0;
p->tmp_mark = 0;
p->is_HTMLDDA = 0;
- p->first_weak_ref = NULL;
+ p->weakref_count = 0;
p->u.opaque = NULL;
p->shape = sh;
p->prop = js_malloc(ctx, sizeof(JSProperty) * sh->prop_size);
@@ -4776,6 +5110,7 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas
case JS_CLASS_UINT32_ARRAY:
case JS_CLASS_BIG_INT64_ARRAY:
case JS_CLASS_BIG_UINT64_ARRAY:
+ case JS_CLASS_FLOAT16_ARRAY:
case JS_CLASS_FLOAT32_ARRAY:
case JS_CLASS_FLOAT64_ARRAY:
p->is_exotic = 1;
@@ -4793,10 +5128,6 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas
case JS_CLASS_SYMBOL:
case JS_CLASS_DATE:
case JS_CLASS_BIG_INT:
-#ifdef CONFIG_BIGNUM
- case JS_CLASS_BIG_FLOAT:
- case JS_CLASS_BIG_DECIMAL:
-#endif
p->u.object_data = JS_UNDEFINED;
goto set_exotic;
case JS_CLASS_REGEXP:
@@ -4856,10 +5187,6 @@ static JSValue JS_GetObjectData(JSContext *ctx, JSValueConst obj)
case JS_CLASS_SYMBOL:
case JS_CLASS_DATE:
case JS_CLASS_BIG_INT:
-#ifdef CONFIG_BIGNUM
- case JS_CLASS_BIG_FLOAT:
- case JS_CLASS_BIG_DECIMAL:
-#endif
return JS_DupValue(ctx, p->u.object_data);
}
}
@@ -4880,12 +5207,10 @@ static int JS_SetObjectData(JSContext *ctx, JSValueConst obj, JSValue val)
case JS_CLASS_SYMBOL:
case JS_CLASS_DATE:
case JS_CLASS_BIG_INT:
-#ifdef CONFIG_BIGNUM
- case JS_CLASS_BIG_FLOAT:
- case JS_CLASS_BIG_DECIMAL:
-#endif
JS_FreeValue(ctx, p->u.object_data);
- p->u.object_data = val;
+ p->u.object_data = val; /* for JS_CLASS_STRING, 'val' must
+ be JS_TAG_STRING (and not a
+ rope) */
return 0;
}
}
@@ -5016,7 +5341,7 @@ static JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func,
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;
@@ -5033,6 +5358,10 @@ static JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func,
if (!name)
name = "";
name_atom = JS_NewAtom(ctx, name);
+ if (name_atom == JS_ATOM_NULL) {
+ JS_FreeValue(ctx, func_obj);
+ return JS_EXCEPTION;
+ }
js_function_set_properties(ctx, func_obj, name_atom, length);
JS_FreeAtom(ctx, name_atom);
return func_obj;
@@ -5227,10 +5556,12 @@ static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref)
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 */
+ list_del(&var_ref->var_ref_link); /* still on the stack */
+ if (var_ref->async_func)
+ async_func_free(rt, var_ref->async_func);
}
+ remove_gc_object(&var_ref->header);
js_free_rt(rt, var_ref);
}
}
@@ -5328,7 +5659,7 @@ static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
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) {
+ if (var_ref) {
mark_func(rt, &var_ref->header);
}
}
@@ -5370,7 +5701,15 @@ static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val)
{
JSObject *p = JS_VALUE_GET_OBJ(val);
JSForInIterator *it = p->u.for_in_iterator;
+ int i;
+
JS_FreeValueRT(rt, it->obj);
+ if (!it->is_array) {
+ for(i = 0; i < it->atom_count; i++) {
+ JS_FreeAtomRT(rt, it->tab_atom[i].atom);
+ }
+ js_free_rt(rt, it->tab_atom);
+ }
js_free_rt(rt, it);
}
@@ -5407,10 +5746,6 @@ static void free_object(JSRuntime *rt, JSObject *p)
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));
@@ -5422,10 +5757,21 @@ static void free_object(JSRuntime *rt, JSObject *p)
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);
+ if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES) {
+ if (p->header.ref_count == 0 && p->weakref_count == 0) {
+ js_free_rt(rt, p);
+ } else {
+ /* keep the object structure because there are may be
+ references to it */
+ list_add_tail(&p->header.link, &rt->gc_zero_ref_count_list);
+ }
} else {
- js_free_rt(rt, p);
+ /* keep the object structure in case there are weak references to it */
+ if (p->weakref_count == 0) {
+ js_free_rt(rt, p);
+ } else {
+ p->header.mark = 0; /* reset the mark so that the weakref can be freed */
+ }
}
}
@@ -5438,6 +5784,9 @@ static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp)
case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
free_function_bytecode(rt, (JSFunctionBytecode *)gp);
break;
+ case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
+ __async_func_free(rt, (JSAsyncFunctionState *)gp);
+ break;
default:
abort();
}
@@ -5447,7 +5796,7 @@ static void free_zero_refcount(JSRuntime *rt)
{
struct list_head *el;
JSGCObjectHeader *p;
-
+
rt->gc_phase = JS_GC_PHASE_DECREF;
for(;;) {
el = rt->gc_zero_ref_count_list.next;
@@ -5491,6 +5840,15 @@ void __JS_FreeValueRT(JSRuntime *rt, JSValue v)
}
}
break;
+ case JS_TAG_STRING_ROPE:
+ /* Note: recursion is acceptable because the rope depth is bounded */
+ {
+ JSStringRope *p = JS_VALUE_GET_STRING_ROPE(v);
+ JS_FreeValueRT(rt, p->left);
+ JS_FreeValueRT(rt, p->right);
+ js_free_rt(rt, p);
+ }
+ break;
case JS_TAG_OBJECT:
case JS_TAG_FUNCTION_BYTECODE:
{
@@ -5498,6 +5856,7 @@ void __JS_FreeValueRT(JSRuntime *rt, JSValue v)
if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {
list_del(&p->link);
list_add(&p->link, &rt->gc_zero_ref_count_list);
+ p->mark = 1; /* indicate that the object is about to be freed */
if (rt->gc_phase == JS_GC_PHASE_NONE) {
free_zero_refcount(rt);
}
@@ -5508,24 +5867,11 @@ void __JS_FreeValueRT(JSRuntime *rt, JSValue v)
abort(); /* never freed here */
break;
case JS_TAG_BIG_INT:
-#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_FLOAT:
-#endif
{
- JSBigFloat *bf = JS_VALUE_GET_PTR(v);
- bf_delete(&bf->num);
- js_free_rt(rt, bf);
- }
- break;
-#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_DECIMAL:
- {
- JSBigDecimal *bf = JS_VALUE_GET_PTR(v);
- bfdec_delete(&bf->num);
- js_free_rt(rt, bf);
+ JSBigInt *p = JS_VALUE_GET_PTR(v);
+ js_free_rt(rt, p);
}
break;
-#endif
case JS_TAG_SYMBOL:
{
JSAtomStruct *p = JS_VALUE_GET_PTR(v);
@@ -5533,7 +5879,6 @@ void __JS_FreeValueRT(JSRuntime *rt, JSValue v)
}
break;
default:
- printf("__JS_FreeValue: unknown tag=%d\n", tag);
abort();
}
}
@@ -5545,6 +5890,36 @@ void __JS_FreeValue(JSContext *ctx, JSValue v)
/* garbage collection */
+static void gc_remove_weak_objects(JSRuntime *rt)
+{
+ struct list_head *el;
+
+ /* add the freed objects to rt->gc_zero_ref_count_list so that
+ rt->weakref_list is not modified while we traverse it */
+ rt->gc_phase = JS_GC_PHASE_DECREF;
+
+ list_for_each(el, &rt->weakref_list) {
+ JSWeakRefHeader *wh = list_entry(el, JSWeakRefHeader, link);
+ switch(wh->weakref_type) {
+ case JS_WEAKREF_TYPE_MAP:
+ map_delete_weakrefs(rt, wh);
+ break;
+ case JS_WEAKREF_TYPE_WEAKREF:
+ weakref_delete_weakref(rt, wh);
+ break;
+ case JS_WEAKREF_TYPE_FINREC:
+ finrec_delete_weakref(rt, wh);
+ break;
+ default:
+ abort();
+ }
+ }
+
+ rt->gc_phase = JS_GC_PHASE_NONE;
+ /* free the freed objects here. */
+ free_zero_refcount(rt);
+}
+
static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
JSGCObjectTypeEnum type)
{
@@ -5596,11 +5971,9 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp,
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);
- }
+ /* 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);
}
@@ -5634,16 +6007,32 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp,
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);
+ if (var_ref->is_detached) {
+ JS_MarkValue(rt, *var_ref->pvalue, mark_func);
+ } else if (var_ref->async_func) {
+ mark_func(rt, &var_ref->async_func->header);
+ }
}
break;
case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
{
- JSAsyncFunctionData *s = (JSAsyncFunctionData *)gp;
- if (s->is_active)
- async_func_mark(rt, &s->func_state, mark_func);
+ JSAsyncFunctionState *s = (JSAsyncFunctionState *)gp;
+ JSStackFrame *sf = &s->frame;
+ JSValue *sp;
+
+ if (!s->is_completed) {
+ JS_MarkValue(rt, sf->cur_func, mark_func);
+ JS_MarkValue(rt, s->this_val, mark_func);
+ /* sf->cur_sp = NULL if the function is running */
+ if (sf->cur_sp) {
+ /* if the function is running, cur_sp is not known so we
+ cannot mark the stack. Marking the variables is not needed
+ because a running function cannot be part of a removable
+ cycle */
+ for(sp = sf->arg_buf; sp < sf->cur_sp; sp++)
+ JS_MarkValue(rt, *sp, mark_func);
+ }
+ }
JS_MarkValue(rt, s->resolving_funcs[0], mark_func);
JS_MarkValue(rt, s->resolving_funcs[1], mark_func);
}
@@ -5681,7 +6070,7 @@ 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
@@ -5728,7 +6117,7 @@ static void gc_scan(JSRuntime *rt)
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);
@@ -5751,12 +6140,13 @@ static void gc_free_cycles(JSRuntime *rt)
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. */
+ /* Only need to free the GC object associated with JS values
+ or async functions. The rest will be automatically removed
+ because they must be referenced by them. */
switch(p->gc_obj_type) {
case JS_GC_OBJ_TYPE_JS_OBJECT:
case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
+ case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
#ifdef DUMP_GC_FREE
if (!header_done) {
printf("Freeing cycles:\n");
@@ -5774,19 +6164,33 @@ static void gc_free_cycles(JSRuntime *rt)
}
}
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);
+ p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE ||
+ p->gc_obj_type == JS_GC_OBJ_TYPE_ASYNC_FUNCTION);
+ if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT &&
+ ((JSObject *)p)->weakref_count != 0) {
+ /* keep the object because there are weak references to it */
+ p->mark = 0;
+ } else {
+ js_free_rt(rt, p);
+ }
}
init_list_head(&rt->gc_zero_ref_count_list);
}
-void JS_RunGC(JSRuntime *rt)
+static void JS_RunGCInternal(JSRuntime *rt, BOOL remove_weak_objects)
{
+ if (remove_weak_objects) {
+ /* free the weakly referenced object or symbol structures, delete
+ the associated Map/Set entries and queue the finalization
+ registry callbacks. */
+ gc_remove_weak_objects(rt);
+ }
+
/* decrement the reference of the children of each object. mark =
1 after this pass. */
gc_decref(rt);
@@ -5798,6 +6202,11 @@ void JS_RunGC(JSRuntime *rt)
gc_free_cycles(rt);
}
+void JS_RunGC(JSRuntime *rt)
+{
+ JS_RunGCInternal(rt, TRUE);
+}
+
/* Return false if not an object or if the object has already been
freed (zombie objects are visible in finalizers when freeing
cycles). */
@@ -5881,11 +6290,7 @@ static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp)
compute_jsstring_size(JS_VALUE_GET_STRING(val), hp);
break;
case JS_TAG_BIG_INT:
-#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_FLOAT:
- case JS_TAG_BIG_DECIMAL:
-#endif
- /* should track JSBigFloat usage */
+ /* should track JSBigInt usage */
break;
}
}
@@ -6011,10 +6416,6 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
case JS_CLASS_SYMBOL: /* u.object_data */
case JS_CLASS_DATE: /* u.object_data */
case JS_CLASS_BIG_INT: /* u.object_data */
-#ifdef CONFIG_BIGNUM
- case JS_CLASS_BIG_FLOAT: /* u.object_data */
- case JS_CLASS_BIG_DECIMAL: /* u.object_data */
-#endif
compute_value_size(p->u.object_data, hp);
break;
case JS_CLASS_C_FUNCTION: /* u.cfunc */
@@ -6105,12 +6506,10 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
case JS_CLASS_UINT32_ARRAY: /* u.typed_array / u.array */
case JS_CLASS_BIG_INT64_ARRAY: /* u.typed_array / u.array */
case JS_CLASS_BIG_UINT64_ARRAY: /* u.typed_array / u.array */
+ case JS_CLASS_FLOAT16_ARRAY: /* u.typed_array / u.array */
case JS_CLASS_FLOAT32_ARRAY: /* u.typed_array / u.array */
case JS_CLASS_FLOAT64_ARRAY: /* u.typed_array / u.array */
case JS_CLASS_DATAVIEW: /* u.typed_array */
-#ifdef CONFIG_BIGNUM
- case JS_CLASS_FLOAT_ENV: /* u.float_env */
-#endif
case JS_CLASS_MAP: /* u.map_state */
case JS_CLASS_SET: /* u.map_state */
case JS_CLASS_WEAKMAP: /* u.map_state */
@@ -6180,12 +6579,8 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt)
{
- fprintf(fp, "QuickJS memory usage -- "
-#ifdef CONFIG_BIGNUM
- "BigNum "
-#endif
- CONFIG_VERSION " version, %d-bit, malloc limit: %"PRId64"\n\n",
- (int)sizeof(void *) * 8, (int64_t)(ssize_t)s->malloc_limit);
+ fprintf(fp, "QuickJS memory usage -- %d-bit, malloc limit: %"PRId64"\n\n",
+ (int)sizeof(void *) * 8, s->malloc_limit);
#if 1
if (rt) {
static const struct {
@@ -6231,10 +6626,10 @@ void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt)
if (obj_classes[0])
fprintf(fp, " %5d %2.0d %s\n", obj_classes[0], 0, "none");
for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) {
- if (obj_classes[class_id]) {
+ if (obj_classes[class_id] && class_id < rt->class_count) {
char buf[ATOM_GET_STR_BUF_SIZE];
fprintf(fp, " %5d %2.0d %s\n", obj_classes[class_id], class_id,
- JS_AtomGetStrRT(rt, buf, sizeof(buf), js_std_class_def[class_id - 1].class_name));
+ JS_AtomGetStrRT(rt, buf, sizeof(buf), rt->class_array[class_id].class_name));
}
}
if (obj_classes[JS_CLASS_INIT_COUNT])
@@ -6318,6 +6713,7 @@ JSValue JS_Throw(JSContext *ctx, JSValue obj)
JSRuntime *rt = ctx->rt;
JS_FreeValue(ctx, rt->current_exception);
rt->current_exception = obj;
+ rt->current_exception_is_uncatchable = FALSE;
return JS_EXCEPTION;
}
@@ -6327,10 +6723,15 @@ JSValue JS_GetException(JSContext *ctx)
JSValue val;
JSRuntime *rt = ctx->rt;
val = rt->current_exception;
- rt->current_exception = JS_NULL;
+ rt->current_exception = JS_UNINITIALIZED;
return val;
}
+JS_BOOL JS_HasException(JSContext *ctx)
+{
+ return !JS_IsUninitialized(ctx->rt->current_exception);
+}
+
static void dbuf_put_leb128(DynBuf *s, uint32_t v)
{
uint32_t a;
@@ -6386,49 +6787,72 @@ static int get_sleb128(int32_t *pval, const uint8_t *buf,
return ret;
}
+/* use pc_value = -1 to get the position of the function definition */
static int find_line_num(JSContext *ctx, JSFunctionBytecode *b,
- uint32_t pc_value)
+ uint32_t pc_value, int *pcol_num)
{
const uint8_t *p_end, *p;
- int new_line_num, line_num, pc, v, ret;
+ int new_line_num, line_num, pc, v, ret, new_col_num, col_num;
+ uint32_t val;
unsigned int op;
- if (!b->has_debug || !b->debug.pc2line_buf) {
- /* function was stripped */
- return -1;
- }
+ if (!b->has_debug || !b->debug.pc2line_buf)
+ goto fail; /* function was stripped */
p = b->debug.pc2line_buf;
p_end = p + b->debug.pc2line_len;
- 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);
+
+ /* get the function line and column numbers */
+ ret = get_leb128(&val, p, p_end);
+ if (ret < 0)
+ goto fail;
+ p += ret;
+ line_num = val + 1;
+
+ ret = get_leb128(&val, p, p_end);
+ if (ret < 0)
+ goto fail;
+ p += ret;
+ col_num = val + 1;
+
+ if (pc_value != -1) {
+ pc = 0;
+ while (p < p_end) {
+ op = *p++;
+ if (op == 0) {
+ ret = get_leb128(&val, p, p_end);
+ if (ret < 0)
+ goto fail;
+ pc += val;
+ p += ret;
+ ret = get_sleb128(&v, p, p_end);
+ if (ret < 0)
+ goto fail;
+ p += ret;
+ new_line_num = line_num + v;
+ } else {
+ op -= PC2LINE_OP_FIRST;
+ pc += (op / PC2LINE_RANGE);
+ new_line_num = line_num + (op % PC2LINE_RANGE) + PC2LINE_BASE;
+ }
+ ret = get_sleb128(&v, p, p_end);
if (ret < 0)
goto fail;
- 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;
+ new_col_num = col_num + v;
+
+ if (pc_value < pc)
+ goto done;
+ line_num = new_line_num;
+ col_num = new_col_num;
}
- if (pc_value < pc)
- return line_num;
- line_num = new_line_num;
}
+ done:
+ *pcol_num = col_num;
return line_num;
+ fail:
+ *pcol_num = 0;
+ return 0;
}
/* in order to avoid executing arbitrary code during the stack trace
@@ -6439,7 +6863,7 @@ 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);
@@ -6454,13 +6878,11 @@ static const char *get_func_name(JSContext *ctx, JSValueConst func)
}
#define JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL (1 << 0)
-/* only taken into account if filename is provided */
-#define JS_BACKTRACE_FLAG_SINGLE_LEVEL (1 << 1)
/* if filename != NULL, an additional level is added with the filename
and line number information (used for parse error). */
static void build_backtrace(JSContext *ctx, JSValueConst error_obj,
- const char *filename, int line_num,
+ const char *filename, int line_num, int col_num,
int backtrace_flags)
{
JSStackFrame *sf;
@@ -6469,23 +6891,32 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_obj,
const char *func_name_str;
const char *str1;
JSObject *p;
- BOOL backtrace_barrier;
+
+ if (!JS_IsObject(error_obj))
+ return; /* protection in the out of memory case */
js_dbuf_init(ctx, &dbuf);
if (filename) {
dbuf_printf(&dbuf, " at %s", filename);
if (line_num != -1)
- dbuf_printf(&dbuf, ":%d", line_num);
+ dbuf_printf(&dbuf, ":%d:%d", line_num, col_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;
+ if (JS_IsException(str))
+ return;
+ /* Note: SpiderMonkey does that, could update once there is a standard */
+ if (JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, str,
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0 ||
+ JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, JS_NewInt32(ctx, line_num),
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0 ||
+ JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_columnNumber, JS_NewInt32(ctx, col_num),
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0) {
+ return;
+ }
}
for(sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) {
+ if (sf->js_mode & JS_MODE_BACKTRACE_BARRIER)
+ break;
if (backtrace_flags & JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL) {
backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL;
continue;
@@ -6499,34 +6930,28 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_obj,
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;
+ int line_num1, col_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);
+ sf->cur_pc - b->byte_code_buf - 1, &col_num1);
atom_str = JS_AtomToCString(ctx, b->debug.filename);
dbuf_printf(&dbuf, " (%s",
atom_str ? atom_str : "");
JS_FreeCString(ctx, atom_str);
- if (line_num1 != -1)
- dbuf_printf(&dbuf, ":%d", line_num1);
+ if (line_num1 != 0)
+ dbuf_printf(&dbuf, ":%d:%d", line_num1, col_num1);
dbuf_putc(&dbuf, ')');
}
} else {
dbuf_printf(&dbuf, " (native)");
}
dbuf_putc(&dbuf, '\n');
- /* 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;
@@ -6572,9 +6997,9 @@ static JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num,
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);
+ if (add_backtrace) {
+ build_backtrace(ctx, obj, NULL, 0, 0, 0);
+ }
}
ret = JS_Throw(ctx, obj);
return ret;
@@ -6760,15 +7185,19 @@ static JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id)
return JS_ThrowTypeErrorAtom(ctx, "%s object expected", name);
}
+static void JS_ThrowInterrupted(JSContext *ctx)
+{
+ JS_ThrowInternalError(ctx, "interrupted");
+ JS_SetUncatchableException(ctx, TRUE);
+}
+
static no_inline __exception int __js_poll_interrupts(JSContext *ctx)
{
JSRuntime *rt = ctx->rt;
ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT;
if (rt->interrupt_handler) {
if (rt->interrupt_handler(rt, rt->interrupt_opaque)) {
- /* XXX: should set a specific flag to avoid catching */
- JS_ThrowInternalError(ctx, "interrupted");
- JS_SetUncatchableError(ctx, ctx->rt->current_exception, TRUE);
+ JS_ThrowInterrupted(ctx);
return -1;
}
}
@@ -6784,7 +7213,17 @@ static inline __exception int js_poll_interrupts(JSContext *ctx)
}
}
-/* return -1 (exception) or TRUE/FALSE */
+static void JS_SetImmutablePrototype(JSContext *ctx, JSValueConst obj)
+{
+ JSObject *p;
+ if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
+ return;
+ p = JS_VALUE_GET_OBJ(obj);
+ p->has_immutable_prototype = TRUE;
+}
+
+/* Return -1 (exception) or TRUE/FALSE. 'throw_flag' = FALSE indicates
+ that it is called from Reflect.setPrototypeOf(). */
static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj,
JSValueConst proto_val,
BOOL throw_flag)
@@ -6815,12 +7254,32 @@ static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj,
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);
+ if (unlikely(p->is_exotic)) {
+ const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
+ int ret;
+ if (em && em->set_prototype) {
+ ret = em->set_prototype(ctx, obj, proto_val);
+ if (ret == 0 && throw_flag) {
+ JS_ThrowTypeError(ctx, "proxy: bad prototype");
+ return -1;
+ } else {
+ return ret;
+ }
+ }
+ }
+
sh = p->shape;
if (sh->proto == proto)
return TRUE;
- if (!p->extensible) {
+ if (unlikely(p->has_immutable_prototype)) {
+ if (throw_flag) {
+ JS_ThrowTypeError(ctx, "prototype is immutable");
+ return -1;
+ } else {
+ return FALSE;
+ }
+ }
+ if (unlikely(!p->extensible)) {
if (throw_flag) {
JS_ThrowTypeError(ctx, "object is not extensible");
return -1;
@@ -6865,17 +7324,10 @@ int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val)
static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val)
{
switch(JS_VALUE_GET_NORM_TAG(val)) {
+ case JS_TAG_SHORT_BIG_INT:
case JS_TAG_BIG_INT:
val = ctx->class_proto[JS_CLASS_BIG_INT];
break;
-#ifdef CONFIG_BIGNUM
- 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];
@@ -6884,6 +7336,7 @@ static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val)
val = ctx->class_proto[JS_CLASS_BOOLEAN];
break;
case JS_TAG_STRING:
+ case JS_TAG_STRING_ROPE:
val = ctx->class_proto[JS_CLASS_STRING];
break;
case JS_TAG_SYMBOL:
@@ -6899,22 +7352,24 @@ static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val)
return val;
}
-/* Return an Object, JS_NULL or JS_EXCEPTION in case of Proxy object. */
+/* Return an Object, JS_NULL or JS_EXCEPTION in case of exotic object. */
JSValue JS_GetPrototype(JSContext *ctx, JSValueConst obj)
{
JSValue val;
if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
JSObject *p;
p = JS_VALUE_GET_OBJ(obj);
- if (unlikely(p->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));
+ if (unlikely(p->is_exotic)) {
+ const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
+ if (em && em->get_prototype) {
+ return em->get_prototype(ctx, obj);
+ }
}
+ p = p->shape->proto;
+ if (!p)
+ val = JS_NULL;
+ else
+ val = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
} else {
val = JS_DupValue(ctx, JS_GetPrototypePrimitive(ctx, obj));
}
@@ -6961,8 +7416,8 @@ static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val,
for(;;) {
proto1 = p->shape->proto;
if (!proto1) {
- /* slow case if proxy in the prototype chain */
- if (unlikely(p->class_id == JS_CLASS_PROXY)) {
+ /* slow case if exotic object in the prototype chain */
+ if (unlikely(p->is_exotic && !p->fast_array)) {
JSValue obj1;
obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, (JSObject *)p));
for(;;) {
@@ -7044,12 +7499,14 @@ static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop,
JSValue val;
JSContext *realm;
JSAutoInitFunc *func;
-
+ JSAutoInitIDEnum id;
+
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)];
+ id = js_autoinit_get_id(pr);
+ func = js_autoinit_func_table[id];
/* 'func' shall not modify the object properties 'pr' */
val = func(realm, p, prop, pr->u.init.opaque);
js_autoinit_free(ctx->rt, pr);
@@ -7057,7 +7514,15 @@ static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop,
pr->u.value = JS_UNDEFINED;
if (JS_IsException(val))
return -1;
- pr->u.value = val;
+ if (id == JS_AUTOINIT_ID_MODULE_NS &&
+ JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
+ /* WARNING: a varref is returned as a string ! */
+ prs->flags |= JS_PROP_VARREF;
+ pr->u.var_ref = JS_VALUE_GET_PTR(val);
+ pr->u.var_ref->header.ref_count++;
+ } else {
+ pr->u.value = val;
+ }
return 0;
}
@@ -7083,14 +7548,24 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
{
JSString *p1 = JS_VALUE_GET_STRING(obj);
if (__JS_AtomIsTaggedInt(prop)) {
- uint32_t idx, ch;
+ uint32_t idx;
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);
+ return js_new_string_char(ctx, string_get(p1, idx));
+ }
+ } else if (prop == JS_ATOM_length) {
+ return JS_NewInt32(ctx, p1->len);
+ }
+ }
+ break;
+ case JS_TAG_STRING_ROPE:
+ {
+ JSStringRope *p1 = JS_VALUE_GET_STRING_ROPE(obj);
+ if (__JS_AtomIsTaggedInt(prop)) {
+ uint32_t idx;
+ idx = __JS_AtomToUInt32(prop);
+ if (idx < p1->len) {
+ return js_new_string_char(ctx, string_rope_get(obj, idx));
}
} else if (prop == JS_ATOM_length) {
return JS_NewInt32(ctx, p1->len);
@@ -7232,7 +7707,7 @@ static int JS_DefinePrivateField(JSContext *ctx, JSValueConst obj,
JS_ThrowTypeErrorNotASymbol(ctx);
goto fail;
}
- prop = js_symbol_to_atom(ctx, (JSValue)name);
+ prop = js_symbol_to_atom(ctx, name);
p = JS_VALUE_GET_OBJ(obj);
prs = find_own_property(&pr, p, prop);
if (prs) {
@@ -7263,7 +7738,7 @@ static JSValue JS_GetPrivateField(JSContext *ctx, JSValueConst obj,
/* safety check */
if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL))
return JS_ThrowTypeErrorNotASymbol(ctx);
- prop = js_symbol_to_atom(ctx, (JSValue)name);
+ prop = js_symbol_to_atom(ctx, name);
p = JS_VALUE_GET_OBJ(obj);
prs = find_own_property(&pr, p, prop);
if (!prs) {
@@ -7290,7 +7765,7 @@ static int JS_SetPrivateField(JSContext *ctx, JSValueConst obj,
JS_ThrowTypeErrorNotASymbol(ctx);
goto fail;
}
- prop = js_symbol_to_atom(ctx, (JSValue)name);
+ prop = js_symbol_to_atom(ctx, name);
p = JS_VALUE_GET_OBJ(obj);
prs = find_own_property(&pr, p, prop);
if (!prs) {
@@ -7303,6 +7778,8 @@ static int JS_SetPrivateField(JSContext *ctx, JSValueConst obj,
return 0;
}
+/* add a private brand field to 'home_obj' if not already present and
+ if obj is != null add a private brand to it */
static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj)
{
JSObject *p, *p1;
@@ -7310,7 +7787,7 @@ static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj)
JSProperty *pr;
JSValue brand;
JSAtom brand_atom;
-
+
if (unlikely(JS_VALUE_GET_TAG(home_obj) != JS_TAG_OBJECT)) {
JS_ThrowTypeErrorNotAnObject(ctx);
return -1;
@@ -7318,10 +7795,10 @@ static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj)
p = JS_VALUE_GET_OBJ(home_obj);
prs = find_own_property(&pr, p, JS_ATOM_Private_brand);
if (!prs) {
+ /* if the brand is not present, add it */
brand = JS_NewSymbolFromAtom(ctx, JS_ATOM_brand, JS_ATOM_TYPE_PRIVATE);
if (JS_IsException(brand))
return -1;
- /* 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);
@@ -7332,34 +7809,38 @@ static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj)
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);
+
+ if (JS_IsObject(obj)) {
+ p1 = JS_VALUE_GET_OBJ(obj);
+ prs = find_own_property(&pr, p1, brand_atom);
+ if (unlikely(prs)) {
+ JS_FreeAtom(ctx, brand_atom);
+ JS_ThrowTypeError(ctx, "private method is already present");
+ return -1;
+ }
+ pr = add_property(ctx, p1, brand_atom, JS_PROP_C_W_E);
+ JS_FreeAtom(ctx, brand_atom);
+ if (!pr)
+ return -1;
+ pr->u.value = JS_UNDEFINED;
+ } else {
JS_FreeAtom(ctx, brand_atom);
- return -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;
}
+/* return a boolean telling if the brand of the home object of 'func'
+ is present on 'obj' or -1 in case of exception */
static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func)
{
JSObject *p, *p1, *home_obj;
JSShapeProperty *prs;
JSProperty *pr;
JSValueConst brand;
-
+
/* get the home object of 'func' */
- if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)) {
- not_obj:
- JS_ThrowTypeErrorNotAnObject(ctx);
- return -1;
- }
+ if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT))
+ goto not_obj;
p1 = JS_VALUE_GET_OBJ(func);
if (!js_class_has_bytecode(p1->class_id))
goto not_obj;
@@ -7375,30 +7856,28 @@ static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func)
/* 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");
+ if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
+ not_obj:
+ JS_ThrowTypeErrorNotAnObject(ctx);
return -1;
}
- return 0;
+ p = JS_VALUE_GET_OBJ(obj);
+ prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, brand));
+ return (prs != NULL);
}
static 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);
+ JSString *p1 = JS_VALUE_GET_STRING(p->u.object_data);
len = p1->len;
}
return len;
@@ -7423,7 +7902,7 @@ static int num_keys_cmp(const void *p1, const void *p2, void *opaque)
return 1;
}
-static void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len)
+void JS_FreePropertyEnum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len)
{
uint32_t i;
if (tab) {
@@ -7450,7 +7929,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
BOOL is_enumerable, num_sorted;
uint32_t num_key;
JSAtomKindEnum kind;
-
+
/* clear pointer for consistency in case of failure */
*ptab = NULL;
*plen = 0;
@@ -7517,7 +7996,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
/* 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);
+ JS_FreePropertyEnum(ctx, tab_exotic, exotic_count);
return -1;
}
if (res) {
@@ -7538,11 +8017,25 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
/* fill them */
- atom_count = num_keys_count + str_keys_count + sym_keys_count + exotic_keys_count;
+ atom_count = num_keys_count + str_keys_count;
+ if (atom_count < str_keys_count)
+ goto add_overflow;
+ atom_count += sym_keys_count;
+ if (atom_count < sym_keys_count)
+ goto add_overflow;
+ atom_count += exotic_keys_count;
+ if (atom_count < exotic_keys_count || atom_count > INT32_MAX) {
+ add_overflow:
+ JS_ThrowOutOfMemory(ctx);
+ JS_FreePropertyEnum(ctx, tab_exotic, exotic_count);
+ return -1;
+ }
+ /* XXX: need generic way to test for js_malloc(ctx, a * b) overflow */
+
/* avoid allocating 0 bytes */
tab_atom = js_malloc(ctx, sizeof(tab_atom[0]) * max_int(atom_count, 1));
if (!tab_atom) {
- js_free_prop_enum(ctx, tab_exotic, exotic_count);
+ JS_FreePropertyEnum(ctx, tab_exotic, exotic_count);
return -1;
}
@@ -7587,7 +8080,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
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);
+ JS_FreePropertyEnum(ctx, tab_atom, num_index);
return -1;
}
tab_atom[num_index].is_enumerable = TRUE;
@@ -7728,7 +8221,7 @@ int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc,
return JS_GetOwnPropertyInternal(ctx, desc, JS_VALUE_GET_OBJ(obj), prop);
}
-/* return -1 if exception (Proxy object only) or TRUE/FALSE */
+/* return -1 if exception (exotic object only) or TRUE/FALSE */
int JS_IsExtensible(JSContext *ctx, JSValueConst obj)
{
JSObject *p;
@@ -7736,13 +8229,16 @@ int JS_IsExtensible(JSContext *ctx, JSValueConst obj)
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;
+ if (unlikely(p->is_exotic)) {
+ const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
+ if (em && em->is_extensible) {
+ return em->is_extensible(ctx, obj);
+ }
+ }
+ return p->extensible;
}
-/* return -1 if exception (Proxy object only) or TRUE/FALSE */
+/* return -1 if exception (exotic object only) or TRUE/FALSE */
int JS_PreventExtensions(JSContext *ctx, JSValueConst obj)
{
JSObject *p;
@@ -7750,8 +8246,12 @@ int JS_PreventExtensions(JSContext *ctx, JSValueConst obj)
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);
+ if (unlikely(p->is_exotic)) {
+ const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
+ if (em && em->prevent_extensions) {
+ return em->prevent_extensions(ctx, obj);
+ }
+ }
p->extensible = FALSE;
return TRUE;
}
@@ -7842,45 +8342,59 @@ static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
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;
+ uint32_t idx;
/* fast path for array access */
p = JS_VALUE_GET_OBJ(this_obj);
- if (unlikely(!p->fast_array))
- goto slow_path;
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:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return JS_DupValue(ctx, p->u.array.u.values[idx]);
case JS_CLASS_INT8_ARRAY:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return JS_NewInt32(ctx, p->u.array.u.int8_ptr[idx]);
case JS_CLASS_UINT8C_ARRAY:
case JS_CLASS_UINT8_ARRAY:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return JS_NewInt32(ctx, p->u.array.u.uint8_ptr[idx]);
case JS_CLASS_INT16_ARRAY:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return JS_NewInt32(ctx, p->u.array.u.int16_ptr[idx]);
case JS_CLASS_UINT16_ARRAY:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return JS_NewInt32(ctx, p->u.array.u.uint16_ptr[idx]);
case JS_CLASS_INT32_ARRAY:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return JS_NewInt32(ctx, p->u.array.u.int32_ptr[idx]);
case JS_CLASS_UINT32_ARRAY:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return JS_NewUint32(ctx, p->u.array.u.uint32_ptr[idx]);
case JS_CLASS_BIG_INT64_ARRAY:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]);
case JS_CLASS_BIG_UINT64_ARRAY:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]);
+ case JS_CLASS_FLOAT16_ARRAY:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
+ return __JS_NewFloat64(ctx, fromfp16(p->u.array.u.fp16_ptr[idx]));
case JS_CLASS_FLOAT32_ARRAY:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return __JS_NewFloat64(ctx, p->u.array.u.float_ptr[idx]);
case JS_CLASS_FLOAT64_ARRAY:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return __JS_NewFloat64(ctx, p->u.array.u.double_ptr[idx]);
default:
goto slow_path;
}
} else {
slow_path:
+ /* ToObject() must be done before ToPropertyKey() */
+ if (JS_IsNull(this_obj) || JS_IsUndefined(this_obj)) {
+ JS_FreeValue(ctx, prop);
+ return JS_ThrowTypeError(ctx, "cannot read property of %s", JS_IsNull(this_obj) ? "null" : "undefined");
+ }
atom = JS_ValueToAtom(ctx, prop);
JS_FreeValue(ctx, prop);
if (unlikely(atom == JS_ATOM_NULL))
@@ -7957,6 +8471,8 @@ JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj,
JSAtom atom;
JSValue ret;
atom = JS_NewAtom(ctx, prop);
+ if (atom == JS_ATOM_NULL)
+ return JS_EXCEPTION;
ret = JS_GetProperty(ctx, this_obj, atom);
JS_FreeAtom(ctx, atom);
return ret;
@@ -8292,6 +8808,30 @@ static int add_fast_array_element(JSContext *ctx, JSObject *p,
return TRUE;
}
+/* Allocate a new fast array. Its 'length' property is set to zero. It
+ maximum size is 2^31-1 elements. For convenience, 'len' is a 64 bit
+ integer. WARNING: the content of the array is not initialized. */
+static JSValue js_allocate_fast_array(JSContext *ctx, int64_t len)
+{
+ JSValue arr;
+ JSObject *p;
+
+ if (len > INT32_MAX)
+ return JS_ThrowRangeError(ctx, "invalid array length");
+ arr = JS_NewArray(ctx);
+ if (JS_IsException(arr))
+ return arr;
+ if (len > 0) {
+ p = JS_VALUE_GET_OBJ(arr);
+ if (expand_fast_array(ctx, p, len) < 0) {
+ JS_FreeValue(ctx, arr);
+ return JS_EXCEPTION;
+ }
+ p->u.array.count = len;
+ }
+ return arr;
+}
+
static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc)
{
JS_FreeValue(ctx, desc->getter);
@@ -8381,7 +8921,7 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj,
goto read_only_prop;
}
}
-
+
for(;;) {
if (p1->is_exotic) {
if (p1->fast_array) {
@@ -8405,17 +8945,21 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj,
return -1;
}
typed_array_oob:
- /* must convert the argument even if out of bound access */
- if (p1->class_id == JS_CLASS_BIG_INT64_ARRAY ||
- p1->class_id == JS_CLASS_BIG_UINT64_ARRAY) {
- int64_t v;
- if (JS_ToBigInt64Free(ctx, &v, val))
- return -1;
+ if (p == p1) {
+ /* must convert the argument even if out of bound access */
+ if (p1->class_id == JS_CLASS_BIG_INT64_ARRAY ||
+ p1->class_id == JS_CLASS_BIG_UINT64_ARRAY) {
+ int64_t v;
+ if (JS_ToBigInt64Free(ctx, &v, val))
+ return -1;
+ } else {
+ val = JS_ToNumberFree(ctx, val);
+ JS_FreeValue(ctx, val);
+ if (JS_IsException(val))
+ return -1;
+ }
} else {
- val = JS_ToNumberFree(ctx, val);
JS_FreeValue(ctx, val);
- if (JS_IsException(val))
- return -1;
}
return TRUE;
}
@@ -8490,6 +9034,8 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj,
goto retry2;
} else if (!(prs->flags & JS_PROP_WRITABLE)) {
goto read_only_prop;
+ } else {
+ break;
}
}
}
@@ -8669,6 +9215,13 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
p->u.array.u.uint64_ptr[idx] = v;
}
break;
+ case JS_CLASS_FLOAT16_ARRAY:
+ if (JS_ToFloat64Free(ctx, &d, val))
+ return -1;
+ if (unlikely(idx >= (uint32_t)p->u.array.count))
+ goto ta_out_of_bound;
+ p->u.array.u.fp16_ptr[idx] = tofp16(d);
+ break;
case JS_CLASS_FLOAT32_ARRAY:
if (JS_ToFloat64Free(ctx, &d, val))
return -1;
@@ -8739,6 +9292,10 @@ int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj,
JSAtom atom;
int ret;
atom = JS_NewAtom(ctx, prop);
+ if (atom == JS_ATOM_NULL) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, JS_PROP_THROW);
JS_FreeAtom(ctx, atom);
return ret;
@@ -8880,15 +9437,13 @@ static BOOL check_define_prop_flags(int prop_flags, int flags)
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)) {
+ if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |
+ JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
has_accessor = ((flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) != 0);
is_getset = ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET);
if (has_accessor != is_getset)
return FALSE;
- if (!has_accessor && !is_getset && !(prop_flags & JS_PROP_WRITABLE)) {
+ if (!is_getset && !(prop_flags & JS_PROP_WRITABLE)) {
/* not writable: cannot set the writable bit */
if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
(JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE))
@@ -8974,7 +9529,7 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
return -1;
}
/* this code relies on the fact that Uint32 are never allocated */
- val = (JSValueConst)JS_NewUint32(ctx, array_length);
+ val = JS_NewUint32(ctx, array_length);
/* prs may have been modified */
prs = find_own_property(&pr, p, prop);
assert(prs != NULL);
@@ -9079,15 +9634,19 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
spaces. */
if (!js_same_value(ctx, val, *pr->u.var_ref->pvalue))
goto not_configurable;
+ } else {
+ /* update the reference */
+ set_value(ctx, pr->u.var_ref->pvalue,
+ JS_DupValue(ctx, val));
}
- /* update the reference */
- set_value(ctx, pr->u.var_ref->pvalue,
- JS_DupValue(ctx, val));
}
/* if writable is set to false, no longer a
reference (for mapped arguments) */
if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) {
JSValue val1;
+ if (p->class_id == JS_CLASS_MODULE_NS) {
+ return JS_ThrowTypeErrorOrFalse(ctx, flags, "module namespace properties have writable = false");
+ }
if (js_shape_prepare_update(ctx, p, &prs))
return -1;
val1 = JS_DupValue(ctx, *pr->u.var_ref->pvalue);
@@ -9293,6 +9852,10 @@ int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj,
JSAtom atom;
int ret;
atom = JS_NewAtom(ctx, prop);
+ if (atom == JS_ATOM_NULL) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
JS_FreeAtom(ctx, atom);
return ret;
@@ -9328,7 +9891,7 @@ static BOOL js_object_has_name(JSContext *ctx, JSValueConst obj)
JSShapeProperty *prs;
JSValueConst val;
JSString *p;
-
+
prs = find_own_property(&pr, JS_VALUE_GET_OBJ(obj), JS_ATOM_name);
if (!prs)
return FALSE;
@@ -9587,12 +10150,38 @@ static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val,
set_value(ctx, &pr->u.value, val);
return 0;
}
+ /* XXX: add a fast path where the property exists and the object
+ is not exotic. Otherwise do as in OP_put_ref_value and remove
+ JS_PROP_NO_ADD which is no longer necessary */
flags = JS_PROP_THROW_STRICT;
- if (is_strict_mode(ctx))
+ if (is_strict_mode(ctx))
flags |= JS_PROP_NO_ADD;
return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, ctx->global_obj, flags);
}
+/* return -1, FALSE or TRUE */
+static int JS_DeleteGlobalVar(JSContext *ctx, JSAtom prop)
+{
+ JSObject *p;
+ JSShapeProperty *prs;
+ JSProperty *pr;
+ int ret;
+
+ /* 9.1.1.4.7 DeleteBinding ( N ) */
+ p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
+ prs = find_own_property(&pr, p, prop);
+ if (prs)
+ return FALSE; /* lexical variables cannot be deleted */
+ ret = JS_HasProperty(ctx, ctx->global_obj, prop);
+ if (ret < 0)
+ return -1;
+ if (ret) {
+ return JS_DeleteProperty(ctx, ctx->global_obj, prop, 0);
+ } else {
+ return TRUE;
+ }
+}
+
/* return -1, FALSE or TRUE. return FALSE if not configurable or
invalid object. return -1 in case of exception.
flags can be 0, JS_PROP_THROW or JS_PROP_THROW_STRICT */
@@ -9601,7 +10190,7 @@ 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;
@@ -9691,29 +10280,10 @@ BOOL JS_IsError(JSContext *ctx, JSValueConst val)
return (p->class_id == JS_CLASS_ERROR);
}
-/* used to avoid catching interrupt exceptions */
-BOOL JS_IsUncatchableError(JSContext *ctx, JSValueConst val)
-{
- JSObject *p;
- if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
- return FALSE;
- p = JS_VALUE_GET_OBJ(val);
- return p->class_id == JS_CLASS_ERROR && p->is_uncatchable_error;
-}
-
-void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag)
-{
- JSObject *p;
- if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
- return;
- p = JS_VALUE_GET_OBJ(val);
- if (p->class_id == JS_CLASS_ERROR)
- p->is_uncatchable_error = flag;
-}
-
-void JS_ResetUncatchableError(JSContext *ctx)
+/* must be called after JS_Throw() */
+void JS_SetUncatchableException(JSContext *ctx, BOOL flag)
{
- JS_SetUncatchableError(ctx, ctx->rt->current_exception, FALSE);
+ ctx->rt->current_exception_is_uncatchable = flag;
}
void JS_SetOpaque(JSValue obj, void *opaque)
@@ -9746,11 +10316,17 @@ void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id)
return p;
}
-#define HINT_STRING 0
-#define HINT_NUMBER 1
-#define HINT_NONE 2
-/* don't try Symbol.toPrimitive */
-#define HINT_FORCE_ORDINARY (1 << 4)
+void *JS_GetAnyOpaque(JSValueConst obj, JSClassID *class_id)
+{
+ JSObject *p;
+ if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
+ *class_id = 0;
+ return NULL;
+ }
+ p = JS_VALUE_GET_OBJ(obj);
+ *class_id = p->class_id;
+ return p->u.opaque;
+}
static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint)
{
@@ -9848,7 +10424,7 @@ static inline BOOL JS_IsHTMLDDA(JSContext *ctx, JSValueConst obj)
p = JS_VALUE_GET_OBJ(obj);
return p->is_HTMLDDA;
}
-
+
static int JS_ToBoolFree(JSContext *ctx, JSValue val)
{
uint32_t tag = JS_VALUE_GET_TAG(val);
@@ -9867,27 +10443,33 @@ static int JS_ToBoolFree(JSContext *ctx, JSValue val)
JS_FreeValue(ctx, val);
return ret;
}
- case JS_TAG_BIG_INT:
-#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_FLOAT:
-#endif
+ case JS_TAG_STRING_ROPE:
{
- JSBigFloat *p = JS_VALUE_GET_PTR(val);
- BOOL ret;
- ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN;
+ BOOL ret = JS_VALUE_GET_STRING_ROPE(val)->len != 0;
JS_FreeValue(ctx, val);
return ret;
}
-#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_DECIMAL:
+ case JS_TAG_SHORT_BIG_INT:
+ return JS_VALUE_GET_SHORT_BIG_INT(val) != 0;
+ case JS_TAG_BIG_INT:
{
- JSBigDecimal *p = JS_VALUE_GET_PTR(val);
+ JSBigInt *p = JS_VALUE_GET_PTR(val);
BOOL ret;
- ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN;
+ int i;
+
+ /* fail safe: we assume it is not necessarily
+ normalized. Beginning from the MSB ensures that the
+ test is fast. */
+ ret = FALSE;
+ for(i = p->len - 1; i >= 0; i--) {
+ if (p->tab[i] != 0) {
+ ret = TRUE;
+ break;
+ }
+ }
JS_FreeValue(ctx, val);
return ret;
}
-#endif
case JS_TAG_OBJECT:
{
JSObject *p = JS_VALUE_GET_OBJ(val);
@@ -9947,1604 +10529,2390 @@ static inline int to_digit(int c)
return 36;
}
-/* XXX: remove */
-static double js_strtod(const char *p, int radix, BOOL is_float)
+/* bigint support */
+
+#define JS_BIGINT_MAX_SIZE ((1024 * 1024) / JS_LIMB_BITS) /* in limbs */
+
+/* it is currently assumed that JS_SHORT_BIG_INT_BITS = JS_LIMB_BITS */
+#if JS_SHORT_BIG_INT_BITS == 32
+#define JS_SHORT_BIG_INT_MIN INT32_MIN
+#define JS_SHORT_BIG_INT_MAX INT32_MAX
+#elif JS_SHORT_BIG_INT_BITS == 64
+#define JS_SHORT_BIG_INT_MIN INT64_MIN
+#define JS_SHORT_BIG_INT_MAX INT64_MAX
+#else
+#error unsupported
+#endif
+
+#define ADDC(res, carry_out, op1, op2, carry_in) \
+do { \
+ js_limb_t __v, __a, __k, __k1; \
+ __v = (op1); \
+ __a = __v + (op2); \
+ __k1 = __a < __v; \
+ __k = (carry_in); \
+ __a = __a + __k; \
+ carry_out = (__a < __k) | __k1; \
+ res = __a; \
+} while (0)
+
+#if JS_LIMB_BITS == 32
+/* a != 0 */
+static inline js_limb_t js_limb_clz(js_limb_t a)
{
- 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++;
- }
+ return clz32(a);
+}
+#else
+static inline js_limb_t js_limb_clz(js_limb_t a)
+{
+ return clz64(a);
+}
+#endif
- /* 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);
+/* handle a = 0 too */
+static inline js_limb_t js_limb_safe_clz(js_limb_t a)
+{
+ if (a == 0)
+ return JS_LIMB_BITS;
+ else
+ return js_limb_clz(a);
+}
+
+static js_limb_t mp_add(js_limb_t *res, const js_limb_t *op1, const js_limb_t *op2,
+ js_limb_t n, js_limb_t carry)
+{
+ int i;
+ for(i = 0;i < n; i++) {
+ ADDC(res[i], carry, op1[i], op2[i], carry);
}
- return d;
+ return carry;
}
-#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)
-#ifdef CONFIG_BIGNUM
-#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)
-#endif
-/* accept -0x1 */
-#define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10)
+static js_limb_t mp_sub(js_limb_t *res, const js_limb_t *op1, const js_limb_t *op2,
+ int n, js_limb_t carry)
+{
+ int i;
+ js_limb_t k, a, v, k1;
+
+ k = carry;
+ for(i=0;i v;
+ v = a - k;
+ k = (v > a) | k1;
+ res[i] = v;
+ }
+ return k;
+}
-static JSValue js_string_to_bigint(JSContext *ctx, const char *buf,
- int radix, int flags, slimb_t *pexponent)
+/* compute 0 - op2. carry = 0 or 1. */
+static js_limb_t mp_neg(js_limb_t *res, const js_limb_t *op2, int n)
{
- 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);
+ int i;
+ js_limb_t v, carry;
+
+ carry = 1;
+ for(i=0;ifp_env.prec,
- ctx->fp_env.flags);
+ js_limb_t i;
+ js_dlimb_t t;
+
+ for(i = 0; i < n; i++) {
+ t = (js_dlimb_t)taba[i] * (js_dlimb_t)b + l;
+ tabr[i] = t;
+ l = t >> JS_LIMB_BITS;
}
- if (ret & BF_ST_MEM_ERROR) {
- JS_FreeValue(ctx, val);
- return JS_ThrowOutOfMemory(ctx);
+ return l;
+}
+
+static js_limb_t mp_div1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,
+ js_limb_t b, js_limb_t r)
+{
+ js_slimb_t i;
+ js_dlimb_t a1;
+ for(i = n - 1; i >= 0; i--) {
+ a1 = ((js_dlimb_t)r << JS_LIMB_BITS) | taba[i];
+ tabr[i] = a1 / b;
+ r = a1 % b;
}
- return val;
+ return r;
}
-static JSValue js_string_to_bigdecimal(JSContext *ctx, const char *buf,
- int radix, int flags, slimb_t *pexponent)
+/* tabr[] += taba[] * b, return the high word. */
+static js_limb_t mp_add_mul1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,
+ js_limb_t b)
{
- 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);
+ js_limb_t i, l;
+ js_dlimb_t t;
+
+ l = 0;
+ for(i = 0; i < n; i++) {
+ t = (js_dlimb_t)taba[i] * (js_dlimb_t)b + l + tabr[i];
+ tabr[i] = t;
+ l = t >> JS_LIMB_BITS;
}
- return val;
+ return l;
}
-#endif
-/* return an exception in case of memory error. Return JS_NAN if
- invalid syntax */
-#ifdef CONFIG_BIGNUM
-static JSValue js_atof2(JSContext *ctx, const char *str, const char **pp,
- int radix, int flags, slimb_t *pexponent)
-#else
-static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
- int radix, int flags)
-#endif
+/* size of the result : op1_size + op2_size. */
+static void mp_mul_basecase(js_limb_t *result,
+ const js_limb_t *op1, js_limb_t op1_size,
+ const js_limb_t *op2, js_limb_t op2_size)
{
- 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;
+ int i;
+ js_limb_t r;
- 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;
+ result[op1_size] = mp_mul1(result, op1, op1_size, op2[0], 0);
+ for(i=1;i= '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;
+}
+
+/* tabr[] -= taba[] * b. Return the value to substract to the high
+ word. */
+static js_limb_t mp_sub_mul1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,
+ js_limb_t b)
+{
+ js_limb_t i, l;
+ js_dlimb_t t;
+
+ l = 0;
+ for(i = 0; i < n; i++) {
+ t = tabr[i] - (js_dlimb_t)taba[i] * (js_dlimb_t)b - l;
+ tabr[i] = t;
+ l = -(t >> JS_LIMB_BITS);
+ }
+ return l;
+}
+
+/* WARNING: d must be >= 2^(JS_LIMB_BITS-1) */
+static inline js_limb_t udiv1norm_init(js_limb_t d)
+{
+ js_limb_t a0, a1;
+ a1 = -d - 1;
+ a0 = -1;
+ return (((js_dlimb_t)a1 << JS_LIMB_BITS) | a0) / d;
+}
+
+/* return the quotient and the remainder in '*pr'of 'a1*2^JS_LIMB_BITS+a0
+ / d' with 0 <= a1 < d. */
+static inline js_limb_t udiv1norm(js_limb_t *pr, js_limb_t a1, js_limb_t a0,
+ js_limb_t d, js_limb_t d_inv)
+{
+ js_limb_t n1m, n_adj, q, r, ah;
+ js_dlimb_t a;
+ n1m = ((js_slimb_t)a0 >> (JS_LIMB_BITS - 1));
+ n_adj = a0 + (n1m & d);
+ a = (js_dlimb_t)d_inv * (a1 - n1m) + n_adj;
+ q = (a >> JS_LIMB_BITS) + a1;
+ /* compute a - q * r and update q so that the remainder is\
+ between 0 and d - 1 */
+ a = ((js_dlimb_t)a1 << JS_LIMB_BITS) | a0;
+ a = a - (js_dlimb_t)q * d - d;
+ ah = a >> JS_LIMB_BITS;
+ q += 1 + ah;
+ r = (js_limb_t)a + (ah & d);
+ *pr = r;
+ return q;
+}
+
+#define UDIV1NORM_THRESHOLD 3
+
+/* b must be >= 1 << (JS_LIMB_BITS - 1) */
+static js_limb_t mp_div1norm(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,
+ js_limb_t b, js_limb_t r)
+{
+ js_slimb_t i;
+
+ if (n >= UDIV1NORM_THRESHOLD) {
+ js_limb_t b_inv;
+ b_inv = udiv1norm_init(b);
+ for(i = n - 1; i >= 0; i--) {
+ tabr[i] = udiv1norm(&r, r, taba[i], b, b_inv);
}
- /* 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
-#ifdef CONFIG_BIGNUM
- || atod_type == ATOD_TYPE_BIG_FLOAT
-#endif
- ) &&
- 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;
+ js_dlimb_t a1;
+ for(i = n - 1; i >= 0; i--) {
+ a1 = ((js_dlimb_t)r << JS_LIMB_BITS) | taba[i];
+ tabr[i] = a1 / b;
+ r = a1 % b;
}
}
- if (radix == 0)
- radix = 10;
- is_float = FALSE;
- p_start = p;
- while (to_digit((uint8_t)*p) < radix
- || (*p == sep && (radix != 10 ||
- p != p_start + 1 || p[-1] != '0') &&
- to_digit((uint8_t)p[1]) < radix)) {
- p++;
- }
- if (!(flags & ATOD_INT_ONLY)) {
- if (*p == '.' && (p > p_start || to_digit((uint8_t)p[1]) < radix)) {
- is_float = TRUE;
- p++;
- if (*p == sep)
- goto fail;
- while (to_digit((uint8_t)*p) < radix ||
- (*p == sep && to_digit((uint8_t)p[1]) < radix))
- p++;
- }
- if (p > p_start &&
- (((*p == 'e' || *p == 'E') && radix == 10) ||
- ((*p == 'p' || *p == 'P') && (radix == 2 || radix == 8 || radix == 16)))) {
- const char *p1 = p + 1;
- is_float = TRUE;
- if (*p1 == '+') {
- p1++;
- } else if (*p1 == '-') {
- p1++;
- }
- if (is_digit((uint8_t)*p1)) {
- p = p1 + 1;
- while (is_digit((uint8_t)*p) || (*p == sep && is_digit((uint8_t)p[1])))
- p++;
- }
- }
+ return r;
+}
+
+/* base case division: divides taba[0..na-1] by tabb[0..nb-1]. tabb[nb
+ - 1] must be >= 1 << (JS_LIMB_BITS - 1). na - nb must be >= 0. 'taba'
+ is modified and contains the remainder (nb limbs). tabq[0..na-nb]
+ contains the quotient with tabq[na - nb] <= 1. */
+static void mp_divnorm(js_limb_t *tabq, js_limb_t *taba, js_limb_t na,
+ const js_limb_t *tabb, js_limb_t nb)
+{
+ js_limb_t r, a, c, q, v, b1, b1_inv, n, dummy_r;
+ int i, j;
+
+ b1 = tabb[nb - 1];
+ if (nb == 1) {
+ taba[0] = mp_div1norm(tabq, taba, na, b1, 0);
+ return;
}
- if (p == p_start)
- goto fail;
+ n = na - nb;
- 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;
+ 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;
+ }
}
- /* 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];
+ tabq[n] = q;
+ if (q) {
+ mp_sub(taba + n, taba + n, tabb, nb, 0);
}
- buf[j] = '\0';
- if (flags & ATOD_ACCEPT_SUFFIX) {
- if (*p == 'n') {
- p++;
- atod_type = ATOD_TYPE_BIG_INT;
- } else
-#ifdef CONFIG_BIGNUM
- 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
-#endif
- {
- if (is_float && radix != 10)
- goto fail;
+ for(i = n - 1; i >= 0; i--) {
+ if (unlikely(taba[i + nb] >= b1)) {
+ q = -1;
+ } else if (b1_inv) {
+ q = udiv1norm(&dummy_r, taba[i + nb], taba[i + nb - 1], b1, b1_inv);
+ } else {
+ js_dlimb_t al;
+ al = ((js_dlimb_t)taba[i + nb] << JS_LIMB_BITS) | taba[i + nb - 1];
+ q = al / b1;
+ r = al % b1;
}
- } else {
- if (atod_type == ATOD_TYPE_FLOAT64) {
-#ifdef CONFIG_BIGNUM
- if (flags & ATOD_MODE_BIGINT) {
- if (!is_float)
- atod_type = ATOD_TYPE_BIG_INT;
- if (has_legacy_octal)
- goto fail;
- } else
-#endif
- {
- if (is_float && radix != 10)
- goto fail;
+ 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;
}
+}
- 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;
-#ifdef CONFIG_BIGNUM
- 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;
-#endif
- default:
- abort();
+/* 1 <= shift <= JS_LIMB_BITS - 1 */
+static js_limb_t mp_shl(js_limb_t *tabr, const js_limb_t *taba, int n,
+ int shift)
+{
+ int i;
+ js_limb_t l, v;
+ l = 0;
+ for(i = 0; i < n; i++) {
+ v = taba[i];
+ tabr[i] = (v << shift) | l;
+ l = v >> (JS_LIMB_BITS - shift);
}
-
-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;
+ return l;
}
-#ifdef CONFIG_BIGNUM
-static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
- int radix, int flags)
+/* r = (a + high*B^n) >> shift. Return the remainder r (0 <= r < 2^shift).
+ 1 <= shift <= LIMB_BITS - 1 */
+static js_limb_t mp_shr(js_limb_t *tab_r, const js_limb_t *tab, int n,
+ int shift, js_limb_t high)
{
- return js_atof2(ctx, str, pp, radix, flags, NULL);
+ int i;
+ js_limb_t l, a;
+
+ l = high;
+ for(i = n - 1; i >= 0; i--) {
+ a = tab[i];
+ tab_r[i] = (a >> shift) | (l << (JS_LIMB_BITS - shift));
+ l = a;
+ }
+ return l & (((js_limb_t)1 << shift) - 1);
}
-#endif
-typedef enum JSToNumberHintEnum {
- TON_FLAG_NUMBER,
- TON_FLAG_NUMERIC,
-} JSToNumberHintEnum;
+static JSBigInt *js_bigint_new(JSContext *ctx, int len)
+{
+ JSBigInt *r;
+ if (len > JS_BIGINT_MAX_SIZE) {
+ JS_ThrowRangeError(ctx, "BigInt is too large to allocate");
+ return NULL;
+ }
+ r = js_malloc(ctx, sizeof(JSBigInt) + len * sizeof(js_limb_t));
+ if (!r)
+ return NULL;
+ r->header.ref_count = 1;
+ r->len = len;
+ return r;
+}
-static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val,
- JSToNumberHintEnum flag)
+static JSBigInt *js_bigint_set_si(JSBigIntBuf *buf, js_slimb_t a)
{
- uint32_t tag;
- JSValue ret;
+ JSBigInt *r = (JSBigInt *)buf->big_int_buf;
+ r->header.ref_count = 0; /* fail safe */
+ r->len = 1;
+ r->tab[0] = a;
+ return r;
+}
- redo:
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- 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;
-#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_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;
+static JSBigInt *js_bigint_set_si64(JSBigIntBuf *buf, int64_t a)
+{
+#if JS_LIMB_BITS == 64
+ return js_bigint_set_si(buf, a);
+#else
+ JSBigInt *r = (JSBigInt *)buf->big_int_buf;
+ r->header.ref_count = 0; /* fail safe */
+ if (a >= INT32_MIN && a <= INT32_MAX) {
+ r->len = 1;
+ r->tab[0] = a;
+ } else {
+ r->len = 2;
+ r->tab[0] = a;
+ r->tab[1] = a >> JS_LIMB_BITS;
}
- return ret;
+ return r;
+#endif
}
-static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val)
+/* val must be a short big int */
+static JSBigInt *js_bigint_set_short(JSBigIntBuf *buf, JSValueConst val)
{
- return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER);
+ return js_bigint_set_si(buf, JS_VALUE_GET_SHORT_BIG_INT(val));
}
-static JSValue JS_ToNumericFree(JSContext *ctx, JSValue val)
+static __maybe_unused void js_bigint_dump1(JSContext *ctx, const char *str,
+ const js_limb_t *tab, int len)
{
- return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC);
+ int i;
+ printf("%s: ", str);
+ for(i = len - 1; i >= 0; i--) {
+#if JS_LIMB_BITS == 32
+ printf(" %08x", tab[i]);
+#else
+ printf(" %016" PRIx64, tab[i]);
+#endif
+ }
+ printf("\n");
}
-static JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val)
+static __maybe_unused void js_bigint_dump(JSContext *ctx, const char *str,
+ const JSBigInt *p)
{
- return JS_ToNumericFree(ctx, JS_DupValue(ctx, val));
+ js_bigint_dump1(ctx, str, p->tab, p->len);
}
-static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres,
- JSValue val)
+static JSBigInt *js_bigint_new_si(JSContext *ctx, js_slimb_t a)
{
- double d;
- uint32_t tag;
+ JSBigInt *r;
+ r = js_bigint_new(ctx, 1);
+ if (!r)
+ return NULL;
+ r->tab[0] = a;
+ return r;
+}
- val = JS_ToNumberFree(ctx, val);
- if (JS_IsException(val)) {
- *pres = JS_FLOAT64_NAN;
- return -1;
+static JSBigInt *js_bigint_new_si64(JSContext *ctx, int64_t a)
+{
+#if JS_LIMB_BITS == 64
+ return js_bigint_new_si(ctx, a);
+#else
+ if (a >= INT32_MIN && a <= INT32_MAX) {
+ return js_bigint_new_si(ctx, a);
+ } else {
+ JSBigInt *r;
+ r = js_bigint_new(ctx, 2);
+ if (!r)
+ return NULL;
+ r->tab[0] = a;
+ r->tab[1] = a >> 32;
+ return r;
}
- 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;
- case JS_TAG_BIG_INT:
-#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_FLOAT:
#endif
- {
- 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;
- default:
- abort();
- }
- *pres = d;
- return 0;
}
-static inline int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val)
+static JSBigInt *js_bigint_new_ui64(JSContext *ctx, uint64_t a)
{
- uint32_t tag;
+ if (a <= INT64_MAX) {
+ return js_bigint_new_si64(ctx, a);
+ } else {
+ JSBigInt *r;
+ r = js_bigint_new(ctx, (65 + JS_LIMB_BITS - 1) / JS_LIMB_BITS);
+ if (!r)
+ return NULL;
+#if JS_LIMB_BITS == 64
+ r->tab[0] = a;
+ r->tab[1] = 0;
+#else
+ r->tab[0] = a;
+ r->tab[1] = a >> 32;
+ r->tab[2] = 0;
+#endif
+ return r;
+ }
+}
- 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;
+static JSBigInt *js_bigint_new_di(JSContext *ctx, js_sdlimb_t a)
+{
+ JSBigInt *r;
+ if (a == (js_slimb_t)a) {
+ r = js_bigint_new(ctx, 1);
+ if (!r)
+ return NULL;
+ r->tab[0] = a;
} else {
- return __JS_ToFloat64Free(ctx, pres, val);
+ r = js_bigint_new(ctx, 2);
+ if (!r)
+ return NULL;
+ r->tab[0] = a;
+ r->tab[1] = a >> JS_LIMB_BITS;
}
+ return r;
}
-int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val)
+/* Remove redundant high order limbs. Warning: 'a' may be
+ reallocated. Can never fail.
+*/
+static JSBigInt *js_bigint_normalize1(JSContext *ctx, JSBigInt *a, int l)
{
- return JS_ToFloat64Free(ctx, pres, JS_DupValue(ctx, val));
+ js_limb_t v;
+
+ assert(a->header.ref_count == 1);
+ while (l > 1) {
+ v = a->tab[l - 1];
+ if ((v != 0 && v != -1) ||
+ (v & 1) != (a->tab[l - 2] >> (JS_LIMB_BITS - 1))) {
+ break;
+ }
+ l--;
+ }
+ if (l != a->len) {
+ JSBigInt *a1;
+ /* realloc to reduce the size */
+ a->len = l;
+ a1 = js_realloc(ctx, a, sizeof(JSBigInt) + l * sizeof(js_limb_t));
+ if (a1)
+ a = a1;
+ }
+ return a;
}
-static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val)
+static JSBigInt *js_bigint_normalize(JSContext *ctx, JSBigInt *a)
{
- return JS_ToNumberFree(ctx, JS_DupValue(ctx, val));
+ return js_bigint_normalize1(ctx, a, a->len);
}
-/* same as JS_ToNumber() but return 0 in case of NaN/Undefined */
-static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
+/* return 0 or 1 depending on the sign */
+static inline int js_bigint_sign(const JSBigInt *a)
{
- uint32_t tag;
- JSValue ret;
+ return a->tab[a->len - 1] >> (JS_LIMB_BITS - 1);
+}
- 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 (!a) {
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- 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;
+static js_slimb_t js_bigint_get_si_sat(const JSBigInt *a)
+{
+ if (a->len == 1) {
+ return a->tab[0];
+ } else {
+#if JS_LIMB_BITS == 32
+ if (js_bigint_sign(a))
+ return INT32_MIN;
+ else
+ return INT32_MAX;
+#else
+ if (js_bigint_sign(a))
+ return INT64_MIN;
+ else
+ return INT64_MAX;
#endif
- 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)
+/* add the op1 limb */
+static JSBigInt *js_bigint_extend(JSContext *ctx, JSBigInt *r,
+ js_limb_t op1)
{
- 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;
- }
+ int n2 = r->len;
+ if ((op1 != 0 && op1 != -1) ||
+ (op1 & 1) != r->tab[n2 - 1] >> (JS_LIMB_BITS - 1)) {
+ JSBigInt *r1;
+ r1 = js_realloc(ctx, r,
+ sizeof(JSBigInt) + (n2 + 1) * sizeof(js_limb_t));
+ if (!r1) {
+ js_free(ctx, r);
+ return NULL;
}
- 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);
+ r = r1;
+ r->len = n2 + 1;
+ r->tab[n2] = op1;
+ } else {
+ /* otherwise still need to normalize the result */
+ r = js_bigint_normalize(ctx, r);
+ }
+ return r;
+}
+
+/* return NULL in case of error. Compute a + b (b_neg = 0) or a - b
+ (b_neg = 1) */
+/* XXX: optimize */
+static JSBigInt *js_bigint_add(JSContext *ctx, const JSBigInt *a,
+ const JSBigInt *b, int b_neg)
+{
+ JSBigInt *r;
+ int n1, n2, i;
+ js_limb_t carry, op1, op2, a_sign, b_sign;
+
+ n2 = max_int(a->len, b->len);
+ n1 = min_int(a->len, b->len);
+ r = js_bigint_new(ctx, n2);
+ if (!r)
+ return NULL;
+ /* XXX: optimize */
+ /* common part */
+ carry = b_neg;
+ for(i = 0; i < n1; i++) {
+ op1 = a->tab[i];
+ op2 = b->tab[i] ^ (-b_neg);
+ ADDC(r->tab[i], carry, op1, op2, carry);
+ }
+ a_sign = -js_bigint_sign(a);
+ b_sign = (-js_bigint_sign(b)) ^ (-b_neg);
+ /* part with sign extension of one operand */
+ if (a->len > b->len) {
+ for(i = n1; i < n2; i++) {
+ op1 = a->tab[i];
+ ADDC(r->tab[i], carry, op1, b_sign, carry);
}
- break;
-#endif
- default:
- val = JS_ToNumberFree(ctx, val);
- if (JS_IsException(val)) {
- *pres = 0;
- return -1;
+ } else if (a->len < b->len) {
+ for(i = n1; i < n2; i++) {
+ op2 = b->tab[i] ^ (-b_neg);
+ ADDC(r->tab[i], carry, a_sign, op2, carry);
}
- goto redo;
}
- *pres = ret;
- return 0;
+
+ /* part with sign extension for both operands. Extend the result
+ if necessary */
+ return js_bigint_extend(ctx, r, a_sign + b_sign + carry);
}
-int JS_ToInt32Sat(JSContext *ctx, int *pres, JSValueConst val)
+/* XXX: optimize */
+static JSBigInt *js_bigint_neg(JSContext *ctx, const JSBigInt *a)
{
- return JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));
+ JSBigIntBuf buf;
+ JSBigInt *b;
+ b = js_bigint_set_si(&buf, 0);
+ return js_bigint_add(ctx, b, a, 1);
}
-int JS_ToInt32Clamp(JSContext *ctx, int *pres, JSValueConst val,
- int min, int max, int min_offset)
+static JSBigInt *js_bigint_mul(JSContext *ctx, const JSBigInt *a,
+ const JSBigInt *b)
{
- int res = JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));
- if (res == 0) {
- if (*pres < min) {
- *pres += min_offset;
- if (*pres < min)
- *pres = min;
+ JSBigInt *r;
+
+ r = js_bigint_new(ctx, a->len + b->len);
+ if (!r)
+ return NULL;
+ mp_mul_basecase(r->tab, a->tab, a->len, b->tab, b->len);
+ /* correct the result if negative operands (no overflow is
+ possible) */
+ if (js_bigint_sign(a))
+ mp_sub(r->tab + a->len, r->tab + a->len, b->tab, b->len, 0);
+ if (js_bigint_sign(b))
+ mp_sub(r->tab + b->len, r->tab + b->len, a->tab, a->len, 0);
+ return js_bigint_normalize(ctx, r);
+}
+
+/* return the division or the remainder. 'b' must be != 0. return NULL
+ in case of exception (division by zero or memory error) */
+static JSBigInt *js_bigint_divrem(JSContext *ctx, const JSBigInt *a,
+ const JSBigInt *b, BOOL is_rem)
+{
+ JSBigInt *r, *q;
+ js_limb_t *tabb, h;
+ int na, nb, a_sign, b_sign, shift;
+
+ if (b->len == 1 && b->tab[0] == 0) {
+ JS_ThrowRangeError(ctx, "BigInt division by zero");
+ return NULL;
+ }
+
+ a_sign = js_bigint_sign(a);
+ b_sign = js_bigint_sign(b);
+ na = a->len;
+ nb = b->len;
+
+ r = js_bigint_new(ctx, na + 2);
+ if (!r)
+ return NULL;
+ if (a_sign) {
+ mp_neg(r->tab, a->tab, na);
+ } else {
+ memcpy(r->tab, a->tab, na * sizeof(a->tab[0]));
+ }
+ /* normalize */
+ while (na > 1 && r->tab[na - 1] == 0)
+ na--;
+
+ tabb = js_malloc(ctx, nb * sizeof(tabb[0]));
+ if (!tabb) {
+ js_free(ctx, r);
+ return NULL;
+ }
+ if (b_sign) {
+ mp_neg(tabb, b->tab, nb);
+ } else {
+ memcpy(tabb, b->tab, nb * sizeof(tabb[0]));
+ }
+ /* normalize */
+ while (nb > 1 && tabb[nb - 1] == 0)
+ nb--;
+
+ /* trivial case if 'a' is small */
+ if (na < nb) {
+ js_free(ctx, r);
+ js_free(ctx, tabb);
+ if (is_rem) {
+ /* r = a */
+ r = js_bigint_new(ctx, a->len);
+ if (!r)
+ return NULL;
+ memcpy(r->tab, a->tab, a->len * sizeof(a->tab[0]));
+ return r;
} else {
- if (*pres > max)
- *pres = max;
+ /* q = 0 */
+ return js_bigint_new_si(ctx, 0);
}
}
- return res;
-}
-static int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val)
-{
- uint32_t tag;
+ /* normalize 'b' */
+ shift = js_limb_clz(tabb[nb - 1]);
+ if (shift != 0) {
+ mp_shl(tabb, tabb, nb, shift);
+ h = mp_shl(r->tab, r->tab, na, shift);
+ if (h != 0)
+ r->tab[na++] = h;
+ }
- redo:
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_INT:
- case JS_TAG_BOOL:
- case JS_TAG_NULL:
- case JS_TAG_UNDEFINED:
- *pres = JS_VALUE_GET_INT(val);
- return 0;
- case JS_TAG_EXCEPTION:
- *pres = 0;
- return -1;
- case JS_TAG_FLOAT64:
- {
- double d = JS_VALUE_GET_FLOAT64(val);
- if (isnan(d)) {
- *pres = 0;
- } else {
- if (d < INT64_MIN)
- *pres = INT64_MIN;
- else if (d > INT64_MAX)
- *pres = INT64_MAX;
- else
- *pres = (int64_t)d;
- }
- }
- return 0;
-#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_FLOAT:
- {
- JSBigFloat *p = JS_VALUE_GET_PTR(val);
- bf_get_int64(pres, &p->num, 0);
- JS_FreeValue(ctx, val);
- }
- return 0;
-#endif
- default:
- val = JS_ToNumberFree(ctx, val);
- if (JS_IsException(val)) {
- *pres = 0;
- return -1;
- }
- goto redo;
+ q = js_bigint_new(ctx, na - nb + 2); /* one more limb for the sign */
+ if (!q) {
+ js_free(ctx, r);
+ js_free(ctx, tabb);
+ return NULL;
}
-}
-int JS_ToInt64Sat(JSContext *ctx, int64_t *pres, JSValueConst val)
-{
- return JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val));
-}
+ // js_bigint_dump1(ctx, "a", r->tab, na);
+ // js_bigint_dump1(ctx, "b", tabb, nb);
+ mp_divnorm(q->tab, r->tab, na, tabb, nb);
+ js_free(ctx, tabb);
-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;
+ if (is_rem) {
+ js_free(ctx, q);
+ if (shift != 0)
+ mp_shr(r->tab, r->tab, nb, shift, 0);
+ r->tab[nb++] = 0;
+ if (a_sign)
+ mp_neg(r->tab, r->tab, nb);
+ r = js_bigint_normalize1(ctx, r, nb);
+ return r;
+ } else {
+ js_free(ctx, r);
+ q->tab[na - nb + 1] = 0;
+ if (a_sign ^ b_sign) {
+ mp_neg(q->tab, q->tab, q->len);
+ }
+ q = js_bigint_normalize(ctx, q);
+ return q;
}
- 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)
+/* and, or, xor */
+static JSBigInt *js_bigint_logic(JSContext *ctx, const JSBigInt *a,
+ const JSBigInt *b, OPCodeEnum op)
{
- uint32_t tag;
- int64_t ret;
+ JSBigInt *r;
+ js_limb_t b_sign;
+ int a_len, b_len, i;
- 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);
+ if (a->len < b->len) {
+ const JSBigInt *tmp;
+ tmp = a;
+ a = b;
+ b = tmp;
+ }
+ /* a_len >= b_len */
+ a_len = a->len;
+ b_len = b->len;
+ b_sign = -js_bigint_sign(b);
+
+ r = js_bigint_new(ctx, a_len);
+ if (!r)
+ return NULL;
+ switch(op) {
+ case OP_or:
+ for(i = 0; i < b_len; i++) {
+ r->tab[i] = a->tab[i] | b->tab[i];
+ }
+ for(i = b_len; i < a_len; i++) {
+ r->tab[i] = a->tab[i] | b_sign;
+ }
break;
- case 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 */
- }
+ case OP_and:
+ for(i = 0; i < b_len; i++) {
+ r->tab[i] = a->tab[i] & b->tab[i];
+ }
+ for(i = b_len; i < a_len; i++) {
+ r->tab[i] = a->tab[i] & b_sign;
}
break;
-#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);
+ case OP_xor:
+ for(i = 0; i < b_len; i++) {
+ r->tab[i] = a->tab[i] ^ b->tab[i];
+ }
+ for(i = b_len; i < a_len; i++) {
+ r->tab[i] = a->tab[i] ^ b_sign;
}
break;
-#endif
default:
- val = JS_ToNumberFree(ctx, val);
- if (JS_IsException(val)) {
- *pres = 0;
- return -1;
- }
- goto redo;
+ abort();
}
- *pres = ret;
- return 0;
+ return js_bigint_normalize(ctx, r);
}
-int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
+static JSBigInt *js_bigint_not(JSContext *ctx, const JSBigInt *a)
{
- return JS_ToInt64Free(ctx, pres, JS_DupValue(ctx, val));
+ JSBigInt *r;
+ int i;
+
+ r = js_bigint_new(ctx, a->len);
+ if (!r)
+ return NULL;
+ for(i = 0; i < a->len; i++) {
+ r->tab[i] = ~a->tab[i];
+ }
+ /* no normalization is needed */
+ return r;
}
-int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val)
+static JSBigInt *js_bigint_shl(JSContext *ctx, const JSBigInt *a,
+ unsigned int shift1)
{
- if (JS_IsBigInt(ctx, val))
- return JS_ToBigInt64(ctx, pres, val);
- else
- return JS_ToInt64(ctx, pres, val);
+ int d, i, shift;
+ JSBigInt *r;
+ js_limb_t l;
+
+ if (a->len == 1 && a->tab[0] == 0)
+ return js_bigint_new_si(ctx, 0); /* zero case */
+ d = shift1 / JS_LIMB_BITS;
+ shift = shift1 % JS_LIMB_BITS;
+ r = js_bigint_new(ctx, a->len + d);
+ if (!r)
+ return NULL;
+ for(i = 0; i < d; i++)
+ r->tab[i] = 0;
+ if (shift == 0) {
+ for(i = 0; i < a->len; i++) {
+ r->tab[i + d] = a->tab[i];
+ }
+ } else {
+ l = mp_shl(r->tab + d, a->tab, a->len, shift);
+ if (js_bigint_sign(a))
+ l |= (js_limb_t)(-1) << shift;
+ r = js_bigint_extend(ctx, r, l);
+ }
+ return r;
}
-/* return (<0, 0) in case of exception */
-static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val)
+static JSBigInt *js_bigint_shr(JSContext *ctx, const JSBigInt *a,
+ unsigned int shift1)
{
- uint32_t tag;
- int32_t ret;
+ int d, i, shift, a_sign, n1;
+ JSBigInt *r;
- 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 */
- }
+ d = shift1 / JS_LIMB_BITS;
+ shift = shift1 % JS_LIMB_BITS;
+ a_sign = js_bigint_sign(a);
+ if (d >= a->len)
+ return js_bigint_new_si(ctx, -a_sign);
+ n1 = a->len - d;
+ r = js_bigint_new(ctx, n1);
+ if (!r)
+ return NULL;
+ if (shift == 0) {
+ for(i = 0; i < n1; i++) {
+ r->tab[i] = a->tab[i + d];
}
- 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);
+ /* no normalization is needed */
+ } else {
+ mp_shr(r->tab, a->tab + d, n1, shift, -a_sign);
+ r = js_bigint_normalize(ctx, r);
+ }
+ return r;
+}
+
+static JSBigInt *js_bigint_pow(JSContext *ctx, const JSBigInt *a, JSBigInt *b)
+{
+ uint32_t e;
+ int n_bits, i;
+ JSBigInt *r, *r1;
+
+ /* b must be >= 0 */
+ if (js_bigint_sign(b)) {
+ JS_ThrowRangeError(ctx, "BigInt negative exponent");
+ return NULL;
+ }
+ if (b->len == 1 && b->tab[0] == 0) {
+ /* a^0 = 1 */
+ return js_bigint_new_si(ctx, 1);
+ } else if (a->len == 1) {
+ js_limb_t v;
+ BOOL is_neg;
+
+ v = a->tab[0];
+ if (v <= 1)
+ return js_bigint_new_si(ctx, v);
+ else if (v == -1)
+ return js_bigint_new_si(ctx, 1 - 2 * (b->tab[0] & 1));
+ is_neg = (js_slimb_t)v < 0;
+ if (is_neg)
+ v = -v;
+ if ((v & (v - 1)) == 0) {
+ uint64_t e1;
+ int n;
+ /* v = 2^n */
+ n = JS_LIMB_BITS - 1 - js_limb_clz(v);
+ if (b->len > 1)
+ goto overflow;
+ if (b->tab[0] > INT32_MAX)
+ goto overflow;
+ e = b->tab[0];
+ e1 = (uint64_t)e * n;
+ if (e1 > JS_BIGINT_MAX_SIZE * JS_LIMB_BITS)
+ goto overflow;
+ e = e1;
+ if (is_neg)
+ is_neg = b->tab[0] & 1;
+ r = js_bigint_new(ctx,
+ (e + JS_LIMB_BITS + 1 - is_neg) / JS_LIMB_BITS);
+ if (!r)
+ return NULL;
+ memset(r->tab, 0, sizeof(r->tab[0]) * r->len);
+ r->tab[e / JS_LIMB_BITS] =
+ (js_limb_t)(1 - 2 * is_neg) << (e % JS_LIMB_BITS);
+ return r;
}
- break;
-#endif
- default:
- val = JS_ToNumberFree(ctx, val);
- if (JS_IsException(val)) {
- *pres = 0;
- return -1;
+ }
+ if (b->len > 1)
+ goto overflow;
+ if (b->tab[0] > INT32_MAX)
+ goto overflow;
+ e = b->tab[0];
+ n_bits = 32 - clz32(e);
+
+ r = js_bigint_new(ctx, a->len);
+ if (!r)
+ return NULL;
+ memcpy(r->tab, a->tab, a->len * sizeof(a->tab[0]));
+ for(i = n_bits - 2; i >= 0; i--) {
+ r1 = js_bigint_mul(ctx, r, r);
+ if (!r1)
+ return NULL;
+ js_free(ctx, r);
+ r = r1;
+ if ((e >> i) & 1) {
+ r1 = js_bigint_mul(ctx, r, a);
+ if (!r1)
+ return NULL;
+ js_free(ctx, r);
+ r = r1;
}
- goto redo;
}
- *pres = ret;
- return 0;
+ return r;
+ overflow:
+ JS_ThrowRangeError(ctx, "BigInt is too large");
+ return NULL;
}
-int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val)
-{
- return JS_ToInt32Free(ctx, pres, JS_DupValue(ctx, val));
+/* return (mant, exp) so that abs(a) ~ mant*2^(exp - (limb_bits -
+ 1). a must be != 0. */
+static uint64_t js_bigint_get_mant_exp(JSContext *ctx,
+ int *pexp, const JSBigInt *a)
+{
+ js_limb_t t[4 - JS_LIMB_BITS / 32], carry, v, low_bits;
+ int n1, n2, sgn, shift, i, j, e;
+ uint64_t a1, a0;
+
+ n2 = 4 - JS_LIMB_BITS / 32;
+ n1 = a->len - n2;
+ sgn = js_bigint_sign(a);
+
+ /* low_bits != 0 if there are a non zero low bit in abs(a) */
+ low_bits = 0;
+ carry = sgn;
+ for(i = 0; i < n1; i++) {
+ v = (a->tab[i] ^ (-sgn)) + carry;
+ carry = v < carry;
+ low_bits |= v;
+ }
+ /* get the n2 high limbs of abs(a) */
+ for(j = 0; j < n2; j++) {
+ i = j + n1;
+ if (i < 0) {
+ v = 0;
+ } else {
+ v = (a->tab[i] ^ (-sgn)) + carry;
+ carry = v < carry;
+ }
+ t[j] = v;
+ }
+
+#if JS_LIMB_BITS == 32
+ a1 = ((uint64_t)t[2] << 32) | t[1];
+ a0 = (uint64_t)t[0] << 32;
+#else
+ a1 = t[1];
+ a0 = t[0];
+#endif
+ a0 |= (low_bits != 0);
+ /* normalize */
+ if (a1 == 0) {
+ /* JS_LIMB_BITS = 64 bit only */
+ shift = 64;
+ a1 = a0;
+ a0 = 0;
+ } else {
+ shift = clz64(a1);
+ if (shift != 0) {
+ a1 = (a1 << shift) | (a0 >> (64 - shift));
+ a0 <<= shift;
+ }
+ }
+ a1 |= (a0 != 0); /* keep the bits for the final rounding */
+ /* compute the exponent */
+ e = a->len * JS_LIMB_BITS - shift - 1;
+ *pexp = e;
+ return a1;
}
-static inline int JS_ToUint32Free(JSContext *ctx, uint32_t *pres, JSValue val)
+/* shift left with round to nearest, ties to even. n >= 1 */
+static uint64_t shr_rndn(uint64_t a, int n)
{
- return JS_ToInt32Free(ctx, (int32_t *)pres, val);
+ uint64_t addend = ((a >> n) & 1) + ((1 << (n - 1)) - 1);
+ return (a + addend) >> n;
}
-static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val)
+/* convert to float64 with round to nearest, ties to even. Return
+ +/-infinity if too large. */
+static double js_bigint_to_float64(JSContext *ctx, const JSBigInt *a)
{
- uint32_t tag;
- int res;
+ int sgn, e;
+ uint64_t mant;
- 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;
+ if (a->len == 1) {
+ /* fast case, including zero */
+ return (double)(js_slimb_t)a->tab[0];
+ }
+
+ sgn = js_bigint_sign(a);
+ mant = js_bigint_get_mant_exp(ctx, &e, a);
+ if (e > 1023) {
+ /* overflow: return infinity */
+ mant = 0;
+ e = 1024;
+ } else {
+ mant = (mant >> 1) | (mant & 1); /* avoid overflow in rounding */
+ mant = shr_rndn(mant, 10);
+ /* rounding can cause an overflow */
+ if (mant >= ((uint64_t)1 << 53)) {
+ mant >>= 1;
+ e++;
}
- goto redo;
+ mant &= (((uint64_t)1 << 52) - 1);
}
- *pres = res;
- return 0;
+ return uint64_as_float64(((uint64_t)sgn << 63) |
+ ((uint64_t)(e + 1023) << 52) |
+ mant);
}
-static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
- JSValue val, BOOL is_array_ctor)
+/* return (1, NULL) if not an integer, (2, NULL) if NaN or Infinity,
+ (0, n) if an integer, (0, NULL) in case of memory error */
+static JSBigInt *js_bigint_from_float64(JSContext *ctx, int *pres, double a1)
{
- uint32_t tag, len;
+ uint64_t a = float64_as_uint64(a1);
+ int sgn, e, shift;
+ uint64_t mant;
+ JSBigIntBuf buf;
+ JSBigInt *r;
+
+ sgn = a >> 63;
+ e = (a >> 52) & ((1 << 11) - 1);
+ mant = a & (((uint64_t)1 << 52) - 1);
+ if (e == 2047) {
+ /* NaN, Infinity */
+ *pres = 2;
+ return NULL;
+ }
+ if (e == 0 && mant == 0) {
+ /* zero */
+ *pres = 0;
+ return js_bigint_new_si(ctx, 0);
+ }
+ e -= 1023;
+ /* 0 < a < 1 : not an integer */
+ if (e < 0)
+ goto not_an_integer;
+ mant |= (uint64_t)1 << 52;
+ if (e < 52) {
+ shift = 52 - e;
+ /* check that there is no fractional part */
+ if (mant & (((uint64_t)1 << shift) - 1)) {
+ not_an_integer:
+ *pres = 1;
+ return NULL;
+ }
+ mant >>= shift;
+ e = 0;
+ } else {
+ e -= 52;
+ }
+ if (sgn)
+ mant = -mant;
+ /* the integer is mant*2^e */
+ r = js_bigint_set_si64(&buf, (int64_t)mant);
+ *pres = 0;
+ return js_bigint_shl(ctx, r, e);
+}
- 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;
+/* return -1, 0, 1 or (2) (unordered) */
+static int js_bigint_float64_cmp(JSContext *ctx, const JSBigInt *a,
+ double b)
+{
+ int b_sign, a_sign, e, f;
+ uint64_t mant, b1, a_mant;
+
+ b1 = float64_as_uint64(b);
+ b_sign = b1 >> 63;
+ e = (b1 >> 52) & ((1 << 11) - 1);
+ mant = b1 & (((uint64_t)1 << 52) - 1);
+ a_sign = js_bigint_sign(a);
+ if (e == 2047) {
+ if (mant != 0) {
+ /* NaN */
+ return 2;
+ } else {
+ /* +/- infinity */
+ return 2 * b_sign - 1;
}
- break;
- case JS_TAG_BIG_INT:
-#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_FLOAT:
-#endif
- {
- 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;
+ } else if (e == 0 && mant == 0) {
+ /* b = +/-0 */
+ if (a->len == 1 && a->tab[0] == 0)
+ return 0;
+ else
+ return 1 - 2 * a_sign;
+ } else if (a->len == 1 && a->tab[0] == 0) {
+ /* a = 0, b != 0 */
+ return 2 * b_sign - 1;
+ } else if (a_sign != b_sign) {
+ return 1 - 2 * a_sign;
+ } else {
+ e -= 1023;
+ /* Note: handling denormals is not necessary because we
+ compare to integers hence f >= 0 */
+ /* compute f so that 2^f <= abs(a) < 2^(f+1) */
+ a_mant = js_bigint_get_mant_exp(ctx, &f, a);
+ if (f != e) {
+ if (f < e)
+ return -1;
+ else
+ return 1;
+ } else {
+ mant = (mant | ((uint64_t)1 << 52)) << 11; /* align to a_mant */
+ if (a_mant < mant)
+ return 2 * a_sign - 1;
+ else if (a_mant > mant)
+ return 1 - 2 * a_sign;
+ else
+ return 0;
}
- break;
- default:
- if (JS_TAG_IS_FLOAT64(tag)) {
- double d;
- d = JS_VALUE_GET_FLOAT64(val);
- len = (uint32_t)d;
- if (len != d)
- goto fail;
+ }
+}
+
+/* return -1, 0 or 1 */
+static int js_bigint_cmp(JSContext *ctx, const JSBigInt *a,
+ const JSBigInt *b)
+{
+ int a_sign, b_sign, res, i;
+ a_sign = js_bigint_sign(a);
+ b_sign = js_bigint_sign(b);
+ if (a_sign != b_sign) {
+ res = 1 - 2 * a_sign;
+ } else {
+ /* we assume the numbers are normalized */
+ if (a->len != b->len) {
+ if (a->len < b->len)
+ res = 2 * a_sign - 1;
+ else
+ res = 1 - 2 * a_sign;
} else {
- uint32_t len1;
+ res = 0;
+ for(i = a->len -1; i >= 0; i--) {
+ if (a->tab[i] != b->tab[i]) {
+ if (a->tab[i] < b->tab[i])
+ res = -1;
+ else
+ res = 1;
+ break;
+ }
+ }
+ }
+ }
+ return res;
+}
- 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;
+/* contains 10^i */
+static const js_limb_t js_pow_dec[JS_LIMB_DIGITS + 1] = {
+ 1U,
+ 10U,
+ 100U,
+ 1000U,
+ 10000U,
+ 100000U,
+ 1000000U,
+ 10000000U,
+ 100000000U,
+ 1000000000U,
+#if JS_LIMB_BITS == 64
+ 10000000000U,
+ 100000000000U,
+ 1000000000000U,
+ 10000000000000U,
+ 100000000000000U,
+ 1000000000000000U,
+ 10000000000000000U,
+ 100000000000000000U,
+ 1000000000000000000U,
+ 10000000000000000000U,
+#endif
+};
+
+/* syntax: [-]digits in base radix. Return NULL if memory error. radix
+ = 10, 2, 8 or 16. */
+static JSBigInt *js_bigint_from_string(JSContext *ctx,
+ const char *str, int radix)
+{
+ const char *p = str;
+ int is_neg, n_digits, n_limbs, len, log2_radix, n_bits, i;
+ JSBigInt *r;
+ js_limb_t v, c, h;
+
+ is_neg = 0;
+ if (*p == '-') {
+ is_neg = 1;
+ p++;
+ }
+ while (*p == '0')
+ p++;
+ n_digits = strlen(p);
+ log2_radix = 32 - clz32(radix - 1); /* ceil(log2(radix)) */
+ /* compute the maximum number of limbs */
+ /* XXX: overflow */
+ if (radix == 10) {
+ n_bits = (n_digits * 27 + 7) / 8; /* >= ceil(n_digits * log2(10)) */
+ } else {
+ n_bits = n_digits * log2_radix;
+ }
+ /* we add one extra bit for the sign */
+ n_limbs = max_int(1, n_bits / JS_LIMB_BITS + 1);
+ r = js_bigint_new(ctx, n_limbs);
+ if (!r)
+ return NULL;
+ if (radix == 10) {
+ int digits_per_limb = JS_LIMB_DIGITS;
+ len = 1;
+ r->tab[0] = 0;
+ for(;;) {
+ /* XXX: slow */
+ v = 0;
+ for(i = 0; i < digits_per_limb; i++) {
+ c = to_digit(*p);
+ if (c >= radix)
+ break;
+ p++;
+ v = v * 10 + c;
+ }
+ if (i == 0)
+ break;
+ if (len == 1 && r->tab[0] == 0) {
+ r->tab[0] = v;
} else {
- /* 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;
+ h = mp_mul1(r->tab, r->tab, len, js_pow_dec[i], v);
+ if (h != 0) {
+ r->tab[len++] = h;
}
}
}
- break;
+ /* add one extra limb to have the correct sign*/
+ if ((r->tab[len - 1] >> (JS_LIMB_BITS - 1)) != 0)
+ r->tab[len++] = 0;
+ r->len = len;
+ } else {
+ unsigned int bit_pos, shift, pos;
+
+ /* power of two base: no multiplication is needed */
+ r->len = n_limbs;
+ memset(r->tab, 0, sizeof(r->tab[0]) * n_limbs);
+ for(i = 0; i < n_digits; i++) {
+ c = to_digit(p[n_digits - 1 - i]);
+ assert(c < radix);
+ bit_pos = i * log2_radix;
+ shift = bit_pos & (JS_LIMB_BITS - 1);
+ pos = bit_pos / JS_LIMB_BITS;
+ r->tab[pos] |= c << shift;
+ /* if log2_radix does not divide JS_LIMB_BITS, needed an
+ additional op */
+ if (shift + log2_radix > JS_LIMB_BITS) {
+ r->tab[pos + 1] |= c >> (JS_LIMB_BITS - shift);
+ }
+ }
+ }
+ r = js_bigint_normalize(ctx, r);
+ /* XXX: could do it in place */
+ if (is_neg) {
+ JSBigInt *r1;
+ r1 = js_bigint_neg(ctx, r);
+ js_free(ctx, r);
+ r = r1;
}
- *plen = len;
- return 0;
+ return r;
}
-#define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1)
+/* 2 <= base <= 36 */
+static char const digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
-static BOOL is_safe_integer(double d)
+/* special version going backwards */
+/* XXX: use dtoa.c */
+static char *js_u64toa(char *q, int64_t n, unsigned int base)
{
- return isfinite(d) && floor(d) == d &&
- fabs(d) <= (double)MAX_SAFE_INTEGER;
+ int digit;
+ if (base == 10) {
+ /* division by known base uses multiplication */
+ do {
+ digit = (uint64_t)n % 10;
+ n = (uint64_t)n / 10;
+ *--q = '0' + digit;
+ } while (n != 0);
+ } else {
+ do {
+ digit = (uint64_t)n % base;
+ n = (uint64_t)n / base;
+ *--q = digits[digit];
+ } while (n != 0);
+ }
+ return q;
}
-int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val)
+/* len >= 1. 2 <= radix <= 36 */
+static char *limb_to_a(char *q, js_limb_t n, unsigned int radix, int len)
{
- 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;
+ int digit, i;
+
+ if (radix == 10) {
+ /* specific case with constant divisor */
+ /* XXX: optimize */
+ for(i = 0; i < len; i++) {
+ digit = (js_limb_t)n % 10;
+ n = (js_limb_t)n / 10;
+ *--q = digit + '0';
+ }
+ } else {
+ for(i = 0; i < len; i++) {
+ digit = (js_limb_t)n % radix;
+ n = (js_limb_t)n / radix;
+ *--q = digits[digit];
+ }
}
- *plen = v;
- return 0;
+ return q;
}
-/* convert a value to a length between 0 and MAX_SAFE_INTEGER.
- return -1 for exception */
-static __exception int JS_ToLengthFree(JSContext *ctx, int64_t *plen,
- JSValue val)
+#define JS_RADIX_MAX 36
+
+static const uint8_t digits_per_limb_table[JS_RADIX_MAX - 1] = {
+#if JS_LIMB_BITS == 32
+32,20,16,13,12,11,10,10, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+#else
+64,40,32,27,24,22,21,20,19,18,17,17,16,16,16,15,15,15,14,14,14,14,13,13,13,13,13,13,13,12,12,12,12,12,12,
+#endif
+};
+
+static const js_limb_t radix_base_table[JS_RADIX_MAX - 1] = {
+#if JS_LIMB_BITS == 32
+ 0x00000000, 0xcfd41b91, 0x00000000, 0x48c27395,
+ 0x81bf1000, 0x75db9c97, 0x40000000, 0xcfd41b91,
+ 0x3b9aca00, 0x8c8b6d2b, 0x19a10000, 0x309f1021,
+ 0x57f6c100, 0x98c29b81, 0x00000000, 0x18754571,
+ 0x247dbc80, 0x3547667b, 0x4c4b4000, 0x6b5a6e1d,
+ 0x94ace180, 0xcaf18367, 0x0b640000, 0x0e8d4a51,
+ 0x1269ae40, 0x17179149, 0x1cb91000, 0x23744899,
+ 0x2b73a840, 0x34e63b41, 0x40000000, 0x4cfa3cc1,
+ 0x5c13d840, 0x6d91b519, 0x81bf1000,
+#else
+ 0x0000000000000000, 0xa8b8b452291fe821, 0x0000000000000000, 0x6765c793fa10079d,
+ 0x41c21cb8e1000000, 0x3642798750226111, 0x8000000000000000, 0xa8b8b452291fe821,
+ 0x8ac7230489e80000, 0x4d28cb56c33fa539, 0x1eca170c00000000, 0x780c7372621bd74d,
+ 0x1e39a5057d810000, 0x5b27ac993df97701, 0x0000000000000000, 0x27b95e997e21d9f1,
+ 0x5da0e1e53c5c8000, 0xd2ae3299c1c4aedb, 0x16bcc41e90000000, 0x2d04b7fdd9c0ef49,
+ 0x5658597bcaa24000, 0xa0e2073737609371, 0x0c29e98000000000, 0x14adf4b7320334b9,
+ 0x226ed36478bfa000, 0x383d9170b85ff80b, 0x5a3c23e39c000000, 0x8e65137388122bcd,
+ 0xdd41bb36d259e000, 0x0aee5720ee830681, 0x1000000000000000, 0x172588ad4f5f0981,
+ 0x211e44f7d02c1000, 0x2ee56725f06e5c71, 0x41c21cb8e1000000,
+#endif
+};
+
+static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix)
{
- int res = JS_ToInt64Clamp(ctx, plen, val, 0, MAX_SAFE_INTEGER, 0);
- JS_FreeValue(ctx, val);
- return res;
+ if (JS_VALUE_GET_TAG(val) == JS_TAG_SHORT_BIG_INT) {
+ char buf[66];
+ int len;
+ len = i64toa_radix(buf, JS_VALUE_GET_SHORT_BIG_INT(val), radix);
+ return js_new_string8_len(ctx, buf, len);
+ } else {
+ JSBigInt *r, *tmp = NULL;
+ char *buf, *q, *buf_end;
+ int is_neg, n_bits, log2_radix, n_digits;
+ BOOL is_binary_radix;
+ JSValue res;
+
+ assert(JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT);
+ r = JS_VALUE_GET_PTR(val);
+ if (r->len == 1 && r->tab[0] == 0) {
+ /* '0' case */
+ return js_new_string8_len(ctx, "0", 1);
+ }
+ is_binary_radix = ((radix & (radix - 1)) == 0);
+ is_neg = js_bigint_sign(r);
+ if (is_neg) {
+ tmp = js_bigint_neg(ctx, r);
+ if (!tmp)
+ return JS_EXCEPTION;
+ r = tmp;
+ } else if (!is_binary_radix) {
+ /* need to modify 'r' */
+ tmp = js_bigint_new(ctx, r->len);
+ if (!tmp)
+ return JS_EXCEPTION;
+ memcpy(tmp->tab, r->tab, r->len * sizeof(r->tab[0]));
+ r = tmp;
+ }
+ log2_radix = 31 - clz32(radix); /* floor(log2(radix)) */
+ n_bits = r->len * JS_LIMB_BITS - js_limb_safe_clz(r->tab[r->len - 1]);
+ /* n_digits is exact only if radix is a power of
+ two. Otherwise it is >= the exact number of digits */
+ n_digits = (n_bits + log2_radix - 1) / log2_radix;
+ /* XXX: could directly build the JSString */
+ buf = js_malloc(ctx, n_digits + is_neg + 1);
+ if (!buf) {
+ js_free(ctx, tmp);
+ return JS_EXCEPTION;
+ }
+ q = buf + n_digits + is_neg + 1;
+ *--q = '\0';
+ buf_end = q;
+ if (!is_binary_radix) {
+ int len;
+ js_limb_t radix_base, v;
+ radix_base = radix_base_table[radix - 2];
+ len = r->len;
+ for(;;) {
+ /* remove leading zero limbs */
+ while (len > 1 && r->tab[len - 1] == 0)
+ len--;
+ if (len == 1 && r->tab[0] < radix_base) {
+ v = r->tab[0];
+ if (v != 0) {
+ q = js_u64toa(q, v, radix);
+ }
+ break;
+ } else {
+ v = mp_div1(r->tab, r->tab, len, radix_base, 0);
+ q = limb_to_a(q, v, radix, digits_per_limb_table[radix - 2]);
+ }
+ }
+ } else {
+ int i, shift;
+ unsigned int bit_pos, pos, c;
+
+ /* radix is a power of two */
+ for(i = 0; i < n_digits; i++) {
+ bit_pos = i * log2_radix;
+ pos = bit_pos / JS_LIMB_BITS;
+ shift = bit_pos % JS_LIMB_BITS;
+ if (likely((shift + log2_radix) <= JS_LIMB_BITS)) {
+ c = r->tab[pos] >> shift;
+ } else {
+ c = (r->tab[pos] >> shift) |
+ (r->tab[pos + 1] << (JS_LIMB_BITS - shift));
+ }
+ c &= (radix - 1);
+ *--q = digits[c];
+ }
+ }
+ if (is_neg)
+ *--q = '-';
+ js_free(ctx, tmp);
+ res = js_new_string8_len(ctx, q, buf_end - q);
+ js_free(ctx, buf);
+ return res;
+ }
}
-/* Note: can return an exception */
-static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val)
+/* if possible transform a BigInt to short big and free it, otherwise
+ return a normal bigint */
+static JSValue JS_CompactBigInt(JSContext *ctx, JSBigInt *p)
{
- double d;
- if (!JS_IsNumber(val))
- return FALSE;
- if (unlikely(JS_ToFloat64(ctx, &d, val)))
- return -1;
- return isfinite(d) && floor(d) == d;
+ JSValue res;
+ if (p->len == 1) {
+ res = __JS_NewShortBigInt(ctx, (js_slimb_t)p->tab[0]);
+ js_free(ctx, p);
+ return res;
+ } else {
+ return JS_MKPTR(JS_TAG_BIG_INT, p);
+ }
}
-static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val)
+#define ATOD_INT_ONLY (1 << 0)
+/* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */
+#define ATOD_ACCEPT_BIN_OCT (1 << 2)
+/* accept O prefix as octal if radix == 0 and properly formed (Annex B) */
+#define ATOD_ACCEPT_LEGACY_OCTAL (1 << 4)
+/* accept _ between digits as a digit separator */
+#define ATOD_ACCEPT_UNDERSCORES (1 << 5)
+/* allow a suffix to override the type */
+#define ATOD_ACCEPT_SUFFIX (1 << 6)
+/* default type */
+#define ATOD_TYPE_MASK (3 << 7)
+#define ATOD_TYPE_FLOAT64 (0 << 7)
+#define ATOD_TYPE_BIG_INT (1 << 7)
+/* accept -0x1 */
+#define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10)
+
+/* return an exception in case of memory error. Return JS_NAN if
+ invalid syntax */
+/* XXX: directly use js_atod() */
+static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
+ int radix, int flags)
{
- uint32_t tag;
+ 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 = NULL;
+ int i, j, len;
+ BOOL buf_allocated = FALSE;
+ JSValue val;
+ JSATODTempMem atod_mem;
+
+ /* optional separator between digits */
+ sep = (flags & ATOD_ACCEPT_UNDERSCORES) ? '_' : 256;
+ has_legacy_octal = FALSE;
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_INT:
- {
- int v;
- v = JS_VALUE_GET_INT(val);
- return (v < 0);
+ 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;
}
- case JS_TAG_FLOAT64:
- {
- JSFloat64Union u;
- u.d = JS_VALUE_GET_FLOAT64(val);
- return (u.u64 >> 63);
+ /* there must be a digit after the prefix */
+ if (to_digit((uint8_t)*p) >= radix)
+ goto fail;
+ no_prefix: ;
+ } else {
+ no_radix_prefix:
+ if (!(flags & ATOD_INT_ONLY) &&
+ (atod_type == ATOD_TYPE_FLOAT64) &&
+ strstart(p, "Infinity", &p)) {
+#ifdef _MSC_VER
+ double d = INFINITY;
+#else
+ double d = 1.0 / 0.0;
+#endif
+ if (is_neg)
+ d = -d;
+ val = JS_NewFloat64(ctx, d);
+ goto done;
}
- 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);
+ }
+ if (radix == 0)
+ radix = 10;
+ is_float = FALSE;
+ p_start = p;
+ while (to_digit((uint8_t)*p) < radix
+ || (*p == sep && (radix != 10 ||
+ p != p_start + 1 || p[-1] != '0') &&
+ to_digit((uint8_t)p[1]) < radix)) {
+ p++;
+ }
+ if (!(flags & ATOD_INT_ONLY)) {
+ if (*p == '.' && (p > p_start || to_digit((uint8_t)p[1]) < radix)) {
+ is_float = TRUE;
+ p++;
+ if (*p == sep)
+ goto fail;
+ while (to_digit((uint8_t)*p) < radix ||
+ (*p == sep && to_digit((uint8_t)p[1]) < radix))
+ p++;
+ }
+ if (p > p_start &&
+ (((*p == 'e' || *p == 'E') && radix == 10) ||
+ ((*p == 'p' || *p == 'P') && (radix == 2 || radix == 8 || radix == 16)))) {
+ const char *p1 = p + 1;
+ is_float = TRUE;
+ if (*p1 == '+') {
+ p1++;
+ } else if (*p1 == '-') {
+ p1++;
+ }
+ if (is_digit((uint8_t)*p1)) {
+ p = p1 + 1;
+ while (is_digit((uint8_t)*p) || (*p == sep && is_digit((uint8_t)p[1])))
+ p++;
+ }
+ }
+ }
+ if (p == p_start)
+ goto fail;
+
+ buf = buf1;
+ buf_allocated = FALSE;
+ len = p - p_start;
+ if (unlikely((len + 2) > sizeof(buf1))) {
+ buf = js_malloc_rt(ctx->rt, len + 2); /* no exception raised */
+ if (!buf)
+ goto mem_error;
+ buf_allocated = TRUE;
+ }
+ /* remove the separators and the radix prefixes */
+ j = 0;
+ if (is_neg)
+ buf[j++] = '-';
+ for (i = 0; i < len; i++) {
+ if (p_start[i] != '_')
+ buf[j++] = p_start[i];
+ }
+ buf[j] = '\0';
+
+ if (flags & ATOD_ACCEPT_SUFFIX) {
+ if (*p == 'n') {
+ p++;
+ atod_type = ATOD_TYPE_BIG_INT;
+ } else {
+ if (is_float && radix != 10)
+ goto fail;
+ }
+ } else {
+ if (atod_type == ATOD_TYPE_FLOAT64) {
+ if (is_float && radix != 10)
+ goto fail;
}
-#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_FLOAT:
+ }
+
+ switch(atod_type) {
+ case ATOD_TYPE_FLOAT64:
{
- JSBigFloat *p = JS_VALUE_GET_PTR(val);
- return p->num.sign;
+ double d;
+ d = js_atod(buf, NULL, radix, is_float ? 0 : JS_ATOD_INT_ONLY,
+ &atod_mem);
+ /* return int or float64 */
+ val = JS_NewFloat64(ctx, d);
}
break;
- case JS_TAG_BIG_DECIMAL:
+ case ATOD_TYPE_BIG_INT:
{
- JSBigDecimal *p = JS_VALUE_GET_PTR(val);
- return p->num.sign;
+ JSBigInt *r;
+ if (has_legacy_octal || is_float)
+ goto fail;
+ r = js_bigint_from_string(ctx, buf, radix);
+ if (!r)
+ goto mem_error;
+ val = JS_CompactBigInt(ctx, r);
}
break;
-#endif
default:
- return FALSE;
+ abort();
}
-}
-
-static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix)
-{
- JSValue ret;
- bf_t a_s, *a;
- char *str;
- int saved_sign;
-
- a = JS_ToBigInt(ctx, &a_s, val);
- if (!a)
- return JS_EXCEPTION;
- saved_sign = a->sign;
- if (a->expn == BF_EXP_ZERO)
- a->sign = 0;
- str = bf_ftoa(NULL, a, radix, 0, BF_RNDZ | BF_FTOA_FORMAT_FRAC |
- BF_FTOA_JS_QUIRKS);
- a->sign = saved_sign;
- JS_FreeBigInt(ctx, a, &a_s);
- if (!str)
- return JS_ThrowOutOfMemory(ctx);
- ret = JS_NewString(ctx, str);
- bf_free(ctx->bf_ctx, str);
- return ret;
-}
-static JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val)
-{
- return js_bigint_to_string1(ctx, val, 10);
+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
+typedef enum JSToNumberHintEnum {
+ TON_FLAG_NUMBER,
+ TON_FLAG_NUMERIC,
+} JSToNumberHintEnum;
-static JSValue js_ftoa(JSContext *ctx, JSValueConst val1, int radix,
- limb_t prec, bf_flags_t flags)
+static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val,
+ JSToNumberHintEnum flag)
{
- JSValue val, ret;
- bf_t a_s, *a;
- char *str;
- int saved_sign;
+ uint32_t tag;
+ JSValue ret;
- val = JS_ToNumeric(ctx, val1);
- if (JS_IsException(val))
- return val;
- a = JS_ToBigFloat(ctx, &a_s, val);
- if (!a) {
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- 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));
+ redo:
+ tag = JS_VALUE_GET_NORM_TAG(val);
+ switch(tag) {
+ case JS_TAG_BIG_INT:
+ case JS_TAG_SHORT_BIG_INT:
+ if (flag != TON_FLAG_NUMERIC) {
+ JS_FreeValue(ctx, val);
+ return JS_ThrowTypeError(ctx, "cannot convert bigint to number");
+ }
+ ret = val;
+ break;
+ case JS_TAG_FLOAT64:
+ case JS_TAG_INT:
+ case JS_TAG_EXCEPTION:
+ ret = val;
+ break;
+ case JS_TAG_BOOL:
+ case JS_TAG_NULL:
+ ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
+ break;
+ case JS_TAG_UNDEFINED:
+ ret = JS_NAN;
+ break;
+ case JS_TAG_OBJECT:
+ val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
+ if (JS_IsException(val))
+ return JS_EXCEPTION;
+ goto redo;
+ case JS_TAG_STRING:
+ case JS_TAG_STRING_ROPE:
+ {
+ const char *str;
+ const char *p;
+ size_t len;
+
+ str = JS_ToCStringLen(ctx, &len, val);
+ JS_FreeValue(ctx, val);
+ if (!str)
+ return JS_EXCEPTION;
+ p = str;
+ p += skip_spaces(p);
+ if ((p - str) == len) {
+ ret = JS_NewInt32(ctx, 0);
} else {
- 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);
+ 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);
}
- } else {
- str = bf_ftoa(NULL, a, radix, prec, flags);
+ 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;
}
- a->sign = saved_sign;
- if (a == &a_s)
- bf_delete(a);
- JS_FreeValue(ctx, val);
- if (!str)
- return JS_ThrowOutOfMemory(ctx);
- ret = JS_NewString(ctx, str);
- bf_free(ctx->bf_ctx, str);
return ret;
}
-static JSValue js_bigfloat_to_string(JSContext *ctx, JSValueConst val)
+static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val)
{
- return js_ftoa(ctx, val, 10, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);
+ return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER);
}
-static JSValue js_bigdecimal_to_string1(JSContext *ctx, JSValueConst val,
- limb_t prec, int flags)
+static JSValue JS_ToNumericFree(JSContext *ctx, JSValue val)
{
- JSValue ret;
- bfdec_t *a;
- char *str;
- int saved_sign;
-
- a = JS_ToBigDecimal(ctx, val);
- if (!a)
- return JS_EXCEPTION;
- 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;
+ return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC);
}
-static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val)
+static JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val)
{
- return js_bigdecimal_to_string1(ctx, val, 0,
- BF_RNDZ | BF_FTOA_FORMAT_FREE);
+ return JS_ToNumericFree(ctx, JS_DupValue(ctx, val));
}
-#endif /* CONFIG_BIGNUM */
-
-/* 2 <= base <= 36 */
-static char *i64toa(char *buf_end, int64_t n, unsigned int base)
+static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres,
+ JSValue val)
{
- 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;
+ double d;
+ uint32_t tag;
+
+ val = JS_ToNumberFree(ctx, val);
+ if (JS_IsException(val))
+ goto fail;
+ tag = JS_VALUE_GET_NORM_TAG(val);
+ switch(tag) {
+ case JS_TAG_INT:
+ d = JS_VALUE_GET_INT(val);
+ break;
+ case JS_TAG_FLOAT64:
+ d = JS_VALUE_GET_FLOAT64(val);
+ break;
+ default:
+ abort();
+ }
+ *pres = d;
+ return 0;
+ fail:
+ *pres = JS_FLOAT64_NAN;
+ return -1;
}
-/* 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;
+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 {
- 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 */
+ return __JS_ToFloat64Free(ctx, pres, val);
}
- 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 JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val)
{
- 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;
+ return JS_ToFloat64Free(ctx, pres, JS_DupValue(ctx, val));
}
-static void js_fcvt(char *buf, int buf_size, double d, int n_digits)
+static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val)
{
- 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);
+ return JS_ToNumberFree(ctx, JS_DupValue(ctx, val));
}
-/* radix != 10 is only supported with flags = JS_DTOA_VAR_FORMAT */
-/* use as many digits as necessary */
-#define JS_DTOA_VAR_FORMAT (0 << 0)
-/* use n_digits significant digits (1 <= n_digits <= 101) */
-#define JS_DTOA_FIXED_FORMAT (1 << 0)
-/* force fractional format: [-]dd.dd with n_digits fractional digits */
-#define JS_DTOA_FRAC_FORMAT (2 << 0)
-/* force exponential notation either in fixed or variable format */
-#define JS_DTOA_FORCE_EXP (1 << 2)
-
-/* XXX: slow and maybe not fully correct. Use libbf when it is fast enough.
- XXX: radix != 10 is only supported for small integers
-*/
-static void js_dtoa1(char *buf, double d, int radix, int n_digits, int flags)
+/* same as JS_ToNumber() but return 0 in case of NaN/Undefined */
+static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
{
- char *q;
+ uint32_t tag;
+ JSValue ret;
- 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';
+ 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 {
- 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);
+ /* convert -0 to +0 */
+ d = trunc(d) + 0.0;
+ ret = JS_NewFloat64(ctx, d);
}
}
+ break;
+ default:
+ val = JS_ToNumberFree(ctx, val);
+ if (JS_IsException(val))
+ return val;
+ goto redo;
}
+ return ret;
}
-static JSValue js_dtoa(JSContext *ctx,
- double d, int radix, int n_digits, int flags)
-{
- char buf[JS_DTOA_BUF_SIZE];
- js_dtoa1(buf, d, radix, n_digits, flags);
- return JS_NewString(ctx, buf);
-}
-
-JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToPropertyKey)
+/* Note: the integer value is satured to 32 bits */
+static int JS_ToInt32SatFree(JSContext *ctx, int *pres, JSValue val)
{
uint32_t tag;
- const char *str;
- char buf[32];
+ int ret;
+ redo:
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);
+ ret = JS_VALUE_GET_INT(val);
+ break;
case JS_TAG_EXCEPTION:
- return JS_EXCEPTION;
- case JS_TAG_OBJECT:
+ *pres = 0;
+ return -1;
+ case JS_TAG_FLOAT64:
{
- 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;
+ 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;
- case JS_TAG_FUNCTION_BYTECODE:
- str = "[function bytecode]";
- goto new_string;
- case JS_TAG_SYMBOL:
- if (is_ToPropertyKey) {
- return JS_DupValue(ctx, val);
+ default:
+ val = JS_ToNumberFree(ctx, val);
+ if (JS_IsException(val)) {
+ *pres = 0;
+ return -1;
+ }
+ goto redo;
+ }
+ *pres = ret;
+ return 0;
+}
+
+int JS_ToInt32Sat(JSContext *ctx, int *pres, JSValueConst val)
+{
+ return JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));
+}
+
+int JS_ToInt32Clamp(JSContext *ctx, int *pres, JSValueConst val,
+ int min, int max, int min_offset)
+{
+ int res = JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));
+ if (res == 0) {
+ if (*pres < min) {
+ *pres += min_offset;
+ if (*pres < min)
+ *pres = min;
+ } else {
+ if (*pres > max)
+ *pres = max;
+ }
+ }
+ return res;
+}
+
+static int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val)
+{
+ uint32_t tag;
+
+ redo:
+ tag = JS_VALUE_GET_NORM_TAG(val);
+ switch(tag) {
+ case JS_TAG_INT:
+ case JS_TAG_BOOL:
+ case JS_TAG_NULL:
+ case JS_TAG_UNDEFINED:
+ *pres = JS_VALUE_GET_INT(val);
+ return 0;
+ case JS_TAG_EXCEPTION:
+ *pres = 0;
+ return -1;
+ case JS_TAG_FLOAT64:
+ {
+ double d = JS_VALUE_GET_FLOAT64(val);
+ if (isnan(d)) {
+ *pres = 0;
+ } else {
+ if (d < INT64_MIN)
+ *pres = INT64_MIN;
+ else if (d >= 0x1p63) /* must use INT64_MAX + 1 because INT64_MAX cannot be exactly represented as a double */
+ *pres = INT64_MAX;
+ else
+ *pres = (int64_t)d;
+ }
+ }
+ return 0;
+ default:
+ val = JS_ToNumberFree(ctx, val);
+ if (JS_IsException(val)) {
+ *pres = 0;
+ return -1;
+ }
+ goto redo;
+ }
+}
+
+int JS_ToInt64Sat(JSContext *ctx, int64_t *pres, JSValueConst val)
+{
+ return JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val));
+}
+
+int JS_ToInt64Clamp(JSContext *ctx, int64_t *pres, JSValueConst val,
+ int64_t min, int64_t max, int64_t neg_offset)
+{
+ int res = JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val));
+ if (res == 0) {
+ if (*pres < 0)
+ *pres += neg_offset;
+ if (*pres < min)
+ *pres = min;
+ else if (*pres > max)
+ *pres = max;
+ }
+ return res;
+}
+
+/* Same as JS_ToInt32Free() but with a 64 bit result. Return (<0, 0)
+ in case of exception */
+static int JS_ToInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
+{
+ uint32_t tag;
+ int64_t ret;
+
+ redo:
+ tag = JS_VALUE_GET_NORM_TAG(val);
+ switch(tag) {
+ case JS_TAG_INT:
+ case JS_TAG_BOOL:
+ case JS_TAG_NULL:
+ case JS_TAG_UNDEFINED:
+ ret = JS_VALUE_GET_INT(val);
+ break;
+ case JS_TAG_FLOAT64:
+ {
+ JSFloat64Union u;
+ double d;
+ int e;
+ d = JS_VALUE_GET_FLOAT64(val);
+ u.d = d;
+ /* we avoid doing fmod(x, 2^64) */
+ e = (u.u64 >> 52) & 0x7ff;
+ if (likely(e <= (1023 + 62))) {
+ /* fast case */
+ ret = (int64_t)d;
+ } else if (e <= (1023 + 62 + 53)) {
+ uint64_t v;
+ /* remainder modulo 2^64 */
+ v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);
+ ret = v << ((e - 1023) - 52);
+ /* take the sign into account */
+ if (u.u64 >> 63)
+ ret = -ret;
+ } else {
+ ret = 0; /* also handles NaN and +inf */
+ }
+ }
+ break;
+ default:
+ val = JS_ToNumberFree(ctx, val);
+ if (JS_IsException(val)) {
+ *pres = 0;
+ return -1;
+ }
+ goto redo;
+ }
+ *pres = ret;
+ return 0;
+}
+
+int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
+{
+ return JS_ToInt64Free(ctx, pres, JS_DupValue(ctx, val));
+}
+
+int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val)
+{
+ if (JS_IsBigInt(ctx, val))
+ return JS_ToBigInt64(ctx, pres, val);
+ else
+ return JS_ToInt64(ctx, pres, val);
+}
+
+/* return (<0, 0) in case of exception */
+static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val)
+{
+ uint32_t tag;
+ int32_t ret;
+
+ redo:
+ tag = JS_VALUE_GET_NORM_TAG(val);
+ switch(tag) {
+ case JS_TAG_INT:
+ case JS_TAG_BOOL:
+ case JS_TAG_NULL:
+ case JS_TAG_UNDEFINED:
+ ret = JS_VALUE_GET_INT(val);
+ break;
+ case JS_TAG_FLOAT64:
+ {
+ JSFloat64Union u;
+ double d;
+ int e;
+ d = JS_VALUE_GET_FLOAT64(val);
+ u.d = d;
+ /* we avoid doing fmod(x, 2^32) */
+ e = (u.u64 >> 52) & 0x7ff;
+ if (likely(e <= (1023 + 30))) {
+ /* fast case */
+ ret = (int32_t)d;
+ } else if (e <= (1023 + 30 + 53)) {
+ uint64_t v;
+ /* remainder modulo 2^32 */
+ v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);
+ v = v << ((e - 1023) - 52 + 32);
+ ret = v >> 32;
+ /* take the sign into account */
+ if (u.u64 >> 63)
+ ret = -ret;
+ } else {
+ ret = 0; /* also handles NaN and +inf */
+ }
+ }
+ break;
+ default:
+ val = JS_ToNumberFree(ctx, val);
+ if (JS_IsException(val)) {
+ *pres = 0;
+ return -1;
+ }
+ goto redo;
+ }
+ *pres = ret;
+ return 0;
+}
+
+int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val)
+{
+ return JS_ToInt32Free(ctx, pres, JS_DupValue(ctx, val));
+}
+
+static inline int JS_ToUint32Free(JSContext *ctx, uint32_t *pres, JSValue val)
+{
+ return JS_ToInt32Free(ctx, (int32_t *)pres, val);
+}
+
+static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val)
+{
+ uint32_t tag;
+ int res;
+
+ redo:
+ tag = JS_VALUE_GET_NORM_TAG(val);
+ switch(tag) {
+ case JS_TAG_INT:
+ case JS_TAG_BOOL:
+ case JS_TAG_NULL:
+ case JS_TAG_UNDEFINED:
+ res = JS_VALUE_GET_INT(val);
+ res = max_int(0, min_int(255, res));
+ break;
+ case JS_TAG_FLOAT64:
+ {
+ double d = JS_VALUE_GET_FLOAT64(val);
+ if (isnan(d)) {
+ res = 0;
+ } else {
+ if (d < 0)
+ res = 0;
+ else if (d > 255)
+ res = 255;
+ else
+ res = lrint(d);
+ }
+ }
+ break;
+ default:
+ val = JS_ToNumberFree(ctx, val);
+ if (JS_IsException(val)) {
+ *pres = 0;
+ return -1;
+ }
+ goto redo;
+ }
+ *pres = res;
+ return 0;
+}
+
+static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
+ JSValue val, BOOL is_array_ctor)
+{
+ uint32_t tag, len;
+
+ tag = JS_VALUE_GET_TAG(val);
+ switch(tag) {
+ case JS_TAG_INT:
+ case JS_TAG_BOOL:
+ case JS_TAG_NULL:
+ {
+ int v;
+ v = JS_VALUE_GET_INT(val);
+ if (v < 0)
+ goto fail;
+ len = v;
+ }
+ break;
+ default:
+ if (JS_TAG_IS_FLOAT64(tag)) {
+ double d;
+ d = JS_VALUE_GET_FLOAT64(val);
+ if (!(d >= 0 && d <= UINT32_MAX))
+ goto fail;
+ len = (uint32_t)d;
+ if (len != d)
+ goto fail;
+ } else {
+ uint32_t len1;
+
+ if (is_array_ctor) {
+ val = JS_ToNumberFree(ctx, val);
+ if (JS_IsException(val))
+ return -1;
+ /* cannot recurse because val is a number */
+ if (JS_ToArrayLengthFree(ctx, &len, val, TRUE))
+ return -1;
+ } else {
+ /* legacy behavior: must do the conversion twice and compare */
+ if (JS_ToUint32(ctx, &len, val)) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ val = JS_ToNumberFree(ctx, val);
+ if (JS_IsException(val))
+ return -1;
+ /* cannot recurse because val is a number */
+ if (JS_ToArrayLengthFree(ctx, &len1, val, FALSE))
+ return -1;
+ if (len1 != len) {
+ fail:
+ JS_ThrowRangeError(ctx, "invalid array length");
+ return -1;
+ }
+ }
+ }
+ break;
+ }
+ *plen = len;
+ return 0;
+}
+
+#define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1)
+
+static BOOL is_safe_integer(double d)
+{
+ return isfinite(d) && floor(d) == d &&
+ fabs(d) <= (double)MAX_SAFE_INTEGER;
+}
+
+int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val)
+{
+ int64_t v;
+ if (JS_ToInt64Sat(ctx, &v, val))
+ return -1;
+ if (v < 0 || v > MAX_SAFE_INTEGER) {
+ JS_ThrowRangeError(ctx, "invalid array index");
+ *plen = 0;
+ return -1;
+ }
+ *plen = v;
+ return 0;
+}
+
+/* convert a value to a length between 0 and MAX_SAFE_INTEGER.
+ return -1 for exception */
+static __exception int JS_ToLengthFree(JSContext *ctx, int64_t *plen,
+ JSValue val)
+{
+ int res = JS_ToInt64Clamp(ctx, plen, val, 0, MAX_SAFE_INTEGER, 0);
+ JS_FreeValue(ctx, val);
+ return res;
+}
+
+/* Note: can return an exception */
+static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val)
+{
+ double d;
+ if (!JS_IsNumber(val))
+ return FALSE;
+ if (unlikely(JS_ToFloat64(ctx, &d, val)))
+ return -1;
+ return isfinite(d) && floor(d) == d;
+}
+
+static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val)
+{
+ uint32_t tag;
+
+ tag = JS_VALUE_GET_NORM_TAG(val);
+ switch(tag) {
+ case JS_TAG_INT:
+ {
+ int v;
+ v = JS_VALUE_GET_INT(val);
+ return (v < 0);
+ }
+ case JS_TAG_FLOAT64:
+ {
+ JSFloat64Union u;
+ u.d = JS_VALUE_GET_FLOAT64(val);
+ return (u.u64 >> 63);
+ }
+ case JS_TAG_SHORT_BIG_INT:
+ return (JS_VALUE_GET_SHORT_BIG_INT(val) < 0);
+ case JS_TAG_BIG_INT:
+ {
+ JSBigInt *p = JS_VALUE_GET_PTR(val);
+ return js_bigint_sign(p);
+ }
+ default:
+ return FALSE;
+ }
+}
+
+static JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val)
+{
+ return js_bigint_to_string1(ctx, val, 10);
+}
+
+static JSValue js_dtoa2(JSContext *ctx,
+ double d, int radix, int n_digits, int flags)
+{
+ char static_buf[128], *buf, *tmp_buf;
+ int len, len_max;
+ JSValue res;
+ JSDTOATempMem dtoa_mem;
+ len_max = js_dtoa_max_len(d, radix, n_digits, flags);
+
+ /* longer buffer may be used if radix != 10 */
+ if (len_max > sizeof(static_buf) - 1) {
+ tmp_buf = js_malloc(ctx, len_max + 1);
+ if (!tmp_buf)
+ return JS_EXCEPTION;
+ buf = tmp_buf;
+ } else {
+ tmp_buf = NULL;
+ buf = static_buf;
+ }
+ len = js_dtoa(buf, d, radix, n_digits, flags, &dtoa_mem);
+ res = js_new_string8_len(ctx, buf, len);
+ js_free(ctx, tmp_buf);
+ return res;
+}
+
+static JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToPropertyKey)
+{
+ uint32_t tag;
+ char buf[32];
+
+ tag = JS_VALUE_GET_NORM_TAG(val);
+ switch(tag) {
+ case JS_TAG_STRING:
+ return JS_DupValue(ctx, val);
+ case JS_TAG_STRING_ROPE:
+ return js_linearize_string_rope(ctx, JS_DupValue(ctx, val));
+ case JS_TAG_INT:
+ {
+ size_t len;
+ len = i32toa(buf, JS_VALUE_GET_INT(val));
+ return js_new_string8_len(ctx, buf, len);
+ }
+ break;
+ case JS_TAG_BOOL:
+ return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ?
+ JS_ATOM_true : JS_ATOM_false);
+ case JS_TAG_NULL:
+ return JS_AtomToString(ctx, JS_ATOM_null);
+ case JS_TAG_UNDEFINED:
+ return JS_AtomToString(ctx, JS_ATOM_undefined);
+ case JS_TAG_EXCEPTION:
+ return JS_EXCEPTION;
+ case JS_TAG_OBJECT:
+ {
+ JSValue val1, ret;
+ val1 = JS_ToPrimitive(ctx, val, HINT_STRING);
+ if (JS_IsException(val1))
+ return val1;
+ ret = JS_ToStringInternal(ctx, val1, is_ToPropertyKey);
+ JS_FreeValue(ctx, val1);
+ return ret;
+ }
+ break;
+ case JS_TAG_FUNCTION_BYTECODE:
+ return js_new_string8(ctx, "[function bytecode]");
+ case JS_TAG_SYMBOL:
+ if (is_ToPropertyKey) {
+ return JS_DupValue(ctx, val);
} else {
return JS_ThrowTypeError(ctx, "cannot convert symbol to string");
}
case JS_TAG_FLOAT64:
- return js_dtoa(ctx, JS_VALUE_GET_FLOAT64(val), 10, 0,
- JS_DTOA_VAR_FORMAT);
+ return js_dtoa2(ctx, JS_VALUE_GET_FLOAT64(val), 10, 0,
+ JS_DTOA_FORMAT_FREE);
+ case JS_TAG_SHORT_BIG_INT:
case JS_TAG_BIG_INT:
- return ctx->rt->bigint_ops.to_string(ctx, val);
-#ifdef CONFIG_BIGNUM
- 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
+ return js_bigint_to_string(ctx, val);
default:
- str = "[unsupported type]";
- new_string:
- return JS_NewString(ctx, str);
+ return js_new_string8(ctx, "[unsupported type]");
}
}
@@ -11627,7 +12995,7 @@ static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1)
goto fail;
break;
default:
- if (c < 32 || (c >= 0xd800 && c < 0xe000)) {
+ if (c < 32 || is_surrogate(c)) {
snprintf(buf, sizeof(buf), "\\u%04x", c);
if (string_buffer_puts8(b, buf))
goto fail;
@@ -11648,158 +13016,495 @@ static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1)
return JS_EXCEPTION;
}
-static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt)
+#define JS_PRINT_MAX_DEPTH 8
+
+typedef struct {
+ JSRuntime *rt;
+ JSContext *ctx; /* may be NULL */
+ JSPrintValueOptions options;
+ JSPrintValueWrite *write_func;
+ void *write_opaque;
+ int level;
+ JSObject *print_stack[JS_PRINT_MAX_DEPTH]; /* level values */
+} JSPrintValueState;
+
+static void js_print_value(JSPrintValueState *s, JSValueConst val);
+
+static void js_putc(JSPrintValueState *s, char c)
{
- printf("%14s %4s %4s %14s %10s %s\n",
- "ADDRESS", "REFS", "SHRF", "PROTO", "CLASS", "PROPS");
+ s->write_func(s->write_opaque, &c, 1);
}
-/* for debug only: dump an object without side effect */
-static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
+static void js_puts(JSPrintValueState *s, const char *str)
{
- uint32_t i;
- char atom_buf[ATOM_GET_STR_BUF_SIZE];
- JSShape *sh;
- JSShapeProperty *prs;
- JSProperty *pr;
- BOOL is_first = TRUE;
+ s->write_func(s->write_opaque, str, strlen(str));
+}
- /* 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);
+static void __attribute__((format(printf, 2, 3))) js_printf(JSPrintValueState *s, const char *fmt, ...)
+{
+ va_list ap;
+ char buf[256];
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ s->write_func(s->write_opaque, buf, strlen(buf));
+}
+
+static void js_print_float64(JSPrintValueState *s, double d)
+{
+ JSDTOATempMem dtoa_mem;
+ char buf[32];
+ int len;
+ len = js_dtoa(buf, d, 10, 0, JS_DTOA_FORMAT_FREE | JS_DTOA_MINUS_ZERO, &dtoa_mem);
+ s->write_func(s->write_opaque, buf, len);
+}
+
+static uint32_t js_string_get_length(JSValueConst val)
+{
+ if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
+ JSString *p = JS_VALUE_GET_STRING(val);
+ return p->len;
+ } else if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING_ROPE) {
+ JSStringRope *r = JS_VALUE_GET_PTR(val);
+ return r->len;
} else {
- 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:
- case JS_CLASS_BIG_INT64_ARRAY:
- case JS_CLASS_BIG_UINT64_ARRAY:
- 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(" ] ");
+ return 0;
}
+}
- if (sh) {
- printf("{ ");
+static void js_dump_char(JSPrintValueState *s, int c, int sep)
+{
+ if (c == sep || c == '\\') {
+ js_putc(s, '\\');
+ js_putc(s, c);
+ } else if (c >= ' ' && c <= 126) {
+ js_putc(s, c);
+ } else if (c == '\n') {
+ js_putc(s, '\\');
+ js_putc(s, 'n');
+ } else {
+ js_printf(s, "\\u%04x", c);
+ }
+}
+
+static void js_print_string_rec(JSPrintValueState *s, JSValueConst val,
+ int sep, uint32_t pos)
+{
+ if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
+ JSString *p = JS_VALUE_GET_STRING(val);
+ uint32_t i, len;
+ if (pos < s->options.max_string_length) {
+ len = min_uint32(p->len, s->options.max_string_length - pos);
+ for(i = 0; i < len; i++) {
+ js_dump_char(s, string_get(p, i), sep);
+ }
+ }
+ } else if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING_ROPE) {
+ JSStringRope *r = JS_VALUE_GET_PTR(val);
+ js_print_string_rec(s, r->left, sep, pos);
+ js_print_string_rec(s, r->right, sep, pos + js_string_get_length(r->left));
+ } else {
+ js_printf(s, "", (int)JS_VALUE_GET_TAG(val));
+ }
+}
+
+static void js_print_string(JSPrintValueState *s, JSValueConst val)
+{
+ int sep;
+ if (s->options.raw_dump && JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
+ JSString *p = JS_VALUE_GET_STRING(val);
+ js_printf(s, "%d", p->header.ref_count);
+ sep = (p->header.ref_count == 1) ? '\"' : '\'';
+ } else {
+ sep = '\"';
+ }
+ js_putc(s, sep);
+ js_print_string_rec(s, val, sep, 0);
+ js_putc(s, sep);
+ if (js_string_get_length(val) > s->options.max_string_length) {
+ uint32_t n = js_string_get_length(val) - s->options.max_string_length;
+ js_printf(s, "... %u more character%s", n, n > 1 ? "s" : "");
+ }
+}
+
+static void js_print_raw_string2(JSPrintValueState *s, JSValueConst val, BOOL remove_last_lf)
+{
+ const char *cstr;
+ size_t len;
+ cstr = JS_ToCStringLen(s->ctx, &len, val);
+ if (cstr) {
+ if (remove_last_lf && len > 0 && cstr[len - 1] == '\n')
+ len--;
+ s->write_func(s->write_opaque, cstr, len);
+ JS_FreeCString(s->ctx, cstr);
+ }
+}
+
+static void js_print_raw_string(JSPrintValueState *s, JSValueConst val)
+{
+ js_print_raw_string2(s, val, FALSE);
+}
+
+static BOOL is_ascii_ident(const JSString *p)
+{
+ int i, c;
+
+ if (p->len == 0)
+ return FALSE;
+ for(i = 0; i < p->len; i++) {
+ c = string_get(p, i);
+ if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+ (c == '_' || c == '$') || (c >= '0' && c <= '9' && i > 0)))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void js_print_atom(JSPrintValueState *s, JSAtom atom)
+{
+ int i;
+ if (__JS_AtomIsTaggedInt(atom)) {
+ js_printf(s, "%u", __JS_AtomToUInt32(atom));
+ } else if (atom == JS_ATOM_NULL) {
+ js_puts(s, "");
+ } else {
+ assert(atom < s->rt->atom_size);
+ JSString *p;
+ p = s->rt->atom_array[atom];
+ if (is_ascii_ident(p)) {
+ for(i = 0; i < p->len; i++) {
+ js_putc(s, string_get(p, i));
+ }
+ } else {
+ js_putc(s, '"');
+ for(i = 0; i < p->len; i++) {
+ js_dump_char(s, string_get(p, i), '\"');
+ }
+ js_putc(s, '"');
+ }
+ }
+}
+
+/* return 0 if invalid length */
+static uint32_t js_print_array_get_length(JSObject *p)
+{
+ JSProperty *pr;
+ JSShapeProperty *prs;
+ JSValueConst val;
+
+ prs = find_own_property(&pr, p, JS_ATOM_length);
+ if (!prs)
+ return 0;
+ if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
+ return 0;
+ val = pr->u.value;
+ switch(JS_VALUE_GET_NORM_TAG(val)) {
+ case JS_TAG_INT:
+ return JS_VALUE_GET_INT(val);
+ case JS_TAG_FLOAT64:
+ return (uint32_t)JS_VALUE_GET_FLOAT64(val);
+ default:
+ return 0;
+ }
+}
+
+static void js_print_comma(JSPrintValueState *s, int *pcomma_state)
+{
+ switch(*pcomma_state) {
+ case 0:
+ break;
+ case 1:
+ js_printf(s, ", ");
+ break;
+ case 2:
+ js_printf(s, " { ");
+ break;
+ }
+ *pcomma_state = 1;
+}
+
+static void js_print_more_items(JSPrintValueState *s, int *pcomma_state,
+ uint32_t n)
+{
+ js_print_comma(s, pcomma_state);
+ js_printf(s, "... %u more item%s", n, n > 1 ? "s" : "");
+}
+
+static void js_print_object(JSPrintValueState *s, JSObject *p)
+{
+ JSRuntime *rt = s->rt;
+ JSShape *sh;
+ JSShapeProperty *prs;
+ JSProperty *pr;
+ int comma_state;
+ BOOL is_array;
+ uint32_t i;
+
+ comma_state = 0;
+ is_array = FALSE;
+ if (p->class_id == JS_CLASS_ARRAY) {
+ is_array = TRUE;
+ js_printf(s, "[ ");
+ /* XXX: print array like properties even if not fast array */
+ if (p->fast_array) {
+ uint32_t len, n, len1;
+ len = js_print_array_get_length(p);
+
+ len1 = min_uint32(p->u.array.count, s->options.max_item_count);
+ for(i = 0; i < len1; i++) {
+ js_print_comma(s, &comma_state);
+ js_print_value(s, p->u.array.u.values[i]);
+ }
+ if (len1 < p->u.array.count)
+ js_print_more_items(s, &comma_state, p->u.array.count - len1);
+ if (p->u.array.count < len) {
+ n = len - p->u.array.count;
+ js_print_comma(s, &comma_state);
+ js_printf(s, "<%u empty item%s>", n, n > 1 ? "s" : "");
+ }
+ }
+ } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
+ uint32_t size = 1 << typed_array_size_log2(p->class_id);
+ uint32_t len1;
+ int64_t v;
+
+ js_print_atom(s, rt->class_array[p->class_id].class_name);
+ js_printf(s, "(%u) [ ", p->u.array.count);
+
+ is_array = TRUE;
+ len1 = min_uint32(p->u.array.count, s->options.max_item_count);
+ for(i = 0; i < len1; i++) {
+ const uint8_t *ptr = p->u.array.u.uint8_ptr + i * size;
+ js_print_comma(s, &comma_state);
+ switch(p->class_id) {
+ case JS_CLASS_UINT8C_ARRAY:
+ case JS_CLASS_UINT8_ARRAY:
+ v = *ptr;
+ goto ta_int64;
+ case JS_CLASS_INT8_ARRAY:
+ v = *(int8_t *)ptr;
+ goto ta_int64;
+ case JS_CLASS_INT16_ARRAY:
+ v = *(int16_t *)ptr;
+ goto ta_int64;
+ case JS_CLASS_UINT16_ARRAY:
+ v = *(uint16_t *)ptr;
+ goto ta_int64;
+ case JS_CLASS_INT32_ARRAY:
+ v = *(int32_t *)ptr;
+ goto ta_int64;
+ case JS_CLASS_UINT32_ARRAY:
+ v = *(uint32_t *)ptr;
+ goto ta_int64;
+ case JS_CLASS_BIG_INT64_ARRAY:
+ v = *(int64_t *)ptr;
+ ta_int64:
+ js_printf(s, "%" PRId64, v);
+ break;
+ case JS_CLASS_BIG_UINT64_ARRAY:
+ js_printf(s, "%" PRIu64, *(uint64_t *)ptr);
+ break;
+ case JS_CLASS_FLOAT16_ARRAY:
+ js_print_float64(s, fromfp16(*(uint16_t *)ptr));
+ break;
+ case JS_CLASS_FLOAT32_ARRAY:
+ js_print_float64(s, *(float *)ptr);
+ break;
+ case JS_CLASS_FLOAT64_ARRAY:
+ js_print_float64(s, *(double *)ptr);
+ break;
+ }
+ }
+ if (len1 < p->u.array.count)
+ js_print_more_items(s, &comma_state, p->u.array.count - len1);
+ } else if (p->class_id == JS_CLASS_BYTECODE_FUNCTION ||
+ (rt->class_array[p->class_id].call != NULL &&
+ p->class_id != JS_CLASS_PROXY)) {
+ js_printf(s, "[Function");
+ /* XXX: allow dump without ctx */
+ if (!s->options.raw_dump && s->ctx) {
+ const char *func_name_str;
+ js_putc(s, ' ');
+ func_name_str = get_func_name(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+ if (!func_name_str || func_name_str[0] == '\0')
+ js_puts(s, "(anonymous)");
+ else
+ js_puts(s, func_name_str);
+ JS_FreeCString(s->ctx, func_name_str);
+ }
+ js_printf(s, "]");
+ comma_state = 2;
+ } else if (p->class_id == JS_CLASS_MAP || p->class_id == JS_CLASS_SET) {
+ JSMapState *ms = p->u.opaque;
+ struct list_head *el;
+
+ if (!ms)
+ goto default_obj;
+ js_print_atom(s, rt->class_array[p->class_id].class_name);
+ js_printf(s, "(%u) { ", ms->record_count);
+ i = 0;
+ list_for_each(el, &ms->records) {
+ JSMapRecord *mr = list_entry(el, JSMapRecord, link);
+ js_print_comma(s, &comma_state);
+ if (mr->empty)
+ continue;
+ js_print_value(s, mr->key);
+ if (p->class_id == JS_CLASS_MAP) {
+ js_printf(s, " => ");
+ js_print_value(s, mr->value);
+ }
+ i++;
+ if (i >= s->options.max_item_count)
+ break;
+ }
+ if (i < ms->record_count)
+ js_print_more_items(s, &comma_state, ms->record_count - i);
+ } else if (p->class_id == JS_CLASS_REGEXP && s->ctx && !s->options.raw_dump) {
+ JSValue str = js_regexp_toString(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), 0, NULL);
+ if (JS_IsException(str))
+ goto default_obj;
+ js_print_raw_string(s, str);
+ JS_FreeValueRT(s->rt, str);
+ comma_state = 2;
+ } else if (p->class_id == JS_CLASS_DATE && s->ctx && !s->options.raw_dump) {
+ JSValue str = get_date_string(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), 0, NULL, 0x23); /* toISOString() */
+ if (JS_IsException(str))
+ goto default_obj;
+ js_print_raw_string(s, str);
+ JS_FreeValueRT(s->rt, str);
+ comma_state = 2;
+ } else if (p->class_id == JS_CLASS_ERROR && s->ctx && !s->options.raw_dump) {
+ JSValue str = js_error_toString(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), 0, NULL);
+ if (JS_IsException(str))
+ goto default_obj;
+ js_print_raw_string(s, str);
+ JS_FreeValueRT(s->rt, str);
+ /* dump the stack if present */
+ str = JS_GetProperty(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), JS_ATOM_stack);
+ if (JS_IsString(str)) {
+ js_putc(s, '\n');
+ /* XXX: should remove the last '\n' in stack as
+ v8. SpiderMonkey does not do it */
+ js_print_raw_string2(s, str, TRUE);
+ }
+ JS_FreeValueRT(s->rt, str);
+ comma_state = 2;
+ } else {
+ default_obj:
+ if (p->class_id != JS_CLASS_OBJECT) {
+ js_print_atom(s, rt->class_array[p->class_id].class_name);
+ js_printf(s, " ");
+ }
+ js_printf(s, "{ ");
+ }
+
+ sh = p->shape; /* the shape can be NULL while freeing an object */
+ if (sh) {
+ uint32_t j;
+
+ j = 0;
for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
if (prs->atom != JS_ATOM_NULL) {
- 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);
+ if (!(prs->flags & JS_PROP_ENUMERABLE) &&
+ !s->options.show_hidden) {
+ continue;
+ }
+ if (j < s->options.max_item_count) {
+ pr = &p->prop[i];
+ js_print_comma(s, &comma_state);
+ js_print_atom(s, prs->atom);
+ js_printf(s, ": ");
+
+ /* XXX: autoinit property */
+ if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
+ if (s->options.raw_dump) {
+ js_printf(s, "[Getter %p Setter %p]",
+ pr->u.getset.getter, pr->u.getset.setter);
+ } else {
+ if (pr->u.getset.getter && pr->u.getset.setter) {
+ js_printf(s, "[Getter/Setter]");
+ } else if (pr->u.getset.setter) {
+ js_printf(s, "[Setter]");
+ } else {
+ js_printf(s, "[Getter]");
+ }
+ }
+ } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
+ if (s->options.raw_dump) {
+ js_printf(s, "[varref %p]", (void *)pr->u.var_ref);
+ } else {
+ js_print_value(s, *pr->u.var_ref->pvalue);
+ }
+ } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
+ if (s->options.raw_dump) {
+ js_printf(s, "[autoinit %p %d %p]",
+ (void *)js_autoinit_get_realm(pr),
+ js_autoinit_get_id(pr),
+ (void *)pr->u.init.opaque);
+ } else {
+ /* XXX: could autoinit but need to restart
+ the iteration */
+ js_printf(s, "[autoinit]");
+ }
+ } else {
+ js_print_value(s, pr->u.value);
+ }
}
- is_first = FALSE;
+ j++;
}
}
- printf(" }");
+ if (j > s->options.max_item_count)
+ js_print_more_items(s, &comma_state, j - s->options.max_item_count);
}
-
- if (js_class_has_bytecode(p->class_id)) {
+ if (s->options.raw_dump && js_class_has_bytecode(p->class_id)) {
JSFunctionBytecode *b = p->u.func.function_bytecode;
- JSVarRef **var_refs;
if (b->closure_var_count) {
+ JSVarRef **var_refs;
var_refs = p->u.func.var_refs;
- printf(" Closure:");
+
+ js_print_comma(s, &comma_state);
+ js_printf(s, "[[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));
+ if (i != 0)
+ js_printf(s, ", ");
+ js_print_value(s, var_refs[i]->value);
}
+ js_printf(s, " ]");
+ }
+ if (p->u.func.home_object) {
+ js_print_comma(s, &comma_state);
+ js_printf(s, "[[HomeObject]]: ");
+ js_print_value(s, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object));
}
}
- 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;
+ if (!is_array) {
+ if (comma_state != 2) {
+ js_printf(s, " }");
}
- printf("\n");
+ } else {
+ js_printf(s, " ]");
}
}
-static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
- JSValueConst val)
+static int js_print_stack_index(JSPrintValueState *s, JSObject *p)
+{
+ int i;
+ for(i = 0; i < s->level; i++)
+ if (s->print_stack[i] == p)
+ return i;
+ return -1;
+}
+
+static void js_print_value(JSPrintValueState *s, JSValueConst val)
{
uint32_t tag = JS_VALUE_GET_NORM_TAG(val);
const char *str;
switch(tag) {
case JS_TAG_INT:
- printf("%d", JS_VALUE_GET_INT(val));
+ js_printf(s, "%d", JS_VALUE_GET_INT(val));
break;
case JS_TAG_BOOL:
if (JS_VALUE_GET_BOOL(val))
@@ -11819,108 +13524,254 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
case JS_TAG_UNDEFINED:
str = "undefined";
print_str:
- printf("%s", str);
+ js_puts(s, str);
break;
case JS_TAG_FLOAT64:
- printf("%.14g", JS_VALUE_GET_FLOAT64(val));
+ js_print_float64(s, JS_VALUE_GET_FLOAT64(val));
break;
- 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;
-#ifdef CONFIG_BIGNUM
- 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);
- }
+ case JS_TAG_SHORT_BIG_INT:
+ js_printf(s, "%" PRId64 "n", (int64_t)JS_VALUE_GET_SHORT_BIG_INT(val));
break;
- case JS_TAG_BIG_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);
+ case JS_TAG_BIG_INT:
+ if (!s->options.raw_dump && s->ctx) {
+ JSValue str = js_bigint_to_string(s->ctx, val);
+ if (JS_IsException(str))
+ goto raw_bigint;
+ js_print_raw_string(s, str);
+ js_putc(s, 'n');
+ JS_FreeValueRT(s->rt, str);
+ } else {
+ JSBigInt *p;
+ int sgn, i;
+ raw_bigint:
+ p = JS_VALUE_GET_PTR(val);
+ /* In order to avoid allocations we just dump the limbs */
+ sgn = js_bigint_sign(p);
+ if (sgn)
+ js_printf(s, "BigInt.asIntN(%d,", p->len * JS_LIMB_BITS);
+ js_printf(s, "0x");
+ for(i = p->len - 1; i >= 0; i--) {
+ if (i != p->len - 1)
+ js_putc(s, '_');
+#if JS_LIMB_BITS == 32
+ js_printf(s, "%08x", p->tab[i]);
+#else
+ js_printf(s, "%016" PRIx64, p->tab[i]);
+#endif
+ }
+ js_putc(s, 'n');
+ if (sgn)
+ js_putc(s, ')');
}
break;
-#endif
case JS_TAG_STRING:
- {
- JSString *p;
- p = JS_VALUE_GET_STRING(val);
- JS_DumpString(rt, p);
+ case JS_TAG_STRING_ROPE:
+ if (s->options.raw_dump && tag == JS_TAG_STRING_ROPE) {
+ JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val);
+ js_printf(s, "[rope len=%d depth=%d]", r->len, r->depth);
+ } else {
+ js_print_string(s, val);
}
break;
case JS_TAG_FUNCTION_BYTECODE:
{
JSFunctionBytecode *b = JS_VALUE_GET_PTR(val);
- char buf[ATOM_GET_STR_BUF_SIZE];
- printf("[bytecode %s]", JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
+ js_puts(s, "[bytecode ");
+ js_print_atom(s, b->func_name);
+ js_putc(s, ']');
}
break;
case JS_TAG_OBJECT:
{
JSObject *p = JS_VALUE_GET_OBJ(val);
- 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);
+ int idx;
+ idx = js_print_stack_index(s, p);
+ if (idx >= 0) {
+ js_printf(s, "[circular %d]", idx);
+ } else if (s->level < s->options.max_depth) {
+ s->print_stack[s->level++] = p;
+ js_print_object(s, JS_VALUE_GET_OBJ(val));
+ s->level--;
+ } else {
+ JSAtom atom = s->rt->class_array[p->class_id].class_name;
+ js_putc(s, '[');
+ js_print_atom(s, atom);
+ if (s->options.raw_dump) {
+ js_printf(s, " %p", (void *)p);
+ }
+ js_putc(s, ']');
+ }
}
break;
case JS_TAG_SYMBOL:
{
JSAtomStruct *p = JS_VALUE_GET_PTR(val);
- 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)));
+ js_puts(s, "Symbol(");
+ js_print_atom(s, js_get_atom_index(s->rt, p));
+ js_putc(s, ')');
}
break;
case JS_TAG_MODULE:
- printf("[module]");
+ js_puts(s, "[module]");
break;
default:
- printf("[unknown tag %d]", tag);
+ js_printf(s, "[unknown tag %d]", tag);
break;
}
}
-static __maybe_unused void JS_DumpValue(JSContext *ctx,
- JSValueConst val)
+void JS_PrintValueSetDefaultOptions(JSPrintValueOptions *options)
+{
+ memset(options, 0, sizeof(*options));
+ options->max_depth = 2;
+ options->max_string_length = 1000;
+ options->max_item_count = 100;
+}
+
+static void JS_PrintValueInternal(JSRuntime *rt, JSContext *ctx,
+ JSPrintValueWrite *write_func, void *write_opaque,
+ JSValueConst val, const JSPrintValueOptions *options)
+{
+ JSPrintValueState ss, *s = &ss;
+ if (options)
+ s->options = *options;
+ else
+ JS_PrintValueSetDefaultOptions(&s->options);
+ if (s->options.max_depth <= 0)
+ s->options.max_depth = JS_PRINT_MAX_DEPTH;
+ else
+ s->options.max_depth = min_int(s->options.max_depth, JS_PRINT_MAX_DEPTH);
+ if (s->options.max_string_length == 0)
+ s->options.max_string_length = UINT32_MAX;
+ if (s->options.max_item_count == 0)
+ s->options.max_item_count = UINT32_MAX;
+ s->rt = rt;
+ s->ctx = ctx;
+ s->write_func = write_func;
+ s->write_opaque = write_opaque;
+ s->level = 0;
+ js_print_value(s, val);
+}
+
+void JS_PrintValueRT(JSRuntime *rt, JSPrintValueWrite *write_func, void *write_opaque,
+ JSValueConst val, const JSPrintValueOptions *options)
+{
+ JS_PrintValueInternal(rt, NULL, write_func, write_opaque, val, options);
+}
+
+void JS_PrintValue(JSContext *ctx, JSPrintValueWrite *write_func, void *write_opaque,
+ JSValueConst val, const JSPrintValueOptions *options)
+{
+ JS_PrintValueInternal(ctx->rt, ctx, write_func, write_opaque, val, options);
+}
+
+static void js_dump_value_write(void *opaque, const char *buf, size_t len)
+{
+ FILE *fo = opaque;
+ fwrite(buf, 1, len, fo);
+}
+
+static __maybe_unused void print_atom(JSContext *ctx, JSAtom atom)
+{
+ JSPrintValueState ss, *s = &ss;
+ memset(s, 0, sizeof(*s));
+ s->rt = ctx->rt;
+ s->ctx = ctx;
+ s->write_func = js_dump_value_write;
+ s->write_opaque = stdout;
+ js_print_atom(s, atom);
+}
+
+static __maybe_unused void JS_DumpValue(JSContext *ctx, const char *str, JSValueConst val)
{
- JS_DumpValueShort(ctx->rt, val);
+ printf("%s=", str);
+ JS_PrintValue(ctx, js_dump_value_write, stdout, val, NULL);
+ printf("\n");
}
-static __maybe_unused void JS_PrintValue(JSContext *ctx,
- const char *str,
- JSValueConst val)
+static __maybe_unused void JS_DumpValueRT(JSRuntime *rt, const char *str, JSValueConst val)
{
printf("%s=", str);
- JS_DumpValueShort(ctx->rt, val);
+ JS_PrintValueRT(rt, js_dump_value_write, stdout, val, NULL);
+ printf("\n");
+}
+
+static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt)
+{
+ printf("%14s %4s %4s %14s %s\n",
+ "ADDRESS", "REFS", "SHRF", "PROTO", "CONTENT");
+}
+
+/* for debug only: dump an object without side effect */
+static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
+{
+ JSShape *sh;
+ JSPrintValueOptions options;
+
+ /* XXX: should encode atoms with special characters */
+ sh = p->shape; /* the shape can be NULL while freeing an object */
+ printf("%14p %4d ",
+ (void *)p,
+ p->header.ref_count);
+ if (sh) {
+ printf("%3d%c %14p ",
+ sh->header.ref_count,
+ " *"[sh->is_hashed],
+ (void *)sh->proto);
+ } else {
+ printf("%3s %14s ", "-", "-");
+ }
+
+ JS_PrintValueSetDefaultOptions(&options);
+ options.max_depth = 1;
+ options.show_hidden = TRUE;
+ options.raw_dump = TRUE;
+ JS_PrintValueRT(rt, js_dump_value_write, stdout, JS_MKPTR(JS_TAG_OBJECT, p), &options);
+
printf("\n");
}
+static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p)
+{
+ if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
+ JS_DumpObject(rt, (JSObject *)p);
+ } else {
+ printf("%14p %4d ",
+ (void *)p,
+ p->ref_count);
+ switch(p->gc_obj_type) {
+ case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
+ printf("[function bytecode]");
+ break;
+ case JS_GC_OBJ_TYPE_SHAPE:
+ printf("[shape]");
+ break;
+ case JS_GC_OBJ_TYPE_VAR_REF:
+ printf("[var_ref]");
+ break;
+ case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
+ printf("[async_function]");
+ break;
+ case JS_GC_OBJ_TYPE_JS_CONTEXT:
+ printf("[js_context]");
+ break;
+ default:
+ printf("[unknown %d]", p->gc_obj_type);
+ break;
+ }
+ printf("\n");
+ }
+}
+
/* return -1 if exception (proxy case) or TRUE/FALSE */
+// TODO: should take flags to make proxy resolution and exceptions optional
int JS_IsArray(JSContext *ctx, JSValueConst val)
{
- JSObject *p;
+ if (js_resolve_proxy(ctx, &val, TRUE))
+ return -1;
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;
+ JSObject *p = JS_VALUE_GET_OBJ(val);
+ return p->class_id == JS_CLASS_ARRAY;
} else {
return FALSE;
}
@@ -11936,48 +13787,34 @@ static double js_pow(double a, double b)
}
}
-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);
+#if JS_SHORT_BIG_INT_BITS == 64
+ return __JS_NewShortBigInt(ctx, v);
+#else
+ if (v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX) {
+ return __JS_NewShortBigInt(ctx, v);
} else {
- return JS_NewBigInt64_1(ctx, v);
+ JSBigInt *p;
+ p = js_bigint_new_si64(ctx, v);
+ if (!p)
+ return JS_EXCEPTION;
+ return JS_MKPTR(JS_TAG_BIG_INT, p);
}
+#endif
}
JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
{
- JSValue val;
- if (is_math_mode(ctx) && v <= MAX_SAFE_INTEGER) {
- val = JS_NewInt64(ctx, v);
+ if (v <= JS_SHORT_BIG_INT_MAX) {
+ return __JS_NewShortBigInt(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);
- }
+ JSBigInt *p;
+ p = js_bigint_new_ui64(ctx, v);
+ if (!p)
+ return JS_EXCEPTION;
+ return JS_MKPTR(JS_TAG_BIG_INT, p);
}
- return val;
}
/* return NaN if bad bigint literal */
@@ -11986,7 +13823,7 @@ static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val)
const char *str, *p;
size_t len;
int flags;
-
+
str = JS_ToCStringLen(ctx, &len, val);
JS_FreeValue(ctx, val);
if (!str)
@@ -11997,10 +13834,6 @@ static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val)
val = JS_NewBigInt64(ctx, 0);
} else {
flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT;
-#ifdef CONFIG_BIGNUM
- if (is_math_mode(ctx))
- flags |= ATOD_MODE_BIGINT;
-#endif
val = js_atof(ctx, p, &p, 0, flags);
p += skip_spaces(p);
if (!JS_IsException(val)) {
@@ -12022,135 +13855,72 @@ static JSValue JS_StringToBigIntErr(JSContext *ctx, JSValue val)
return val;
}
-/* if the returned bigfloat is allocated it is equal to
- 'buf'. Otherwise it is a pointer to the bigfloat in 'val'. */
-static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val)
+/* JS Numbers are not allowed */
+static JSValue JS_ToBigIntFree(JSContext *ctx, JSValue val)
{
uint32_t tag;
- bf_t *r;
- JSBigFloat *p;
redo:
tag = JS_VALUE_GET_NORM_TAG(val);
switch(tag) {
+ case JS_TAG_SHORT_BIG_INT:
+ case JS_TAG_BIG_INT:
+ break;
case JS_TAG_INT:
case JS_TAG_NULL:
case JS_TAG_UNDEFINED:
- 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;
-#ifdef CONFIG_BIGNUM
- 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);
+ goto fail;
+ case JS_TAG_BOOL:
+ val = __JS_NewShortBigInt(ctx, JS_VALUE_GET_INT(val));
break;
-#endif
case JS_TAG_STRING:
+ case JS_TAG_STRING_ROPE:
val = JS_StringToBigIntErr(ctx, val);
if (JS_IsException(val))
- return NULL;
+ return val;
goto redo;
case JS_TAG_OBJECT:
val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
if (JS_IsException(val))
- return NULL;
+ return val;
goto redo;
default:
fail:
JS_FreeValue(ctx, val);
- JS_ThrowTypeError(ctx, "cannot convert to bigint");
- return NULL;
- }
- return r;
-}
-
-static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val)
-{
- return JS_ToBigIntFree(ctx, buf, JS_DupValue(ctx, val));
-}
-
-static __maybe_unused JSValue JS_ToBigIntValueFree(JSContext *ctx, JSValue val)
-{
- if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT) {
- return val;
- } else {
- bf_t a_s, *a, *r;
- int ret;
- JSValue res;
-
- res = JS_NewBigInt(ctx);
- if (JS_IsException(res))
- return JS_EXCEPTION;
- a = JS_ToBigIntFree(ctx, &a_s, val);
- if (!a) {
- JS_FreeValue(ctx, res);
- return JS_EXCEPTION;
- }
- r = JS_GetBigInt(res);
- ret = bf_set(r, a);
- JS_FreeBigInt(ctx, a, &a_s);
- if (ret) {
- JS_FreeValue(ctx, res);
- return JS_ThrowOutOfMemory(ctx);
- }
- return JS_CompactBigInt(ctx, res);
+ return JS_ThrowTypeError(ctx, "cannot convert to bigint");
}
+ return val;
}
-/* free the bf_t allocated by JS_ToBigInt */
-static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf)
+static JSValue JS_ToBigInt(JSContext *ctx, JSValueConst val)
{
- if (a == buf) {
- bf_delete(a);
- } else {
- JSBigFloat *p = (JSBigFloat *)((uint8_t *)a -
- offsetof(JSBigFloat, num));
- JS_FreeValue(ctx, JS_MKPTR(JS_TAG_BIG_INT, p));
- }
+ return JS_ToBigIntFree(ctx, JS_DupValue(ctx, val));
}
-/* XXX: merge with JS_ToInt64Free with a specific flag */
+/* XXX: merge with JS_ToInt64Free with a specific flag ? */
static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
{
- bf_t a_s, *a;
+ uint64_t res;
- a = JS_ToBigIntFree(ctx, &a_s, val);
- if (!a) {
+ val = JS_ToBigIntFree(ctx, val);
+ if (JS_IsException(val)) {
*pres = 0;
return -1;
}
- bf_get_int64(pres, a, BF_GET_INT_MOD);
- JS_FreeBigInt(ctx, a, &a_s);
+ if (JS_VALUE_GET_TAG(val) == JS_TAG_SHORT_BIG_INT) {
+ res = JS_VALUE_GET_SHORT_BIG_INT(val);
+ } else {
+ JSBigInt *p = JS_VALUE_GET_PTR(val);
+ /* return the value mod 2^64 */
+ res = p->tab[0];
+#if JS_LIMB_BITS == 32
+ if (p->len >= 2)
+ res |= (uint64_t)p->tab[1] << 32;
+#endif
+ JS_FreeValue(ctx, val);
+ }
+ *pres = res;
return 0;
}
@@ -12159,727 +13929,121 @@ int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
return JS_ToBigInt64Free(ctx, pres, JS_DupValue(ctx, val));
}
-static JSBigFloat *js_new_bf(JSContext *ctx)
-{
- JSBigFloat *p;
- p = js_malloc(ctx, sizeof(*p));
- if (!p)
- return NULL;
- p->header.ref_count = 1;
- bf_init(ctx->bf_ctx, &p->num);
- return p;
-}
-
-static JSValue JS_NewBigInt(JSContext *ctx)
-{
- JSBigFloat *p;
- p = js_malloc(ctx, sizeof(*p));
- if (!p)
- return JS_EXCEPTION;
- p->header.ref_count = 1;
- bf_init(ctx->bf_ctx, &p->num);
- return JS_MKPTR(JS_TAG_BIG_INT, p);
-}
-
-static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
- BOOL convert_to_safe_integer)
-{
- int64_t v;
- bf_t *a;
-
- if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT)
- return val; /* fail safe */
- a = JS_GetBigInt(val);
- if (convert_to_safe_integer && bf_get_int64(&v, a, 0) == 0 &&
- v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
- JS_FreeValue(ctx, val);
- return JS_NewInt64(ctx, v);
- } else if (a->expn == BF_EXP_ZERO && a->sign) {
- JSBigFloat *p = JS_VALUE_GET_PTR(val);
- assert(p->header.ref_count == 1);
- a->sign = 0;
- }
- return val;
-}
-
-/* Convert the big int to a safe integer if in math mode. normalize
- the zero representation. Could also be used to convert the bigint
- to a short bigint value. The reference count of the value must be
- 1. Cannot fail */
-static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val)
-{
- return JS_CompactBigInt1(ctx, val, is_math_mode(ctx));
-}
-
-static JSValue throw_bf_exception(JSContext *ctx, int status)
-{
- const char *str;
- if (status & BF_ST_MEM_ERROR)
- return JS_ThrowOutOfMemory(ctx);
- if (status & BF_ST_DIVIDE_ZERO) {
- str = "division by zero";
- } else if (status & BF_ST_INVALID_OP) {
- str = "invalid operation";
- } else {
- str = "integer overflow";
- }
- return JS_ThrowRangeError(ctx, "%s", str);
-}
-
-/* if the returned bigfloat is allocated it is equal to
- 'buf'. Otherwise it is a pointer to the bigfloat in 'val'. Return
- NULL in case of error. */
-static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val)
+static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
+ JSValue *sp,
+ OPCodeEnum op)
{
+ JSValue op1;
+ int v;
uint32_t tag;
- bf_t *r;
- JSBigFloat *p;
+ JSBigIntBuf buf1;
+ JSBigInt *p1;
- tag = JS_VALUE_GET_NORM_TAG(val);
+ op1 = sp[-1];
+ /* fast path for float64 */
+ if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)))
+ goto handle_float64;
+ op1 = JS_ToNumericFree(ctx, op1);
+ if (JS_IsException(op1))
+ goto exception;
+ tag = JS_VALUE_GET_TAG(op1);
switch(tag) {
case JS_TAG_INT:
- 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;
+ {
+ 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_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;
+ case JS_TAG_SHORT_BIG_INT:
+ {
+ int64_t v;
+ v = JS_VALUE_GET_SHORT_BIG_INT(op1);
+ switch(op) {
+ case OP_plus:
+ JS_ThrowTypeError(ctx, "bigint argument with unary +");
+ goto exception;
+ case OP_inc:
+ if (v == JS_SHORT_BIG_INT_MAX)
+ goto bigint_slow_case;
+ sp[-1] = __JS_NewShortBigInt(ctx, v + 1);
+ break;
+ case OP_dec:
+ if (v == JS_SHORT_BIG_INT_MIN)
+ goto bigint_slow_case;
+ sp[-1] = __JS_NewShortBigInt(ctx, v - 1);
+ break;
+ case OP_neg:
+ v = JS_VALUE_GET_SHORT_BIG_INT(op1);
+ if (v == JS_SHORT_BIG_INT_MIN) {
+ bigint_slow_case:
+ p1 = js_bigint_set_short(&buf1, op1);
+ goto bigint_slow_case1;
+ }
+ sp[-1] = __JS_NewShortBigInt(ctx, -v);
+ break;
+ default:
+ abort();
+ }
}
break;
case JS_TAG_BIG_INT:
-#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_FLOAT:
-#endif
- 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;
-}
-
-#ifdef CONFIG_BIGNUM
-/* return NULL if invalid type */
-static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val)
-{
- uint32_t tag;
- JSBigDecimal *p;
- bfdec_t *r;
-
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_BIG_DECIMAL:
- p = JS_VALUE_GET_PTR(val);
- r = &p->num;
+ {
+ JSBigInt *r;
+ p1 = JS_VALUE_GET_PTR(op1);
+ bigint_slow_case1:
+ switch(op) {
+ case OP_plus:
+ JS_ThrowTypeError(ctx, "bigint argument with unary +");
+ JS_FreeValue(ctx, op1);
+ goto exception;
+ case OP_inc:
+ case OP_dec:
+ {
+ JSBigIntBuf buf2;
+ JSBigInt *p2;
+ p2 = js_bigint_set_si(&buf2, 2 * (op - OP_dec) - 1);
+ r = js_bigint_add(ctx, p1, p2, 0);
+ }
+ break;
+ case OP_neg:
+ r = js_bigint_neg(ctx, p1);
+ break;
+ case OP_not:
+ r = js_bigint_not(ctx, p1);
+ break;
+ default:
+ abort();
+ }
+ JS_FreeValue(ctx, op1);
+ if (!r)
+ goto exception;
+ sp[-1] = JS_CompactBigInt(ctx, r);
+ }
break;
- default:
- JS_ThrowTypeError(ctx, "bigdecimal expected");
- r = NULL;
- break;
- }
- return r;
-}
-
-static JSValue JS_NewBigFloat(JSContext *ctx)
-{
- JSBigFloat *p;
- p = js_malloc(ctx, sizeof(*p));
- if (!p)
- return JS_EXCEPTION;
- p->header.ref_count = 1;
- bf_init(ctx->bf_ctx, &p->num);
- return JS_MKPTR(JS_TAG_BIG_FLOAT, p);
-}
-
-static JSValue JS_NewBigDecimal(JSContext *ctx)
-{
- JSBigDecimal *p;
- p = js_malloc(ctx, sizeof(*p));
- if (!p)
- return JS_EXCEPTION;
- p->header.ref_count = 1;
- bfdec_init(ctx->bf_ctx, &p->num);
- return JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
-}
-
-/* must be kept in sync with JSOverloadableOperatorEnum */
-/* XXX: use atoms ? */
-static const char js_overloadable_operator_names[JS_OVOP_COUNT][4] = {
- "+",
- "-",
- "*",
- "/",
- "%",
- "**",
- "|",
- "&",
- "^",
- "<<",
- ">>",
- ">>>",
- "==",
- "<",
- "pos",
- "neg",
- "++",
- "--",
- "~",
-};
-
-static int get_ovop_from_opcode(OPCodeEnum op)
-{
- switch(op) {
- case OP_add:
- return JS_OVOP_ADD;
- case OP_sub:
- return JS_OVOP_SUB;
- case OP_mul:
- return JS_OVOP_MUL;
- case OP_div:
- return JS_OVOP_DIV;
- case OP_mod:
- case OP_math_mod:
- return JS_OVOP_MOD;
- case OP_pow:
- return JS_OVOP_POW;
- case OP_or:
- return JS_OVOP_OR;
- case OP_and:
- return JS_OVOP_AND;
- case OP_xor:
- return JS_OVOP_XOR;
- case OP_shl:
- return JS_OVOP_SHL;
- case OP_sar:
- return JS_OVOP_SAR;
- case OP_shr:
- return JS_OVOP_SHR;
- case OP_eq:
- case OP_neq:
- return JS_OVOP_EQ;
- case OP_lt:
- case OP_lte:
- case OP_gt:
- case OP_gte:
- return JS_OVOP_LESS;
- case OP_plus:
- return JS_OVOP_POS;
- case OP_neg:
- return JS_OVOP_NEG;
- case OP_inc:
- return JS_OVOP_INC;
- case OP_dec:
- return JS_OVOP_DEC;
- default:
- abort();
- }
-}
-
-/* return NULL if not present */
-static JSObject *find_binary_op(JSBinaryOperatorDef *def,
- uint32_t operator_index,
- JSOverloadableOperatorEnum op)
-{
- JSBinaryOperatorDefEntry *ent;
- int i;
- for(i = 0; i < def->count; i++) {
- ent = &def->tab[i];
- if (ent->operator_index == operator_index)
- return ent->ops[op];
- }
- return NULL;
-}
-
-/* return -1 if exception, 0 if no operator overloading, 1 if
- overloaded operator called */
-static __exception int js_call_binary_op_fallback(JSContext *ctx,
- JSValue *pret,
- JSValueConst op1,
- JSValueConst op2,
- OPCodeEnum op,
- BOOL is_numeric,
- int hint)
-{
- JSValue opset1_obj, opset2_obj, method, ret, new_op1, new_op2;
- JSOperatorSetData *opset1, *opset2;
- JSOverloadableOperatorEnum ovop;
- JSObject *p;
- JSValueConst args[2];
-
- if (!ctx->allow_operator_overloading)
- return 0;
-
- opset2_obj = JS_UNDEFINED;
- opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
- if (JS_IsException(opset1_obj))
- goto exception;
- if (JS_IsUndefined(opset1_obj))
- return 0;
- opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
- if (!opset1)
- goto exception;
-
- opset2_obj = JS_GetProperty(ctx, op2, JS_ATOM_Symbol_operatorSet);
- if (JS_IsException(opset2_obj))
- goto exception;
- if (JS_IsUndefined(opset2_obj)) {
- JS_FreeValue(ctx, opset1_obj);
- return 0;
- }
- opset2 = JS_GetOpaque2(ctx, opset2_obj, JS_CLASS_OPERATOR_SET);
- if (!opset2)
- goto exception;
-
- if (opset1->is_primitive && opset2->is_primitive) {
- JS_FreeValue(ctx, opset1_obj);
- JS_FreeValue(ctx, opset2_obj);
- return 0;
- }
-
- ovop = get_ovop_from_opcode(op);
-
- if (opset1->operator_counter == opset2->operator_counter) {
- p = opset1->self_ops[ovop];
- } else if (opset1->operator_counter > opset2->operator_counter) {
- p = find_binary_op(&opset1->left, opset2->operator_counter, ovop);
- } else {
- p = find_binary_op(&opset2->right, opset1->operator_counter, ovop);
- }
- if (!p) {
- JS_ThrowTypeError(ctx, "operator %s: no function defined",
- js_overloadable_operator_names[ovop]);
- goto exception;
- }
-
- if (opset1->is_primitive) {
- if (is_numeric) {
- new_op1 = JS_ToNumeric(ctx, op1);
- } else {
- new_op1 = JS_ToPrimitive(ctx, op1, hint);
- }
- if (JS_IsException(new_op1))
- goto exception;
- } else {
- new_op1 = JS_DupValue(ctx, op1);
- }
-
- if (opset2->is_primitive) {
- if (is_numeric) {
- new_op2 = JS_ToNumeric(ctx, op2);
- } else {
- new_op2 = JS_ToPrimitive(ctx, op2, hint);
- }
- if (JS_IsException(new_op2)) {
- JS_FreeValue(ctx, new_op1);
- goto exception;
- }
- } else {
- new_op2 = JS_DupValue(ctx, op2);
- }
-
- /* XXX: could apply JS_ToPrimitive() if primitive type so that the
- operator function does not get a value object */
-
- method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
- if (ovop == JS_OVOP_LESS && (op == OP_lte || op == OP_gt)) {
- args[0] = new_op2;
- args[1] = new_op1;
- } else {
- args[0] = new_op1;
- args[1] = new_op2;
- }
- ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
- JS_FreeValue(ctx, new_op1);
- JS_FreeValue(ctx, new_op2);
- if (JS_IsException(ret))
- goto exception;
- if (ovop == JS_OVOP_EQ) {
- BOOL res = JS_ToBoolFree(ctx, ret);
- if (op == OP_neq)
- res ^= 1;
- ret = JS_NewBool(ctx, res);
- } else if (ovop == JS_OVOP_LESS) {
- if (JS_IsUndefined(ret)) {
- ret = JS_FALSE;
- } else {
- BOOL res = JS_ToBoolFree(ctx, ret);
- if (op == OP_lte || op == OP_gte)
- res ^= 1;
- ret = JS_NewBool(ctx, res);
- }
- }
- JS_FreeValue(ctx, opset1_obj);
- JS_FreeValue(ctx, opset2_obj);
- *pret = ret;
- return 1;
- exception:
- JS_FreeValue(ctx, opset1_obj);
- JS_FreeValue(ctx, opset2_obj);
- *pret = JS_UNDEFINED;
- return -1;
-}
-
-/* try to call the operation on the operatorSet field of 'obj'. Only
- used for "/" and "**" on the BigInt prototype in math mode */
-static __exception int js_call_binary_op_simple(JSContext *ctx,
- JSValue *pret,
- JSValueConst obj,
- JSValueConst op1,
- JSValueConst op2,
- OPCodeEnum op)
-{
- JSValue opset1_obj, method, ret, new_op1, new_op2;
- JSOperatorSetData *opset1;
- JSOverloadableOperatorEnum ovop;
- JSObject *p;
- JSValueConst args[2];
-
- opset1_obj = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet);
- if (JS_IsException(opset1_obj))
- goto exception;
- if (JS_IsUndefined(opset1_obj))
- return 0;
- opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
- if (!opset1)
- goto exception;
- ovop = get_ovop_from_opcode(op);
-
- p = opset1->self_ops[ovop];
- if (!p) {
- JS_FreeValue(ctx, opset1_obj);
- return 0;
- }
-
- new_op1 = JS_ToNumeric(ctx, op1);
- if (JS_IsException(new_op1))
- goto exception;
- new_op2 = JS_ToNumeric(ctx, op2);
- if (JS_IsException(new_op2)) {
- JS_FreeValue(ctx, new_op1);
- goto exception;
- }
-
- method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
- args[0] = new_op1;
- args[1] = new_op2;
- ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
- JS_FreeValue(ctx, new_op1);
- JS_FreeValue(ctx, new_op2);
- if (JS_IsException(ret))
- goto exception;
- JS_FreeValue(ctx, opset1_obj);
- *pret = ret;
- return 1;
- exception:
- JS_FreeValue(ctx, opset1_obj);
- *pret = JS_UNDEFINED;
- return -1;
-}
-
-/* return -1 if exception, 0 if no operator overloading, 1 if
- overloaded operator called */
-static __exception int js_call_unary_op_fallback(JSContext *ctx,
- JSValue *pret,
- JSValueConst op1,
- OPCodeEnum op)
-{
- JSValue opset1_obj, method, ret;
- JSOperatorSetData *opset1;
- JSOverloadableOperatorEnum ovop;
- JSObject *p;
-
- if (!ctx->allow_operator_overloading)
- return 0;
-
- opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
- if (JS_IsException(opset1_obj))
- goto exception;
- if (JS_IsUndefined(opset1_obj))
- return 0;
- opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
- if (!opset1)
- goto exception;
- if (opset1->is_primitive) {
- JS_FreeValue(ctx, opset1_obj);
- return 0;
- }
-
- ovop = get_ovop_from_opcode(op);
-
- p = opset1->self_ops[ovop];
- if (!p) {
- JS_ThrowTypeError(ctx, "no overloaded operator %s",
- js_overloadable_operator_names[ovop]);
- goto exception;
- }
- method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
- ret = JS_CallFree(ctx, method, JS_UNDEFINED, 1, &op1);
- if (JS_IsException(ret))
- goto exception;
- JS_FreeValue(ctx, opset1_obj);
- *pret = ret;
- return 1;
- exception:
- JS_FreeValue(ctx, opset1_obj);
- *pret = JS_UNDEFINED;
- return -1;
-}
-
-static 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);
- if (!a) {
- JS_FreeValue(ctx, res);
- JS_FreeValue(ctx, op1);
- return -1;
- }
- ret = 0;
- switch(op) {
- case OP_inc:
- case OP_dec:
- v = 2 * (op - OP_dec) - 1;
- ret = bf_add_si(r, a, v, ctx->fp_env.prec, ctx->fp_env.flags);
- break;
- case OP_plus:
- ret = bf_set(r, a);
- break;
- case OP_neg:
- ret = bf_set(r, a);
- bf_neg(r);
- break;
- default:
- abort();
- }
- if (a == &a_s)
- bf_delete(a);
- JS_FreeValue(ctx, op1);
- if (unlikely(ret & BF_ST_MEM_ERROR)) {
- JS_FreeValue(ctx, res);
- throw_bf_exception(ctx, ret);
- return -1;
- }
- *pres = res;
- return 0;
-}
-
-static int js_unary_arith_bigdecimal(JSContext *ctx,
- JSValue *pres, OPCodeEnum op, JSValue op1)
-{
- bfdec_t *r, *a;
- int ret, v;
- JSValue res;
-
- if (op == OP_plus && !is_math_mode(ctx)) {
- JS_ThrowTypeError(ctx, "bigdecimal argument with unary +");
- JS_FreeValue(ctx, op1);
- return -1;
- }
-
- res = JS_NewBigDecimal(ctx);
- if (JS_IsException(res)) {
- JS_FreeValue(ctx, op1);
- return -1;
- }
- r = JS_GetBigDecimal(res);
- a = JS_ToBigDecimal(ctx, op1);
- if (!a) {
- JS_FreeValue(ctx, res);
- JS_FreeValue(ctx, op1);
- return -1;
- }
- 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;
-}
-
-#endif /* CONFIG_BIGNUM */
-
-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);
- if (!a) {
- JS_FreeValue(ctx, res);
- JS_FreeValue(ctx, op1);
- return -1;
- }
- ret = 0;
- switch(op) {
- case OP_inc:
- case OP_dec:
- v = 2 * (op - OP_dec) - 1;
- ret = bf_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
- break;
- case OP_plus:
- ret = bf_set(r, a);
- break;
- case OP_neg:
- ret = bf_set(r, a);
- bf_neg(r);
- break;
- case OP_not:
- ret = bf_add_si(r, a, 1, BF_PREC_INF, BF_RNDZ);
- bf_neg(r);
- break;
- default:
- abort();
- }
- JS_FreeBigInt(ctx, a, &a_s);
- JS_FreeValue(ctx, op1);
- if (unlikely(ret)) {
- JS_FreeValue(ctx, res);
- throw_bf_exception(ctx, ret);
- return -1;
- }
- res = JS_CompactBigInt(ctx, res);
- *pres = res;
- return 0;
-}
-
-static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
- JSValue *sp,
- OPCodeEnum op)
-{
- JSValue op1;
- int v;
- uint32_t tag;
-
- op1 = sp[-1];
- /* fast path for float64 */
- if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)))
- goto handle_float64;
-#ifdef CONFIG_BIGNUM
- if (JS_IsObject(op1)) {
- JSValue val;
- int 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;
- }
- }
-#endif
- 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;
-#ifdef CONFIG_BIGNUM
- 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;
-#endif
default:
handle_float64:
{
double d;
- if (is_math_mode(ctx))
- goto handle_bigint;
d = JS_VALUE_GET_FLOAT64(op1);
switch(op) {
case OP_inc:
@@ -12925,27 +14089,20 @@ static __exception int js_post_inc_slow(JSContext *ctx,
static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
{
JSValue op1;
-
+
op1 = sp[-1];
-#ifdef CONFIG_BIGNUM
- if (JS_IsObject(op1)) {
- JSValue val;
- int 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;
- }
- }
-#endif
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))
+ if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT) {
+ sp[-1] = __JS_NewShortBigInt(ctx, ~JS_VALUE_GET_SHORT_BIG_INT(op1));
+ } else if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) {
+ JSBigInt *r;
+ r = js_bigint_not(ctx, JS_VALUE_GET_PTR(op1));
+ JS_FreeValue(ctx, op1);
+ if (!r)
goto exception;
+ sp[-1] = JS_CompactBigInt(ctx, r);
} else {
int32_t v1;
if (unlikely(JS_ToInt32Free(ctx, &v1, op1)))
@@ -12958,328 +14115,6 @@ static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
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;
-#ifdef CONFIG_BIGNUM
- 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;
-#endif
- 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:
-#ifdef CONFIG_BIGNUM
- 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
- abort();
-#endif
- }
- } 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;
-}
-
-#ifdef CONFIG_BIGNUM
-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))
- goto fail;
- r = JS_GetBigFloat(res);
- a = JS_ToBigFloat(ctx, &a_s, op1);
- if (!a) {
- JS_FreeValue(ctx, res);
- goto fail;
- }
- b = JS_ToBigFloat(ctx, &b_s, op2);
- if (!b) {
- if (a == &a_s)
- bf_delete(a);
- JS_FreeValue(ctx, res);
- goto fail;
- }
- 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;
- fail:
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- return -1;
-}
-
-/* b must be a positive integer */
-static int js_bfdec_pow(bfdec_t *r, const bfdec_t *a, const bfdec_t *b)
-{
- bfdec_t b1;
- int32_t b2;
- int ret;
-
- bfdec_init(b->ctx, &b1);
- ret = bfdec_set(&b1, b);
- if (ret) {
- bfdec_delete(&b1);
- return ret;
- }
- ret = bfdec_rint(&b1, BF_RNDZ);
- if (ret) {
- bfdec_delete(&b1);
- return BF_ST_INVALID_OP; /* must be an integer */
- }
- ret = bfdec_get_int32(&b2, &b1);
- bfdec_delete(&b1);
- if (ret)
- return ret; /* overflow */
- if (b2 < 0)
- return BF_ST_INVALID_OP; /* must be positive */
- return bfdec_pow_ui(r, a, b2);
-}
-
-static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op,
- JSValue *pres, JSValue op1, JSValue op2)
-{
- bfdec_t *r, *a, *b;
- int ret;
- JSValue res;
-
- res = JS_NewBigDecimal(ctx);
- if (JS_IsException(res))
- goto fail;
- r = JS_GetBigDecimal(res);
-
- a = JS_ToBigDecimal(ctx, op1);
- if (!a)
- goto fail;
- b = JS_ToBigDecimal(ctx, op2);
- if (!b)
- goto fail;
- switch(op) {
- case OP_add:
- ret = bfdec_add(r, a, b, BF_PREC_INF, BF_RNDZ);
- break;
- case OP_sub:
- ret = bfdec_sub(r, a, b, BF_PREC_INF, BF_RNDZ);
- break;
- case OP_mul:
- ret = bfdec_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
- break;
- case OP_div:
- ret = bfdec_div(r, a, b, BF_PREC_INF, BF_RNDZ);
- break;
- case OP_math_mod:
- /* Euclidian remainder */
- ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_DIVREM_EUCLIDIAN);
- break;
- case OP_mod:
- ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ);
- break;
- case OP_pow:
- ret = js_bfdec_pow(r, a, b);
- break;
- default:
- abort();
- }
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- if (unlikely(ret)) {
- JS_FreeValue(ctx, res);
- throw_bf_exception(ctx, ret);
- return -1;
- }
- *pres = res;
- return 0;
- fail:
- JS_FreeValue(ctx, res);
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- return -1;
-}
-#endif /* CONFIG_BIGNUM */
-
static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
OPCodeEnum op)
{
@@ -13297,28 +14132,50 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s
d2 = JS_VALUE_GET_FLOAT64(op2);
goto handle_float64;
}
-
-#ifdef CONFIG_BIGNUM
- /* 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))) {
- JSValue res;
- int 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;
+ /* fast path for short big int operations */
+ if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) {
+ js_slimb_t v1, v2;
+ js_sdlimb_t v;
+ v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);
+ v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);
+ switch(op) {
+ case OP_sub:
+ v = (js_sdlimb_t)v1 - (js_sdlimb_t)v2;
+ break;
+ case OP_mul:
+ v = (js_sdlimb_t)v1 * (js_sdlimb_t)v2;
+ break;
+ case OP_div:
+ if (v2 == 0 ||
+ ((js_limb_t)v1 == (js_limb_t)1 << (JS_LIMB_BITS - 1) &&
+ v2 == -1)) {
+ goto slow_big_int;
+ }
+ sp[-2] = __JS_NewShortBigInt(ctx, v1 / v2);
+ return 0;
+ case OP_mod:
+ if (v2 == 0 ||
+ ((js_limb_t)v1 == (js_limb_t)1 << (JS_LIMB_BITS - 1) &&
+ v2 == -1)) {
+ goto slow_big_int;
}
+ sp[-2] = __JS_NewShortBigInt(ctx, v1 % v2);
+ return 0;
+ case OP_pow:
+ goto slow_big_int;
+ default:
+ abort();
+ }
+ if (likely(v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX)) {
+ sp[-2] = __JS_NewShortBigInt(ctx, v);
+ } else {
+ JSBigInt *r = js_bigint_new_di(ctx, v);
+ if (!r)
+ goto exception;
+ sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r);
}
+ return 0;
}
-#endif
-
op1 = JS_ToNumericFree(ctx, op1);
if (JS_IsException(op1)) {
JS_FreeValue(ctx, op2);
@@ -13343,34 +14200,14 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s
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);
+ sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2);
return 0;
-#ifdef CONFIG_BIGNUM
- 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;
-#endif
case OP_mod:
if (v1 < 0 || v2 <= 0) {
sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2));
@@ -13380,65 +14217,76 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s
}
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;
+ sp[-2] = JS_NewFloat64(ctx, js_pow(v1, v2));
+ return 0;
default:
abort();
}
sp[-2] = JS_NewInt64(ctx, v);
- } else
-#ifdef CONFIG_BIGNUM
- 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
-#endif
- 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;
+ } else if ((tag1 == JS_TAG_SHORT_BIG_INT || tag1 == JS_TAG_BIG_INT) &&
+ (tag2 == JS_TAG_SHORT_BIG_INT || tag2 == JS_TAG_BIG_INT)) {
+ JSBigInt *p1, *p2, *r;
+ JSBigIntBuf buf1, buf2;
+ slow_big_int:
+ /* bigint result */
+ if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)
+ p1 = js_bigint_set_short(&buf1, op1);
+ else
+ p1 = JS_VALUE_GET_PTR(op1);
+ if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)
+ p2 = js_bigint_set_short(&buf2, op2);
+ else
+ p2 = JS_VALUE_GET_PTR(op2);
switch(op) {
+ case OP_add:
+ r = js_bigint_add(ctx, p1, p2, 0);
+ break;
case OP_sub:
- dr = d1 - d2;
+ r = js_bigint_add(ctx, p1, p2, 1);
break;
case OP_mul:
- dr = d1 * d2;
+ r = js_bigint_mul(ctx, p1, p2);
break;
case OP_div:
- dr = d1 / d2;
+ r = js_bigint_divrem(ctx, p1, p2, FALSE);
break;
case OP_mod:
- dr = fmod(d1, d2);
+ r = js_bigint_divrem(ctx, p1, p2, TRUE);
+ break;
+ case OP_pow:
+ r = js_bigint_pow(ctx, p1, p2);
+ break;
+ default:
+ abort();
+ }
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ if (!r)
+ goto exception;
+ sp[-2] = JS_CompactBigInt(ctx, r);
+ } else {
+ double dr;
+ /* float64 result */
+ if (JS_ToFloat64Free(ctx, &d1, op1)) {
+ JS_FreeValue(ctx, op2);
+ goto exception;
+ }
+ if (JS_ToFloat64Free(ctx, &d2, op2))
+ goto exception;
+ handle_float64:
+ switch(op) {
+ case OP_sub:
+ dr = d1 - d2;
+ break;
+ case OP_mul:
+ dr = d1 * d2;
+ break;
+ case OP_div:
+ dr = d1 / d2;
break;
-#ifdef CONFIG_BIGNUM
- case OP_math_mod:
- d2 = fabs(d2);
+ case OP_mod:
dr = fmod(d1, d2);
- /* XXX: loss of accuracy if dr < 0 */
- if (dr < 0)
- dr += d2;
break;
-#endif
case OP_pow:
dr = js_pow(d1, d2);
break;
@@ -13454,6 +14302,11 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s
return -1;
}
+static inline BOOL tag_is_string(uint32_t tag)
+{
+ return tag == JS_TAG_STRING || tag == JS_TAG_STRING_ROPE;
+}
+
static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
{
JSValue op1, op2;
@@ -13472,31 +14325,25 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
return 0;
}
-
- if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) {
-#ifdef CONFIG_BIGNUM
- /* 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))) {
- JSValue res;
- int 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;
- }
- }
+ /* fast path for short bigint */
+ if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) {
+ js_slimb_t v1, v2;
+ js_sdlimb_t v;
+ v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);
+ v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);
+ v = (js_sdlimb_t)v1 + (js_sdlimb_t)v2;
+ if (likely(v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX)) {
+ sp[-2] = __JS_NewShortBigInt(ctx, v);
+ } else {
+ JSBigInt *r = js_bigint_new_di(ctx, v);
+ if (!r)
+ goto exception;
+ sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r);
}
-#endif
+ return 0;
+ }
+
+ if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) {
op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
if (JS_IsException(op1)) {
JS_FreeValue(ctx, op2);
@@ -13512,7 +14359,7 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
tag2 = JS_VALUE_GET_NORM_TAG(op2);
}
- if (tag1 == JS_TAG_STRING || tag2 == JS_TAG_STRING) {
+ if (tag_is_string(tag1) || tag_is_string(tag2)) {
sp[-2] = JS_ConcatString(ctx, op1, op2);
if (JS_IsException(sp[-2]))
goto exception;
@@ -13539,20 +14386,25 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
v2 = JS_VALUE_GET_INT(op2);
v = (int64_t)v1 + (int64_t)v2;
sp[-2] = JS_NewInt64(ctx, v);
- } else
-#ifdef CONFIG_BIGNUM
- 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
-#endif
- 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))
+ } else if ((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) &&
+ (tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT)) {
+ JSBigInt *p1, *p2, *r;
+ JSBigIntBuf buf1, buf2;
+ /* bigint result */
+ if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)
+ p1 = js_bigint_set_short(&buf1, op1);
+ else
+ p1 = JS_VALUE_GET_PTR(op1);
+ if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)
+ p2 = js_bigint_set_short(&buf2, op2);
+ else
+ p2 = JS_VALUE_GET_PTR(op2);
+ r = js_bigint_add(ctx, p1, p2, 0);
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ if (!r)
goto exception;
+ sp[-2] = JS_CompactBigInt(ctx, r);
} else {
double d1, d2;
/* float64 result */
@@ -13562,8 +14414,6 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
}
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;
@@ -13586,27 +14436,62 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx,
tag1 = JS_VALUE_GET_NORM_TAG(op1);
tag2 = JS_VALUE_GET_NORM_TAG(op2);
-#ifdef CONFIG_BIGNUM
- /* 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))) {
- JSValue res;
- int 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;
+ if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) {
+ js_slimb_t v1, v2, v;
+ js_sdlimb_t vd;
+ v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);
+ v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);
+ /* bigint fast path */
+ switch(op) {
+ case OP_and:
+ v = v1 & v2;
+ break;
+ case OP_or:
+ v = v1 | v2;
+ break;
+ case OP_xor:
+ v = v1 ^ v2;
+ break;
+ case OP_sar:
+ if (v2 > (JS_LIMB_BITS - 1)) {
+ goto slow_big_int;
+ } else if (v2 < 0) {
+ if (v2 < -(JS_LIMB_BITS - 1))
+ goto slow_big_int;
+ v2 = -v2;
+ goto bigint_shl;
+ }
+ bigint_sar:
+ v = v1 >> v2;
+ break;
+ case OP_shl:
+ if (v2 > (JS_LIMB_BITS - 1)) {
+ goto slow_big_int;
+ } else if (v2 < 0) {
+ if (v2 < -(JS_LIMB_BITS - 1))
+ goto slow_big_int;
+ v2 = -v2;
+ goto bigint_sar;
+ }
+ bigint_shl:
+ vd = (js_dlimb_t)v1 << v2;
+ if (likely(vd >= JS_SHORT_BIG_INT_MIN &&
+ vd <= JS_SHORT_BIG_INT_MAX)) {
+ v = vd;
} else {
- sp[-2] = res;
+ JSBigInt *r = js_bigint_new_di(ctx, vd);
+ if (!r)
+ goto exception;
+ sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r);
return 0;
}
+ break;
+ default:
+ abort();
}
+ sp[-2] = __JS_NewShortBigInt(ctx, v);
+ return 0;
}
-#endif
-
op1 = JS_ToNumericFree(ctx, op1);
if (JS_IsException(op1)) {
JS_FreeValue(ctx, op2);
@@ -13618,22 +14503,52 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx,
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;
+ if ((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) &&
+ (tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT)) {
+ JSBigInt *p1, *p2, *r;
+ JSBigIntBuf buf1, buf2;
+ slow_big_int:
+ if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)
+ p1 = js_bigint_set_short(&buf1, op1);
+ else
+ p1 = JS_VALUE_GET_PTR(op1);
+ if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)
+ p2 = js_bigint_set_short(&buf2, op2);
+ else
+ p2 = JS_VALUE_GET_PTR(op2);
+ switch(op) {
+ case OP_and:
+ case OP_or:
+ case OP_xor:
+ r = js_bigint_logic(ctx, p1, p2, op);
+ break;
+ case OP_shl:
+ case OP_sar:
+ {
+ js_slimb_t shift;
+ shift = js_bigint_get_si_sat(p2);
+ if (shift > INT32_MAX)
+ shift = INT32_MAX;
+ else if (shift < -INT32_MAX)
+ shift = -INT32_MAX;
+ if (op == OP_sar)
+ shift = -shift;
+ if (shift >= 0)
+ r = js_bigint_shl(ctx, p1, shift);
+ else
+ r = js_bigint_shr(ctx, p1, -shift);
+ }
+ break;
+ default:
+ abort();
}
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ if (!r)
+ goto exception;
+ sp[-2] = JS_CompactBigInt(ctx, r);
} else {
if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {
JS_FreeValue(ctx, op2);
@@ -13669,100 +14584,98 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx,
return -1;
}
-/* Note: also used for bigint */
-static int js_compare_bigfloat(JSContext *ctx, OPCodeEnum op,
- JSValue op1, JSValue op2)
+/* op1 must be a bigint or int. */
+static JSBigInt *JS_ToBigIntBuf(JSContext *ctx, JSBigIntBuf *buf1,
+ JSValue op1)
{
- bf_t a_s, b_s, *a, *b;
- int res;
+ JSBigInt *p1;
- 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 */
+ switch(JS_VALUE_GET_TAG(op1)) {
+ case JS_TAG_INT:
+ p1 = js_bigint_set_si(buf1, JS_VALUE_GET_INT(op1));
break;
- case OP_gte:
- res = bf_cmp_le(b, a); /* if NaN return false */
+ case JS_TAG_SHORT_BIG_INT:
+ p1 = js_bigint_set_short(buf1, op1);
break;
- case OP_eq:
- res = bf_cmp_eq(a, b); /* if NaN return false */
+ case JS_TAG_BIG_INT:
+ p1 = JS_VALUE_GET_PTR(op1);
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;
+ return p1;
}
-#ifdef CONFIG_BIGNUM
-static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op,
- JSValue op1, JSValue op2)
+/* op1 and op2 must be numeric types and at least one must be a
+ bigint. No exception is generated. */
+static int js_compare_bigint(JSContext *ctx, OPCodeEnum op,
+ JSValue op1, JSValue op2)
{
- 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)) {
+ int res, val, tag1, tag2;
+ JSBigIntBuf buf1, buf2;
+ JSBigInt *p1, *p2;
+
+ tag1 = JS_VALUE_GET_NORM_TAG(op1);
+ tag2 = JS_VALUE_GET_NORM_TAG(op2);
+ if ((tag1 == JS_TAG_SHORT_BIG_INT || tag1 == JS_TAG_INT) &&
+ (tag2 == JS_TAG_SHORT_BIG_INT || tag2 == JS_TAG_INT)) {
+ /* fast path */
+ js_slimb_t v1, v2;
+ if (tag1 == JS_TAG_INT)
+ v1 = JS_VALUE_GET_INT(op1);
+ else
+ v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);
+ if (tag2 == JS_TAG_INT)
+ v2 = JS_VALUE_GET_INT(op2);
+ else
+ v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);
+ val = (v1 > v2) - (v1 < v2);
+ } else {
+ if (tag1 == JS_TAG_FLOAT64) {
+ p2 = JS_ToBigIntBuf(ctx, &buf2, op2);
+ val = js_bigint_float64_cmp(ctx, p2, JS_VALUE_GET_FLOAT64(op1));
+ if (val == 2)
+ goto unordered;
+ val = -val;
+ } else if (tag2 == JS_TAG_FLOAT64) {
+ p1 = JS_ToBigIntBuf(ctx, &buf1, op1);
+ val = js_bigint_float64_cmp(ctx, p1, JS_VALUE_GET_FLOAT64(op2));
+ if (val == 2) {
+ unordered:
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ return FALSE;
+ }
+ } else {
+ p1 = JS_ToBigIntBuf(ctx, &buf1, op1);
+ p2 = JS_ToBigIntBuf(ctx, &buf2, op2);
+ val = js_bigint_cmp(ctx, p1, p2);
+ }
JS_FreeValue(ctx, op1);
- return -1;
+ JS_FreeValue(ctx, op2);
}
- a = JS_ToBigDecimal(ctx, op1); /* cannot fail */
- b = JS_ToBigDecimal(ctx, op2); /* cannot fail */
-
+
switch(op) {
case OP_lt:
- res = bfdec_cmp_lt(a, b); /* if NaN return false */
+ res = val < 0;
break;
case OP_lte:
- res = bfdec_cmp_le(a, b); /* if NaN return false */
+ res = val <= 0;
break;
case OP_gt:
- res = bfdec_cmp_lt(b, a); /* if NaN return false */
+ res = val > 0;
break;
case OP_gte:
- res = bfdec_cmp_le(b, a); /* if NaN return false */
+ res = val >= 0;
break;
case OP_eq:
- res = bfdec_cmp_eq(a, b); /* if NaN return false */
+ res = val == 0;
break;
default:
abort();
}
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
return res;
}
-#endif /* !CONFIG_BIGNUM */
static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
OPCodeEnum op)
@@ -13775,27 +14688,6 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
op2 = sp[-1];
tag1 = JS_VALUE_GET_NORM_TAG(op1);
tag2 = JS_VALUE_GET_NORM_TAG(op2);
-#ifdef CONFIG_BIGNUM
- /* 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))) {
- JSValue ret;
- 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;
- }
- }
- }
-#endif
op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER);
if (JS_IsException(op1)) {
JS_FreeValue(ctx, op2);
@@ -13809,11 +14701,13 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
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);
+ if (tag_is_string(tag1) && tag_is_string(tag2)) {
+ if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) {
+ res = js_string_compare(ctx, JS_VALUE_GET_STRING(op1),
+ JS_VALUE_GET_STRING(op2));
+ } else {
+ res = js_string_rope_compare(ctx, op1, op2, FALSE);
+ }
switch(op) {
case OP_lt:
res = (res < 0);
@@ -13836,17 +14730,20 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
/* 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) {
+ if ((((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) &&
+ tag_is_string(tag2)) ||
+ ((tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) &&
+ tag_is_string(tag1)))) {
+ if (tag_is_string(tag1)) {
op1 = JS_StringToBigInt(ctx, op1);
- if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
+ if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT &&
+ JS_VALUE_GET_TAG(op1) != JS_TAG_SHORT_BIG_INT)
goto invalid_bigint_string;
}
- if (tag2 == JS_TAG_STRING) {
+ if (tag_is_string(tag2)) {
op2 = JS_StringToBigInt(ctx, op2);
- if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT) {
+ if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT &&
+ JS_VALUE_GET_TAG(op2) != JS_TAG_SHORT_BIG_INT) {
invalid_bigint_string:
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
@@ -13870,21 +14767,9 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
tag1 = JS_VALUE_GET_NORM_TAG(op1);
tag2 = JS_VALUE_GET_NORM_TAG(op2);
-#ifdef CONFIG_BIGNUM
- 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
-#endif
- 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;
+ if (tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT ||
+ tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) {
+ res = js_compare_bigint(ctx, op, op1, op2);
} else {
double d1, d2;
@@ -13928,21 +14813,15 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
static BOOL tag_is_number(uint32_t tag)
{
- return (tag == JS_TAG_INT || tag == JS_TAG_BIG_INT ||
- tag == JS_TAG_FLOAT64
-#ifdef CONFIG_BIGNUM
- || tag == JS_TAG_BIG_FLOAT || tag == JS_TAG_BIG_DECIMAL
-#endif
- );
+ return (tag == JS_TAG_INT ||
+ tag == JS_TAG_FLOAT64 ||
+ tag == JS_TAG_BIG_INT || tag == JS_TAG_SHORT_BIG_INT);
}
static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
BOOL is_neq)
{
JSValue op1, op2;
-#ifdef CONFIG_BIGNUM
- JSValue ret;
-#endif
int res;
uint32_t tag1, tag2;
@@ -13970,59 +14849,32 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
d2 = JS_VALUE_GET_INT(op2);
}
res = (d1 == d2);
- } else
-#ifdef CONFIG_BIGNUM
- 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
-#endif
- {
- res = ctx->rt->bigint_ops.compare(ctx, OP_eq, op1, op2);
- if (res < 0)
- goto exception;
+ } else {
+ res = js_compare_bigint(ctx, OP_eq, op1, op2);
}
} else if (tag1 == tag2) {
-#ifdef CONFIG_BIGNUM
- 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;
- }
- }
- }
-#endif
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))) {
+ } else if (tag_is_string(tag1) && tag_is_string(tag2)) {
+ /* needed when comparing strings and ropes */
+ res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
+ } else if ((tag_is_string(tag1) && tag_is_number(tag2)) ||
+ (tag_is_string(tag2) && tag_is_number(tag1))) {
- if ((tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) &&
- !is_math_mode(ctx)) {
- if (tag1 == JS_TAG_STRING) {
+ if (tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT ||
+ tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) {
+ if (tag_is_string(tag1)) {
op1 = JS_StringToBigInt(ctx, op1);
- if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
+ if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT &&
+ JS_VALUE_GET_TAG(op1) != JS_TAG_SHORT_BIG_INT)
goto invalid_bigint_string;
}
- if (tag2 == JS_TAG_STRING) {
+ if (tag_is_string(tag2)) {
op2 = JS_StringToBigInt(ctx, op2);
- if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT) {
+ if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT &&
+ JS_VALUE_GET_TAG(op2) != JS_TAG_SHORT_BIG_INT ) {
invalid_bigint_string:
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
@@ -14042,7 +14894,7 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
goto exception;
}
}
- res = js_strict_eq(ctx, op1, op2);
+ res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
} else if (tag1 == JS_TAG_BOOL) {
op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));
goto redo;
@@ -14050,25 +14902,9 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
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)) ||
+ (tag_is_number(tag2) || tag_is_string(tag2) || tag2 == JS_TAG_SYMBOL)) ||
(tag2 == JS_TAG_OBJECT &&
- (tag_is_number(tag1) || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL))) {
-#ifdef CONFIG_BIGNUM
- /* 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;
- }
- }
-#endif
+ (tag_is_number(tag1) || tag_is_string(tag1) || tag1 == JS_TAG_SYMBOL))) {
op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
if (JS_IsException(op1)) {
JS_FreeValue(ctx, op2);
@@ -14119,10 +14955,10 @@ static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp)
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)) {
+ if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT ||
+ JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT ||
+ JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_INT ||
+ JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT) {
JS_ThrowTypeError(ctx, "bigint operands are forbidden for >>>");
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
@@ -14140,67 +14976,6 @@ static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp)
return -1;
}
-#ifdef CONFIG_BIGNUM
-static JSValue js_mul_pow10_to_float64(JSContext *ctx, const bf_t *a,
- int64_t exponent)
-{
- bf_t r_s, *r = &r_s;
- double d;
- int ret;
-
- /* always convert to Float64 */
- bf_init(ctx->bf_ctx, r);
- ret = bf_mul_pow_radix(r, a, 10, exponent,
- 53, bf_set_exp_bits(11) | BF_RNDN |
- BF_FLAG_SUBNORMAL);
- bf_get_float64(r, &d, BF_RNDN);
- bf_delete(r);
- if (ret & BF_ST_MEM_ERROR)
- return JS_ThrowOutOfMemory(ctx);
- else
- return __JS_NewFloat64(ctx, d);
-}
-
-static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp)
-{
- bf_t a_s, *a, *r;
- JSValue op1, op2, res;
- int64_t e;
- int ret;
-
- res = JS_NewBigFloat(ctx);
- if (JS_IsException(res))
- return -1;
- r = JS_GetBigFloat(res);
- op1 = sp[-2];
- op2 = sp[-1];
- a = JS_ToBigFloat(ctx, &a_s, op1);
- if (!a) {
- JS_FreeValue(ctx, res);
- 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;
-}
-#endif
-
/* XXX: Should take JSValueConst arguments */
static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
JSStrictEqModeEnum eq_mode)
@@ -14225,14 +15000,15 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
res = (tag1 == tag2);
break;
case JS_TAG_STRING:
+ case JS_TAG_STRING_ROPE:
{
- JSString *p1, *p2;
- if (tag1 != tag2) {
+ if (!tag_is_string(tag2)) {
res = FALSE;
+ } else if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) {
+ res = (js_string_compare(ctx, JS_VALUE_GET_STRING(op1),
+ JS_VALUE_GET_STRING(op2)) == 0);
} else {
- p1 = JS_VALUE_GET_STRING(op1);
- p2 = JS_VALUE_GET_STRING(op2);
- res = (js_string_compare(ctx, p1, p2) == 0);
+ res = (js_string_rope_compare(ctx, op1, op2, TRUE) == 0);
}
}
break;
@@ -14293,63 +15069,29 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
res = (d1 == d2); /* if NaN return false and +0 == -0 */
}
goto done_no_free;
+ case JS_TAG_SHORT_BIG_INT:
case JS_TAG_BIG_INT:
{
- bf_t a_s, *a, b_s, *b;
- if (tag1 != tag2) {
- res = FALSE;
- break;
- }
- a = JS_ToBigFloat(ctx, &a_s, op1); /* cannot fail */
- b = JS_ToBigFloat(ctx, &b_s, op2); /* cannot fail */
- res = bf_cmp_eq(a, b);
- if (a == &a_s)
- bf_delete(a);
- if (b == &b_s)
- bf_delete(b);
- }
- break;
-#ifdef CONFIG_BIGNUM
- 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) {
+ JSBigIntBuf buf1, buf2;
+ JSBigInt *p1, *p2;
+
+ if (tag2 != JS_TAG_SHORT_BIG_INT &&
+ tag2 != JS_TAG_BIG_INT) {
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);
+
+ if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)
+ p1 = js_bigint_set_short(&buf1, op1);
+ else
+ p1 = JS_VALUE_GET_PTR(op1);
+ if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)
+ p2 = js_bigint_set_short(&buf2, op2);
+ else
+ p2 = JS_VALUE_GET_PTR(op2);
+ res = (js_bigint_cmp(ctx, p1, p2) == 0);
}
break;
-#endif
default:
res = FALSE;
break;
@@ -14360,9 +15102,16 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
return res;
}
-static BOOL js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2)
+static BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2)
{
- return js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
+ return js_strict_eq2(ctx,
+ JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),
+ JS_EQ_STRICT);
+}
+
+BOOL JS_StrictEq(JSContext *ctx, JSValueConst op1, JSValueConst op2)
+{
+ return js_strict_eq(ctx, op1, op2);
}
static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2)
@@ -14372,6 +15121,11 @@ static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2)
JS_EQ_SAME_VALUE);
}
+BOOL JS_SameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2)
+{
+ return js_same_value(ctx, op1, op2);
+}
+
static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2)
{
return js_strict_eq2(ctx,
@@ -14379,11 +15133,16 @@ static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op
JS_EQ_SAME_VALUE_ZERO);
}
+BOOL JS_SameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2)
+{
+ return js_same_value_zero(ctx, op1, op2);
+}
+
static no_inline int js_strict_eq_slow(JSContext *ctx, JSValue *sp,
BOOL is_neq)
{
BOOL res;
- res = js_strict_eq(ctx, sp[-2], sp[-1]);
+ res = js_strict_eq2(ctx, sp[-2], sp[-1], JS_EQ_STRICT);
sp[-2] = JS_NewBool(ctx, res ^ is_neq);
return 0;
}
@@ -14414,6 +15173,43 @@ static __exception int js_operator_in(JSContext *ctx, JSValue *sp)
return 0;
}
+static __exception int js_operator_private_in(JSContext *ctx, JSValue *sp)
+{
+ JSValue op1, op2;
+ int ret;
+
+ op1 = sp[-2]; /* object */
+ op2 = sp[-1]; /* field name or method function */
+
+ if (JS_VALUE_GET_TAG(op1) != JS_TAG_OBJECT) {
+ JS_ThrowTypeError(ctx, "invalid 'in' operand");
+ return -1;
+ }
+ if (JS_IsObject(op2)) {
+ /* method: use the brand */
+ ret = JS_CheckBrand(ctx, op1, op2);
+ if (ret < 0)
+ return -1;
+ } else {
+ JSAtom atom;
+ JSObject *p;
+ JSShapeProperty *prs;
+ JSProperty *pr;
+ /* field */
+ atom = JS_ValueToAtom(ctx, op2);
+ if (unlikely(atom == JS_ATOM_NULL))
+ return -1;
+ p = JS_VALUE_GET_OBJ(op1);
+ prs = find_own_property(&pr, p, atom);
+ JS_FreeAtom(ctx, atom);
+ ret = (prs != NULL);
+ }
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ sp[-2] = JS_NewBool(ctx, ret);
+ return 0;
+}
+
static __exception int js_has_unscopable(JSContext *ctx, JSValueConst obj,
JSAtom atom)
{
@@ -14455,17 +15251,10 @@ static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1)
tag = JS_VALUE_GET_NORM_TAG(op1);
switch(tag) {
+ case JS_TAG_SHORT_BIG_INT:
case JS_TAG_BIG_INT:
atom = JS_ATOM_bigint;
break;
-#ifdef CONFIG_BIGNUM
- 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;
@@ -14477,13 +15266,14 @@ static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1)
atom = JS_ATOM_boolean;
break;
case JS_TAG_STRING:
+ case JS_TAG_STRING_ROPE:
atom = JS_ATOM_string;
break;
case JS_TAG_OBJECT:
{
JSObject *p;
p = JS_VALUE_GET_OBJ(op1);
- if (unlikely(p->is_HTMLDDA))
+ if (unlikely(p->is_HTMLDDA))
atom = JS_ATOM_undefined;
else if (JS_IsFunction(ctx, op1))
atom = JS_ATOM_function;
@@ -14526,21 +15316,15 @@ static __exception int js_operator_delete(JSContext *ctx, JSValue *sp)
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)
+static JSValue js_throw_type_error(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
{
JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
- if (!b || (b->js_mode & JS_MODE_STRICT) || !b->has_prototype) {
- return js_throw_type_error(ctx, this_val, 0, NULL);
+ if (!b || (b->js_mode & JS_MODE_STRICT) || !b->has_prototype || argc >= 1) {
+ return JS_ThrowTypeError(ctx, "invalid property access");
}
return JS_UNDEFINED;
}
@@ -14556,11 +15340,16 @@ static JSValue js_function_proto_fileName(JSContext *ctx,
}
static JSValue js_function_proto_lineNumber(JSContext *ctx,
- JSValueConst this_val)
+ JSValueConst this_val, int is_col)
{
JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
if (b && b->has_debug) {
- return JS_NewInt32(ctx, b->debug.line_num);
+ int line_num, col_num;
+ line_num = find_line_num(ctx, b, -1, &col_num);
+ if (is_col)
+ return JS_NewInt32(ctx, col_num);
+ else
+ return JS_NewInt32(ctx, line_num);
}
return JS_UNDEFINED;
}
@@ -14604,16 +15393,16 @@ static JSValue js_build_arguments(JSContext *ctx, int argc, JSValueConst *argv)
/* add the length field (cannot fail) */
pr = add_property(ctx, p, JS_ATOM_length,
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+ if (unlikely(!pr))
+ goto fail;
pr->u.value = JS_NewInt32(ctx, argc);
/* initialize the fast array part */
tab = NULL;
if (argc > 0) {
tab = js_malloc(ctx, sizeof(tab[0]) * argc);
- if (!tab) {
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
+ if (!tab)
+ goto fail;
for(i = 0; i < argc; i++) {
tab[i] = JS_DupValue(ctx, argv[i]);
}
@@ -14629,6 +15418,9 @@ static JSValue js_build_arguments(JSContext *ctx, int argc, JSValueConst *argv)
ctx->throw_type_error, ctx->throw_type_error,
JS_PROP_HAS_GET | JS_PROP_HAS_SET);
return val;
+ fail:
+ JS_FreeValue(ctx, val);
+ return JS_EXCEPTION;
}
#define GLOBAL_VAR_OFFSET 0x40000000
@@ -14653,6 +15445,8 @@ static JSValue js_build_mapped_arguments(JSContext *ctx, int argc,
/* add the length field (cannot fail) */
pr = add_property(ctx, p, JS_ATOM_length,
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+ if (unlikely(!pr))
+ goto fail;
pr->u.value = JS_NewInt32(ctx, argc);
for(i = 0; i < arg_count; i++) {
@@ -14712,10 +15506,10 @@ static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValueConst *
static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
{
- JSObject *p;
+ JSObject *p, *p1;
JSPropertyEnum *tab_atom;
int i;
- JSValue enum_obj, obj1;
+ JSValue enum_obj;
JSForInIterator *it;
uint32_t tag, tab_atom_count;
@@ -14738,40 +15532,16 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
it->is_array = FALSE;
it->obj = obj;
it->idx = 0;
- p = JS_VALUE_GET_OBJ(enum_obj);
- p->u.for_in_iterator = it;
+ it->tab_atom = NULL;
+ it->atom_count = 0;
+ it->in_prototype_chain = FALSE;
+ p1 = JS_VALUE_GET_OBJ(enum_obj);
+ p1->u.for_in_iterator = it;
if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
return enum_obj;
- /* 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;
@@ -14783,61 +15553,90 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
}
/* for fast arrays, we only store the number of elements */
it->is_array = TRUE;
- it->array_length = p->u.array.count;
+ it->atom_count = p->u.array.count;
} else {
normal_case:
if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
- JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY))
- goto fail;
- for(i = 0; i < tab_atom_count; i++) {
- JS_SetPropertyInternal(ctx, enum_obj, tab_atom[i].atom, JS_NULL, enum_obj, 0);
+ JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
+ JS_FreeValue(ctx, enum_obj);
+ return JS_EXCEPTION;
}
- js_free_prop_enum(ctx, tab_atom, tab_atom_count);
+ it->tab_atom = tab_atom;
+ it->atom_count = tab_atom_count;
}
return enum_obj;
+}
- slow_path:
- /* non enumerable properties hide the enumerables ones in the
- prototype chain */
- obj1 = JS_DupValue(ctx, obj);
+/* obj -> enum_obj */
+static __exception int js_for_in_start(JSContext *ctx, JSValue *sp)
+{
+ sp[-1] = build_for_in_iterator(ctx, sp[-1]);
+ if (JS_IsException(sp[-1]))
+ return -1;
+ return 0;
+}
+
+/* return -1 if exception, 0 if slow case, 1 if the enumeration is finished */
+static __exception int js_for_in_prepare_prototype_chain_enum(JSContext *ctx,
+ JSValueConst enum_obj)
+{
+ JSObject *p;
+ JSForInIterator *it;
+ JSPropertyEnum *tab_atom;
+ uint32_t tab_atom_count, i;
+ JSValue obj1;
+
+ p = JS_VALUE_GET_OBJ(enum_obj);
+ it = p->u.for_in_iterator;
+
+ /* check if there are enumerable properties in the prototype chain (fast path) */
+ obj1 = JS_DupValue(ctx, it->obj);
for(;;) {
+ obj1 = JS_GetPrototypeFree(ctx, obj1);
+ if (JS_IsNull(obj1))
+ break;
+ if (JS_IsException(obj1))
+ goto fail;
if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
JS_VALUE_GET_OBJ(obj1),
- JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
+ JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) {
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_FreePropertyEnum(ctx, tab_atom, tab_atom_count);
+ if (tab_atom_count != 0) {
+ JS_FreeValue(ctx, obj1);
+ goto slow_path;
}
- 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;
+ JS_FreeValue(ctx, obj1);
+ return 1;
- fail:
- JS_FreeValue(ctx, enum_obj);
- return JS_EXCEPTION;
-}
+ slow_path:
+ /* add the visited properties, even if they are not enumerable */
+ if (it->is_array) {
+ if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
+ JS_VALUE_GET_OBJ(it->obj),
+ JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
+ goto fail;
+ }
+ it->is_array = FALSE;
+ it->tab_atom = tab_atom;
+ it->atom_count = tab_atom_count;
+ }
-/* 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;
+ for(i = 0; i < it->atom_count; i++) {
+ if (JS_DefinePropertyValue(ctx, enum_obj, it->tab_atom[i].atom, JS_NULL, JS_PROP_ENUMERABLE) < 0)
+ goto fail;
+ }
return 0;
+ fail:
+ return -1;
}
/* enum_obj -> enum_obj value done */
@@ -14847,6 +15646,8 @@ static __exception int js_for_in_next(JSContext *ctx, JSValue *sp)
JSObject *p;
JSAtom prop;
JSForInIterator *it;
+ JSPropertyEnum *tab_atom;
+ uint32_t tab_atom_count;
int ret;
enum_obj = sp[-1];
@@ -14859,28 +15660,68 @@ static __exception int js_for_in_next(JSContext *ctx, JSValue *sp)
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++;
+ if (it->idx >= it->atom_count) {
+ if (JS_IsNull(it->obj) || JS_IsUndefined(it->obj))
+ goto done; /* not an object */
+ /* no more property in the current object: look in the prototype */
+ if (!it->in_prototype_chain) {
+ ret = js_for_in_prepare_prototype_chain_enum(ctx, enum_obj);
+ if (ret < 0)
+ return -1;
+ if (ret)
+ goto done;
+ it->in_prototype_chain = TRUE;
+ }
+ it->obj = JS_GetPrototypeFree(ctx, it->obj);
+ if (JS_IsException(it->obj))
+ return -1;
+ if (JS_IsNull(it->obj))
+ goto done; /* no more prototype */
+
+ /* must check for timeout to avoid infinite loop */
+ if (js_poll_interrupts(ctx))
+ return -1;
+
+ if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
+ JS_VALUE_GET_OBJ(it->obj),
+ JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
+ return -1;
+ }
+ JS_FreePropertyEnum(ctx, it->tab_atom, it->atom_count);
+ it->tab_atom = tab_atom;
+ it->atom_count = tab_atom_count;
+ it->idx = 0;
} else {
- 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;
+ if (it->is_array) {
+ prop = __JS_AtomFromUInt32(it->idx);
+ it->idx++;
+ } else {
+ BOOL is_enumerable;
+ prop = it->tab_atom[it->idx].atom;
+ is_enumerable = it->tab_atom[it->idx].is_enumerable;
+ it->idx++;
+ if (it->in_prototype_chain) {
+ /* slow case: we are in the prototype chain */
+ ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(enum_obj), prop);
+ if (ret < 0)
+ return ret;
+ if (ret)
+ continue; /* already visited */
+ /* add to the visited property list */
+ if (JS_DefinePropertyValue(ctx, enum_obj, prop, JS_NULL,
+ JS_PROP_ENUMERABLE) < 0)
+ return -1;
+ }
+ if (!is_enumerable)
+ continue;
+ }
+ /* check if the property was deleted */
+ ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(it->obj), prop);
+ if (ret < 0)
+ return ret;
+ if (ret)
+ break;
}
- /* 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);
@@ -14983,6 +15824,7 @@ static JSValue JS_IteratorNext2(JSContext *ctx, JSValueConst enum_obj,
return JS_EXCEPTION;
}
+/* Note: always return JS_UNDEFINED when *pdone = TRUE. */
static JSValue JS_IteratorNext(JSContext *ctx, JSValueConst enum_obj,
JSValueConst method,
int argc, JSValueConst *argv, BOOL *pdone)
@@ -14993,9 +15835,13 @@ static JSValue JS_IteratorNext(JSContext *ctx, JSValueConst enum_obj,
obj = JS_IteratorNext2(ctx, enum_obj, method, argc, argv, &done);
if (JS_IsException(obj))
goto fail;
- if (done != 2) {
- *pdone = done;
+ if (likely(done == 0)) {
+ *pdone = FALSE;
return obj;
+ } else if (done != 2) {
+ JS_FreeValue(ctx, obj);
+ *pdone = TRUE;
+ return JS_UNDEFINED;
} else {
done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);
if (JS_IsException(done_val))
@@ -15023,7 +15869,7 @@ static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj,
if (is_exception_pending) {
ex_obj = ctx->rt->current_exception;
- ctx->rt->current_exception = JS_NULL;
+ ctx->rt->current_exception = JS_UNINITIALIZED;
res = -1;
} else {
ex_obj = JS_UNDEFINED;
@@ -15103,6 +15949,21 @@ static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset)
return 0;
}
+static __exception int js_for_await_of_next(JSContext *ctx, JSValue *sp)
+{
+ JSValue obj, iter, next;
+
+ sp[-1] = JS_UNDEFINED; /* disable the catch offset so that
+ exceptions do not close the iterator */
+ iter = sp[-3];
+ next = sp[-2];
+ obj = JS_Call(ctx, next, iter, 0, NULL);
+ if (JS_IsException(obj))
+ return -1;
+ sp[0] = obj;
+ return 0;
+}
+
static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValueConst obj,
BOOL *pdone)
{
@@ -15135,6 +15996,9 @@ static __exception int js_iterator_get_value_done(JSContext *ctx, JSValue *sp)
if (JS_IsException(value))
return -1;
JS_FreeValue(ctx, obj);
+ /* put again the catch offset so that exceptions close the
+ iterator */
+ sp[-2] = JS_NewCatchOffset(ctx, 0);
sp[-1] = value;
sp[0] = JS_NewBool(ctx, done);
return 0;
@@ -15204,7 +16068,7 @@ static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp)
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;
@@ -15292,7 +16156,7 @@ static __exception int JS_CopyDataProperties(JSContext *ctx,
int ret, gpn_flags;
JSPropertyDescriptor desc;
BOOL is_enumerable;
-
+
if (JS_VALUE_GET_TAG(source) != JS_TAG_OBJECT)
return 0;
@@ -15313,7 +16177,7 @@ static __exception int JS_CopyDataProperties(JSContext *ctx,
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);
@@ -15346,10 +16210,10 @@ static __exception int JS_CopyDataProperties(JSContext *ctx,
if (ret < 0)
goto exception;
}
- js_free_prop_enum(ctx, tab_atom, tab_atom_count);
+ JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count);
return 0;
exception:
- js_free_prop_enum(ctx, tab_atom, tab_atom_count);
+ JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count);
return -1;
}
@@ -15364,10 +16228,16 @@ static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf,
{
JSVarRef *var_ref;
struct list_head *el;
+ JSValue *pvalue;
+
+ if (is_arg)
+ pvalue = &sf->arg_buf[var_idx];
+ else
+ pvalue = &sf->var_buf[var_idx];
list_for_each(el, &sf->var_ref_list) {
- var_ref = list_entry(el, JSVarRef, header.link);
- if (var_ref->var_idx == var_idx && var_ref->is_arg == is_arg) {
+ var_ref = list_entry(el, JSVarRef, var_ref_link);
+ if (var_ref->pvalue == pvalue) {
var_ref->header.ref_count++;
return var_ref;
}
@@ -15377,15 +16247,24 @@ static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf,
if (!var_ref)
return NULL;
var_ref->header.ref_count = 1;
+ add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
var_ref->is_detached = FALSE;
- 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;
+ list_add_tail(&var_ref->var_ref_link, &sf->var_ref_list);
+ if (sf->js_mode & JS_MODE_ASYNC) {
+ /* The stack frame is detached and may be destroyed at any
+ time so its reference count must be increased. Calling
+ close_var_refs() when destroying the stack frame is not
+ possible because it would change the graph between the GC
+ objects. Another solution could be to temporarily detach
+ the JSVarRef of async functions during the GC. It would
+ have the advantage of allowing the release of unused stack
+ frames in a cycle. */
+ var_ref->async_func = container_of(sf, JSAsyncFunctionState, frame);
+ var_ref->async_func->header.ref_count++;
+ } else {
+ var_ref->async_func = NULL;
+ }
+ var_ref->pvalue = pvalue;
return var_ref;
}
@@ -15613,37 +16492,36 @@ 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 = list_entry(el, JSVarRef, var_ref_link);
+ /* no need to unlink var_ref->var_ref_link as the list is never used afterwards */
+ if (var_ref->async_func)
+ async_func_free(rt, var_ref->async_func);
+ var_ref->value = JS_DupValueRT(rt, *var_ref->pvalue);
var_ref->pvalue = &var_ref->value;
/* the reference is no longer to a local variable */
var_ref->is_detached = TRUE;
- add_gc_object(rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
}
}
-static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int idx, int is_arg)
+static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int var_idx)
{
+ JSValue *pvalue;
struct list_head *el, *el1;
JSVarRef *var_ref;
- int var_idx = idx;
+ pvalue = &sf->var_buf[var_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 = list_entry(el, JSVarRef, var_ref_link);
+ if (var_ref->pvalue == pvalue) {
+ list_del(&var_ref->var_ref_link);
+ if (var_ref->async_func)
+ async_func_free(ctx->rt, var_ref->async_func);
+ var_ref->value = JS_DupValue(ctx, *var_ref->pvalue);
var_ref->pvalue = &var_ref->value;
- 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);
}
}
}
@@ -15676,18 +16554,8 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
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->cur_func = func_obj;
sf->arg_count = argc;
arg_buf = argv;
@@ -15834,9 +16702,10 @@ typedef enum {
OP_SPECIAL_OBJECT_IMPORT_META,
} OPSpecialObjectEnum;
-#define FUNC_RET_AWAIT 0
-#define FUNC_RET_YIELD 1
-#define FUNC_RET_YIELD_STAR 2
+#define FUNC_RET_AWAIT 0
+#define FUNC_RET_YIELD 1
+#define FUNC_RET_YIELD_STAR 2
+#define FUNC_RET_INITIAL_YIELD 3
/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
@@ -15864,7 +16733,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
#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
+#else
#define def(id, size, n_pop, n_push, f) && case_default,
#endif
#include "quickjs-opcode.h"
@@ -15931,7 +16800,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
sf->js_mode = b->js_mode;
arg_buf = argv;
sf->arg_count = argc;
- sf->cur_func = (JSValue)func_obj;
+ sf->cur_func = func_obj;
init_list_head(&sf->var_ref_list);
var_refs = p->u.func.var_refs;
@@ -15958,7 +16827,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
sf->prev_frame = rt->current_stack_frame;
rt->current_stack_frame = sf;
ctx = b->realm; /* set the current realm */
-
+
restart:
for(;;) {
int call_argc;
@@ -15969,6 +16838,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
*sp++ = JS_NewInt32(ctx, get_u32(pc));
pc += 4;
BREAK;
+ CASE(OP_push_bigint_i32):
+ *sp++ = __JS_NewShortBigInt(ctx, (int)get_u32(pc));
+ pc += 4;
+ BREAK;
CASE(OP_push_const):
*sp++ = JS_DupValue(ctx, b->cpool[get_u32(pc)]);
pc += 4;
@@ -16008,6 +16881,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
JSValue val;
+ sf->cur_pc = pc;
val = JS_GetProperty(ctx, sp[-1], JS_ATOM_length);
if (unlikely(JS_IsException(val)))
goto exception;
@@ -16360,6 +17234,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
int magic;
magic = get_u16(pc);
pc += 2;
+ sf->cur_pc = pc;
ret_val = js_function_apply(ctx, sp[-3], 2, (JSValueConst *)&sp[-2], magic);
if (unlikely(JS_IsException(ret_val)))
@@ -16393,13 +17268,37 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
BREAK;
CASE(OP_check_ctor):
if (JS_IsUndefined(new_target)) {
+ non_ctor_call:
JS_ThrowTypeError(ctx, "class constructors must be invoked with 'new'");
goto exception;
}
BREAK;
+ CASE(OP_init_ctor):
+ {
+ JSValue super, ret;
+ sf->cur_pc = pc;
+ if (JS_IsUndefined(new_target))
+ goto non_ctor_call;
+ super = JS_GetPrototype(ctx, func_obj);
+ if (JS_IsException(super))
+ goto exception;
+ ret = JS_CallConstructor2(ctx, super, new_target, argc, (JSValueConst *)argv);
+ JS_FreeValue(ctx, super);
+ if (JS_IsException(ret))
+ goto exception;
+ *sp++ = ret;
+ }
+ BREAK;
CASE(OP_check_brand):
- if (JS_CheckBrand(ctx, sp[-2], sp[-1]) < 0)
- goto exception;
+ {
+ int ret = JS_CheckBrand(ctx, sp[-2], sp[-1]);
+ if (ret < 0)
+ goto exception;
+ if (!ret) {
+ JS_ThrowTypeError(ctx, "invalid brand on object");
+ goto exception;
+ }
+ }
BREAK;
CASE(OP_add_brand):
if (JS_AddBrand(ctx, sp[-2], sp[-1]) < 0)
@@ -16408,7 +17307,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JS_FreeValue(ctx, sp[-1]);
sp -= 2;
BREAK;
-
+
CASE(OP_throw):
JS_Throw(ctx, *--sp);
goto exception;
@@ -16449,7 +17348,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JSValueConst obj;
int scope_idx;
call_argc = get_u16(pc);
- scope_idx = get_u16(pc + 2) - 1;
+ scope_idx = get_u16(pc + 2) + ARG_SCOPE_END;
pc += 4;
call_argv = sp - call_argc;
sf->cur_pc = pc;
@@ -16480,8 +17379,9 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JSValue *tab;
JSValueConst obj;
- scope_idx = get_u16(pc) - 1;
+ scope_idx = get_u16(pc) + ARG_SCOPE_END;
pc += 2;
+ sf->cur_pc = pc;
tab = build_arg_list(ctx, &len, sp[-1]);
if (!tab)
goto exception;
@@ -16517,6 +17417,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
CASE(OP_get_super):
{
JSValue proto;
+ sf->cur_pc = pc;
proto = JS_GetPrototype(ctx, sp[-1]);
if (JS_IsException(proto))
goto exception;
@@ -16528,10 +17429,13 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
CASE(OP_import):
{
JSValue val;
- val = js_dynamic_import(ctx, sp[-1]);
+ sf->cur_pc = pc;
+ val = js_dynamic_import(ctx, sp[-2], sp[-1]);
if (JS_IsException(val))
goto exception;
+ JS_FreeValue(ctx, sp[-2]);
JS_FreeValue(ctx, sp[-1]);
+ sp--;
sp[-1] = val;
}
BREAK;
@@ -16542,6 +17446,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JSAtom atom;
atom = get_u32(pc);
pc += 4;
+ sf->cur_pc = pc;
ret = JS_CheckGlobalVar(ctx, atom);
if (ret < 0)
@@ -16557,6 +17462,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JSAtom atom;
atom = get_u32(pc);
pc += 4;
+ sf->cur_pc = pc;
val = JS_GetGlobalVar(ctx, atom, opcode - OP_get_var_undef);
if (unlikely(JS_IsException(val)))
@@ -16572,6 +17478,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JSAtom atom;
atom = get_u32(pc);
pc += 4;
+ sf->cur_pc = pc;
ret = JS_SetGlobalVar(ctx, atom, sp[-1], opcode - OP_put_var);
sp--;
@@ -16586,6 +17493,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JSAtom atom;
atom = get_u32(pc);
pc += 4;
+ sf->cur_pc = pc;
/* sp[-2] is JS_TRUE or JS_FALSE */
if (unlikely(!JS_VALUE_GET_INT(sp[-2]))) {
@@ -16606,6 +17514,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
atom = get_u32(pc);
flags = pc[4];
pc += 5;
+ sf->cur_pc = pc;
if (JS_CheckDefineGlobalVar(ctx, atom, flags))
goto exception;
}
@@ -16617,6 +17526,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
atom = get_u32(pc);
flags = pc[4];
pc += 5;
+ sf->cur_pc = pc;
if (JS_DefineGlobalVar(ctx, atom, flags))
goto exception;
}
@@ -16628,6 +17538,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
atom = get_u32(pc);
flags = pc[4];
pc += 5;
+ sf->cur_pc = pc;
if (JS_DefineGlobalFunction(ctx, atom, sp[-1], flags))
goto exception;
JS_FreeValue(ctx, sp[-1]);
@@ -16821,6 +17732,19 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
sp++;
}
BREAK;
+ CASE(OP_get_loc_checkthis):
+ {
+ int idx;
+ idx = get_u16(pc);
+ pc += 2;
+ if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
+ JS_ThrowReferenceErrorUninitialized2(caller_ctx, b, idx, FALSE);
+ goto exception;
+ }
+ sp[0] = JS_DupValue(ctx, var_buf[idx]);
+ sp++;
+ }
+ BREAK;
CASE(OP_put_loc_check):
{
int idx;
@@ -16852,7 +17776,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
int idx;
idx = get_u16(pc);
pc += 2;
- close_lexical_var(ctx, sf, idx, FALSE);
+ close_lexical_var(ctx, sf, idx);
}
BREAK;
@@ -16893,6 +17817,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JSAtom atom;
atom = get_u32(pc);
pc += 4;
+ sf->cur_pc = pc;
if (JS_GetGlobalVarRef(ctx, atom, sp))
goto exception;
@@ -16944,6 +17869,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
op1 = sp[-1];
pc += 4;
+ /* quick and dirty test for JS_TAG_INT, JS_TAG_BOOL, JS_TAG_NULL and JS_TAG_UNDEFINED */
if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
res = JS_VALUE_GET_INT(op1);
} else {
@@ -17037,15 +17963,18 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
BREAK;
CASE(OP_for_in_start):
+ sf->cur_pc = pc;
if (js_for_in_start(ctx, sp))
goto exception;
BREAK;
CASE(OP_for_in_next):
+ sf->cur_pc = pc;
if (js_for_in_next(ctx, sp))
goto exception;
sp += 2;
BREAK;
CASE(OP_for_of_start):
+ sf->cur_pc = pc;
if (js_for_of_start(ctx, sp, FALSE))
goto exception;
sp += 1;
@@ -17055,18 +17984,27 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
int offset = -3 - pc[0];
pc += 1;
+ sf->cur_pc = pc;
if (js_for_of_next(ctx, sp, offset))
goto exception;
sp += 2;
}
BREAK;
+ CASE(OP_for_await_of_next):
+ sf->cur_pc = pc;
+ if (js_for_await_of_next(ctx, sp))
+ goto exception;
+ sp++;
+ BREAK;
CASE(OP_for_await_of_start):
+ sf->cur_pc = pc;
if (js_for_of_start(ctx, sp, TRUE))
goto exception;
sp += 1;
*sp++ = JS_NewCatchOffset(ctx, 0);
BREAK;
CASE(OP_iterator_get_value_done):
+ sf->cur_pc = pc;
if (js_iterator_get_value_done(ctx, sp))
goto exception;
sp += 1;
@@ -17084,32 +18022,28 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JS_FreeValue(ctx, sp[-1]); /* drop the next method */
sp--;
if (!JS_IsUndefined(sp[-1])) {
+ sf->cur_pc = pc;
if (JS_IteratorClose(ctx, sp[-1], FALSE))
goto exception;
JS_FreeValue(ctx, sp[-1]);
}
sp--;
BREAK;
- CASE(OP_iterator_close_return):
+ CASE(OP_nip_catch):
{
JSValue ret_val;
- /* iter_obj next catch_offset ... ret_val ->
- ret_eval iter_obj next catch_offset */
+ /* catch_offset ... ret_val -> ret_eval */
ret_val = *--sp;
while (sp > stack_buf &&
JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_CATCH_OFFSET) {
JS_FreeValue(ctx, *--sp);
}
- if (unlikely(sp < stack_buf + 3)) {
- JS_ThrowInternalError(ctx, "iterator_close_return");
+ if (unlikely(sp == stack_buf)) {
+ JS_ThrowInternalError(ctx, "nip_catch");
JS_FreeValue(ctx, ret_val);
goto exception;
}
- sp[0] = sp[-1];
- sp[-1] = sp[-2];
- sp[-2] = sp[-3];
- sp[-3] = ret_val;
- sp++;
+ sp[-1] = ret_val;
}
BREAK;
@@ -17117,6 +18051,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
/* stack: iter_obj next catch_offset val */
{
JSValue ret;
+ sf->cur_pc = pc;
ret = JS_Call(ctx, sp[-3], sp[-4],
1, (JSValueConst *)(sp - 1));
if (JS_IsException(ret))
@@ -17133,6 +18068,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
BOOL ret_flag;
int flags;
flags = *pc++;
+ sf->cur_pc = pc;
method = JS_GetProperty(ctx, sp[-4], (flags & 1) ?
JS_ATOM_throw : JS_ATOM_return);
if (JS_IsException(method))
@@ -17181,6 +18117,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
atom = get_u32(pc);
pc += 4;
+ sf->cur_pc = pc;
val = JS_GetProperty(ctx, sp[-1], atom);
if (unlikely(JS_IsException(val)))
goto exception;
@@ -17196,6 +18133,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
atom = get_u32(pc);
pc += 4;
+ sf->cur_pc = pc;
val = JS_GetProperty(ctx, sp[-1], atom);
if (unlikely(JS_IsException(val)))
goto exception;
@@ -17209,6 +18147,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JSAtom atom;
atom = get_u32(pc);
pc += 4;
+ sf->cur_pc = pc;
ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1], sp[-2],
JS_PROP_THROW_STRICT);
@@ -17223,7 +18162,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
JSAtom atom;
JSValue val;
-
+
atom = get_u32(pc);
pc += 4;
val = JS_NewSymbolFromAtom(ctx, atom, JS_ATOM_TYPE_PRIVATE);
@@ -17232,7 +18171,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
*sp++ = val;
}
BREAK;
-
+
CASE(OP_get_private_field):
{
JSValue val;
@@ -17308,6 +18247,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
CASE(OP_set_proto):
{
JSValue proto;
+ sf->cur_pc = pc;
proto = sp[-1];
if (JS_IsObject(proto) || JS_IsNull(proto)) {
if (JS_SetPrototypeInternal(ctx, sp[-2], proto, TRUE) < 0)
@@ -17385,7 +18325,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
int class_flags;
JSAtom atom;
-
+
atom = get_u32(pc);
class_flags = pc[4];
pc += 5;
@@ -17400,6 +18340,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
JSValue val;
+ sf->cur_pc = pc;
val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
JS_FreeValue(ctx, sp[-2]);
sp[-2] = val;
@@ -17413,6 +18354,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
JSValue val;
+ sf->cur_pc = pc;
val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
sp[-1] = val;
if (unlikely(JS_IsException(val)))
@@ -17420,19 +18362,69 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
}
BREAK;
+ CASE(OP_get_array_el3):
+ {
+ JSValue val;
+
+ switch (JS_VALUE_GET_TAG(sp[-2])) {
+ case JS_TAG_INT:
+ case JS_TAG_STRING:
+ case JS_TAG_SYMBOL:
+ /* undefined and null are tested in JS_GetPropertyValue() */
+ break;
+ default:
+ /* must be tested nefore JS_ToPropertyKey */
+ if (unlikely(JS_IsUndefined(sp[-2]) || JS_IsNull(sp[-2]))) {
+ JS_ThrowTypeError(ctx, "value has no property");
+ goto exception;
+ }
+ sf->cur_pc = pc;
+ ret_val = JS_ToPropertyKey(ctx, sp[-1]);
+ if (JS_IsException(ret_val))
+ goto exception;
+ JS_FreeValue(ctx, sp[-1]);
+ sp[-1] = ret_val;
+ break;
+ }
+ sf->cur_pc = pc;
+ val = JS_GetPropertyValue(ctx, sp[-2], JS_DupValue(ctx, sp[-1]));
+ *sp++ = val;
+ if (unlikely(JS_IsException(val)))
+ goto exception;
+ }
+ BREAK;
+
CASE(OP_get_ref_value):
{
JSValue val;
+ JSAtom atom;
+ int ret;
+
+ sf->cur_pc = pc;
+ atom = JS_ValueToAtom(ctx, sp[-1]);
+ if (atom == JS_ATOM_NULL)
+ goto exception;
if (unlikely(JS_IsUndefined(sp[-2]))) {
- JSAtom atom = JS_ValueToAtom(ctx, sp[-1]);
- if (atom != JS_ATOM_NULL) {
- JS_ThrowReferenceErrorNotDefined(ctx, atom);
+ JS_ThrowReferenceErrorNotDefined(ctx, atom);
+ JS_FreeAtom(ctx, atom);
+ goto exception;
+ }
+ ret = JS_HasProperty(ctx, sp[-2], atom);
+ if (unlikely(ret <= 0)) {
+ if (ret < 0) {
JS_FreeAtom(ctx, atom);
+ goto exception;
}
- goto exception;
+ if (is_strict_mode(ctx)) {
+ JS_ThrowReferenceErrorNotDefined(ctx, atom);
+ JS_FreeAtom(ctx, atom);
+ goto exception;
+ }
+ val = JS_UNDEFINED;
+ } else {
+ val = JS_GetProperty(ctx, sp[-2], atom);
}
- val = JS_GetPropertyValue(ctx, sp[-2],
- JS_DupValue(ctx, sp[-1]));
+ JS_FreeAtom(ctx, atom);
if (unlikely(JS_IsException(val)))
goto exception;
sp[0] = val;
@@ -17444,6 +18436,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
JSValue val;
JSAtom atom;
+ sf->cur_pc = pc;
atom = JS_ValueToAtom(ctx, sp[-1]);
if (unlikely(atom == JS_ATOM_NULL))
goto exception;
@@ -17463,6 +18456,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
int ret;
+ sf->cur_pc = pc;
ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT);
JS_FreeValue(ctx, sp[-3]);
sp -= 3;
@@ -17473,24 +18467,36 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
CASE(OP_put_ref_value):
{
- int ret, flags;
- flags = JS_PROP_THROW_STRICT;
+ int ret;
+ JSAtom atom;
+ sf->cur_pc = pc;
+ atom = JS_ValueToAtom(ctx, sp[-2]);
+ if (unlikely(atom == JS_ATOM_NULL))
+ goto exception;
if (unlikely(JS_IsUndefined(sp[-3]))) {
if (is_strict_mode(ctx)) {
- JSAtom atom = JS_ValueToAtom(ctx, sp[-2]);
- if (atom != JS_ATOM_NULL) {
- JS_ThrowReferenceErrorNotDefined(ctx, atom);
- JS_FreeAtom(ctx, atom);
- }
+ 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);
+ ret = JS_HasProperty(ctx, sp[-3], atom);
+ if (unlikely(ret <= 0)) {
+ if (unlikely(ret < 0)) {
+ JS_FreeAtom(ctx, atom);
+ goto exception;
+ }
+ if (is_strict_mode(ctx)) {
+ JS_ThrowReferenceErrorNotDefined(ctx, atom);
+ JS_FreeAtom(ctx, atom);
+ goto exception;
+ }
+ }
+ ret = JS_SetPropertyInternal(ctx, sp[-3], atom, sp[-1], sp[-3], JS_PROP_THROW_STRICT);
+ JS_FreeAtom(ctx, atom);
+ JS_FreeValue(ctx, sp[-2]);
JS_FreeValue(ctx, sp[-3]);
sp -= 3;
if (unlikely(ret < 0))
@@ -17502,6 +18508,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
int ret;
JSAtom atom;
+ sf->cur_pc = pc;
if (JS_VALUE_GET_TAG(sp[-3]) != JS_TAG_OBJECT) {
JS_ThrowTypeErrorNotAnObject(ctx);
goto exception;
@@ -17534,6 +18541,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
CASE(OP_append): /* array pos enumobj -- array pos */
{
+ sf->cur_pc = pc;
if (js_append_enumerate(ctx, sp))
goto exception;
JS_FreeValue(ctx, *--sp);
@@ -17549,6 +18557,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
int mask;
mask = *pc++;
+ sf->cur_pc = pc;
if (JS_CopyDataProperties(ctx, sp[-1 - (mask & 3)],
sp[-1 - ((mask >> 2) & 7)],
sp[-1 - ((mask >> 5) & 7)], 0))
@@ -17572,8 +18581,14 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) +
JS_VALUE_GET_FLOAT64(op2));
sp--;
+ } else if (JS_IsString(op1) && JS_IsString(op2)) {
+ sp[-2] = JS_ConcatString(ctx, op1, op2);
+ sp--;
+ if (JS_IsException(sp[-1]))
+ goto exception;
} else {
add_slow:
+ sf->cur_pc = pc;
if (js_add_slow(ctx, sp))
goto exception;
sp--;
@@ -17582,38 +18597,47 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
BREAK;
CASE(OP_add_loc):
{
+ JSValue op2;
JSValue *pv;
int idx;
idx = *pc;
pc += 1;
+ op2 = sp[-1];
pv = &var_buf[idx];
- if (likely(JS_VALUE_IS_BOTH_INT(*pv, sp[-1]))) {
+ if (likely(JS_VALUE_IS_BOTH_INT(*pv, op2))) {
int64_t r;
- r = (int64_t)JS_VALUE_GET_INT(*pv) +
- JS_VALUE_GET_INT(sp[-1]);
+ r = (int64_t)JS_VALUE_GET_INT(*pv) + JS_VALUE_GET_INT(op2);
if (unlikely((int)r != r))
goto add_loc_slow;
*pv = JS_NewInt32(ctx, r);
sp--;
+ } else if (JS_VALUE_IS_BOTH_FLOAT(*pv, op2)) {
+ *pv = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(*pv) +
+ JS_VALUE_GET_FLOAT64(op2));
+ sp--;
} else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING) {
- 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))
+ sf->cur_pc = pc;
+ op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
+ if (JS_IsException(op2))
goto exception;
- set_value(ctx, pv, op1);
+ if (JS_ConcatStringInPlace(ctx, JS_VALUE_GET_STRING(*pv), op2)) {
+ JS_FreeValue(ctx, op2);
+ } else {
+ op2 = JS_ConcatString(ctx, JS_DupValue(ctx, *pv), op2);
+ if (JS_IsException(op2))
+ goto exception;
+ set_value(ctx, pv, op2);
+ }
} else {
JSValue ops[2];
add_loc_slow:
/* In case of exception, js_add_slow frees ops[0]
and ops[1], so we must duplicate *pv */
+ sf->cur_pc = pc;
ops[0] = JS_DupValue(ctx, *pv);
- ops[1] = sp[-1];
+ ops[1] = op2;
sp--;
if (js_add_slow(ctx, ops + 2))
goto exception;
@@ -17655,11 +18679,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
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;
}
@@ -17671,10 +18690,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
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);
@@ -17691,8 +18706,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
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);
@@ -17703,9 +18716,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
}
BREAK;
CASE(OP_mod):
-#ifdef CONFIG_BIGNUM
- CASE(OP_math_mod):
-#endif
{
JSValue op1, op2;
op1 = sp[-2];
@@ -17728,6 +18738,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
BREAK;
CASE(OP_pow):
binary_arith_slow:
+ sf->cur_pc = pc;
if (js_binary_arith_slow(ctx, sp, opcode))
goto exception;
sp--;
@@ -17741,6 +18752,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
tag = JS_VALUE_GET_TAG(op1);
if (tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag)) {
} else {
+ sf->cur_pc = pc;
if (js_unary_arith_slow(ctx, sp, opcode))
goto exception;
}
@@ -17771,6 +18783,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
neg_fp_res:
sp[-1] = __JS_NewFloat64(ctx, d);
} else {
+ sf->cur_pc = pc;
if (js_unary_arith_slow(ctx, sp, opcode))
goto exception;
}
@@ -17788,6 +18801,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
sp[-1] = JS_NewInt32(ctx, val + 1);
} else {
inc_slow:
+ sf->cur_pc = pc;
if (js_unary_arith_slow(ctx, sp, opcode))
goto exception;
}
@@ -17805,6 +18819,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
sp[-1] = JS_NewInt32(ctx, val - 1);
} else {
dec_slow:
+ sf->cur_pc = pc;
if (js_unary_arith_slow(ctx, sp, opcode))
goto exception;
}
@@ -17812,6 +18827,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
BREAK;
CASE(OP_post_inc):
CASE(OP_post_dec):
+ sf->cur_pc = pc;
if (js_post_inc_slow(ctx, sp, opcode))
goto exception;
sp++;
@@ -17832,6 +18848,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
var_buf[idx] = JS_NewInt32(ctx, val + 1);
} else {
inc_loc_slow:
+ sf->cur_pc = pc;
/* must duplicate otherwise the variable value may
be destroyed before JS code accesses it */
op1 = JS_DupValue(ctx, op1);
@@ -17857,6 +18874,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
var_buf[idx] = JS_NewInt32(ctx, val - 1);
} else {
dec_loc_slow:
+ sf->cur_pc = pc;
/* must duplicate otherwise the variable value may
be destroyed before JS code accesses it */
op1 = JS_DupValue(ctx, op1);
@@ -17873,6 +18891,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
sp[-1] = JS_NewInt32(ctx, ~JS_VALUE_GET_INT(op1));
} else {
+ sf->cur_pc = pc;
if (js_not_slow(ctx, sp))
goto exception;
}
@@ -17888,28 +18907,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
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
+ sf->cur_pc = pc;
if (js_binary_logic_slow(ctx, sp, opcode))
goto exception;
sp--;
@@ -17924,13 +18926,13 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
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 {
+ sf->cur_pc = pc;
if (js_shr_slow(ctx, sp))
goto exception;
sp--;
@@ -17945,23 +18947,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
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
+ sf->cur_pc = pc;
if (js_binary_logic_slow(ctx, sp, opcode))
goto exception;
sp--;
@@ -17979,6 +18970,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JS_VALUE_GET_INT(op2));
sp--;
} else {
+ sf->cur_pc = pc;
if (js_binary_logic_slow(ctx, sp, opcode))
goto exception;
sp--;
@@ -17996,6 +18988,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JS_VALUE_GET_INT(op2));
sp--;
} else {
+ sf->cur_pc = pc;
if (js_binary_logic_slow(ctx, sp, opcode))
goto exception;
sp--;
@@ -18013,6 +19006,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JS_VALUE_GET_INT(op2));
sp--;
} else {
+ sf->cur_pc = pc;
if (js_binary_logic_slow(ctx, sp, opcode))
goto exception;
sp--;
@@ -18031,6 +19025,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
sp[-2] = JS_NewBool(ctx, JS_VALUE_GET_INT(op1) binary_op JS_VALUE_GET_INT(op2)); \
sp--; \
} else { \
+ sf->cur_pc = pc; \
if (slow_call) \
goto exception; \
sp--; \
@@ -18047,19 +19042,20 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
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))
+ CASE(OP_in):
+ sf->cur_pc = pc;
+ if (js_operator_in(ctx, sp))
goto exception;
sp--;
BREAK;
-#endif
- CASE(OP_in):
- if (js_operator_in(ctx, sp))
+ CASE(OP_private_in):
+ sf->cur_pc = pc;
+ if (js_operator_private_in(ctx, sp))
goto exception;
sp--;
BREAK;
CASE(OP_instanceof):
+ sf->cur_pc = pc;
if (js_operator_instanceof(ctx, sp))
goto exception;
sp--;
@@ -18076,6 +19072,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
}
BREAK;
CASE(OP_delete):
+ sf->cur_pc = pc;
if (js_operator_delete(ctx, sp))
goto exception;
sp--;
@@ -18087,8 +19084,9 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
atom = get_u32(pc);
pc += 4;
+ sf->cur_pc = pc;
- ret = JS_DeleteProperty(ctx, ctx->global_obj, atom, 0);
+ ret = JS_DeleteGlobalVar(ctx, atom);
if (unlikely(ret < 0))
goto exception;
*sp++ = JS_NewBool(ctx, ret);
@@ -18097,6 +19095,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
CASE(OP_to_object):
if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_OBJECT) {
+ sf->cur_pc = pc;
ret_val = JS_ToObject(ctx, sp[-1]);
if (JS_IsException(ret_val))
goto exception;
@@ -18112,6 +19111,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
case JS_TAG_SYMBOL:
break;
default:
+ sf->cur_pc = pc;
ret_val = JS_ToPropertyKey(ctx, sp[-1]);
if (JS_IsException(ret_val))
goto exception;
@@ -18121,26 +19121,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
}
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) {
@@ -18157,7 +19137,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
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;
@@ -18167,6 +19146,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
diff = get_u32(pc + 4);
is_with = pc[8];
pc += 9;
+ sf->cur_pc = pc;
obj = sp[-1];
ret = JS_HasProperty(ctx, obj, atom);
@@ -18182,13 +19162,34 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
}
switch (opcode) {
case OP_with_get_var:
- val = JS_GetProperty(ctx, obj, atom);
- if (unlikely(JS_IsException(val)))
- goto exception;
+ /* in Object Environment Records, GetBindingValue() calls HasProperty() */
+ ret = JS_HasProperty(ctx, obj, atom);
+ if (unlikely(ret <= 0)) {
+ if (ret < 0)
+ goto exception;
+ if (is_strict_mode(ctx)) {
+ JS_ThrowReferenceErrorNotDefined(ctx, atom);
+ goto exception;
+ }
+ val = JS_UNDEFINED;
+ } else {
+ val = JS_GetProperty(ctx, obj, atom);
+ if (unlikely(JS_IsException(val)))
+ goto exception;
+ }
set_value(ctx, &sp[-1], val);
break;
- case OP_with_put_var:
- /* XXX: check if strict mode */
+ case OP_with_put_var: /* used e.g. in for in/of */
+ /* in Object Environment Records, SetMutableBinding() calls HasProperty() */
+ ret = JS_HasProperty(ctx, obj, atom);
+ if (unlikely(ret <= 0)) {
+ if (ret < 0)
+ goto exception;
+ if (is_strict_mode(ctx)) {
+ JS_ThrowReferenceErrorNotDefined(ctx, atom);
+ goto exception;
+ }
+ }
ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2], obj,
JS_PROP_THROW_STRICT);
JS_FreeValue(ctx, sp[-1]);
@@ -18209,18 +19210,17 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
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)))
+ /* in Object Environment Records, GetBindingValue() calls HasProperty() */
+ ret = JS_HasProperty(ctx, obj, atom);
+ if (unlikely(ret < 0))
goto exception;
- JS_FreeValue(ctx, sp[-1]);
- sp[-1] = JS_UNDEFINED;
+ if (!ret) {
+ val = JS_UNDEFINED;
+ } else {
+ val = JS_GetProperty(ctx, obj, atom);
+ if (unlikely(JS_IsException(val)))
+ goto exception;
+ }
*sp++ = val;
break;
}
@@ -18245,9 +19245,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
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_initial_yield):
+ ret_val = JS_NewInt32(ctx, FUNC_RET_INITIAL_YIELD);
+ goto done_generator;
CASE(OP_nop):
BREAK;
@@ -18308,9 +19310,9 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
before if the exception happens in a bytecode
operation */
sf->cur_pc = pc;
- build_backtrace(ctx, rt->current_exception, NULL, 0, 0);
+ build_backtrace(ctx, rt->current_exception, NULL, 0, 0, 0);
}
- if (!JS_IsUncatchableError(ctx, rt->current_exception)) {
+ if (!rt->current_exception_is_uncatchable) {
while (sp > stack_buf) {
JSValue val = *--sp;
JS_FreeValue(ctx, val);
@@ -18323,7 +19325,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JS_IteratorClose(ctx, sp[-1], TRUE);
} else {
*sp++ = rt->current_exception;
- rt->current_exception = JS_NULL;
+ rt->current_exception = JS_UNINITIALIZED;
pc = b->byte_code_buf + pos;
goto restart;
}
@@ -18375,7 +19377,7 @@ static JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj)
{
JSObject *p;
JSContext *realm;
-
+
if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
return ctx;
p = JS_VALUE_GET_OBJ(func_obj);
@@ -18424,7 +19426,7 @@ static JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor,
{
JSValue proto, obj;
JSContext *realm;
-
+
if (JS_IsUndefined(ctor)) {
proto = JS_DupValue(ctx, ctx->class_proto[class_id]);
} else {
@@ -18529,26 +19531,35 @@ static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
}
/* JSAsyncFunctionState (used by generator and async functions) */
-static __exception int async_func_init(JSContext *ctx, JSAsyncFunctionState *s,
- JSValueConst func_obj, JSValueConst this_obj,
- int argc, JSValueConst *argv)
+static JSAsyncFunctionState *async_func_init(JSContext *ctx,
+ JSValueConst func_obj, JSValueConst this_obj,
+ int argc, JSValueConst *argv)
{
+ JSAsyncFunctionState *s;
JSObject *p;
JSFunctionBytecode *b;
JSStackFrame *sf;
int local_count, i, arg_buf_len, n;
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return NULL;
+ s->header.ref_count = 1;
+ add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION);
+
sf = &s->frame;
init_list_head(&sf->var_ref_list);
p = JS_VALUE_GET_OBJ(func_obj);
b = p->u.func.function_bytecode;
- sf->js_mode = b->js_mode;
+ sf->js_mode = b->js_mode | JS_MODE_ASYNC;
sf->cur_pc = b->byte_code_buf;
arg_buf_len = max_int(b->arg_count, argc);
local_count = arg_buf_len + b->var_count + b->stack_size;
sf->arg_buf = js_malloc(ctx, sizeof(JSValue) * max_int(local_count, 1));
- if (!sf->arg_buf)
- return -1;
+ if (!sf->arg_buf) {
+ js_free(ctx, s);
+ return NULL;
+ }
sf->cur_func = JS_DupValue(ctx, func_obj);
s->this_val = JS_DupValue(ctx, this_obj);
s->argc = argc;
@@ -18560,38 +19571,17 @@ static __exception int async_func_init(JSContext *ctx, JSAsyncFunctionState *s,
n = arg_buf_len + b->var_count;
for(i = argc; i < n; i++)
sf->arg_buf[i] = JS_UNDEFINED;
- return 0;
-}
-
-static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s,
- JS_MarkFunc *mark_func)
-{
- JSStackFrame *sf;
- JSValue *sp;
-
- sf = &s->frame;
- JS_MarkValue(rt, sf->cur_func, mark_func);
- JS_MarkValue(rt, s->this_val, mark_func);
- if (sf->cur_sp) {
- /* if the function is running, cur_sp is not known so we
- cannot mark the stack. Marking the variables is not needed
- because a running function cannot be part of a removable
- cycle */
- for(sp = sf->arg_buf; sp < sf->cur_sp; sp++)
- JS_MarkValue(rt, *sp, mark_func);
- }
+ s->resolving_funcs[0] = JS_UNDEFINED;
+ s->resolving_funcs[1] = JS_UNDEFINED;
+ s->is_completed = FALSE;
+ return s;
}
-static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
+static void async_func_free_frame(JSRuntime *rt, JSAsyncFunctionState *s)
{
- JSStackFrame *sf;
+ JSStackFrame *sf = &s->frame;
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);
@@ -18599,6 +19589,7 @@ static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
JS_FreeValueRT(rt, *sp);
}
js_free_rt(rt, sf->arg_buf);
+ sf->arg_buf = NULL;
}
JS_FreeValueRT(rt, sf->cur_func);
JS_FreeValueRT(rt, s->this_val);
@@ -18606,17 +19597,66 @@ static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s)
{
- JSValue func_obj;
+ JSRuntime *rt = ctx->rt;
+ JSStackFrame *sf = &s->frame;
+ JSValue func_obj, ret;
- if (js_check_stack_overflow(ctx->rt, 0))
- return JS_ThrowStackOverflow(ctx);
+ assert(!s->is_completed);
+ if (js_check_stack_overflow(ctx->rt, 0)) {
+ ret = JS_ThrowStackOverflow(ctx);
+ } else {
+ /* the tag does not matter provided it is not an object */
+ func_obj = JS_MKPTR(JS_TAG_INT, s);
+ ret = JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED,
+ s->argc, sf->arg_buf, JS_CALL_FLAG_GENERATOR);
+ }
+ if (JS_IsException(ret) || JS_IsUndefined(ret)) {
+ if (JS_IsUndefined(ret)) {
+ ret = sf->cur_sp[-1];
+ sf->cur_sp[-1] = JS_UNDEFINED;
+ }
+ /* end of execution */
+ s->is_completed = TRUE;
+
+ /* close the closure variables. */
+ close_var_refs(rt, sf);
- /* 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);
+ async_func_free_frame(rt, s);
+ }
+ return ret;
}
+static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
+{
+ /* cannot close the closure variables here because it would
+ potentially modify the object graph */
+ if (!s->is_completed) {
+ async_func_free_frame(rt, s);
+ }
+
+ JS_FreeValueRT(rt, s->resolving_funcs[0]);
+ JS_FreeValueRT(rt, s->resolving_funcs[1]);
+
+ remove_gc_object(&s->header);
+ if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && s->header.ref_count != 0) {
+ list_add_tail(&s->header.link, &rt->gc_zero_ref_count_list);
+ } else {
+ js_free_rt(rt, s);
+ }
+}
+
+static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
+{
+ if (--s->header.ref_count == 0) {
+ if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {
+ list_del(&s->header.link);
+ list_add(&s->header.link, &rt->gc_zero_ref_count_list);
+ if (rt->gc_phase == JS_GC_PHASE_NONE) {
+ free_zero_refcount(rt);
+ }
+ }
+ }
+}
/* Generators */
@@ -18630,14 +19670,17 @@ typedef enum JSGeneratorStateEnum {
typedef struct JSGeneratorData {
JSGeneratorStateEnum state;
- JSAsyncFunctionState func_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);
+ if (s->func_state) {
+ async_func_free(rt, s->func_state);
+ s->func_state = NULL;
+ }
s->state = JS_GENERATOR_STATE_COMPLETED;
}
@@ -18662,9 +19705,9 @@ static void js_generator_mark(JSRuntime *rt, JSValueConst val,
JSObject *p = JS_VALUE_GET_OBJ(val);
JSGeneratorData *s = p->u.generator_data;
- if (!s || s->state == JS_GENERATOR_STATE_COMPLETED)
+ if (!s || !s->func_state)
return;
- async_func_mark(rt, &s->func_state, mark_func);
+ mark_func(rt, &s->func_state->header);
}
/* XXX: use enum */
@@ -18683,10 +19726,10 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
*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:
+ sf = &s->func_state->frame;
if (magic == GEN_MAGIC_NEXT) {
goto exec_no_arg;
} else {
@@ -18696,28 +19739,29 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
break;
case JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
case JS_GENERATOR_STATE_SUSPENDED_YIELD:
+ sf = &s->func_state->frame;
/* cur_sp[-1] was set to JS_UNDEFINED in the previous call */
ret = JS_DupValue(ctx, argv[0]);
if (magic == GEN_MAGIC_THROW &&
s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) {
JS_Throw(ctx, ret);
- s->func_state.throw_flag = TRUE;
+ 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->func_state->throw_flag = FALSE;
}
s->state = JS_GENERATOR_STATE_EXECUTING;
- func_ret = async_func_resume(ctx, &s->func_state);
+ 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 */
+ if (s->func_state->is_completed) {
+ /* finalize the execution in case of exception or normal return */
free_generator_stack(ctx, s);
return func_ret;
- }
- if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) {
+ } else {
+ assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT);
/* get the returned yield value at the top of the stack */
ret = sf->cur_sp[-1];
sf->cur_sp[-1] = JS_UNDEFINED;
@@ -18728,12 +19772,6 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
} 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:
@@ -18771,13 +19809,14 @@ static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
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->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv);
+ if (!s->func_state) {
s->state = JS_GENERATOR_STATE_COMPLETED;
goto fail;
}
/* execute the function up to 'OP_initial_yield' */
- func_ret = async_func_resume(ctx, &s->func_state);
+ func_ret = async_func_resume(ctx, s->func_state);
if (JS_IsException(func_ret))
goto fail;
JS_FreeValue(ctx, func_ret);
@@ -18795,36 +19834,12 @@ static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
/* AsyncFunction */
-static void js_async_function_terminate(JSRuntime *rt, JSAsyncFunctionData *s)
-{
- if (s->is_active) {
- async_func_free(rt, &s->func_state);
- s->is_active = FALSE;
- }
-}
-
-static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s)
-{
- js_async_function_terminate(rt, s);
- JS_FreeValueRT(rt, s->resolving_funcs[0]);
- JS_FreeValueRT(rt, s->resolving_funcs[1]);
- remove_gc_object(&s->header);
- js_free_rt(rt, s);
-}
-
-static void js_async_function_free(JSRuntime *rt, JSAsyncFunctionData *s)
-{
- if (--s->header.ref_count == 0) {
- js_async_function_free0(rt, s);
- }
-}
-
static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val)
{
JSObject *p = JS_VALUE_GET_OBJ(val);
- JSAsyncFunctionData *s = p->u.async_function_data;
+ JSAsyncFunctionState *s = p->u.async_function_data;
if (s) {
- js_async_function_free(rt, s);
+ async_func_free(rt, s);
}
}
@@ -18832,14 +19847,14 @@ 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;
+ JSAsyncFunctionState *s = p->u.async_function_data;
if (s) {
mark_func(rt, &s->header);
}
}
static int js_async_function_resolve_create(JSContext *ctx,
- JSAsyncFunctionData *s,
+ JSAsyncFunctionState *s,
JSValue *resolving_funcs)
{
int i;
@@ -18861,60 +19876,58 @@ static int js_async_function_resolve_create(JSContext *ctx,
return 0;
}
-static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionData *s)
+static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionState *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);
+ func_ret = async_func_resume(ctx, s);
+ if (s->is_completed) {
+ if (JS_IsException(func_ret)) {
+ JSValue error;
+ fail:
+ error = JS_GetException(ctx);
+ ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED,
+ 1, (JSValueConst *)&error);
+ JS_FreeValue(ctx, error);
JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
- JS_FreeValue(ctx, value);
- js_async_function_terminate(ctx->rt, s);
} else {
- JSValue promise, resolving_funcs[2], resolving_funcs1[2];
- int i, res;
+ /* normal return */
+ ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED,
+ 1, (JSValueConst *)&func_ret);
+ JS_FreeValue(ctx, func_ret);
+ JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
+ }
+ } else {
+ JSValue value, promise, resolving_funcs[2], resolving_funcs1[2];
+ int i, res;
- /* 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;
- }
+ value = s->frame.cur_sp[-1];
+ s->frame.cur_sp[-1] = JS_UNDEFINED;
- /* 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);
+ /* 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);
- for(i = 0; i < 2; i++)
- JS_FreeValue(ctx, resolving_funcs[i]);
- if (res)
- goto fail;
+ 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;
}
}
@@ -18925,7 +19938,7 @@ static JSValue js_async_function_resolve_call(JSContext *ctx,
int flags)
{
JSObject *p = JS_VALUE_GET_OBJ(func_obj);
- JSAsyncFunctionData *s = p->u.async_function_data;
+ JSAsyncFunctionState *s = p->u.async_function_data;
BOOL is_reject = p->class_id - JS_CLASS_ASYNC_FUNCTION_RESOLVE;
JSValueConst arg;
@@ -18933,12 +19946,12 @@ static JSValue js_async_function_resolve_call(JSContext *ctx,
arg = argv[0];
else
arg = JS_UNDEFINED;
- s->func_state.throw_flag = is_reject;
+ s->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);
+ s->frame.cur_sp[-1] = JS_DupValue(ctx, arg);
}
js_async_function_resume(ctx, s);
return JS_UNDEFINED;
@@ -18949,32 +19962,21 @@ static JSValue js_async_function_call(JSContext *ctx, JSValueConst func_obj,
int argc, JSValueConst *argv, int flags)
{
JSValue promise;
- JSAsyncFunctionData *s;
+ JSAsyncFunctionState *s;
- s = js_mallocz(ctx, sizeof(*s));
+ s = async_func_init(ctx, func_obj, this_obj, argc, argv);
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);
+ if (JS_IsException(promise)) {
+ async_func_free(ctx->rt, s);
return JS_EXCEPTION;
}
- s->is_active = TRUE;
js_async_function_resume(ctx, s);
- js_async_function_free(ctx->rt, s);
+ async_func_free(ctx->rt, s);
return promise;
}
@@ -19003,7 +20005,8 @@ typedef struct JSAsyncGeneratorRequest {
typedef struct JSAsyncGeneratorData {
JSObject *generator; /* back pointer to the object (const) */
JSAsyncGeneratorStateEnum state;
- JSAsyncFunctionState func_state;
+ /* func_state is NULL is state AWAITING_RETURN and COMPLETED */
+ JSAsyncFunctionState *func_state;
struct list_head queue; /* list of JSAsyncGeneratorRequest.link */
} JSAsyncGeneratorData;
@@ -19021,10 +20024,8 @@ static void js_async_generator_free(JSRuntime *rt,
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);
- }
+ if (s->func_state)
+ async_func_free(rt, s->func_state);
js_free_rt(rt, s);
}
@@ -19051,9 +20052,8 @@ static void js_async_generator_mark(JSRuntime *rt, JSValueConst val,
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);
+ if (s->func_state) {
+ mark_func(rt, &s->func_state->header);
}
}
}
@@ -19163,7 +20163,8 @@ static void js_async_generator_complete(JSContext *ctx,
{
if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED) {
s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
- async_func_free(ctx->rt, &s->func_state);
+ async_func_free(ctx->rt, s->func_state);
+ s->func_state = NULL;
}
}
@@ -19174,10 +20175,19 @@ static int js_async_generator_completed_return(JSContext *ctx,
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;
+ // Can fail looking up JS_ATOM_constructor when is_reject==0.
+ promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, &value,
+ /*is_reject*/0);
+ // A poisoned .constructor property is observable and the resulting
+ // exception should be delivered to the catch handler.
+ if (JS_IsException(promise)) {
+ JSValue err = JS_GetException(ctx);
+ promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, (JSValueConst *)&err,
+ /*is_reject*/1);
+ JS_FreeValue(ctx, err);
+ if (JS_IsException(promise))
+ return -1;
+ }
if (js_async_generator_resolve_function_create(ctx,
JS_MKPTR(JS_TAG_OBJECT, s->generator),
resolving_funcs1,
@@ -19225,7 +20235,6 @@ static void js_async_generator_resume_next(JSContext *ctx,
} 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);
}
@@ -19236,30 +20245,38 @@ static void js_async_generator_resume_next(JSContext *ctx,
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;
+ 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] =
+ 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++;
+ s->func_state->frame.cur_sp++;
exec_no_arg:
- s->func_state.throw_flag = FALSE;
+ 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 = async_func_resume(ctx, s->func_state);
+ if (s->func_state->is_completed) {
+ if (JS_IsException(func_ret)) {
+ value = JS_GetException(ctx);
+ js_async_generator_complete(ctx, s);
+ js_async_generator_reject(ctx, s, value);
+ JS_FreeValue(ctx, value);
+ } else {
+ /* end of function */
+ js_async_generator_complete(ctx, s);
+ js_async_generator_resolve(ctx, s, func_ret, TRUE);
+ JS_FreeValue(ctx, func_ret);
+ }
+ } else {
+ int func_ret_code, ret;
+ assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT);
func_ret_code = JS_VALUE_GET_INT(func_ret);
+ value = s->func_state->frame.cur_sp[-1];
+ s->func_state->frame.cur_sp[-1] = JS_UNDEFINED;
switch(func_ret_code) {
case FUNC_RET_YIELD:
case FUNC_RET_YIELD_STAR:
@@ -19271,20 +20288,17 @@ static void js_async_generator_resume_next(JSContext *ctx,
JS_FreeValue(ctx, value);
break;
case FUNC_RET_AWAIT:
- js_async_generator_await(ctx, s, value);
+ ret = js_async_generator_await(ctx, s, value);
JS_FreeValue(ctx, value);
+ if (ret < 0) {
+ /* exception: throw it */
+ s->func_state->throw_flag = TRUE;
+ goto resume_exec;
+ }
goto done;
default:
abort();
}
- } 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:
@@ -19318,12 +20332,12 @@ static JSValue js_async_generator_resolve_function(JSContext *ctx,
} else {
/* restart function execution after await() */
assert(s->state == JS_ASYNC_GENERATOR_STATE_EXECUTING);
- s->func_state.throw_flag = is_reject;
+ 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);
+ s->func_state->frame.cur_sp[-1] = JS_DupValue(ctx, arg);
}
js_async_generator_resume_next(ctx, s);
}
@@ -19387,14 +20401,12 @@ static JSValue js_async_generator_function_call(JSContext *ctx, JSValueConst fun
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;
+ s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv);
+ if (!s->func_state)
goto fail;
- }
-
/* execute the function up to 'OP_initial_yield' (no yield nor
await are possible) */
- func_ret = async_func_resume(ctx, &s->func_state);
+ func_ret = async_func_resume(ctx, s->func_state);
if (JS_IsException(func_ret))
goto fail;
JS_FreeValue(ctx, func_ret);
@@ -19430,9 +20442,6 @@ enum {
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,
@@ -19452,9 +20461,6 @@ enum {
TOK_STRICT_NEQ,
TOK_LAND,
TOK_LOR,
-#ifdef CONFIG_BIGNUM
- TOK_MATH_POW,
-#endif
TOK_POW,
TOK_ARROW,
TOK_ELLIPSIS,
@@ -19533,7 +20539,8 @@ typedef struct BlockEnv {
int drop_count; /* number of stack elements to drop */
int label_finally; /* -1 if none */
int scope_level;
- int has_iterator;
+ uint8_t has_iterator : 1;
+ uint8_t is_regular_stmt : 1; /* i.e. not a loop statement */
} BlockEnv;
typedef struct JSGlobalVar {
@@ -19569,9 +20576,17 @@ typedef struct LabelSlot {
typedef struct LineNumberSlot {
uint32_t pc;
- int line_num;
+ uint32_t source_pos;
} LineNumberSlot;
+typedef struct {
+ /* last source position */
+ const uint8_t *ptr;
+ int line_num;
+ int col_num;
+ const uint8_t *buf_start;
+} GetLineColCache;
+
typedef enum JSParseFunctionEnum {
JS_PARSE_FUNC_STATEMENT,
JS_PARSE_FUNC_VAR,
@@ -19580,6 +20595,7 @@ typedef enum JSParseFunctionEnum {
JS_PARSE_FUNC_GETTER,
JS_PARSE_FUNC_SETTER,
JS_PARSE_FUNC_METHOD,
+ JS_PARSE_FUNC_CLASS_STATIC_INIT,
JS_PARSE_FUNC_CLASS_CONSTRUCTOR,
JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR,
} JSParseFunctionEnum;
@@ -19621,7 +20637,6 @@ typedef struct JSFunctionDef {
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 */
@@ -19637,7 +20652,7 @@ typedef struct JSFunctionDef {
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,
+ 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) */
@@ -19647,7 +20662,7 @@ typedef struct JSFunctionDef {
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 */
@@ -19662,9 +20677,9 @@ typedef struct JSFunctionDef {
DynBuf byte_code;
int last_opcode_pos; /* -1 if no last opcode */
- int last_opcode_line_num;
+ const uint8_t *last_opcode_source_ptr;
BOOL use_short_opcodes; /* true if short opcodes are used in byte_code */
-
+
LabelSlot *label_slots;
int label_size; /* allocated size for label_slots[] */
int label_count;
@@ -19691,20 +20706,23 @@ typedef struct JSFunctionDef {
int line_number_last_pc;
/* pc2line table */
+ BOOL strip_debug : 1; /* strip all debug info (implies strip_source = TRUE) */
+ BOOL strip_source : 1; /* strip only source code */
JSAtom filename;
- int line_num;
+ uint32_t source_pos; /* pointer in the eval() source */
+ GetLineColCache *get_line_col_cache; /* XXX: could remove to save memory */
DynBuf pc2line;
char *source; /* raw source, utf-8 encoded */
int source_len;
JSModuleDef *module; /* != NULL when parsing a module */
+ BOOL has_await; /* TRUE if await is used (used in module eval) */
} JSFunctionDef;
typedef struct JSToken {
int val;
- int line_num; /* line number of token start */
- const uint8_t *ptr;
+ const uint8_t *ptr; /* position in the source */
union {
struct {
JSValue str;
@@ -19712,9 +20730,6 @@ typedef struct JSToken {
} str;
struct {
JSValue val;
-#ifdef CONFIG_BIGNUM
- slimb_t exponent; /* may be != 0 only if val is a float */
-#endif
} num;
struct {
JSAtom atom;
@@ -19730,12 +20745,11 @@ typedef struct 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_start;
const uint8_t *buf_ptr;
const uint8_t *buf_end;
@@ -19744,6 +20758,7 @@ typedef struct JSParseState {
BOOL is_module; /* parsing a module */
BOOL allow_html_comments;
BOOL ext_json; /* true if accepting JSON superset */
+ GetLineColCache get_line_col_cache;
} JSParseState;
typedef struct JSOpCode {
@@ -19872,21 +20887,95 @@ static void __attribute((unused)) dump_token(JSParseState *s,
}
}
-int __attribute__((format(printf, 2, 3))) js_parse_error(JSParseState *s, const char *fmt, ...)
+/* return the zero based line and column number in the source. */
+/* Note: we no longer support '\r' as line terminator */
+static int get_line_col(int *pcol_num, const uint8_t *buf, size_t len)
+{
+ int line_num, col_num, c;
+ size_t i;
+
+ line_num = 0;
+ col_num = 0;
+ for(i = 0; i < len; i++) {
+ c = buf[i];
+ if (c == '\n') {
+ line_num++;
+ col_num = 0;
+ } else if (c < 0x80 || c >= 0xc0) {
+ col_num++;
+ }
+ }
+ *pcol_num = col_num;
+ return line_num;
+}
+
+static int get_line_col_cached(GetLineColCache *s, int *pcol_num, const uint8_t *ptr)
+{
+ int line_num, col_num;
+ if (ptr >= s->ptr) {
+ line_num = get_line_col(&col_num, s->ptr, ptr - s->ptr);
+ if (line_num == 0) {
+ s->col_num += col_num;
+ } else {
+ s->line_num += line_num;
+ s->col_num = col_num;
+ }
+ } else {
+ line_num = get_line_col(&col_num, ptr, s->ptr - ptr);
+ if (line_num == 0) {
+ s->col_num -= col_num;
+ } else {
+ const uint8_t *p;
+ s->line_num -= line_num;
+ /* find the absolute column position */
+ col_num = 0;
+ for(p = ptr - 1; p >= s->buf_start; p--) {
+ if (*p == '\n') {
+ break;
+ } else if (*p < 0x80 || *p >= 0xc0) {
+ col_num++;
+ }
+ }
+ s->col_num = col_num;
+ }
+ }
+ s->ptr = ptr;
+ *pcol_num = s->col_num;
+ return s->line_num;
+}
+
+/* 'ptr' is the position of the error in the source */
+static int js_parse_error_v(JSParseState *s, const uint8_t *ptr, const char *fmt, va_list ap)
{
JSContext *ctx = s->ctx;
+ int line_num, col_num;
+ line_num = get_line_col(&col_num, s->buf_start, ptr - s->buf_start);
+ JS_ThrowError2(ctx, JS_SYNTAX_ERROR, fmt, ap, FALSE);
+ build_backtrace(ctx, ctx->rt->current_exception, s->filename,
+ line_num + 1, col_num + 1, 0);
+ return -1;
+}
+
+static __attribute__((format(printf, 3, 4))) int js_parse_error_pos(JSParseState *s, const uint8_t *ptr, const char *fmt, ...)
+{
va_list ap;
- int backtrace_flags;
+ int ret;
va_start(ap, fmt);
- JS_ThrowError2(ctx, JS_SYNTAX_ERROR, fmt, ap, FALSE);
+ ret = js_parse_error_v(s, ptr, fmt, ap);
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;
+ return ret;
+}
+
+static __attribute__((format(printf, 2, 3))) int js_parse_error(JSParseState *s, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = js_parse_error_v(s, s->token.ptr, fmt, ap);
+ va_end(ap);
+ return ret;
}
static int js_parse_expect(JSParseState *s, int tok)
@@ -19922,6 +21011,7 @@ static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p)
{
uint32_t c;
StringBuffer b_s, *b = &b_s;
+ JSValue str;
/* p points to the first byte of the template part */
if (string_buffer_init(s->ctx, b, 32))
@@ -19952,13 +21042,11 @@ static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p)
p++;
c = '\n';
}
- if (c == '\n') {
- s->line_num++;
- } else if (c >= 0x80) {
+ 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");
+ js_parse_error_pos(s, p - 1, "invalid UTF-8 sequence");
goto fail;
}
p = p_next;
@@ -19966,9 +21054,12 @@ static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p)
if (string_buffer_putc(b, c))
goto fail;
}
+ str = string_buffer_end(b);
+ if (JS_IsException(str))
+ return -1;
s->token.val = TOK_TEMPLATE;
s->token.u.str.sep = c;
- s->token.u.str.str = string_buffer_end(b);
+ s->token.u.str.str = str;
s->buf_ptr = p;
return 0;
@@ -19986,6 +21077,8 @@ static __exception int js_parse_string(JSParseState *s, int sep,
int ret;
uint32_t c;
StringBuffer b_s, *b = &b_s;
+ const uint8_t *p_escape;
+ JSValue str;
/* string */
if (string_buffer_init(s->ctx, b, 32))
@@ -19995,11 +21088,6 @@ static __exception int js_parse_string(JSParseState *s, int sep,
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')
@@ -20019,6 +21107,7 @@ static __exception int js_parse_string(JSParseState *s, int sep,
break;
}
if (c == '\\') {
+ p_escape = p - 1;
c = *p;
/* XXX: need a specific JSON case to avoid
accepting invalid escapes */
@@ -20041,13 +21130,9 @@ static __exception int js_parse_string(JSParseState *s, int sep,
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')) {
@@ -20060,7 +21145,7 @@ static __exception int js_parse_string(JSParseState *s, int sep,
goto invalid_escape;
} else {
if (do_throw)
- js_parse_error(s, "octal escape sequences are not allowed in strict mode");
+ js_parse_error_pos(s, p_escape, "octal escape sequences are not allowed in strict mode");
}
goto fail;
}
@@ -20080,7 +21165,7 @@ static __exception int js_parse_string(JSParseState *s, int sep,
if (ret == -1) {
invalid_escape:
if (do_throw)
- js_parse_error(s, "malformed escape sequence in string literal");
+ js_parse_error_pos(s, p_escape, "malformed escape sequence in string literal");
goto fail;
} else if (ret < 0) {
/* ignore the '\' (could output a warning) */
@@ -20101,9 +21186,12 @@ static __exception int js_parse_string(JSParseState *s, int sep,
if (string_buffer_putc(b, c))
goto fail;
}
+ str = string_buffer_end(b);
+ if (JS_IsException(str))
+ return -1;
token->val = TOK_STRING;
token->u.str.sep = c;
- token->u.str.str = string_buffer_end(b);
+ token->u.str.str = str;
*pp = p;
return 0;
@@ -20131,6 +21219,7 @@ static __exception int js_parse_regexp(JSParseState *s)
StringBuffer b_s, *b = &b_s;
StringBuffer b2_s, *b2 = &b2_s;
uint32_t c;
+ JSValue body_str, flags_str;
p = s->buf_ptr;
p++;
@@ -20179,16 +21268,16 @@ static __exception int js_parse_regexp(JSParseState *s)
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");
+ js_parse_error_pos(s, p - 1, "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");
+ js_parse_error_pos(s, p - 1, "unexpected line terminator in regexp");
goto fail;
}
+ p = p_next;
}
if (string_buffer_putc(b, c))
goto fail;
@@ -20201,6 +21290,7 @@ static __exception int js_parse_regexp(JSParseState *s)
if (c >= 0x80) {
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
if (c > 0x10FFFF) {
+ p++;
goto invalid_utf8;
}
}
@@ -20211,9 +21301,17 @@ static __exception int js_parse_regexp(JSParseState *s)
p = p_next;
}
+ body_str = string_buffer_end(b);
+ flags_str = string_buffer_end(b2);
+ if (JS_IsException(body_str) ||
+ JS_IsException(flags_str)) {
+ JS_FreeValue(s->ctx, body_str);
+ JS_FreeValue(s->ctx, flags_str);
+ return -1;
+ }
s->token.val = TOK_REGEXP;
- s->token.u.regexp.body = string_buffer_end(b);
- s->token.u.regexp.flags = string_buffer_end(b2);
+ s->token.u.regexp.body = body_str;
+ s->token.u.regexp.flags = flags_str;
s->buf_ptr = p;
return 0;
fail:
@@ -20227,7 +21325,7 @@ static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize,
{
char *buf, *new_buf;
size_t size, new_size;
-
+
buf = *pbuf;
size = *psize;
if (size >= (SIZE_MAX / 3) * 2)
@@ -20249,6 +21347,48 @@ static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize,
return 0;
}
+/* convert a TOK_IDENT to a keyword when needed */
+static void update_token_ident(JSParseState *s)
+{
+ if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD ||
+ (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD &&
+ (s->cur_func->js_mode & JS_MODE_STRICT)) ||
+ (s->token.u.ident.atom == JS_ATOM_yield &&
+ ((s->cur_func->func_kind & JS_FUNC_GENERATOR) ||
+ (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
+ !s->cur_func->in_function_body && s->cur_func->parent &&
+ (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) ||
+ (s->token.u.ident.atom == JS_ATOM_await &&
+ (s->is_module ||
+ (s->cur_func->func_kind & JS_FUNC_ASYNC) ||
+ s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT ||
+ (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
+ !s->cur_func->in_function_body && s->cur_func->parent &&
+ ((s->cur_func->parent->func_kind & JS_FUNC_ASYNC) ||
+ s->cur_func->parent->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))))) {
+ if (s->token.u.ident.has_escape) {
+ s->token.u.ident.is_reserved = TRUE;
+ s->token.val = TOK_IDENT;
+ } else {
+ /* The keywords atoms are pre allocated */
+ s->token.val = s->token.u.ident.atom - 1 + TOK_FIRST_KEYWORD;
+ }
+ }
+}
+
+/* if the current token is an identifier or keyword, reparse it
+ according to the current function type */
+static void reparse_ident_token(JSParseState *s)
+{
+ if (s->token.val == TOK_IDENT ||
+ (s->token.val >= TOK_FIRST_KEYWORD &&
+ s->token.val <= TOK_LAST_KEYWORD)) {
+ s->token.val = TOK_IDENT;
+ s->token.u.ident.is_reserved = FALSE;
+ update_token_ident(s);
+ }
+}
+
/* 'c' is the first character. Return JS_ATOM_NULL in case of error */
static JSAtom parse_ident(JSParseState *s, const uint8_t **pp,
BOOL *pident_has_escape, int c, BOOL is_private)
@@ -20257,7 +21397,7 @@ static JSAtom parse_ident(JSParseState *s, const uint8_t **pp,
char ident_buf[128], *buf;
size_t ident_size, ident_pos;
JSAtom atom;
-
+
p = *pp;
buf = ident_buf;
ident_size = sizeof(ident_buf);
@@ -20266,7 +21406,7 @@ static JSAtom parse_ident(JSParseState *s, const uint8_t **pp,
buf[ident_pos++] = '#';
for(;;) {
p1 = p;
-
+
if (c < 128) {
buf[ident_pos++] = c;
} else {
@@ -20304,18 +21444,16 @@ static __exception int next_token(JSParseState *s)
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) {
@@ -20345,7 +21483,6 @@ static __exception int next_token(JSParseState *s)
p++;
line_terminator:
s->got_lf = TRUE;
- s->line_num++;
goto redo;
case '\f':
case '\v':
@@ -20366,11 +21503,7 @@ static __exception int next_token(JSParseState *s)
p += 2;
break;
}
- if (*p == '\n') {
- s->line_num++;
- s->got_lf = TRUE; /* considered as LF for ASI */
- p++;
- } else if (*p == '\r') {
+ if (*p == '\n' || *p == '\r') {
s->got_lf = TRUE; /* considered as LF for ASI */
p++;
} else if (*p >= 0x80) {
@@ -20435,14 +21568,14 @@ static __exception int next_token(JSParseState *s)
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 '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 'Y': case 'Z':
case '_':
case '$':
/* identifier */
@@ -20455,30 +21588,8 @@ static __exception int next_token(JSParseState *s)
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;
- }
+ s->token.val = TOK_IDENT;
+ update_token_ident(s);
break;
case '#':
/* private name */
@@ -20526,32 +21637,17 @@ static __exception int next_token(JSParseState *s)
goto parse_number;
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8':
- case '9':
+ case '9':
/* number */
parse_number:
{
JSValue ret;
const uint8_t *p1;
- int flags, radix;
+ int flags;
flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL |
- ATOD_ACCEPT_UNDERSCORES;
- flags |= ATOD_ACCEPT_SUFFIX;
-#ifdef CONFIG_BIGNUM
- 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,
+ ATOD_ACCEPT_UNDERSCORES | ATOD_ACCEPT_SUFFIX;
+ ret = js_atof(s->ctx, (const char *)p, (const char **)&p, 0,
flags);
-#endif
if (JS_IsException(ret))
goto fail;
/* reject `10instanceof Number` */
@@ -20605,8 +21701,8 @@ static __exception int next_token(JSParseState *s)
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) {
+ if (s->allow_html_comments && p[2] == '>' &&
+ (s->got_lf || s->last_ptr == s->buf_start)) {
/* Annex B: `-->` at beginning of line is an html comment end.
It extends to the end of the line.
*/
@@ -20707,33 +21803,6 @@ static __exception int next_token(JSParseState *s)
goto def_token;
}
break;
-#ifdef CONFIG_BIGNUM
- /* in math mode, '^' is the power operator. '^^' is always the
- xor operator and '**' is always the power operator */
- case '^':
- if (p[1] == '=') {
- p += 2;
- if (s->cur_func->js_mode & JS_MODE_MATH)
- s->token.val = TOK_MATH_POW_ASSIGN;
- else
- s->token.val = TOK_XOR_ASSIGN;
- } else if (p[1] == '^') {
- if (p[2] == '=') {
- p += 3;
- s->token.val = TOK_XOR_ASSIGN;
- } else {
- p += 2;
- s->token.val = '^';
- }
- } else {
- p++;
- if (s->cur_func->js_mode & JS_MODE_MATH)
- s->token.val = TOK_MATH_POW;
- else
- s->token.val = '^';
- }
- break;
-#else
case '^':
if (p[1] == '=') {
p += 2;
@@ -20742,7 +21811,6 @@ static __exception int next_token(JSParseState *s)
goto def_token;
}
break;
-#endif
case '|':
if (p[1] == '=') {
p += 2;
@@ -20784,7 +21852,7 @@ static __exception int next_token(JSParseState *s)
case CP_LS:
/* XXX: should avoid incrementing line_number, but
needed to handle HTML comments */
- goto line_terminator;
+ goto line_terminator;
default:
if (lre_is_space(c)) {
goto redo;
@@ -20813,13 +21881,14 @@ static __exception int next_token(JSParseState *s)
}
/* 'c' is the first character. Return JS_ATOM_NULL in case of error */
+/* XXX: accept unicode identifiers as JSON5 ? */
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);
@@ -20827,8 +21896,7 @@ static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c)
for(;;) {
buf[ident_pos++] = c;
c = *p;
- if (c >= 128 ||
- !((lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1))
+ if (c >= 128 || !lre_is_id_continue_byte(c))
break;
p++;
if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
@@ -20846,22 +21914,196 @@ static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c)
return atom;
}
+static int json_parse_string(JSParseState *s, const uint8_t **pp, int sep)
+{
+ const uint8_t *p, *p_next;
+ int i;
+ uint32_t c;
+ StringBuffer b_s, *b = &b_s;
+
+ if (string_buffer_init(s->ctx, b, 32))
+ goto fail;
+
+ p = *pp;
+ for(;;) {
+ if (p >= s->buf_end) {
+ goto end_of_input;
+ }
+ c = *p++;
+ if (c == sep)
+ break;
+ if (c < 0x20) {
+ js_parse_error_pos(s, p - 1, "Bad control character in string literal");
+ goto fail;
+ }
+ if (c == '\\') {
+ c = *p++;
+ switch(c) {
+ case 'b': c = '\b'; break;
+ case 'f': c = '\f'; break;
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ case 't': c = '\t'; break;
+ case '\\': break;
+ case '/': break;
+ case 'u':
+ c = 0;
+ for(i = 0; i < 4; i++) {
+ int h = from_hex(*p++);
+ if (h < 0) {
+ js_parse_error_pos(s, p - 1, "Bad Unicode escape");
+ goto fail;
+ }
+ c = (c << 4) | h;
+ }
+ break;
+ case '\n':
+ if (s->ext_json)
+ continue;
+ goto bad_escape;
+ case 'v':
+ if (s->ext_json) {
+ c = '\v';
+ break;
+ }
+ goto bad_escape;
+ default:
+ if (c == sep)
+ break;
+ if (p > s->buf_end)
+ goto end_of_input;
+ bad_escape:
+ js_parse_error_pos(s, p - 1, "Bad escaped character");
+ goto fail;
+ }
+ } else
+ if (c >= 0x80) {
+ c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
+ if (c > 0x10FFFF) {
+ js_parse_error_pos(s, p - 1, "Bad UTF-8 sequence");
+ goto fail;
+ }
+ p = p_next;
+ }
+ if (string_buffer_putc(b, c))
+ goto fail;
+ }
+ s->token.val = TOK_STRING;
+ s->token.u.str.sep = sep;
+ s->token.u.str.str = string_buffer_end(b);
+ *pp = p;
+ return 0;
+
+ end_of_input:
+ js_parse_error(s, "Unexpected end of JSON input");
+ fail:
+ string_buffer_free(b);
+ return -1;
+}
+
+static int json_parse_number(JSParseState *s, const uint8_t **pp)
+{
+ const uint8_t *p = *pp;
+ const uint8_t *p_start = p;
+ int radix;
+ double d;
+ JSATODTempMem atod_mem;
+
+ if (*p == '+' || *p == '-')
+ p++;
+
+ if (!is_digit(*p)) {
+ if (s->ext_json) {
+ if (strstart((const char *)p, "Infinity", (const char **)&p)) {
+#ifdef _MSC_VER
+ d = INFINITY;
+#else
+ d = 1.0 / 0.0;
+#endif
+ if (*p_start == '-')
+ d = -d;
+ goto done;
+ } else if (strstart((const char *)p, "NaN", (const char **)&p)) {
+ d = NAN;
+ goto done;
+ } else if (*p != '.') {
+ goto unexpected_token;
+ }
+ } else {
+ goto unexpected_token;
+ }
+ }
+
+ if (p[0] == '0') {
+ if (s->ext_json) {
+ /* also accepts base 16, 8 and 2 prefix for integers */
+ radix = 10;
+ if (p[1] == 'x' || p[1] == 'X') {
+ p += 2;
+ radix = 16;
+ } else if ((p[1] == 'o' || p[1] == 'O')) {
+ p += 2;
+ radix = 8;
+ } else if ((p[1] == 'b' || p[1] == 'B')) {
+ p += 2;
+ radix = 2;
+ }
+ if (radix != 10) {
+ /* prefix is present */
+ if (to_digit(*p) >= radix) {
+ unexpected_token:
+ return js_parse_error_pos(s, p, "Unexpected token '%c'", *p);
+ }
+ d = js_atod((const char *)p_start, (const char **)&p, 0,
+ JS_ATOD_INT_ONLY | JS_ATOD_ACCEPT_BIN_OCT, &atod_mem);
+ goto done;
+ }
+ }
+ if (is_digit(p[1]))
+ return js_parse_error_pos(s, p, "Unexpected number");
+ }
+
+ while (is_digit(*p))
+ p++;
+
+ if (*p == '.') {
+ p++;
+ if (!is_digit(*p))
+ return js_parse_error_pos(s, p, "Unterminated fractional number");
+ while (is_digit(*p))
+ p++;
+ }
+ if (*p == 'e' || *p == 'E') {
+ p++;
+ if (*p == '+' || *p == '-')
+ p++;
+ if (!is_digit(*p))
+ return js_parse_error_pos(s, p, "Exponent part is missing a number");
+ while (is_digit(*p))
+ p++;
+ }
+ d = js_atod((const char *)p_start, NULL, 10, 0, &atod_mem);
+ done:
+ s->token.val = TOK_NUMBER;
+ s->token.u.num.val = JS_NewFloat64(s->ctx, d);
+ *pp = p;
+ return 0;
+}
+
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) {
@@ -20879,7 +22121,8 @@ static __exception int json_next_token(JSParseState *s)
}
/* fall through */
case '\"':
- if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
+ p++;
+ if (json_parse_string(s, &p, c))
goto fail;
break;
case '\r': /* accept DOS and MAC newline sequences */
@@ -20889,7 +22132,6 @@ static __exception int json_next_token(JSParseState *s)
/* fall thru */
case '\n':
p++;
- s->line_num++;
goto redo;
case '\f':
case '\v':
@@ -20919,12 +22161,7 @@ static __exception int json_next_token(JSParseState *s)
p += 2;
break;
}
- if (*p == '\n') {
- s->line_num++;
- p++;
- } else if (*p == '\r') {
- p++;
- } else if (*p >= 0x80) {
+ if (*p >= 0x80) {
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
if (c == -1) {
p++; /* skip invalid UTF-8 */
@@ -20965,17 +22202,16 @@ static __exception int json_next_token(JSParseState *s)
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 '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 '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)
@@ -20986,39 +22222,23 @@ static __exception int json_next_token(JSParseState *s)
s->token.val = TOK_IDENT;
break;
case '+':
- if (!s->ext_json || !is_digit(p[1]))
+ if (!s->ext_json)
goto def_token;
goto parse_number;
- case '0':
- if (is_digit(p[1]))
+ case '.':
+ if (s->ext_json && is_digit(p[1]))
+ goto parse_number;
+ else
goto def_token;
- goto parse_number;
case '-':
- if (!is_digit(p[1]))
- goto def_token;
- goto parse_number;
+ case '0':
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8':
- case '9':
+ 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;
- }
+ if (json_parse_number(s, &p))
+ goto fail;
break;
default:
if (c >= 128) {
@@ -21040,14 +22260,34 @@ static __exception int json_next_token(JSParseState *s)
return -1;
}
-/* only used for ':' and '=>', 'let' or 'function' look-ahead. *pp is
- only set if TOK_IMPORT is returned */
-/* XXX: handle all unicode cases */
+static int match_identifier(const uint8_t *p, const char *s) {
+ uint32_t c;
+ while (*s) {
+ if ((uint8_t)*s++ != *p++)
+ return 0;
+ }
+ c = *p;
+ if (c >= 128)
+ c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
+ return !lre_js_is_ident_next(c);
+}
+
+/* simple_next_token() is used to check for the next token in simple cases.
+ It is only used for ':' and '=>', 'let' or 'function' look-ahead.
+ (*pp) is only set if TOK_IMPORT is returned for JS_DetectModule()
+ Whitespace and comments are skipped correctly.
+ Then the next token is analyzed, only for specific words.
+ Return values:
+ - '\n' if !no_line_terminator
+ - TOK_ARROW, TOK_IN, TOK_IMPORT, TOK_OF, TOK_EXPORT, TOK_FUNCTION
+ - TOK_IDENT is returned for other identifiers and keywords
+ - otherwise the next character or unicode codepoint is returned.
+ */
static int simple_next_token(const uint8_t **pp, BOOL no_line_terminator)
{
const uint8_t *p;
uint32_t c;
-
+
/* skip spaces and comments */
p = *pp;
for (;;) {
@@ -21086,33 +22326,42 @@ static int simple_next_token(const uint8_t **pp, BOOL no_line_terminator)
if (*p == '>')
return TOK_ARROW;
break;
+ case 'i':
+ if (match_identifier(p, "n"))
+ return TOK_IN;
+ if (match_identifier(p, "mport")) {
+ *pp = p + 5;
+ return TOK_IMPORT;
+ }
+ return TOK_IDENT;
+ case 'o':
+ if (match_identifier(p, "f"))
+ return TOK_OF;
+ return TOK_IDENT;
+ case 'e':
+ if (match_identifier(p, "xport"))
+ return TOK_EXPORT;
+ return TOK_IDENT;
+ case 'f':
+ if (match_identifier(p, "unction"))
+ return TOK_FUNCTION;
+ return TOK_IDENT;
+ case '\\':
+ if (*p == 'u') {
+ if (lre_js_is_ident_first(lre_parse_escape(&p, TRUE)))
+ return TOK_IDENT;
+ }
+ break;
default:
- if (lre_js_is_ident_first(c)) {
- if (c == 'i') {
- if (p[0] == 'n' && !lre_js_is_ident_next(p[1])) {
- return TOK_IN;
- }
- if (p[0] == 'm' && p[1] == 'p' && p[2] == 'o' &&
- p[3] == 'r' && p[4] == 't' &&
- !lre_js_is_ident_next(p[5])) {
- *pp = p + 5;
- return TOK_IMPORT;
- }
- } else if (c == 'o' && *p == 'f' && !lre_js_is_ident_next(p[1])) {
- return TOK_OF;
- } else if (c == 'e' &&
- p[0] == 'x' && p[1] == 'p' && p[2] == 'o' &&
- p[3] == 'r' && p[4] == 't' &&
- !lre_js_is_ident_next(p[5])) {
- *pp = p + 5;
- return TOK_EXPORT;
- } else if (c == 'f' && p[0] == 'u' && p[1] == 'n' &&
- p[2] == 'c' && p[3] == 't' && p[4] == 'i' &&
- p[5] == 'o' && p[6] == 'n' && !lre_js_is_ident_next(p[7])) {
- return TOK_FUNCTION;
- }
- return TOK_IDENT;
+ if (c >= 128) {
+ c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p);
+ if (no_line_terminator && (c == CP_PS || c == CP_LS))
+ return '\n';
}
+ if (lre_is_space(c))
+ continue;
+ if (lre_js_is_ident_first(c))
+ return TOK_IDENT;
break;
}
return c;
@@ -21125,6 +22374,31 @@ static int peek_token(JSParseState *s, BOOL no_line_terminator)
return simple_next_token(&p, no_line_terminator);
}
+static void skip_shebang(const uint8_t **pp, const uint8_t *buf_end)
+{
+ const uint8_t *p = *pp;
+ int c;
+
+ if (p[0] == '#' && p[1] == '!') {
+ p += 2;
+ while (p < 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++;
+ }
+ }
+ *pp = p;
+ }
+}
+
/* return true if 'input' contains the source of a module
(heuristic). 'input' must be a zero terminated.
@@ -21135,6 +22409,8 @@ BOOL JS_DetectModule(const char *input, size_t input_len)
{
const uint8_t *p = (const uint8_t *)input;
int tok;
+
+ skip_shebang(&p, p + input_len);
switch(simple_next_token(&p, FALSE)) {
case TOK_IMPORT:
tok = simple_next_token(&p, FALSE);
@@ -21147,7 +22423,7 @@ BOOL JS_DetectModule(const char *input, size_t input_len)
}
static inline int get_prev_opcode(JSFunctionDef *fd) {
- if (fd->last_opcode_pos < 0)
+ if (fd->last_opcode_pos < 0 || dbuf_error(&fd->byte_code))
return OP_invalid;
else
return fd->byte_code.buf[fd->last_opcode_pos];
@@ -21189,26 +22465,34 @@ static void emit_u32(JSParseState *s, uint32_t val)
dbuf_put_u32(&s->cur_func->byte_code, val);
}
-static void emit_op(JSParseState *s, uint8_t val)
+static void emit_source_pos(JSParseState *s, const uint8_t *source_ptr)
{
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)) {
+ if (unlikely(fd->last_opcode_source_ptr != source_ptr)) {
dbuf_putc(bc, OP_line_num);
- dbuf_put_u32(bc, s->last_line_num);
- fd->last_opcode_line_num = s->last_line_num;
+ dbuf_put_u32(bc, source_ptr - s->buf_start);
+ fd->last_opcode_source_ptr = source_ptr;
}
+}
+
+static void emit_op(JSParseState *s, uint8_t val)
+{
+ JSFunctionDef *fd = s->cur_func;
+ DynBuf *bc = &fd->byte_code;
+
fd->last_opcode_pos = bc->size;
dbuf_putc(bc, val);
}
static void emit_atom(JSParseState *s, JSAtom name)
{
- emit_u32(s, JS_DupAtom(s->ctx, name));
+ DynBuf *bc = &s->cur_func->byte_code;
+ if (dbuf_realloc(bc, bc->size + 4))
+ return; /* not enough memory : don't duplicate the atom */
+ put_u32(bc->buf + bc->size, JS_DupAtom(s->ctx, name));
+ bc->size += 4;
}
static int update_label(JSFunctionDef *s, int label, int delta)
@@ -21222,29 +22506,41 @@ static int update_label(JSFunctionDef *s, int label, int delta)
return ls->ref_count;
}
-static int new_label_fd(JSFunctionDef *fd, int label)
+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;
- }
+ 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;
}
static int new_label(JSParseState *s)
{
- return new_label_fd(s->cur_func, -1);
+ int label;
+ label = new_label_fd(s->cur_func);
+ if (unlikely(label < 0)) {
+ dbuf_set_error(&s->cur_func->byte_code);
+ }
+ return label;
+}
+
+/* don't update the last opcode and don't emit line number info */
+static void emit_label_raw(JSParseState *s, int label)
+{
+ emit_u8(s, OP_label);
+ emit_u32(s, label);
+ s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size;
}
/* return the label ID offset */
@@ -21264,8 +22560,11 @@ static int emit_label(JSParseState *s, int label)
static int emit_goto(JSParseState *s, int opcode, int label)
{
if (js_is_live_code(s)) {
- if (label < 0)
+ if (label < 0) {
label = new_label(s);
+ if (label < 0)
+ return -1;
+ }
emit_op(s, opcode);
emit_u32(s, label);
s->cur_func->label_slots[label].ref_count++;
@@ -21278,7 +22577,7 @@ static int emit_goto(JSParseState *s, int opcode, int label)
static 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;
@@ -21664,7 +22963,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom 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);
@@ -21673,7 +22972,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
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) &&
@@ -21765,15 +23064,13 @@ static __exception int js_parse_expr(JSParseState *s);
static __exception int js_parse_function_decl(JSParseState *s,
JSParseFunctionEnum func_type,
JSFunctionKindEnum func_kind,
- JSAtom func_name, const uint8_t *ptr,
- int start_line);
+ JSAtom func_name, const uint8_t *ptr);
static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s);
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);
static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags);
@@ -21896,7 +23193,6 @@ static __exception int js_parse_template(JSParseState *s, int call, int *argc)
/* 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;
}
@@ -21945,17 +23241,23 @@ static int __exception js_parse_property_name(JSParseState *s,
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)) {
+ /* if allow_private is true (for class field parsing) and
+ get/set is following by ';' (or LF with ASI), then it
+ is a field name */
+ if ((token_is_pseudo_keyword(s, JS_ATOM_get) ||
+ token_is_pseudo_keyword(s, JS_ATOM_set)) &&
+ (!allow_private || peek_token(s, TRUE) != '\n')) {
/* 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 == '(') {
+ s->token.val == '}' || s->token.val == '(' ||
+ s->token.val == '=' ||
+ (s->token.val == ';' && allow_private)) {
is_non_reserved_ident = TRUE;
goto ident_found;
}
@@ -21971,7 +23273,8 @@ static int __exception js_parse_property_name(JSParseState *s,
if (next_token(s))
goto fail1;
if (s->token.val == ':' || s->token.val == ',' ||
- s->token.val == '}' || s->token.val == '(') {
+ s->token.val == '}' || s->token.val == '(' ||
+ s->token.val == '=') {
is_non_reserved_ident = TRUE;
goto ident_found;
}
@@ -22011,21 +23314,7 @@ static int __exception js_parse_property_name(JSParseState *s,
} 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);
- }
+ name = JS_ValueToAtom(s->ctx, val);
if (name == JS_ATOM_NULL)
goto fail;
if (next_token(s))
@@ -22063,16 +23352,12 @@ static int __exception js_parse_property_name(JSParseState *s,
}
typedef struct JSParsePos {
- int last_line_num;
- int line_num;
BOOL got_lf;
const uint8_t *ptr;
} JSParsePos;
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;
@@ -22080,8 +23365,6 @@ static int js_parse_get_pos(JSParseState *s, JSParsePos *sp)
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);
@@ -22114,6 +23397,17 @@ static BOOL is_regexp_allowed(int tok)
#define SKIP_HAS_ELLIPSIS (1 << 1)
#define SKIP_HAS_ASSIGNMENT (1 << 2)
+static BOOL has_lf_in_range(const uint8_t *p1, const uint8_t *p2)
+{
+ const uint8_t *tmp;
+ if (p1 > p2) {
+ tmp = p1;
+ p1 = p2;
+ p2 = tmp;
+ }
+ return (memchr(p1, '\n', p2 - p1) != NULL);
+}
+
/* XXX: improve speed with early bailout */
/* XXX: no longer works if regexps are present. Could use previous
regexp parsing heuristics to handle most cases */
@@ -22124,7 +23418,8 @@ static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_
JSParsePos pos;
int last_tok, tok = TOK_EOF;
int c, tok_len, bits = 0;
-
+ const uint8_t *last_token_ptr;
+
/* protect from underflow */
state[level++] = 0;
@@ -22155,7 +23450,6 @@ static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_
/* 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;
@@ -22171,7 +23465,7 @@ static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_
if (level >= sizeof(state))
goto done;
state[level++] = '`';
- }
+ }
break;
case TOK_EOF:
goto done;
@@ -22188,7 +23482,7 @@ static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_
case '=':
bits |= SKIP_HAS_ASSIGNMENT;
break;
-
+
case TOK_DIV_ASSIGN:
tok_len = 2;
goto parse_regexp;
@@ -22212,6 +23506,7 @@ static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_
} else {
last_tok = s->token.val;
}
+ last_token_ptr = s->token.ptr;
if (next_token(s)) {
/* XXX: should clear the exception generated by next_token() */
break;
@@ -22220,7 +23515,7 @@ static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_
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)
+ if (no_line_terminator && has_lf_in_range(last_token_ptr, s->token.ptr))
tok = '\n';
break;
}
@@ -22287,7 +23582,7 @@ static __exception int js_parse_object_literal(JSParseState *s)
{
JSAtom name = JS_ATOM_NULL;
const uint8_t *start_ptr;
- int start_line, prop_type;
+ int prop_type;
BOOL has_proto;
if (next_token(s))
@@ -22298,7 +23593,6 @@ static __exception int js_parse_object_literal(JSParseState *s)
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))
@@ -22344,7 +23638,7 @@ static __exception int js_parse_object_literal(JSParseState *s)
func_kind = JS_FUNC_ASYNC_GENERATOR;
}
if (js_parse_function_decl(s, func_type, func_kind, JS_ATOM_NULL,
- start_ptr, start_line))
+ start_ptr))
goto fail;
if (name == JS_ATOM_NULL) {
emit_op(s, OP_define_method_computed);
@@ -22360,6 +23654,10 @@ static __exception int js_parse_object_literal(JSParseState *s)
}
emit_u8(s, op_flags | OP_DEFINE_METHOD_ENUMERABLE);
} else {
+ if (name == JS_ATOM_NULL) {
+ /* must be done before evaluating expr */
+ emit_op(s, OP_to_propkey);
+ }
if (js_parse_expect(s, ':'))
goto fail;
if (js_parse_assign_expr(s))
@@ -22398,56 +23696,84 @@ static __exception int js_parse_object_literal(JSParseState *s)
}
/* allow the 'in' binary operator */
-#define PF_IN_ACCEPTED (1 << 0)
+#define PF_IN_ACCEPTED (1 << 0)
/* allow function calls parsing in js_parse_postfix_expr() */
-#define PF_POSTFIX_CALL (1 << 1)
-/* allow arrow functions parsing in js_parse_postfix_expr() */
-#define PF_ARROW_FUNC (1 << 2)
+#define PF_POSTFIX_CALL (1 << 1)
/* allow the exponentiation operator in js_parse_unary() */
-#define PF_POW_ALLOWED (1 << 3)
+#define PF_POW_ALLOWED (1 << 2)
/* forbid the exponentiation operator in js_parse_unary() */
-#define PF_POW_FORBIDDEN (1 << 4)
+#define PF_POW_FORBIDDEN (1 << 3)
static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags);
+static void emit_class_field_init(JSParseState *s);
+static JSFunctionDef *js_new_function_def(JSContext *ctx,
+ JSFunctionDef *parent,
+ BOOL is_eval,
+ BOOL is_func_expr,
+ const char *filename,
+ const uint8_t *source_ptr,
+ GetLineColCache *get_line_col_cache);
+static void emit_return(JSParseState *s, BOOL hasval);
static __exception int js_parse_left_hand_side_expr(JSParseState *s)
{
return js_parse_postfix_expr(s, PF_POSTFIX_CALL);
}
-/* 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);
+ JSFunctionDef *fd = s->cur_func;
+ int idx;
+
+ fd = js_new_function_def(s->ctx, fd, FALSE, FALSE, s->filename,
+ s->token.ptr, &s->get_line_col_cache);
+ if (!fd)
+ return -1;
+
+ s->cur_func = fd;
+ fd->has_home_object = TRUE;
+ fd->super_allowed = TRUE;
+ fd->has_prototype = FALSE;
+ fd->has_this_binding = TRUE;
+ fd->new_target_allowed = TRUE;
+
+ push_scope(s); /* enter body scope */
+ fd->body_scope = fd->scope_level;
if (has_super) {
- /* spec change: no argument evaluation */
- str = "(){super(...arguments);}";
+ fd->is_derived_class_constructor = TRUE;
+ fd->super_call_allowed = TRUE;
+ fd->arguments_allowed = TRUE;
+ fd->has_arguments_binding = TRUE;
func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;
+ emit_op(s, OP_init_ctor);
+ // TODO(bnoordhuis) roll into OP_init_ctor
+ emit_op(s, OP_scope_put_var_init);
+ emit_atom(s, JS_ATOM_this);
+ emit_u16(s, 0);
+ emit_class_field_init(s);
} else {
- str = "(){}";
func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;
+ /* error if not invoked as a constructor */
+ emit_op(s, OP_check_ctor);
+ emit_class_field_init(s);
}
- 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;
+
+ fd->func_kind = JS_FUNC_NORMAL;
+ fd->func_type = func_type;
+ emit_return(s, FALSE);
+
+ s->cur_func = fd->parent;
+ if (pfd)
+ *pfd = fd;
+
+ /* the real object will be set at the end of the compilation */
+ idx = cpool_add(s, JS_NULL);
+ fd->parent_cpool_idx = idx;
+
+ return 0;
}
/* find field in the current scope */
@@ -22472,7 +23798,7 @@ static int find_private_class_field(JSContext *ctx, JSFunctionDef *fd,
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);
@@ -22480,13 +23806,13 @@ static void emit_class_field_init(JSParseState *s)
/* 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);
@@ -22503,67 +23829,54 @@ static JSAtom get_private_setter_name(JSContext *ctx, JSAtom name)
typedef struct {
JSFunctionDef *fields_init_fd;
int computed_fields_count;
- BOOL has_brand;
+ BOOL need_brand;
int brand_push_pos;
+ BOOL is_static;
} ClassFieldsDef;
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;
-}
+ if (!cf->is_static) {
+ /* add the brand to the newly created instance */
+ /* 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);
-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;
+ 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 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);
@@ -22586,7 +23899,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
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;
@@ -22649,7 +23962,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
} else {
class_name1 = class_name;
}
-
+
emit_op(s, OP_define_class);
emit_atom(s, class_name1);
emit_u8(s, class_flags);
@@ -22659,9 +23972,10 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
ClassFieldsDef *cf = &class_fields[i];
cf->fields_init_fd = NULL;
cf->computed_fields_count = 0;
- cf->has_brand = FALSE;
+ cf->need_brand = FALSE;
+ cf->is_static = i;
}
-
+
ctor_fd = NULL;
while (s->token.val != '}') {
if (s->token.val == ';') {
@@ -22669,11 +23983,51 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
goto fail;
continue;
}
- is_static = (s->token.val == TOK_STATIC);
+ is_static = FALSE;
+ if (s->token.val == TOK_STATIC) {
+ int next = peek_token(s, TRUE);
+ if (!(next == ';' || next == '}' || next == '(' || next == '='))
+ is_static = TRUE;
+ }
prop_type = -1;
if (is_static) {
if (next_token(s))
goto fail;
+ if (s->token.val == '{') {
+ ClassFieldsDef *cf = &class_fields[is_static];
+ JSFunctionDef *init;
+ if (!cf->fields_init_fd) {
+ if (emit_class_init_start(s, cf))
+ goto fail;
+ }
+ s->cur_func = cf->fields_init_fd;
+ /* XXX: could try to avoid creating a new function and
+ reuse 'fields_init_fd' with a specific 'var'
+ scope */
+ // stack is now:
+ if (js_parse_function_decl2(s, JS_PARSE_FUNC_CLASS_STATIC_INIT,
+ JS_FUNC_NORMAL, JS_ATOM_NULL,
+ s->token.ptr,
+ JS_PARSE_EXPORT_NONE, &init) < 0) {
+ goto fail;
+ }
+ // stack is now: fclosure
+ push_scope(s);
+ emit_op(s, OP_scope_get_var);
+ emit_atom(s, JS_ATOM_this);
+ emit_u16(s, 0);
+ // stack is now: fclosure this
+ emit_op(s, OP_swap);
+ // stack is now: this fclosure
+ emit_op(s, OP_call_method);
+ emit_u16(s, 0);
+ // stack is now: returnvalue
+ emit_op(s, OP_drop);
+ // stack is now:
+ pop_scope(s);
+ s->cur_func = s->cur_func->parent;
+ continue;
+ }
/* allow "static" field name */
if (s->token.val == ';' || s->token.val == '=') {
is_static = FALSE;
@@ -22691,7 +24045,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
}
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) ||
@@ -22723,13 +24077,12 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
JS_VAR_PRIVATE_GETTER + is_set, is_static) < 0)
goto fail;
}
- if (add_brand(s, &class_fields[is_static]) < 0)
- goto fail;
+ class_fields[is_static].need_brand = TRUE;
}
if (js_parse_function_decl2(s, JS_PARSE_FUNC_GETTER + is_set,
JS_FUNC_NORMAL, JS_ATOM_NULL,
- start_ptr, s->token.line_num,
+ start_ptr,
JS_PARSE_EXPORT_NONE, &method_fd))
goto fail;
if (is_private) {
@@ -22740,7 +24093,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
if (is_set) {
JSAtom setter_name;
int ret;
-
+
setter_name = get_private_setter_name(ctx, name);
if (setter_name == JS_ATOM_NULL)
goto fail;
@@ -22766,7 +24119,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
} 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 */
@@ -22774,7 +24127,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
js_parse_error(s, "invalid field name");
goto fail;
}
-
+
if (is_private) {
if (find_private_class_field(ctx, fd, name,
fd->scope_level) >= 0) {
@@ -22824,7 +24177,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
emit_atom(s, name);
emit_u16(s, s->cur_func->scope_level);
}
-
+
if (s->token.val == '=') {
if (next_token(s))
goto fail;
@@ -22851,7 +24204,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
} else {
JSParseFunctionEnum func_type;
JSFunctionKindEnum func_kind;
-
+
func_type = JS_PARSE_FUNC_METHOD;
func_kind = JS_FUNC_NORMAL;
if (prop_type == PROP_TYPE_STAR) {
@@ -22871,10 +24224,9 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;
}
if (is_private) {
- if (add_brand(s, &class_fields[is_static]) < 0)
- goto fail;
+ class_fields[is_static].need_brand = TRUE;
}
- 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))
+ if (js_parse_function_decl2(s, func_type, func_kind, JS_ATOM_NULL, start_ptr, JS_PARSE_EXPORT_NONE, &method_fd))
goto fail;
if (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR ||
func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) {
@@ -22925,7 +24277,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
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)) {
+ if (!fd->strip_source) {
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,
@@ -22938,12 +24290,29 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
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;
-
+
+ if (cf->need_brand) {
+ /* add a private brand to the prototype */
+ emit_op(s, OP_dup);
+ emit_op(s, OP_null);
+ emit_op(s, OP_swap);
+ emit_op(s, OP_add_brand);
+
+ /* define the brand field in 'this' of the initializer */
+ if (!cf->fields_init_fd) {
+ if (emit_class_init_start(s, cf))
+ goto fail;
+ }
+ /* patch the start of the function to enable the
+ OP_add_brand_instance code */
+ cf->fields_init_fd->byte_code.buf[cf->brand_push_pos] = OP_push_true;
+ }
+
+ /* store the function to initialize the fields to that it can be
+ referenced by the constructor */
var_idx = define_var(s, fd, JS_ATOM_class_fields_init,
JS_VAR_DEF_CONST);
if (var_idx < 0)
@@ -22961,16 +24330,13 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
/* 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];
+ if (class_fields[1].need_brand) {
+ /* add a private brand to the class */
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);
+ emit_op(s, OP_dup);
+ emit_op(s, OP_add_brand);
}
-
+
if (class_name != JS_ATOM_NULL) {
/* store the class name in the scoped class name variable (it
is independent from the class statement variable
@@ -22980,6 +24346,17 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
emit_atom(s, class_name);
emit_u16(s, fd->scope_level);
}
+
+ /* 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);
+ }
+
pop_scope(s);
pop_scope(s);
@@ -23228,6 +24605,8 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
switch(opcode) {
case OP_scope_get_var:
label = new_label(s);
+ if (label < 0)
+ return -1;
emit_op(s, OP_scope_make_ref);
emit_atom(s, name);
emit_u32(s, label);
@@ -23246,10 +24625,7 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
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);
+ emit_op(s, OP_get_array_el3);
break;
case OP_get_super_value:
emit_op(s, OP_to_propkey);
@@ -23263,6 +24639,8 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
switch(opcode) {
case OP_scope_get_var:
label = new_label(s);
+ if (label < 0)
+ return -1;
emit_op(s, OP_scope_make_ref);
emit_atom(s, name);
emit_u32(s, label);
@@ -23270,11 +24648,7 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
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);
+ default:
break;
}
}
@@ -23374,7 +24748,7 @@ static void put_lvalue(JSParseState *s, int opcode, int scope,
default:
break;
}
-
+
switch(opcode) {
case OP_scope_get_var: /* val -- */
assert(special == PUT_LVALUE_NOKEEP ||
@@ -23428,7 +24802,7 @@ 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");
}
@@ -23436,7 +24810,7 @@ static __exception int js_define_var(JSParseState *s, JSAtom name, int tok)
&& (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)
+ if (name == JS_ATOM_let
&& (tok == TOK_LET || tok == TOK_CONST)) {
return js_parse_error(s, "invalid lexical variable name");
}
@@ -23506,6 +24880,25 @@ static int js_parse_check_duplicate_parameter(JSParseState *s, JSAtom name)
return js_parse_error(s, "duplicate parameter names not allowed in this context");
}
+/* tok = TOK_VAR, TOK_LET or TOK_CONST. Return whether a reference
+ must be taken to the variable for proper 'with' or global variable
+ evaluation */
+/* Note: this function is needed only because variable references are
+ not yet optimized in destructuring */
+static BOOL need_var_reference(JSParseState *s, int tok)
+{
+ JSFunctionDef *fd = s->cur_func;
+ if (tok != TOK_VAR)
+ return FALSE; /* no reference for let/const */
+ if (fd->js_mode & JS_MODE_STRICT) {
+ if (!fd->is_global_var)
+ return FALSE; /* local definitions in strict mode in function or direct eval */
+ if (s->is_module)
+ return FALSE; /* in a module global variables are like closure variables */
+ }
+ return TRUE;
+}
+
static JSAtom js_parse_destructuring_var(JSParseState *s, int tok, int is_arg)
{
JSAtom name;
@@ -23532,14 +24925,14 @@ static JSAtom js_parse_destructuring_var(JSParseState *s, int tok, int is_arg)
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)
+ BOOL allow_initializer, BOOL export_flag)
{
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);
@@ -23587,14 +24980,23 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
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;
+ if (need_var_reference(s, tok)) {
+ /* Must make a reference for proper `with` semantics */
+ emit_op(s, OP_scope_get_var);
+ emit_atom(s, var_name);
+ emit_u16(s, s->cur_func->scope_level);
+ JS_FreeAtom(s->ctx, var_name);
+ goto lvalue0;
+ } else {
+ 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;
-
+ lvalue0:
if (get_lvalue(s, &opcode, &scope, &var_name,
&label_lvalue, &depth_lvalue, FALSE, '{'))
return -1;
@@ -23612,10 +25014,6 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
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;
@@ -23648,7 +25046,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
emit_op(s, OP_get_field2);
emit_u32(s, prop_name);
}
- if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE) < 0)
+ if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE, export_flag) < 0)
return -1;
if (s->token.val == '}')
break;
@@ -23658,7 +25056,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
continue;
}
if (prop_name == JS_ATOM_NULL) {
- emit_op(s, OP_to_propkey2);
+ emit_op(s, OP_to_propkey);
if (has_ellipsis) {
/* define the property in excludeList */
emit_op(s, OP_perm3);
@@ -23684,10 +25082,24 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
var_name = js_parse_destructuring_var(s, tok, is_arg);
if (var_name == JS_ATOM_NULL)
goto prop_error;
+ if (need_var_reference(s, tok)) {
+ /* Must make a reference for proper `with` semantics */
+ emit_op(s, OP_scope_get_var);
+ emit_atom(s, var_name);
+ emit_u16(s, s->cur_func->scope_level);
+ JS_FreeAtom(s->ctx, var_name);
+ goto lvalue1;
+ } else {
+ /* no need to make a reference for let/const */
+ 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))
goto prop_error;
- lvalue:
+ lvalue1:
if (get_lvalue(s, &opcode, &scope, &var_name,
&label_lvalue, &depth_lvalue, FALSE, '{'))
goto prop_error;
@@ -23754,25 +25166,37 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
emit_atom(s, prop_name);
emit_op(s, OP_swap);
}
- if (!tok || tok == TOK_VAR) {
+ if (!tok || need_var_reference(s, tok)) {
/* 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;
+ goto lvalue1;
+ } else {
+ /* no need to make a reference for let/const */
+ var_name = JS_DupAtom(s->ctx, prop_name);
+ opcode = OP_scope_get_var;
+ scope = s->cur_func->scope_level;
+ label_lvalue = -1;
+ depth_lvalue = 0;
+
+ /* source -- source val */
+ emit_op(s, OP_get_field2);
+ emit_u32(s, prop_name);
}
- 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 (export_flag) {
+ if (!add_export_entry(s, s->cur_func->module, var_name, var_name,
+ JS_EXPORT_TYPE_LOCAL))
+ goto var_error;
+ }
+ scope = s->cur_func->scope_level; /* XXX: check */
}
if (s->token.val == '=') { /* handle optional default value */
int label_hasval;
@@ -23847,22 +25271,34 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
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)
+ if (js_parse_destructuring_element(s, tok, is_arg, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE, export_flag) < 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;
+ if (need_var_reference(s, tok)) {
+ /* Must make a reference for proper `with` semantics */
+ emit_op(s, OP_scope_get_var);
+ emit_atom(s, var_name);
+ emit_u16(s, s->cur_func->scope_level);
+ JS_FreeAtom(s->ctx, var_name);
+ goto lvalue2;
+ } else {
+ /* no need to make a reference for let/const */
+ opcode = OP_scope_get_var;
+ scope = s->cur_func->scope_level;
+ label_lvalue = -1;
+ enum_depth = 0;
+ }
} else {
if (js_parse_left_hand_side_expr(s))
return -1;
+ lvalue2:
if (get_lvalue(s, &opcode, &scope, &var_name,
&label_lvalue, &enum_depth, FALSE, '[')) {
return -1;
@@ -23972,12 +25408,13 @@ static void optional_chain_test(JSParseState *s, int *poptional_chaining_label,
emit_label(s, label_next);
}
-/* allowed parse_flags: PF_POSTFIX_CALL, PF_ARROW_FUNC */
+/* allowed parse_flags: PF_POSTFIX_CALL */
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;
+ const uint8_t *op_token_ptr;
call_type = FUNC_CALL_NORMAL;
switch(s->token.val) {
@@ -23989,34 +25426,17 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
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 if (JS_VALUE_GET_TAG(val) == JS_TAG_SHORT_BIG_INT) {
+ int64_t v;
+ v = JS_VALUE_GET_SHORT_BIG_INT(val);
+ if (v >= INT32_MIN && v <= INT32_MAX) {
+ emit_op(s, OP_push_bigint_i32);
+ emit_u32(s, v);
} 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;
+ goto large_number;
}
- emit_op(s, OP_mul_pow10);
- } else
-#endif
- {
+ } else {
+ large_number:
if (emit_push_const(s, val, 0) < 0)
return -1;
}
@@ -24034,7 +25454,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
if (next_token(s))
return -1;
break;
-
+
case TOK_DIV_ASSIGN:
s->buf_ptr -= 2;
goto parse_regexp;
@@ -24043,7 +25463,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
parse_regexp:
{
JSValue str;
- int ret, backtrace_flags;
+ int ret;
if (!s->ctx->compile_regexp)
return js_parse_error(s, "RegExp are not supported");
/* the previous token is '/' or '/=', so no need to free */
@@ -24054,12 +25474,10 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
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;
+ int line_num, col_num;
+ line_num = get_line_col(&col_num, s->buf_start, s->token.ptr - s->buf_start);
build_backtrace(s->ctx, s->ctx->rt->current_exception,
- s->filename, s->token.line_num,
- backtrace_flags);
+ s->filename, line_num + 1, col_num + 1, 0);
return -1;
}
ret = emit_push_const(s, str, 0);
@@ -24075,21 +25493,13 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
}
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;
- }
+ 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))
+ s->token.ptr))
return -1;
break;
case TOK_CLASS:
@@ -24121,37 +25531,19 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
case TOK_IDENT:
{
JSAtom name;
+ const uint8_t *source_ptr;
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;
+ source_ptr = s->token.ptr;
+ if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
+ peek_token(s, TRUE) != '\n') {
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))
+ source_ptr))
return -1;
} else {
name = JS_DupAtom(s->ctx, JS_ATOM_async);
@@ -24164,9 +25556,12 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
return -1;
}
name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
- if (next_token(s)) /* update line number before emitting code */
+ if (next_token(s)) {
+ JS_FreeAtom(s->ctx, name);
return -1;
+ }
do_get_var:
+ emit_source_pos(s, source_ptr);
emit_op(s, OP_scope_get_var);
emit_u32(s, name);
emit_u16(s, s->cur_func->scope_level);
@@ -24175,20 +25570,12 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
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;
- }
- }
+ 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:
@@ -24212,6 +25599,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
accept_lparen = TRUE;
if (s->token.val != '(') {
/* new operator on an object */
+ emit_source_pos(s, s->token.ptr);
emit_op(s, OP_dup);
emit_op(s, OP_call_constructor);
emit_u16(s, 0);
@@ -24262,6 +25650,23 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
return js_parse_error(s, "invalid use of 'import()'");
if (js_parse_assign_expr(s))
return -1;
+ if (s->token.val == ',') {
+ if (next_token(s))
+ return -1;
+ if (s->token.val != ')') {
+ if (js_parse_assign_expr(s))
+ return -1;
+ /* accept a trailing comma */
+ if (s->token.val == ',') {
+ if (next_token(s))
+ return -1;
+ }
+ } else {
+ emit_op(s, OP_undefined);
+ }
+ } else {
+ emit_op(s, OP_undefined);
+ }
if (js_parse_expect(s, ')'))
return -1;
emit_op(s, OP_import);
@@ -24276,8 +25681,11 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
for(;;) {
JSFunctionDef *fd = s->cur_func;
BOOL has_optional_chain = FALSE;
-
+
if (s->token.val == TOK_QUESTION_MARK_DOT) {
+ if ((parse_flags & PF_POSTFIX_CALL) == 0)
+ return js_parse_error(s, "new keyword cannot be used with an optional chain");
+ op_token_ptr = s->token.ptr;
/* optional chaining */
if (next_token(s))
return -1;
@@ -24295,12 +25703,14 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
return js_parse_error(s, "template literal cannot appear in an optional chain");
}
call_type = FUNC_CALL_TEMPLATE;
+ op_token_ptr = s->token.ptr; /* XXX: check if right position */
goto parse_func_call2;
} else if (s->token.val == '(' && accept_lparen) {
int opcode, arg_count, drop_count;
/* function call */
parse_func_call:
+ op_token_ptr = s->token.ptr;
if (next_token(s))
return -1;
@@ -24312,6 +25722,25 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
drop_count = 2;
break;
+ case OP_get_field_opt_chain:
+ {
+ int opt_chain_label, next_label;
+ opt_chain_label = get_u32(fd->byte_code.buf +
+ fd->last_opcode_pos + 1 + 4 + 1);
+ /* keep the object on the stack */
+ fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
+ fd->byte_code.size = fd->last_opcode_pos + 1 + 4;
+ next_label = emit_goto(s, OP_goto, -1);
+ emit_label(s, opt_chain_label);
+ /* need an additional undefined value for the
+ case where the optional field does not
+ exists */
+ emit_op(s, OP_undefined);
+ emit_label(s, next_label);
+ drop_count = 2;
+ opcode = OP_get_field;
+ }
+ 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;
@@ -24322,6 +25751,25 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;
drop_count = 2;
break;
+ case OP_get_array_el_opt_chain:
+ {
+ int opt_chain_label, next_label;
+ opt_chain_label = get_u32(fd->byte_code.buf +
+ fd->last_opcode_pos + 1 + 1);
+ /* keep the object on the stack */
+ fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;
+ fd->byte_code.size = fd->last_opcode_pos + 1;
+ next_label = emit_goto(s, OP_goto, -1);
+ emit_label(s, opt_chain_label);
+ /* need an additional undefined value for the
+ case where the optional field does not
+ exists */
+ emit_op(s, OP_undefined);
+ emit_label(s, next_label);
+ drop_count = 2;
+ opcode = OP_get_array_el;
+ }
+ break;
case OP_scope_get_var:
{
JSAtom name;
@@ -24461,6 +25909,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
/* drop the index */
emit_op(s, OP_drop);
+ emit_source_pos(s, op_token_ptr);
/* apply function call */
switch(opcode) {
case OP_get_field:
@@ -24506,6 +25955,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
if (next_token(s))
return -1;
emit_func_call:
+ emit_source_pos(s, op_token_ptr);
switch(opcode) {
case OP_get_field:
case OP_scope_get_private_field:
@@ -24544,9 +25994,11 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
}
call_type = FUNC_CALL_NORMAL;
} else if (s->token.val == '.') {
+ op_token_ptr = s->token.ptr;
if (next_token(s))
return -1;
parse_property:
+ emit_source_pos(s, op_token_ptr);
if (s->token.val == TOK_PRIVATE_NAME) {
/* private class field */
if (get_prev_opcode(fd) == OP_get_super) {
@@ -24583,7 +26035,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
return -1;
} else if (s->token.val == '[') {
int prev_op;
-
+ op_token_ptr = s->token.ptr;
parse_array_access:
prev_op = get_prev_opcode(fd);
if (has_optional_chain) {
@@ -24595,6 +26047,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
return -1;
if (js_parse_expect(s, ']'))
return -1;
+ emit_source_pos(s, op_token_ptr);
if (prev_op == OP_get_super) {
emit_op(s, OP_get_super_value);
} else {
@@ -24604,8 +26057,23 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
break;
}
}
- if (optional_chaining_label >= 0)
- emit_label(s, optional_chaining_label);
+ if (optional_chaining_label >= 0) {
+ JSFunctionDef *fd = s->cur_func;
+ int opcode;
+ emit_label_raw(s, optional_chaining_label);
+ /* modify the last opcode so that it is an indicator of an
+ optional chain */
+ opcode = get_prev_opcode(fd);
+ if (opcode == OP_get_field || opcode == OP_get_array_el) {
+ if (opcode == OP_get_field)
+ opcode = OP_get_field_opt_chain;
+ else
+ opcode = OP_get_array_el_opt_chain;
+ fd->byte_code.buf[fd->last_opcode_pos] = opcode;
+ } else {
+ fd->last_opcode_pos = -1;
+ }
+ }
return 0;
}
@@ -24621,27 +26089,57 @@ static __exception int js_parse_delete(JSParseState *s)
return -1;
switch(opcode = get_prev_opcode(fd)) {
case OP_get_field:
+ case OP_get_field_opt_chain:
{
JSValue val;
- int ret;
-
+ int ret, opt_chain_label, next_label;
+ if (opcode == OP_get_field_opt_chain) {
+ opt_chain_label = get_u32(fd->byte_code.buf +
+ fd->last_opcode_pos + 1 + 4 + 1);
+ } else {
+ opt_chain_label = -1;
+ }
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;
+ emit_op(s, OP_delete);
+ if (opt_chain_label >= 0) {
+ next_label = emit_goto(s, OP_goto, -1);
+ emit_label(s, opt_chain_label);
+ /* if the optional chain is not taken, return 'true' */
+ emit_op(s, OP_drop);
+ emit_op(s, OP_push_true);
+ emit_label(s, next_label);
+ }
+ fd->last_opcode_pos = -1;
}
- goto do_delete;
+ break;
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_get_array_el_opt_chain:
+ {
+ int opt_chain_label, next_label;
+ opt_chain_label = get_u32(fd->byte_code.buf +
+ fd->last_opcode_pos + 1 + 1);
+ fd->byte_code.size = fd->last_opcode_pos;
+ emit_op(s, OP_delete);
+ next_label = emit_goto(s, OP_goto, -1);
+ emit_label(s, opt_chain_label);
+ /* if the optional chain is not taken, return 'true' */
+ emit_op(s, OP_drop);
+ emit_op(s, OP_push_true);
+ emit_label(s, next_label);
+ fd->last_opcode_pos = -1;
+ }
+ 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);
@@ -24671,10 +26169,11 @@ static __exception int js_parse_delete(JSParseState *s)
return 0;
}
-/* allowed parse_flags: PF_ARROW_FUNC, PF_POW_ALLOWED, PF_POW_FORBIDDEN */
+/* allowed parse_flags: PF_POW_ALLOWED, PF_POW_FORBIDDEN */
static __exception int js_parse_unary(JSParseState *s, int parse_flags)
{
int op;
+ const uint8_t *op_token_ptr;
switch(s->token.val) {
case '+':
@@ -24682,6 +26181,7 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags)
case '!':
case '~':
case TOK_VOID:
+ op_token_ptr = s->token.ptr;
op = s->token.val;
if (next_token(s))
return -1;
@@ -24689,15 +26189,18 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags)
return -1;
switch(op) {
case '-':
+ emit_source_pos(s, op_token_ptr);
emit_op(s, OP_neg);
break;
case '+':
+ emit_source_pos(s, op_token_ptr);
emit_op(s, OP_plus);
break;
case '!':
emit_op(s, OP_lnot);
break;
case '~':
+ emit_source_pos(s, op_token_ptr);
emit_op(s, OP_not);
break;
case TOK_VOID:
@@ -24715,12 +26218,14 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags)
int opcode, op, scope, label;
JSAtom name;
op = s->token.val;
+ op_token_ptr = s->token.ptr;
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_source_pos(s, op_token_ptr);
emit_op(s, OP_dec + op - TOK_DEC);
put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP,
FALSE);
@@ -24757,47 +26262,31 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags)
return -1;
if (js_parse_unary(s, PF_POW_FORBIDDEN))
return -1;
+ s->cur_func->has_await = TRUE;
emit_op(s, OP_await);
parse_flags = 0;
break;
default:
- if (js_parse_postfix_expr(s, (parse_flags & PF_ARROW_FUNC) |
- PF_POSTFIX_CALL))
+ if (js_parse_postfix_expr(s, 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;
+ op_token_ptr = s->token.ptr;
if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))
return -1;
+ emit_source_pos(s, op_token_ptr);
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;
+ 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
@@ -24808,31 +26297,56 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags)
JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'");
return -1;
}
+ op_token_ptr = s->token.ptr;
if (next_token(s))
return -1;
if (js_parse_unary(s, PF_POW_ALLOWED))
return -1;
+ emit_source_pos(s, op_token_ptr);
emit_op(s, OP_pow);
}
-#endif
}
return 0;
}
-/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
+/* allowed parse_flags: PF_IN_ACCEPTED */
static __exception int js_parse_expr_binary(JSParseState *s, int level,
int parse_flags)
{
int op, opcode;
-
+ const uint8_t *op_token_ptr;
+
if (level == 0) {
- return js_parse_unary(s, (parse_flags & PF_ARROW_FUNC) |
- PF_POW_ALLOWED);
+ return js_parse_unary(s, PF_POW_ALLOWED);
+ } else if (s->token.val == TOK_PRIVATE_NAME &&
+ (parse_flags & PF_IN_ACCEPTED) && level == 4 &&
+ peek_token(s, FALSE) == TOK_IN) {
+ JSAtom atom;
+
+ atom = JS_DupAtom(s->ctx, s->token.u.ident.atom);
+ if (next_token(s))
+ goto fail_private_in;
+ if (s->token.val != TOK_IN)
+ goto fail_private_in;
+ if (next_token(s))
+ goto fail_private_in;
+ if (js_parse_expr_binary(s, level - 1, parse_flags)) {
+ fail_private_in:
+ JS_FreeAtom(s->ctx, atom);
+ return -1;
+ }
+ emit_op(s, OP_scope_in_private_field);
+ emit_atom(s, atom);
+ emit_u16(s, s->cur_func->scope_level);
+ JS_FreeAtom(s->ctx, atom);
+ return 0;
+ } else {
+ if (js_parse_expr_binary(s, level - 1, parse_flags))
+ return -1;
}
- if (js_parse_expr_binary(s, level - 1, parse_flags))
- return -1;
for(;;) {
op = s->token.val;
+ op_token_ptr = s->token.ptr;
switch(level) {
case 1:
switch(op) {
@@ -24843,12 +26357,7 @@ static __exception int js_parse_expr_binary(JSParseState *s, int level,
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;
+ opcode = OP_mod;
break;
default:
return 0;
@@ -24959,14 +26468,15 @@ static __exception int js_parse_expr_binary(JSParseState *s, int level,
}
if (next_token(s))
return -1;
- if (js_parse_expr_binary(s, level - 1, parse_flags & ~PF_ARROW_FUNC))
+ if (js_parse_expr_binary(s, level - 1, parse_flags))
return -1;
+ emit_source_pos(s, op_token_ptr);
emit_op(s, opcode);
}
return 0;
}
-/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
+/* allowed parse_flags: PF_IN_ACCEPTED */
static __exception int js_parse_logical_and_or(JSParseState *s, int op,
int parse_flags)
{
@@ -24990,11 +26500,11 @@ static __exception int js_parse_logical_and_or(JSParseState *s, int op,
emit_op(s, OP_drop);
if (op == TOK_LAND) {
- if (js_parse_expr_binary(s, 8, parse_flags & ~PF_ARROW_FUNC))
+ if (js_parse_expr_binary(s, 8, parse_flags))
return -1;
} else {
if (js_parse_logical_and_or(s, TOK_LAND,
- parse_flags & ~PF_ARROW_FUNC))
+ parse_flags))
return -1;
}
if (s->token.val != op) {
@@ -25012,7 +26522,7 @@ static __exception int js_parse_logical_and_or(JSParseState *s, int op,
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) {
@@ -25020,13 +26530,13 @@ static __exception int js_parse_coalesce_expr(JSParseState *s, int parse_flags)
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))
+
+ if (js_parse_expr_binary(s, 8, parse_flags))
return -1;
if (s->token.val != TOK_DOUBLE_QUESTION_MARK)
break;
@@ -25036,7 +26546,7 @@ static __exception int js_parse_coalesce_expr(JSParseState *s, int parse_flags)
return 0;
}
-/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
+/* allowed parse_flags: PF_IN_ACCEPTED */
static __exception int js_parse_cond_expr(JSParseState *s, int parse_flags)
{
int label1, label2;
@@ -25065,18 +26575,16 @@ static __exception int js_parse_cond_expr(JSParseState *s, int parse_flags)
return 0;
}
-static void emit_return(JSParseState *s, BOOL hasval);
-
/* allowed parse_flags: PF_IN_ACCEPTED */
static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
{
- int opcode, op, scope;
+ int opcode, op, scope, skip_bits;
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)
@@ -25114,9 +26622,9 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
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)
@@ -25130,7 +26638,6 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
/* 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 */
@@ -25140,13 +26647,13 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
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);
@@ -25162,13 +26669,13 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
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);
@@ -25193,7 +26700,7 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
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);
@@ -25203,7 +26710,7 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
emit_op(s, OP_nip);
} else {
int label_next;
-
+
if (is_async)
emit_op(s, OP_await);
emit_op(s, OP_yield);
@@ -25212,17 +26719,61 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
emit_label(s, label_next);
}
return 0;
+ } else if (s->token.val == '(' &&
+ js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) {
+ return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
+ JS_FUNC_NORMAL, JS_ATOM_NULL,
+ s->token.ptr);
+ } else if (token_is_pseudo_keyword(s, JS_ATOM_async)) {
+ const uint8_t *source_ptr;
+ int tok;
+ JSParsePos pos;
+
+ /* fast test */
+ tok = peek_token(s, TRUE);
+ if (tok == TOK_FUNCTION || tok == '\n')
+ goto next;
+
+ source_ptr = s->token.ptr;
+ js_parse_get_pos(s, &pos);
+ if (next_token(s))
+ return -1;
+ if ((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)) {
+ return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
+ JS_FUNC_ASYNC, JS_ATOM_NULL,
+ source_ptr);
+ } else {
+ /* undo the token parsing */
+ if (js_parse_seek_token(s, &pos))
+ return -1;
+ }
+ } else if (s->token.val == TOK_IDENT &&
+ peek_token(s, TRUE) == TOK_ARROW) {
+ return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
+ JS_FUNC_NORMAL, JS_ATOM_NULL,
+ s->token.ptr);
+ } else if ((s->token.val == '{' || s->token.val == '[') &&
+ js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
+ if (js_parse_destructuring_element(s, 0, 0, FALSE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE, FALSE) < 0)
+ return -1;
+ return 0;
}
+ next:
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))
+ if (js_parse_cond_expr(s, parse_flags))
return -1;
op = s->token.val;
if (op == '=' || (op >= TOK_MUL_ASSIGN && op <= TOK_POW_ASSIGN)) {
int label;
+ const uint8_t *op_token_ptr;
+ op_token_ptr = s->token.ptr;
if (next_token(s))
return -1;
if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, (op != '='), op) < 0)
@@ -25241,24 +26792,16 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
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_source_pos(s, op_token_ptr);
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,
@@ -25271,7 +26814,7 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
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;
@@ -25280,7 +26823,7 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
if (opcode == OP_get_ref_value && name == name0) {
set_object_name(s, name);
}
-
+
switch(depth_lvalue) {
case 1:
emit_op(s, OP_insert2);
@@ -25300,7 +26843,7 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
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 */
@@ -25363,6 +26906,7 @@ static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
be->label_finally = -1;
be->scope_level = fd->scope_level;
be->has_iterator = FALSE;
+ be->is_regular_stmt = FALSE;
}
static void pop_break_entry(JSFunctionDef *fd)
@@ -25391,7 +26935,8 @@ static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont)
}
if (!is_cont &&
top->label_break != -1 &&
- (name == JS_ATOM_NULL || top->label_name == name)) {
+ ((name == JS_ATOM_NULL && !top->is_regular_stmt) ||
+ top->label_name == name)) {
emit_goto(s, OP_goto, top->label_break);
return 0;
}
@@ -25424,61 +26969,61 @@ static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont)
static void emit_return(JSParseState *s, BOOL hasval)
{
BlockEnv *top;
- int drop_count;
- drop_count = 0;
+ if (s->cur_func->func_kind != JS_FUNC_NORMAL) {
+ if (!hasval) {
+ /* no value: direct return in case of async generator */
+ emit_op(s, OP_undefined);
+ hasval = TRUE;
+ } else if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
+ /* the await must be done before handling the "finally" in
+ case it raises an exception */
+ emit_op(s, OP_await);
+ }
+ }
+
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 (top->has_iterator || top->label_finally != -1) {
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);
+ /* Remove the stack elements up to and including the catch
+ offset. When 'yield' is used in an expression we have
+ no easy way to count them, so we use this specific
+ instruction instead. */
+ emit_op(s, OP_nip_catch);
+ /* stack: iter_obj next ret_val */
+ if (top->has_iterator) {
+ if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
+ int label_next, label_next2;
+ emit_op(s, OP_nip); /* next */
+ emit_op(s, OP_swap);
+ 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_rot3r);
+ emit_op(s, OP_undefined); /* dummy catch offset */
+ emit_op(s, OP_iterator_close);
+ }
} 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;
+ /* execute the "finally" block */
+ emit_goto(s, OP_gosub, top->label_finally);
}
- emit_goto(s, OP_gosub, top->label_finally);
}
top = top->prev;
}
@@ -25495,20 +27040,15 @@ static void emit_return(JSParseState *s, BOOL hasval)
label_return = -1;
}
- /* XXX: if this is not initialized, should throw the
- ReferenceError in the caller realm */
- emit_op(s, OP_scope_get_var);
+ /* The error should be raised in the caller context, so we use
+ a specific opcode */
+ emit_op(s, OP_scope_get_var_checkthis);
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);
@@ -25579,7 +27119,7 @@ static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
if (s->token.val == '=') {
if (next_token(s))
goto var_error;
- if (tok == TOK_VAR) {
+ if (need_var_reference(s, tok)) {
/* Must make a reference for proper `with` semantics */
int opcode, scope, label;
JSAtom name1;
@@ -25624,7 +27164,7 @@ static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
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)
+ if (js_parse_destructuring_element(s, tok, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE, export_flag) < 0)
return -1;
} else {
return js_parse_error(s, "variable name expected");
@@ -25653,12 +27193,13 @@ static BOOL is_label(JSParseState *s)
static int is_let(JSParseState *s, int decl_mask)
{
int res = FALSE;
-
+ const uint8_t *last_token_ptr;
+
if (token_is_pseudo_keyword(s, JS_ATOM_let)) {
-#if 1
JSParsePos pos;
js_parse_get_pos(s, &pos);
for (;;) {
+ last_token_ptr = s->token.ptr;
if (next_token(s)) {
res = -1;
break;
@@ -25677,7 +27218,8 @@ static int is_let(JSParseState *s, int decl_mask)
/* 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)) {
+ if (!has_lf_in_range(last_token_ptr, s->token.ptr) ||
+ (decl_mask & DECL_MASK_OTHER)) {
res = TRUE;
break;
}
@@ -25688,12 +27230,6 @@ static int is_let(JSParseState *s, int decl_mask)
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;
}
@@ -25753,7 +27289,7 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
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)
+ if (js_parse_destructuring_element(s, tok, 0, TRUE, -1, FALSE, FALSE) < 0)
return -1;
has_destructuring = TRUE;
} else {
@@ -25775,11 +27311,14 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
emit_atom(s, var_name);
emit_u16(s, fd->scope_level);
}
+ } else if (!is_async && token_is_pseudo_keyword(s, JS_ATOM_async) &&
+ peek_token(s, FALSE) == TOK_OF) {
+ return js_parse_error(s, "'for of' expression cannot start with 'async'");
} 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)
+ if (js_parse_destructuring_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE, FALSE) < 0)
return -1;
} else {
int lvalue_label;
@@ -25888,12 +27427,9 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
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);
+ /* call the next method */
+ emit_op(s, OP_for_await_of_next);
/* get the result of the promise */
emit_op(s, OP_await);
/* unwrap the value and done values */
@@ -25967,6 +27503,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
label_break = new_label(s);
push_break_entry(s->cur_func, &break_entry,
label_name, label_break, -1, 0);
+ break_entry.is_regular_stmt = TRUE;
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;
@@ -25987,34 +27524,49 @@ static __exception int js_parse_statement_or_decl(JSParseState *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))
+ {
+ const uint8_t *op_token_ptr;
+ if (s->cur_func->is_eval) {
+ js_parse_error(s, "return not in a function");
+ goto fail;
+ }
+ if (s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) {
+ js_parse_error(s, "return in a static initializer block");
+ goto fail;
+ }
+ op_token_ptr = s->token.ptr;
+ if (next_token(s))
+ goto fail;
+ if (s->token.val != ';' && s->token.val != '}' && !s->got_lf) {
+ if (js_parse_expr(s))
+ goto fail;
+ emit_source_pos(s, op_token_ptr);
+ emit_return(s, TRUE);
+ } else {
+ emit_source_pos(s, op_token_ptr);
+ emit_return(s, FALSE);
+ }
+ if (js_parse_expect_semi(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;
+ {
+ const uint8_t *op_token_ptr;
+ op_token_ptr = s->token.ptr;
+ 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_source_pos(s, op_token_ptr);
+ emit_op(s, OP_throw);
+ if (js_parse_expect_semi(s))
+ 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:
@@ -26159,6 +27711,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
is_async = TRUE;
if (next_token(s))
goto fail;
+ s->cur_func->has_await = TRUE;
}
if (js_parse_expect(s, '('))
goto fail;
@@ -26451,7 +28004,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
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)
+ if (js_parse_destructuring_element(s, TOK_LET, 0, TRUE, -1, TRUE, FALSE) < 0)
goto fail;
} else {
js_parse_error(s, "identifier expected");
@@ -26518,7 +28071,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
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 */
@@ -26538,7 +28091,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
emit_u16(s, saved_eval_ret_idx);
set_eval_ret_undefined(s);
}
-
+
if (js_parse_block(s))
goto fail;
@@ -26621,7 +28174,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
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))
+ s->token.ptr))
goto fail;
break;
}
@@ -26643,7 +28196,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
if (js_parse_expect_semi(s))
goto fail;
break;
-
+
case TOK_ENUM:
case TOK_EXPORT:
case TOK_EXTENDS:
@@ -26652,6 +28205,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
default:
hasexpr:
+ emit_source_pos(s, s->token.ptr);
if (js_parse_expr(s))
goto fail;
if (s->cur_func->eval_ret_idx >= 0) {
@@ -26689,6 +28243,10 @@ static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name)
m->func_obj = JS_UNDEFINED;
m->eval_exception = JS_UNDEFINED;
m->meta_obj = JS_UNDEFINED;
+ m->promise = JS_UNDEFINED;
+ m->resolving_funcs[0] = JS_UNDEFINED;
+ m->resolving_funcs[1] = JS_UNDEFINED;
+ m->private_value = JS_UNDEFINED;
list_add_tail(&m->link, &ctx->loaded_modules);
return m;
}
@@ -26698,6 +28256,11 @@ static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
{
int i;
+ for(i = 0; i < m->req_module_entries_count; i++) {
+ JSReqModuleEntry *rme = &m->req_module_entries[i];
+ JS_MarkValue(rt, rme->attributes, mark_func);
+ }
+
for(i = 0; i < m->export_entries_count; i++) {
JSExportEntry *me = &m->export_entries[i];
if (me->export_type == JS_EXPORT_TYPE_LOCAL &&
@@ -26710,6 +28273,10 @@ static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
JS_MarkValue(rt, m->func_obj, mark_func);
JS_MarkValue(rt, m->eval_exception, mark_func);
JS_MarkValue(rt, m->meta_obj, mark_func);
+ JS_MarkValue(rt, m->promise, mark_func);
+ JS_MarkValue(rt, m->resolving_funcs[0], mark_func);
+ JS_MarkValue(rt, m->resolving_funcs[1], mark_func);
+ JS_MarkValue(rt, m->private_value, mark_func);
}
static void js_free_module_def(JSContext *ctx, JSModuleDef *m)
@@ -26721,6 +28288,7 @@ static void js_free_module_def(JSContext *ctx, JSModuleDef *m)
for(i = 0; i < m->req_module_entries_count; i++) {
JSReqModuleEntry *rme = &m->req_module_entries[i];
JS_FreeAtom(ctx, rme->module_name);
+ JS_FreeValue(ctx, rme->attributes);
}
js_free(ctx, m->req_module_entries);
@@ -26740,11 +28308,16 @@ static void js_free_module_def(JSContext *ctx, JSModuleDef *m)
JS_FreeAtom(ctx, mi->import_name);
}
js_free(ctx, m->import_entries);
+ js_free(ctx, m->async_parent_modules);
JS_FreeValue(ctx, m->module_ns);
JS_FreeValue(ctx, m->func_obj);
JS_FreeValue(ctx, m->eval_exception);
JS_FreeValue(ctx, m->meta_obj);
+ JS_FreeValue(ctx, m->promise);
+ JS_FreeValue(ctx, m->resolving_funcs[0]);
+ JS_FreeValue(ctx, m->resolving_funcs[1]);
+ JS_FreeValue(ctx, m->private_value);
list_del(&m->link);
js_free(ctx, m);
}
@@ -26753,14 +28326,6 @@ 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),
@@ -26770,7 +28335,8 @@ static int add_req_module_entry(JSContext *ctx, JSModuleDef *m,
rme = &m->req_module_entries[m->req_module_entries_count++];
rme->module_name = JS_DupAtom(ctx, module_name);
rme->module = NULL;
- return i;
+ rme->attributes = JS_UNDEFINED;
+ return m->req_module_entries_count - 1;
}
static JSExportEntry *find_export_entry(JSContext *ctx, JSModuleDef *m,
@@ -26850,6 +28416,8 @@ JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str,
if (name == JS_ATOM_NULL)
return NULL;
m = js_new_module_def(ctx, name);
+ if (!m)
+ return NULL;
m->init_func = func;
return m;
}
@@ -26889,12 +28457,38 @@ int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name,
return -1;
}
+int JS_SetModulePrivateValue(JSContext *ctx, JSModuleDef *m, JSValue val)
+{
+ set_value(ctx, &m->private_value, val);
+ return 0;
+}
+
+JSValue JS_GetModulePrivateValue(JSContext *ctx, JSModuleDef *m)
+{
+ return JS_DupValue(ctx, m->private_value);
+}
+
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_has_attr = FALSE;
+ rt->u.module_loader_func = module_loader;
+ rt->module_check_attrs = NULL;
+ rt->module_loader_opaque = opaque;
+}
+
+void JS_SetModuleLoaderFunc2(JSRuntime *rt,
+ JSModuleNormalizeFunc *module_normalize,
+ JSModuleLoaderFunc2 *module_loader,
+ JSModuleCheckSupportedImportAttributes *module_check_attrs,
+ void *opaque)
+{
+ rt->module_normalize_func = module_normalize;
+ rt->module_loader_has_attr = TRUE;
+ rt->u.module_loader_func2 = module_loader;
+ rt->module_check_attrs = module_check_attrs;
rt->module_loader_opaque = opaque;
}
@@ -26905,6 +28499,7 @@ static char *js_default_module_normalize_name(JSContext *ctx,
{
char *filename, *p;
const char *r;
+ int cap;
int len;
if (name[0] != '.') {
@@ -26918,7 +28513,8 @@ static char *js_default_module_normalize_name(JSContext *ctx,
else
len = 0;
- filename = js_malloc(ctx, len + strlen(name) + 1 + 1);
+ cap = len + strlen(name) + 1 + 1;
+ filename = js_malloc(ctx, cap);
if (!filename)
return NULL;
memcpy(filename, base_name, len);
@@ -26950,8 +28546,8 @@ static char *js_default_module_normalize_name(JSContext *ctx,
}
}
if (filename[0] != '\0')
- strcat(filename, "/");
- strcat(filename, r);
+ pstrcat(filename, cap, "/");
+ pstrcat(filename, cap, r);
// printf("normalize: %s %s -> %s\n", base_name, name, filename);
return filename;
}
@@ -26960,7 +28556,7 @@ static 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);
@@ -26973,7 +28569,8 @@ static JSModuleDef *js_find_loaded_module(JSContext *ctx, JSAtom name)
/* 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)
+ const char *cname1,
+ JSValueConst attributes)
{
JSRuntime *rt = ctx->rt;
JSModuleDef *m;
@@ -27006,26 +28603,30 @@ static JSModuleDef *js_host_resolve_imported_module(JSContext *ctx,
JS_FreeAtom(ctx, module_name);
/* load the module */
- if (!rt->module_loader_func) {
+ if (!rt->u.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);
+ if (rt->module_loader_has_attr) {
+ m = rt->u.module_loader_func2(ctx, cname, rt->module_loader_opaque, attributes);
+ } else {
+ m = rt->u.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)
+ JSAtom base_module_name,
+ JSAtom module_name1,
+ JSValueConst attributes)
{
const char *base_cname, *cname;
JSModuleDef *m;
-
+
base_cname = JS_AtomToCString(ctx, base_module_name);
if (!base_cname)
return NULL;
@@ -27034,7 +28635,7 @@ static JSModuleDef *js_host_resolve_imported_module_atom(JSContext *ctx,
JS_FreeCString(ctx, base_cname);
return NULL;
}
- m = js_host_resolve_imported_module(ctx, base_cname, cname);
+ m = js_host_resolve_imported_module(ctx, base_cname, cname, attributes);
JS_FreeCString(ctx, base_cname);
JS_FreeCString(ctx, cname);
return m;
@@ -27218,7 +28819,7 @@ static void js_resolve_export_throw_error(JSContext *ctx,
typedef enum {
EXPORTED_NAME_AMBIGUOUS,
EXPORTED_NAME_NORMAL,
- EXPORTED_NAME_NS,
+ EXPORTED_NAME_DELAYED,
} ExportedNameEntryEnum;
typedef struct ExportedNameEntry {
@@ -27227,7 +28828,6 @@ typedef struct ExportedNameEntry {
union {
JSExportEntry *me; /* using when the list is built */
JSVarRef *var_ref; /* EXPORTED_NAME_NORMAL */
- JSModuleDef *module; /* for EXPORTED_NAME_NS */
} u;
} ExportedNameEntry;
@@ -27333,13 +28933,33 @@ static int exported_names_cmp(const void *p1, const void *p2, void *opaque)
return ret;
}
-static JSValue js_get_module_ns(JSContext *ctx, JSModuleDef *m);
-
static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
void *opaque)
{
JSModuleDef *m = opaque;
- return js_get_module_ns(ctx, m);
+ JSResolveResultEnum res;
+ JSExportEntry *res_me;
+ JSModuleDef *res_m;
+ JSVarRef *var_ref;
+
+ res = js_resolve_export(ctx, &res_m, &res_me, m, atom);
+ if (res != JS_RESOLVE_RES_FOUND) {
+ /* fail safe: normally no error should happen here except for memory */
+ js_resolve_export_throw_error(ctx, res, m, atom);
+ return JS_EXCEPTION;
+ }
+ if (res_me->local_name == JS_ATOM__star_) {
+ return JS_GetModuleNamespace(ctx, res_m->req_module_entries[res_me->u.req_module_idx].module);
+ } else {
+ if (res_me->u.local.var_ref) {
+ var_ref = res_me->u.local.var_ref;
+ } else {
+ JSObject *p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
+ var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
+ }
+ /* WARNING: a varref is returned as a string ! */
+ return JS_MKPTR(JS_TAG_STRING, var_ref);
+ }
}
static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m)
@@ -27384,17 +29004,18 @@ static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m)
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;
+ en->export_type = EXPORTED_NAME_DELAYED;
} 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];
}
+ if (en->u.var_ref == NULL)
+ en->export_type = EXPORTED_NAME_DELAYED;
+ else
+ en->export_type = EXPORTED_NAME_NORMAL;
}
}
}
@@ -27418,13 +29039,13 @@ static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m)
pr->u.var_ref = var_ref;
}
break;
- case EXPORTED_NAME_NS:
- /* the exported namespace must be created on demand */
+ case EXPORTED_NAME_DELAYED:
+ /* the exported namespace or reference may depend on
+ circular references, so we resolve it lazily */
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;
+ m, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
break;
default:
break;
@@ -27445,7 +29066,7 @@ static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m)
return JS_EXCEPTION;
}
-static JSValue js_get_module_ns(JSContext *ctx, JSModuleDef *m)
+JSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m)
{
if (JS_IsUndefined(m->module_ns)) {
JSValue val;
@@ -27476,7 +29097,8 @@ static int js_resolve_module(JSContext *ctx, JSModuleDef *m)
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);
+ rme->module_name,
+ rme->attributes);
if (!m1)
return -1;
rme->module = m1;
@@ -27563,7 +29185,7 @@ 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;
@@ -27587,7 +29209,7 @@ static int js_create_module_function(JSContext *ctx, JSModuleDef *m)
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)
@@ -27595,12 +29217,13 @@ static int js_create_module_function(JSContext *ctx, JSModuleDef *m)
}
return 0;
-}
+}
+
-
/* Prepare a module to be executed by resolving all the imported
variables. */
-static int js_link_module(JSContext *ctx, JSModuleDef *m)
+static int js_inner_module_linking(JSContext *ctx, JSModuleDef *m,
+ JSModuleDef **pstack_top, int index)
{
int i;
JSImportEntry *mi;
@@ -27609,22 +29232,48 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m)
JSObject *p;
BOOL is_c_module;
JSValue ret_val;
-
- if (m->instantiated)
- return 0;
- m->instantiated = TRUE;
+
+ if (js_check_stack_overflow(ctx->rt, 0)) {
+ JS_ThrowStackOverflow(ctx);
+ return -1;
+ }
#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));
+ printf("js_inner_module_linking '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
}
#endif
+ if (m->status == JS_MODULE_STATUS_LINKING ||
+ m->status == JS_MODULE_STATUS_LINKED ||
+ m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m->status == JS_MODULE_STATUS_EVALUATED)
+ return index;
+
+ assert(m->status == JS_MODULE_STATUS_UNLINKED);
+ m->status = JS_MODULE_STATUS_LINKING;
+ m->dfs_index = index;
+ m->dfs_ancestor_index = index;
+ index++;
+ /* push 'm' on stack */
+ m->stack_prev = *pstack_top;
+ *pstack_top = m;
+
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)
+ m1 = rme->module;
+ index = js_inner_module_linking(ctx, m1, pstack_top, index);
+ if (index < 0)
goto fail;
+ assert(m1->status == JS_MODULE_STATUS_LINKING ||
+ m1->status == JS_MODULE_STATUS_LINKED ||
+ m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m1->status == JS_MODULE_STATUS_EVALUATED);
+ if (m1->status == JS_MODULE_STATUS_LINKING) {
+ m->dfs_ancestor_index = min_int(m->dfs_ancestor_index,
+ m1->dfs_ancestor_index);
+ }
}
#ifdef DUMP_MODULE_RESOLVE
@@ -27676,10 +29325,10 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m)
printf(": ");
#endif
m1 = m->req_module_entries[mi->req_module_idx].module;
- if (mi->import_name == JS_ATOM__star_) {
+ if (mi->is_star) {
JSValue val;
/* name space import */
- val = js_get_module_ns(ctx, m1);
+ val = JS_GetModuleNamespace(ctx, m1);
if (JS_IsException(val))
goto fail;
set_value(ctx, &var_refs[mi->var_idx]->value, val);
@@ -27703,7 +29352,7 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m)
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);
+ val = JS_GetModuleNamespace(ctx, m2);
if (JS_IsException(val))
goto fail;
var_ref = js_create_module_var(ctx, TRUE);
@@ -27750,14 +29399,59 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m)
JS_FreeValue(ctx, ret_val);
}
+ assert(m->dfs_ancestor_index <= m->dfs_index);
+ if (m->dfs_index == m->dfs_ancestor_index) {
+ for(;;) {
+ /* pop m1 from stack */
+ m1 = *pstack_top;
+ *pstack_top = m1->stack_prev;
+ m1->status = JS_MODULE_STATUS_LINKED;
+ if (m1 == m)
+ break;
+ }
+ }
+
#ifdef DUMP_MODULE_RESOLVE
- printf("done instantiate\n");
+ printf("js_inner_module_linking done\n");
#endif
- return 0;
+ return index;
fail:
return -1;
}
+/* Prepare a module to be executed by resolving all the imported
+ variables. */
+static int js_link_module(JSContext *ctx, JSModuleDef *m)
+{
+ JSModuleDef *stack_top, *m1;
+
+#ifdef DUMP_MODULE_RESOLVE
+ {
+ char buf1[ATOM_GET_STR_BUF_SIZE];
+ printf("js_link_module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
+ }
+#endif
+ assert(m->status == JS_MODULE_STATUS_UNLINKED ||
+ m->status == JS_MODULE_STATUS_LINKED ||
+ m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m->status == JS_MODULE_STATUS_EVALUATED);
+ stack_top = NULL;
+ if (js_inner_module_linking(ctx, m, &stack_top, 0) < 0) {
+ while (stack_top != NULL) {
+ m1 = stack_top;
+ assert(m1->status == JS_MODULE_STATUS_LINKING);
+ m1->status = JS_MODULE_STATUS_UNLINKED;
+ stack_top = m1->stack_prev;
+ }
+ return -1;
+ }
+ assert(stack_top == NULL);
+ assert(m->status == JS_MODULE_STATUS_LINKED ||
+ m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m->status == JS_MODULE_STATUS_EVALUATED);
+ return 0;
+}
+
/* 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)
@@ -27766,8 +29460,8 @@ JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels)
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 */
+ function from the debug info. May need to add a ScriptOrModule
+ info in JSFunctionBytecode. */
sf = ctx->rt->current_stack_frame;
if (!sf)
return JS_ATOM_NULL;
@@ -27776,15 +29470,23 @@ JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels)
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);
+ for(;;) {
+ 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->is_direct_or_indirect_eval) {
+ if (!b->has_debug)
+ return JS_ATOM_NULL;
+ return JS_DupAtom(ctx, b->debug.filename);
+ } else {
+ sf = sf->prev_frame;
+ if (!sf)
+ return JS_ATOM_NULL;
+ }
+ }
}
JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m)
@@ -27810,7 +29512,7 @@ static JSValue js_import_meta(JSContext *ctx)
{
JSAtom filename;
JSModuleDef *m;
-
+
filename = JS_GetScriptOrModuleName(ctx, 0);
if (filename == JS_ATOM_NULL)
goto fail;
@@ -27827,29 +29529,111 @@ static JSValue js_import_meta(JSContext *ctx)
return JS_GetImportMeta(ctx, m);
}
-/* used by os.Worker() and import() */
-JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename,
- const char *filename)
+static JSValue JS_NewModuleValue(JSContext *ctx, JSModuleDef *m)
+{
+ return JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
+}
+
+static JSValue js_load_module_rejected(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int magic, JSValue *func_data)
+{
+ JSValueConst *resolving_funcs = (JSValueConst *)func_data;
+ JSValueConst error;
+ JSValue ret;
+
+ /* XXX: check if the test is necessary */
+ if (argc >= 1)
+ error = argv[0];
+ else
+ error = JS_UNDEFINED;
+ ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
+ 1, &error);
+ JS_FreeValue(ctx, ret);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_load_module_fulfilled(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int magic, JSValue *func_data)
+{
+ JSValueConst *resolving_funcs = (JSValueConst *)func_data;
+ JSModuleDef *m = JS_VALUE_GET_PTR(func_data[2]);
+ JSValue ret, ns;
+
+ /* return the module namespace */
+ ns = JS_GetModuleNamespace(ctx, m);
+ if (JS_IsException(ns)) {
+ JSValue err = JS_GetException(ctx);
+ js_load_module_rejected(ctx, JS_UNDEFINED, 1, (JSValueConst *)&err, 0, func_data);
+ return JS_UNDEFINED;
+ }
+ ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED,
+ 1, (JSValueConst *)&ns);
+ JS_FreeValue(ctx, ret);
+ JS_FreeValue(ctx, ns);
+ return JS_UNDEFINED;
+}
+
+static void JS_LoadModuleInternal(JSContext *ctx, const char *basename,
+ const char *filename,
+ JSValueConst *resolving_funcs,
+ JSValueConst attributes)
{
+ JSValue evaluate_promise;
JSModuleDef *m;
- JSValue ret, func_obj;
-
- m = js_host_resolve_imported_module(ctx, basename, filename);
+ JSValue ret, err, func_obj, evaluate_resolving_funcs[2];
+ JSValueConst func_data[3];
+
+ m = js_host_resolve_imported_module(ctx, basename, filename, attributes);
if (!m)
- return NULL;
-
+ goto fail;
+
if (js_resolve_module(ctx, m) < 0) {
js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
- return NULL;
+ goto fail;
}
/* 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;
+ func_obj = JS_NewModuleValue(ctx, m);
+ evaluate_promise = JS_EvalFunction(ctx, func_obj);
+ if (JS_IsException(evaluate_promise)) {
+ fail:
+ 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);
+ return;
+ }
+
+ func_obj = JS_NewModuleValue(ctx, m);
+ func_data[0] = resolving_funcs[0];
+ func_data[1] = resolving_funcs[1];
+ func_data[2] = func_obj;
+ evaluate_resolving_funcs[0] = JS_NewCFunctionData(ctx, js_load_module_fulfilled, 0, 0, 3, func_data);
+ evaluate_resolving_funcs[1] = JS_NewCFunctionData(ctx, js_load_module_rejected, 0, 0, 3, func_data);
+ JS_FreeValue(ctx, func_obj);
+ ret = js_promise_then(ctx, evaluate_promise, 2, (JSValueConst *)evaluate_resolving_funcs);
JS_FreeValue(ctx, ret);
- return m;
+ JS_FreeValue(ctx, evaluate_resolving_funcs[0]);
+ JS_FreeValue(ctx, evaluate_resolving_funcs[1]);
+ JS_FreeValue(ctx, evaluate_promise);
+}
+
+/* Return a promise or an exception in case of memory error. Used by
+ os.Worker() */
+JSValue JS_LoadModule(JSContext *ctx, const char *basename,
+ const char *filename)
+{
+ JSValue promise, resolving_funcs[2];
+
+ promise = JS_NewPromiseCapability(ctx, resolving_funcs);
+ if (JS_IsException(promise))
+ return JS_EXCEPTION;
+ JS_LoadModuleInternal(ctx, basename, filename,
+ (JSValueConst *)resolving_funcs, JS_UNDEFINED);
+ JS_FreeValue(ctx, resolving_funcs[0]);
+ JS_FreeValue(ctx, resolving_funcs[1]);
+ return promise;
}
static JSValue js_dynamic_import_job(JSContext *ctx,
@@ -27858,9 +29642,9 @@ static JSValue js_dynamic_import_job(JSContext *ctx,
JSValueConst *resolving_funcs = argv;
JSValueConst basename_val = argv[2];
JSValueConst specifier = argv[3];
- JSModuleDef *m;
+ JSValueConst attributes = argv[4];
const char *basename = NULL, *filename;
- JSValue ret, err, ns;
+ JSValue ret, err;
if (!JS_IsString(basename_val)) {
JS_ThrowTypeError(ctx, "no function filename for import()");
@@ -27873,25 +29657,13 @@ static JSValue js_dynamic_import_job(JSContext *ctx,
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_LoadModuleInternal(ctx, basename, filename,
+ resolving_funcs, attributes);
+ JS_FreeCString(ctx, filename);
JS_FreeCString(ctx, basename);
return JS_UNDEFINED;
exception:
-
err = JS_GetException(ctx);
ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
1, (JSValueConst *)&err);
@@ -27901,11 +29673,12 @@ static JSValue js_dynamic_import_job(JSContext *ctx,
return JS_UNDEFINED;
}
-static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier)
+static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier, JSValueConst options)
{
JSAtom basename;
- JSValue promise, resolving_funcs[2], basename_val;
- JSValueConst args[4];
+ JSValue promise, resolving_funcs[2], basename_val, err, ret;
+ JSValue specifier_str = JS_UNDEFINED, attributes = JS_UNDEFINED, attributes_obj = JS_UNDEFINED;
+ JSValueConst args[5];
basename = JS_GetScriptOrModuleName(ctx, 0);
if (basename == JS_ATOM_NULL)
@@ -27915,103 +29688,587 @@ static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier)
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;
}
+ /* the string conversion must occur here */
+ specifier_str = JS_ToString(ctx, specifier);
+ if (JS_IsException(specifier_str))
+ goto exception;
+
+ if (!JS_IsUndefined(options)) {
+ if (!JS_IsObject(options)) {
+ JS_ThrowTypeError(ctx, "options must be an object");
+ goto exception;
+ }
+ attributes_obj = JS_GetProperty(ctx, options, JS_ATOM_with);
+ if (JS_IsException(attributes_obj))
+ goto exception;
+ if (!JS_IsUndefined(attributes_obj)) {
+ JSPropertyEnum *atoms;
+ uint32_t atoms_len, i;
+ JSValue val;
+
+ if (!JS_IsObject(attributes_obj)) {
+ JS_ThrowTypeError(ctx, "options.with must be an object");
+ goto exception;
+ }
+ attributes = JS_NewObjectProto(ctx, JS_NULL);
+ if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &atoms_len, JS_VALUE_GET_OBJ(attributes_obj),
+ JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) {
+ goto exception;
+ }
+ for(i = 0; i < atoms_len; i++) {
+ val = JS_GetProperty(ctx, attributes_obj, atoms[i].atom);
+ if (JS_IsException(val))
+ goto exception1;
+ if (!JS_IsString(val)) {
+ JS_FreeValue(ctx, val);
+ JS_ThrowTypeError(ctx, "module attribute values must be strings");
+ goto exception1;
+ }
+ if (JS_DefinePropertyValue(ctx, attributes, atoms[i].atom, val,
+ JS_PROP_C_W_E) < 0) {
+ exception1:
+ JS_FreePropertyEnum(ctx, atoms, atoms_len);
+ goto exception;
+ }
+ }
+ JS_FreePropertyEnum(ctx, atoms, atoms_len);
+ if (ctx->rt->module_check_attrs &&
+ ctx->rt->module_check_attrs(ctx, ctx->rt->module_loader_opaque, attributes) < 0) {
+ goto exception;
+ }
+ JS_FreeValue(ctx, attributes_obj);
+ }
+ }
+
args[0] = resolving_funcs[0];
args[1] = resolving_funcs[1];
args[2] = basename_val;
- args[3] = specifier;
+ args[3] = specifier_str;
+ args[4] = attributes;
- JS_EnqueueJob(ctx, js_dynamic_import_job, 4, args);
-
+ /* cannot run JS_LoadModuleInternal synchronously because it would
+ cause an unexpected recursion in js_evaluate_module() */
+ JS_EnqueueJob(ctx, js_dynamic_import_job, 5, args);
+ done:
JS_FreeValue(ctx, basename_val);
JS_FreeValue(ctx, resolving_funcs[0]);
JS_FreeValue(ctx, resolving_funcs[1]);
+ JS_FreeValue(ctx, specifier_str);
+ JS_FreeValue(ctx, attributes);
return promise;
+ exception:
+ JS_FreeValue(ctx, attributes_obj);
+ err = JS_GetException(ctx);
+ ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
+ 1, (JSValueConst *)&err);
+ JS_FreeValue(ctx, ret);
+ JS_FreeValue(ctx, err);
+ goto done;
}
-/* Run the function of the module and of all its requested
- modules. */
-static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m)
+static void js_set_module_evaluated(JSContext *ctx, JSModuleDef *m)
+{
+ m->status = JS_MODULE_STATUS_EVALUATED;
+ if (!JS_IsUndefined(m->promise)) {
+ JSValue value, ret_val;
+ assert(m->cycle_root == m);
+ value = JS_UNDEFINED;
+ ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED,
+ 1, (JSValueConst *)&value);
+ JS_FreeValue(ctx, ret_val);
+ }
+}
+
+typedef struct {
+ JSModuleDef **tab;
+ int count;
+ int size;
+} ExecModuleList;
+
+/* XXX: slow. Could use a linked list instead of ExecModuleList */
+static BOOL find_in_exec_module_list(ExecModuleList *exec_list, JSModuleDef *m)
+{
+ int i;
+ for(i = 0; i < exec_list->count; i++) {
+ if (exec_list->tab[i] == m)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static int gather_available_ancestors(JSContext *ctx, JSModuleDef *module,
+ ExecModuleList *exec_list)
+{
+ int i;
+
+ if (js_check_stack_overflow(ctx->rt, 0)) {
+ JS_ThrowStackOverflow(ctx);
+ return -1;
+ }
+ for(i = 0; i < module->async_parent_modules_count; i++) {
+ JSModuleDef *m = module->async_parent_modules[i];
+ if (!find_in_exec_module_list(exec_list, m) &&
+ !m->cycle_root->eval_has_exception) {
+ assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC);
+ assert(!m->eval_has_exception);
+ assert(m->async_evaluation);
+ assert(m->pending_async_dependencies > 0);
+ m->pending_async_dependencies--;
+ if (m->pending_async_dependencies == 0) {
+ if (js_resize_array(ctx, (void **)&exec_list->tab, sizeof(exec_list->tab[0]), &exec_list->size, exec_list->count + 1)) {
+ return -1;
+ }
+ exec_list->tab[exec_list->count++] = m;
+ if (!m->has_tla) {
+ if (gather_available_ancestors(ctx, m, exec_list))
+ return -1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int exec_module_list_cmp(const void *p1, const void *p2, void *opaque)
+{
+ JSModuleDef *m1 = *(JSModuleDef **)p1;
+ JSModuleDef *m2 = *(JSModuleDef **)p2;
+ return (m1->async_evaluation_timestamp > m2->async_evaluation_timestamp) -
+ (m1->async_evaluation_timestamp < m2->async_evaluation_timestamp);
+}
+
+static int js_execute_async_module(JSContext *ctx, JSModuleDef *m);
+static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m,
+ JSValue *pvalue);
+
+static JSValue js_async_module_execution_rejected(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int magic, JSValue *func_data)
+{
+ JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]);
+ JSValueConst error = argv[0];
+ int i;
+
+ if (js_check_stack_overflow(ctx->rt, 0))
+ return JS_ThrowStackOverflow(ctx);
+
+ if (module->status == JS_MODULE_STATUS_EVALUATED) {
+ assert(module->eval_has_exception);
+ return JS_UNDEFINED;
+ }
+
+ assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC);
+ assert(!module->eval_has_exception);
+ assert(module->async_evaluation);
+
+ module->eval_has_exception = TRUE;
+ module->eval_exception = JS_DupValue(ctx, error);
+ module->status = JS_MODULE_STATUS_EVALUATED;
+
+ for(i = 0; i < module->async_parent_modules_count; i++) {
+ JSModuleDef *m = module->async_parent_modules[i];
+ JSValue m_obj = JS_NewModuleValue(ctx, m);
+ js_async_module_execution_rejected(ctx, JS_UNDEFINED, 1, &error, 0,
+ &m_obj);
+ JS_FreeValue(ctx, m_obj);
+ }
+
+ if (!JS_IsUndefined(module->promise)) {
+ JSValue ret_val;
+ assert(module->cycle_root == module);
+ ret_val = JS_Call(ctx, module->resolving_funcs[1], JS_UNDEFINED,
+ 1, &error);
+ JS_FreeValue(ctx, ret_val);
+ }
+ return JS_UNDEFINED;
+}
+
+static JSValue js_async_module_execution_fulfilled(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int magic, JSValue *func_data)
+{
+ JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]);
+ ExecModuleList exec_list_s, *exec_list = &exec_list_s;
+ int i;
+
+ if (module->status == JS_MODULE_STATUS_EVALUATED) {
+ assert(module->eval_has_exception);
+ return JS_UNDEFINED;
+ }
+ assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC);
+ assert(!module->eval_has_exception);
+ assert(module->async_evaluation);
+ module->async_evaluation = FALSE;
+ js_set_module_evaluated(ctx, module);
+
+ exec_list->tab = NULL;
+ exec_list->count = 0;
+ exec_list->size = 0;
+
+ if (gather_available_ancestors(ctx, module, exec_list) < 0) {
+ js_free(ctx, exec_list->tab);
+ return JS_EXCEPTION;
+ }
+
+ /* sort by increasing async_evaluation timestamp */
+ rqsort(exec_list->tab, exec_list->count, sizeof(exec_list->tab[0]),
+ exec_module_list_cmp, NULL);
+
+ for(i = 0; i < exec_list->count; i++) {
+ JSModuleDef *m = exec_list->tab[i];
+ if (m->status == JS_MODULE_STATUS_EVALUATED) {
+ assert(m->eval_has_exception);
+ } else if (m->has_tla) {
+ js_execute_async_module(ctx, m);
+ } else {
+ JSValue error;
+ if (js_execute_sync_module(ctx, m, &error) < 0) {
+ JSValue m_obj = JS_NewModuleValue(ctx, m);
+ js_async_module_execution_rejected(ctx, JS_UNDEFINED,
+ 1, (JSValueConst *)&error, 0,
+ &m_obj);
+ JS_FreeValue(ctx, m_obj);
+ JS_FreeValue(ctx, error);
+ } else {
+ js_set_module_evaluated(ctx, m);
+ }
+ }
+ }
+ js_free(ctx, exec_list->tab);
+ return JS_UNDEFINED;
+}
+
+static int js_execute_async_module(JSContext *ctx, JSModuleDef *m)
+{
+ JSValue promise, m_obj;
+ JSValue resolve_funcs[2], ret_val;
+ promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0);
+ if (JS_IsException(promise))
+ return -1;
+ m_obj = JS_NewModuleValue(ctx, m);
+ resolve_funcs[0] = JS_NewCFunctionData(ctx, js_async_module_execution_fulfilled, 0, 0, 1, (JSValueConst *)&m_obj);
+ resolve_funcs[1] = JS_NewCFunctionData(ctx, js_async_module_execution_rejected, 0, 0, 1, (JSValueConst *)&m_obj);
+ ret_val = js_promise_then(ctx, promise, 2, (JSValueConst *)resolve_funcs);
+ JS_FreeValue(ctx, ret_val);
+ JS_FreeValue(ctx, m_obj);
+ JS_FreeValue(ctx, resolve_funcs[0]);
+ JS_FreeValue(ctx, resolve_funcs[1]);
+ JS_FreeValue(ctx, promise);
+ return 0;
+}
+
+/* return < 0 in case of exception. *pvalue contains the exception. */
+static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m,
+ JSValue *pvalue)
+{
+ if (m->init_func) {
+ /* C module init : no asynchronous execution */
+ if (m->init_func(ctx, m) < 0)
+ goto fail;
+ } else {
+ JSValue promise;
+ JSPromiseStateEnum state;
+
+ promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0);
+ if (JS_IsException(promise))
+ goto fail;
+ state = JS_PromiseState(ctx, promise);
+ if (state == JS_PROMISE_FULFILLED) {
+ JS_FreeValue(ctx, promise);
+ } else if (state == JS_PROMISE_REJECTED) {
+ *pvalue = JS_PromiseResult(ctx, promise);
+ JS_FreeValue(ctx, promise);
+ return -1;
+ } else {
+ JS_FreeValue(ctx, promise);
+ JS_ThrowTypeError(ctx, "promise is pending");
+ fail:
+ *pvalue = JS_GetException(ctx);
+ return -1;
+ }
+ }
+ *pvalue = JS_UNDEFINED;
+ return 0;
+}
+
+/* spec: InnerModuleEvaluation. Return (index, JS_UNDEFINED) or (-1,
+ exception) */
+static int js_inner_module_evaluation(JSContext *ctx, JSModuleDef *m,
+ int index, JSModuleDef **pstack_top,
+ JSValue *pvalue)
{
JSModuleDef *m1;
int i;
- JSValue ret_val;
- if (m->eval_mark)
- return JS_UNDEFINED; /* avoid cycles */
+ if (js_check_stack_overflow(ctx->rt, 0)) {
+ JS_ThrowStackOverflow(ctx);
+ *pvalue = JS_GetException(ctx);
+ return -1;
+ }
+
+#ifdef DUMP_MODULE_RESOLVE
+ {
+ char buf1[ATOM_GET_STR_BUF_SIZE];
+ printf("js_inner_module_evaluation '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
+ }
+#endif
- if (m->evaluated) {
- /* if the module was already evaluated, rethrow the exception
- it raised */
+ if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m->status == JS_MODULE_STATUS_EVALUATED) {
if (m->eval_has_exception) {
- return JS_Throw(ctx, JS_DupValue(ctx, m->eval_exception));
+ *pvalue = JS_DupValue(ctx, m->eval_exception);
+ return -1;
} else {
- return JS_UNDEFINED;
+ *pvalue = JS_UNDEFINED;
+ return index;
}
}
+ if (m->status == JS_MODULE_STATUS_EVALUATING) {
+ *pvalue = JS_UNDEFINED;
+ return index;
+ }
+ assert(m->status == JS_MODULE_STATUS_LINKED);
- m->eval_mark = TRUE;
+ m->status = JS_MODULE_STATUS_EVALUATING;
+ m->dfs_index = index;
+ m->dfs_ancestor_index = index;
+ m->pending_async_dependencies = 0;
+ index++;
+ /* push 'm' on stack */
+ m->stack_prev = *pstack_top;
+ *pstack_top = m;
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;
+ index = js_inner_module_evaluation(ctx, m1, index, pstack_top, pvalue);
+ if (index < 0)
+ return -1;
+ assert(m1->status == JS_MODULE_STATUS_EVALUATING ||
+ m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m1->status == JS_MODULE_STATUS_EVALUATED);
+ if (m1->status == JS_MODULE_STATUS_EVALUATING) {
+ m->dfs_ancestor_index = min_int(m->dfs_ancestor_index,
+ m1->dfs_ancestor_index);
+ } else {
+ m1 = m1->cycle_root;
+ assert(m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m1->status == JS_MODULE_STATUS_EVALUATED);
+ if (m1->eval_has_exception) {
+ *pvalue = JS_DupValue(ctx, m1->eval_exception);
+ return -1;
}
- JS_FreeValue(ctx, ret_val);
+ }
+ if (m1->async_evaluation) {
+ m->pending_async_dependencies++;
+ if (js_resize_array(ctx, (void **)&m1->async_parent_modules, sizeof(m1->async_parent_modules[0]), &m1->async_parent_modules_size, m1->async_parent_modules_count + 1)) {
+ *pvalue = JS_GetException(ctx);
+ return -1;
+ }
+ m1->async_parent_modules[m1->async_parent_modules_count++] = m;
}
}
- if (m->init_func) {
- /* C module init */
- if (m->init_func(ctx, m) < 0)
- ret_val = JS_EXCEPTION;
- else
- ret_val = JS_UNDEFINED;
+ if (m->pending_async_dependencies > 0) {
+ assert(!m->async_evaluation);
+ m->async_evaluation = TRUE;
+ m->async_evaluation_timestamp =
+ ctx->rt->module_async_evaluation_next_timestamp++;
+ } else if (m->has_tla) {
+ assert(!m->async_evaluation);
+ m->async_evaluation = TRUE;
+ m->async_evaluation_timestamp =
+ ctx->rt->module_async_evaluation_next_timestamp++;
+ js_execute_async_module(ctx, m);
} else {
- ret_val = JS_CallFree(ctx, m->func_obj, JS_UNDEFINED, 0, NULL);
- m->func_obj = JS_UNDEFINED;
+ if (js_execute_sync_module(ctx, m, pvalue) < 0)
+ return -1;
}
- 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);
+
+ assert(m->dfs_ancestor_index <= m->dfs_index);
+ if (m->dfs_index == m->dfs_ancestor_index) {
+ for(;;) {
+ /* pop m1 from stack */
+ m1 = *pstack_top;
+ *pstack_top = m1->stack_prev;
+ if (!m1->async_evaluation) {
+ m1->status = JS_MODULE_STATUS_EVALUATED;
+ } else {
+ m1->status = JS_MODULE_STATUS_EVALUATING_ASYNC;
+ }
+ /* spec bug: cycle_root must be assigned before the test */
+ m1->cycle_root = m;
+ if (m1 == m)
+ break;
+ }
}
- m->eval_mark = FALSE;
- m->evaluated = TRUE;
- return ret_val;
+ *pvalue = JS_UNDEFINED;
+ return index;
+}
+
+/* Run the function of the module and of all its requested
+ modules. Return a promise or an exception. */
+static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m)
+{
+ JSModuleDef *m1, *stack_top;
+ JSValue ret_val, result;
+
+ assert(m->status == JS_MODULE_STATUS_LINKED ||
+ m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m->status == JS_MODULE_STATUS_EVALUATED);
+ if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m->status == JS_MODULE_STATUS_EVALUATED) {
+ m = m->cycle_root;
+ }
+ /* a promise may be created only on the cycle_root of a cycle */
+ if (!JS_IsUndefined(m->promise))
+ return JS_DupValue(ctx, m->promise);
+ m->promise = JS_NewPromiseCapability(ctx, m->resolving_funcs);
+ if (JS_IsException(m->promise))
+ return JS_EXCEPTION;
+
+ stack_top = NULL;
+ if (js_inner_module_evaluation(ctx, m, 0, &stack_top, &result) < 0) {
+ while (stack_top != NULL) {
+ m1 = stack_top;
+ assert(m1->status == JS_MODULE_STATUS_EVALUATING);
+ m1->status = JS_MODULE_STATUS_EVALUATED;
+ m1->eval_has_exception = TRUE;
+ m1->eval_exception = JS_DupValue(ctx, result);
+ m1->cycle_root = m; /* spec bug: should be present */
+ stack_top = m1->stack_prev;
+ }
+ JS_FreeValue(ctx, result);
+ assert(m->status == JS_MODULE_STATUS_EVALUATED);
+ assert(m->eval_has_exception);
+ ret_val = JS_Call(ctx, m->resolving_funcs[1], JS_UNDEFINED,
+ 1, (JSValueConst *)&m->eval_exception);
+ JS_FreeValue(ctx, ret_val);
+ } else {
+ assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m->status == JS_MODULE_STATUS_EVALUATED);
+ assert(!m->eval_has_exception);
+ if (!m->async_evaluation) {
+ JSValue value;
+ assert(m->status == JS_MODULE_STATUS_EVALUATED);
+ value = JS_UNDEFINED;
+ ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED,
+ 1, (JSValueConst *)&value);
+ JS_FreeValue(ctx, ret_val);
+ }
+ assert(stack_top == NULL);
+ }
+ return JS_DupValue(ctx, m->promise);
+}
+
+static __exception int js_parse_with_clause(JSParseState *s, JSReqModuleEntry *rme)
+{
+ JSContext *ctx = s->ctx;
+ JSAtom key;
+ int ret;
+ const uint8_t *key_token_ptr;
+
+ if (next_token(s))
+ return -1;
+ if (js_parse_expect(s, '{'))
+ return -1;
+ while (s->token.val != '}') {
+ key_token_ptr = s->token.ptr;
+ if (s->token.val == TOK_STRING) {
+ key = JS_ValueToAtom(ctx, s->token.u.str.str);
+ if (key == JS_ATOM_NULL)
+ return -1;
+ } else {
+ if (!token_is_ident(s->token.val)) {
+ js_parse_error(s, "identifier expected");
+ return -1;
+ }
+ key = JS_DupAtom(ctx, s->token.u.ident.atom);
+ }
+ if (next_token(s))
+ return -1;
+ if (js_parse_expect(s, ':')) {
+ JS_FreeAtom(ctx, key);
+ return -1;
+ }
+ if (s->token.val != TOK_STRING) {
+ js_parse_error_pos(s, key_token_ptr, "string expected");
+ return -1;
+ }
+ if (JS_IsUndefined(rme->attributes)) {
+ JSValue attributes = JS_NewObjectProto(ctx, JS_NULL);
+ if (JS_IsException(attributes)) {
+ JS_FreeAtom(ctx, key);
+ return -1;
+ }
+ rme->attributes = attributes;
+ }
+ ret = JS_HasProperty(ctx, rme->attributes, key);
+ if (ret != 0) {
+ JS_FreeAtom(ctx, key);
+ if (ret < 0)
+ return -1;
+ else
+ return js_parse_error(s, "duplicate with key");
+ }
+ ret = JS_DefinePropertyValue(ctx, rme->attributes, key,
+ JS_DupValue(ctx, s->token.u.str.str), JS_PROP_C_W_E);
+ JS_FreeAtom(ctx, key);
+ if (ret < 0)
+ return -1;
+ if (next_token(s))
+ return -1;
+ if (s->token.val != ',')
+ break;
+ if (next_token(s))
+ return -1;
+ }
+ if (!JS_IsUndefined(rme->attributes) &&
+ ctx->rt->module_check_attrs &&
+ ctx->rt->module_check_attrs(ctx, ctx->rt->module_loader_opaque, rme->attributes) < 0) {
+ return -1;
+ }
+ return js_parse_expect(s, '}');
}
-static __exception JSAtom js_parse_from_clause(JSParseState *s)
+/* return the module index in m->req_module_entries[] or < 0 if error */
+static __exception int js_parse_from_clause(JSParseState *s, JSModuleDef *m)
{
JSAtom module_name;
+ int idx;
+
if (!token_is_pseudo_keyword(s, JS_ATOM_from)) {
js_parse_error(s, "from clause expected");
- return JS_ATOM_NULL;
+ return -1;
}
if (next_token(s))
- return JS_ATOM_NULL;
+ return -1;
if (s->token.val != TOK_STRING) {
js_parse_error(s, "string expected");
- return JS_ATOM_NULL;
+ return -1;
}
module_name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
if (module_name == JS_ATOM_NULL)
- return JS_ATOM_NULL;
+ return -1;
if (next_token(s)) {
JS_FreeAtom(s->ctx, module_name);
- return JS_ATOM_NULL;
+ return -1;
}
- return module_name;
+
+ idx = add_req_module_entry(s->ctx, m, module_name);
+ JS_FreeAtom(s->ctx, module_name);
+ if (idx < 0)
+ return -1;
+ if (s->token.val == TOK_WITH) {
+ if (js_parse_with_clause(s, &m->req_module_entries[idx]))
+ return -1;
+ }
+ return idx;
}
static __exception int js_parse_export(JSParseState *s)
@@ -28020,7 +30277,6 @@ static __exception int js_parse_export(JSParseState *s)
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))
@@ -28034,7 +30290,7 @@ static __exception int js_parse_export(JSParseState *s)
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,
+ s->token.ptr,
JS_PARSE_EXPORT_NAMED, NULL);
}
@@ -28056,11 +30312,21 @@ static __exception int js_parse_export(JSParseState *s)
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;
+ if (s->token.val == TOK_STRING) {
+ if (js_string_find_invalid_codepoint(JS_VALUE_GET_STRING(s->token.u.str.str)) >= 0) {
+ js_parse_error(s, "contains unpaired surrogate");
+ goto fail;
+ }
+ export_name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
+ if (export_name == JS_ATOM_NULL)
+ goto fail;
+ } else {
+ 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);
}
- export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
if (next_token(s)) {
fail:
JS_FreeAtom(ctx, local_name);
@@ -28085,11 +30351,7 @@ static __exception int js_parse_export(JSParseState *s)
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);
+ idx = js_parse_from_clause(s, m);
if (idx < 0)
return -1;
for(i = first_export; i < m->export_entries_count; i++) {
@@ -28111,11 +30373,7 @@ static __exception int js_parse_export(JSParseState *s)
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);
+ idx = js_parse_from_clause(s, m);
if (idx < 0)
goto fail1;
me = add_export_entry(s, m, JS_ATOM__star_, export_name,
@@ -28125,11 +30383,7 @@ static __exception int js_parse_export(JSParseState *s)
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);
+ idx = js_parse_from_clause(s, m);
if (idx < 0)
return -1;
if (add_star_export_entry(ctx, m, idx) < 0)
@@ -28144,7 +30398,7 @@ static __exception int js_parse_export(JSParseState *s)
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,
+ s->token.ptr,
JS_PARSE_EXPORT_DEFAULT, NULL);
} else {
if (js_parse_assign_expr(s))
@@ -28183,12 +30437,11 @@ static int add_closure_var(JSContext *ctx, JSFunctionDef *s,
JSVarKindEnum var_kind);
static int add_import(JSParseState *s, JSModuleDef *m,
- JSAtom local_name, JSAtom import_name)
+ JSAtom local_name, JSAtom import_name, BOOL is_star)
{
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");
@@ -28200,8 +30453,7 @@ static int add_import(JSParseState *s, JSModuleDef *m,
}
}
- is_local = (import_name == JS_ATOM__star_);
- var_idx = add_closure_var(ctx, s->cur_func, is_local, FALSE,
+ var_idx = add_closure_var(ctx, s->cur_func, is_star, FALSE,
m->import_entries_count,
local_name, TRUE, TRUE, FALSE);
if (var_idx < 0)
@@ -28214,6 +30466,7 @@ static int add_import(JSParseState *s, JSModuleDef *m,
mi = &m->import_entries[m->import_entries_count++];
mi->import_name = JS_DupAtom(ctx, import_name);
mi->var_idx = var_idx;
+ mi->is_star = is_star;
return 0;
}
@@ -28236,6 +30489,14 @@ static __exception int js_parse_import(JSParseState *s)
JS_FreeAtom(ctx, module_name);
return -1;
}
+ idx = add_req_module_entry(ctx, m, module_name);
+ JS_FreeAtom(ctx, module_name);
+ if (idx < 0)
+ return -1;
+ if (s->token.val == TOK_WITH) {
+ if (js_parse_with_clause(s, &m->req_module_entries[idx]))
+ return -1;
+ }
} else {
if (s->token.val == TOK_IDENT) {
if (s->token.u.ident.is_reserved) {
@@ -28246,7 +30507,7 @@ static __exception int js_parse_import(JSParseState *s)
import_name = JS_ATOM_default;
if (next_token(s))
goto fail;
- if (add_import(s, m, local_name, import_name))
+ if (add_import(s, m, local_name, import_name, FALSE))
goto fail;
JS_FreeAtom(ctx, local_name);
@@ -28272,7 +30533,7 @@ static __exception int js_parse_import(JSParseState *s)
import_name = JS_ATOM__star_;
if (next_token(s))
goto fail;
- if (add_import(s, m, local_name, import_name))
+ if (add_import(s, m, local_name, import_name, TRUE))
goto fail;
JS_FreeAtom(ctx, local_name);
} else if (s->token.val == '{') {
@@ -28280,11 +30541,24 @@ static __exception int js_parse_import(JSParseState *s)
return -1;
while (s->token.val != '}') {
- if (!token_is_ident(s->token.val)) {
- js_parse_error(s, "identifier expected");
- return -1;
+ BOOL is_string;
+ if (s->token.val == TOK_STRING) {
+ is_string = TRUE;
+ if (js_string_find_invalid_codepoint(JS_VALUE_GET_STRING(s->token.u.str.str)) >= 0) {
+ js_parse_error(s, "contains unpaired surrogate");
+ return -1;
+ }
+ import_name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
+ if (import_name == JS_ATOM_NULL)
+ return -1;
+ } else {
+ is_string = FALSE;
+ 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);
}
- import_name = JS_DupAtom(ctx, s->token.u.ident.atom);
local_name = JS_ATOM_NULL;
if (next_token(s))
goto fail;
@@ -28296,16 +30570,19 @@ static __exception int js_parse_import(JSParseState *s)
goto fail;
}
local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
- if (next_token(s)) {
+ if (next_token(s))
+ goto fail;
+ } else {
+ if (is_string) {
+ js_parse_error(s, "expecting 'as'");
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))
+ if (add_import(s, m, local_name, import_name, FALSE))
goto fail;
JS_FreeAtom(ctx, local_name);
JS_FreeAtom(ctx, import_name);
@@ -28318,14 +30595,10 @@ static __exception int js_parse_import(JSParseState *s)
return -1;
}
end_import_clause:
- module_name = js_parse_from_clause(s);
- if (module_name == JS_ATOM_NULL)
+ idx = js_parse_from_clause(s, m);
+ if (idx < 0)
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;
@@ -28336,13 +30609,13 @@ 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))
+ s->token.ptr))
return -1;
} else if (s->token.val == TOK_EXPORT && fd->module) {
if (js_parse_export(s))
@@ -28364,7 +30637,9 @@ static JSFunctionDef *js_new_function_def(JSContext *ctx,
JSFunctionDef *parent,
BOOL is_eval,
BOOL is_func_expr,
- const char *filename, int line_num)
+ const char *filename,
+ const uint8_t *source_ptr,
+ GetLineColCache *get_line_col_cache)
{
JSFunctionDef *fd;
@@ -28383,6 +30658,8 @@ static JSFunctionDef *js_new_function_def(JSContext *ctx,
fd->js_mode = parent->js_mode;
fd->parent_scope_level = parent->scope_level;
}
+ fd->strip_debug = ((ctx->rt->strip_flags & JS_STRIP_DEBUG) != 0);
+ fd->strip_source = ((ctx->rt->strip_flags & (JS_STRIP_DEBUG | JS_STRIP_SOURCE)) != 0);
fd->is_eval = is_eval;
fd->is_func_expr = is_func_expr;
@@ -28411,13 +30688,13 @@ static JSFunctionDef *js_new_function_def(JSContext *ctx,
fd->body_scope = -1;
fd->filename = JS_NewAtom(ctx, filename);
- fd->line_num = line_num;
-
+ fd->source_pos = source_ptr - get_line_col_cache->buf_start;
+ fd->get_line_col_cache = get_line_col_cache;
+
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;
-
+ fd->last_opcode_source_ptr = source_ptr;
return fd;
}
@@ -28428,7 +30705,7 @@ static void free_bytecode_atoms(JSRuntime *rt,
int pos, len, op;
JSAtom atom;
const JSOpCode *oi;
-
+
pos = 0;
while (pos < bc_len) {
op = bc_buf[pos];
@@ -28436,7 +30713,7 @@ static void free_bytecode_atoms(JSRuntime *rt,
oi = &short_opcode_info(op);
else
oi = &opcode_info[op];
-
+
len = oi->size;
switch(oi->fmt) {
case OP_FMT_atom:
@@ -28444,6 +30721,8 @@ static void free_bytecode_atoms(JSRuntime *rt,
case OP_FMT_atom_u16:
case OP_FMT_atom_label_u8:
case OP_FMT_atom_label_u16:
+ if ((pos + 1 + 4) > bc_len)
+ break; /* may happen if there is not enough memory when emiting bytecode */
atom = get_u32(bc_buf + pos + 1);
JS_FreeAtomRT(rt, atom);
break;
@@ -28546,14 +30825,19 @@ static void dump_byte_code(JSContext *ctx, int pass,
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 char *source,
const LabelSlot *label_slots, JSFunctionBytecode *b)
{
const JSOpCode *oi;
- int pos, pos_next, op, size, idx, addr, line, line1, in_source;
+ int pos, pos_next, op, size, idx, addr, line, line1, in_source, line_num;
uint8_t *bits = js_mallocz(ctx, len * sizeof(*bits));
BOOL use_short_opcodes = (b != NULL);
+ if (b) {
+ int col_num;
+ line_num = find_line_num(ctx, b, -1, &col_num);
+ }
+
/* scan for jump targets */
for (pos = 0; pos < len; pos = pos_next) {
op = tab[pos];
@@ -28606,10 +30890,12 @@ static void dump_byte_code(JSContext *ctx, int pass,
pos = 0;
while (pos < len) {
op = tab[pos];
- if (source) {
+ if (source && b) {
+ int col_num;
if (b) {
- line1 = find_line_num(ctx, b, pos) - line_num + 1;
+ line1 = find_line_num(ctx, b, pos, &col_num) - line_num + 1;
} else if (op == OP_line_num) {
+ /* XXX: no longer works */
line1 = get_u32(tab + pos + 1) - line_num + 1;
}
if (line1 > line) {
@@ -28727,7 +31013,7 @@ static void dump_byte_code(JSContext *ctx, int pass,
has_pool_idx:
printf(" %u: ", idx);
if (idx < cpool_count) {
- JS_DumpValue(ctx, cpool[idx]);
+ JS_PrintValue(ctx, js_dump_value_write, stdout, cpool[idx], NULL);
}
break;
case OP_FMT_atom:
@@ -28810,49 +31096,64 @@ static void dump_byte_code(JSContext *ctx, int pass,
js_free(ctx, bits);
}
-static __maybe_unused void dump_pc2line(JSContext *ctx, const uint8_t *buf, int len,
- int line_num)
+static __maybe_unused void dump_pc2line(JSContext *ctx, const uint8_t *buf, int len)
{
- const uint8_t *p_end, *p_next, *p;
- int pc, v;
+ const uint8_t *p_end, *p;
+ int pc, v, line_num, col_num, ret;
unsigned int op;
-
+ uint32_t val;
+
if (len <= 0)
return;
- printf("%5s %5s\n", "PC", "LINE");
+ printf("%5s %5s %5s\n", "PC", "LINE", "COL");
p = buf;
p_end = buf + len;
+
+ /* get the function line and column numbers */
+ ret = get_leb128(&val, p, p_end);
+ if (ret < 0)
+ goto fail;
+ p += ret;
+ line_num = val + 1;
+
+ ret = get_leb128(&val, p, p_end);
+ if (ret < 0)
+ goto fail;
+ p += ret;
+ col_num = val + 1;
+
+ printf("%5s %5d %5d\n", "-", line_num, col_num);
+
pc = 0;
while (p < p_end) {
op = *p++;
if (op == 0) {
- v = unicode_from_utf8(p, p_end - p, &p_next);
- if (v < 0)
+ ret = get_leb128(&val, p, p_end);
+ if (ret < 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;
- }
+ pc += val;
+ p += ret;
+ ret = get_sleb128(&v, p, p_end);
+ if (ret < 0)
+ goto fail;
+ p += ret;
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);
+ ret = get_sleb128(&v, p, p_end);
+ if (ret < 0)
+ goto fail;
+ p += ret;
+ col_num += v;
+
+ printf("%5d %5d %5d\n", pc, line_num, col_num);
}
+ fail: ;
}
static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionBytecode *b)
@@ -28862,8 +31163,10 @@ static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionB
const char *str;
if (b->has_debug && b->debug.filename != JS_ATOM_NULL) {
+ int line_num, col_num;
str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->debug.filename);
- printf("%s:%d: ", str, b->debug.line_num);
+ line_num = find_line_num(ctx, b, -1, &col_num);
+ printf("%s:%d:%d: ", str, line_num, col_num);
}
str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->func_name);
@@ -28872,10 +31175,6 @@ static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionB
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) {
@@ -28922,10 +31221,10 @@ static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionB
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);
+ 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);
+ dump_pc2line(ctx, b->debug.pc2line_buf, b->debug.pc2line_len);
#endif
printf("\n");
}
@@ -29213,13 +31512,19 @@ static void var_object_test(JSContext *ctx, JSFunctionDef *s,
{
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);
+ if (*plabel_done < 0) {
+ *plabel_done = new_label_fd(s);
+ if (*plabel_done < 0) {
+ dbuf_set_error(bc);
+ return;
+ }
+ }
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,
@@ -29342,6 +31647,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
case OP_scope_get_ref:
dbuf_putc(bc, OP_undefined);
/* fall thru */
+ case OP_scope_get_var_checkthis:
case OP_scope_get_var_undef:
case OP_scope_get_var:
case OP_scope_put_var:
@@ -29367,7 +31673,12 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
}
} else {
if (s->vars[var_idx].is_lexical) {
- dbuf_putc(bc, OP_get_loc_check);
+ if (op == OP_scope_get_var_checkthis) {
+ /* only used for 'this' return in derived class constructors */
+ dbuf_putc(bc, OP_get_loc_checkthis);
+ } else {
+ dbuf_putc(bc, OP_get_loc_check);
+ }
} else {
dbuf_putc(bc, OP_get_loc);
}
@@ -29425,7 +31736,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
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)
@@ -29469,7 +31780,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
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 */
}
@@ -29672,7 +31983,7 @@ 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)
+ if (is_ref)
dbuf_putc(bc, OP_get_var_ref);
else
dbuf_putc(bc, OP_get_loc);
@@ -29687,7 +31998,7 @@ static int resolve_scope_private_field1(JSContext *ctx,
int idx, var_kind;
JSFunctionDef *fd;
BOOL is_ref;
-
+
fd = s;
is_ref = FALSE;
for(;;) {
@@ -29831,6 +32142,10 @@ static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s,
abort();
}
break;
+ case OP_scope_in_private_field:
+ get_loc_or_ref(bc, is_ref, idx);
+ dbuf_putc(bc, OP_private_in);
+ break;
default:
abort();
}
@@ -30015,7 +32330,7 @@ static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
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;
@@ -30248,8 +32563,11 @@ static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, Dy
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);
-
+ label_next = new_label_fd(s);
+ if (label_next < 0) {
+ dbuf_set_error(bc);
+ return;
+ }
/* if 'this' is true, initialize the global variables and return */
dbuf_putc(bc, OP_push_this);
dbuf_putc(bc, OP_if_false);
@@ -30257,7 +32575,7 @@ static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, Dy
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++) {
@@ -30286,7 +32604,7 @@ static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, Dy
}
if (!has_closure) {
int flags;
-
+
flags = 0;
if (s->eval_type != JS_EVAL_TYPE_GLOBAL)
flags |= JS_PROP_CONFIGURABLE;
@@ -30294,11 +32612,11 @@ static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, Dy
/* 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) {
@@ -30342,7 +32660,7 @@ static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, Dy
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;
@@ -30447,7 +32765,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
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];
@@ -30469,7 +32787,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
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;
@@ -30499,15 +32817,16 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
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);
+ dbuf_put_u16(&bc_out, s->scopes[scope].first - ARG_SCOPE_END);
}
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);
+ dbuf_put_u16(&bc_out, s->scopes[scope].first - ARG_SCOPE_END);
break;
+ case OP_scope_get_var_checkthis:
case OP_scope_get_var_undef:
case OP_scope_get_var:
case OP_scope_put_var:
@@ -30537,6 +32856,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
case OP_scope_get_private_field:
case OP_scope_get_private_field2:
case OP_scope_put_private_field:
+ case OP_scope_in_private_field:
{
int ret;
var_name = get_u32(bc_buf + pos + 1);
@@ -30748,7 +33068,18 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
case OP_set_class_name:
/* only used during parsing */
break;
-
+
+ case OP_get_field_opt_chain: /* equivalent to OP_get_field */
+ {
+ JSAtom name = get_u32(bc_buf + pos + 1);
+ dbuf_putc(&bc_out, OP_get_field);
+ dbuf_put_u32(&bc_out, name);
+ }
+ break;
+ case OP_get_array_el_opt_chain: /* equivalent to OP_get_array_el */
+ dbuf_putc(&bc_out, OP_get_array_el);
+ break;
+
default:
no_change:
dbuf_put(&bc_out, bc_buf + pos, len);
@@ -30778,40 +33109,58 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
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)
+/* the pc2line table gives a source position for each PC value */
+static void add_pc2line_info(JSFunctionDef *s, uint32_t pc, uint32_t source_pos)
{
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) {
+ && source_pos != 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_slots[s->line_number_count].source_pos = source_pos;
s->line_number_count++;
s->line_number_last_pc = pc;
- s->line_number_last = line_num;
+ s->line_number_last = source_pos;
}
}
+/* XXX: could use a more compact storage */
+/* XXX: get_line_col_cached() is slow. For more predictable
+ performance, line/cols could be stored every N source
+ bytes. Alternatively, get_line_col_cached() could be issued in
+ emit_source_pos() so that the deltas are more likely to be
+ small. */
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;
+ if (!s->strip_debug) {
+ int last_line_num, last_col_num;
uint32_t last_pc = 0;
- int i;
-
+ int i, line_num, col_num;
+ const uint8_t *buf_start = s->get_line_col_cache->buf_start;
js_dbuf_init(s->ctx, &s->pc2line);
+
+ last_line_num = get_line_col_cached(s->get_line_col_cache,
+ &last_col_num,
+ buf_start + s->source_pos);
+ dbuf_put_leb128(&s->pc2line, last_line_num); /* line number minus 1 */
+ dbuf_put_leb128(&s->pc2line, last_col_num); /* column number minus 1 */
+
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;
+ uint32_t source_pos = s->line_number_slots[i].source_pos;
+ int diff_pc, diff_line, diff_col;
- if (line_num < 0)
+ if (source_pos == -1)
continue;
-
diff_pc = pc - last_pc;
+ if (diff_pc < 0)
+ continue;
+
+ line_num = get_line_col_cached(s->get_line_col_cache, &col_num,
+ buf_start + source_pos);
diff_line = line_num - last_line_num;
- if (diff_line == 0 || diff_pc < 0)
+ diff_col = col_num - last_col_num;
+ if (diff_line == 0 && diff_col == 0)
continue;
if (diff_line >= PC2LINE_BASE &&
@@ -30825,8 +33174,11 @@ static void compute_pc2line_info(JSFunctionDef *s)
dbuf_put_leb128(&s->pc2line, diff_pc);
dbuf_put_sleb128(&s->pc2line, diff_line);
}
+ dbuf_put_sleb128(&s->pc2line, diff_col);
+
last_pc = pc;
last_line_num = line_num;
+ last_col_num = col_num;
}
}
}
@@ -30872,10 +33224,11 @@ static BOOL code_has_label(CodeContext *s, int pos, int label)
/* 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)
+static int find_jump_target(JSFunctionDef *s, int label0, int *pop, int *pline)
{
- int i, pos, op;
+ int i, pos, op, label;
+ label = label0;
update_label(s, label, -1);
for (i = 0; i < 10; i++) {
assert(label >= 0 && label < s->label_count);
@@ -30906,6 +33259,19 @@ static int find_jump_target(JSFunctionDef *s, int label, int *pop, int *pline)
}
}
/* cycle detected, could issue a warning */
+ /* XXX: the combination of find_jump_target() and skip_dead_code()
+ seems incorrect with cyclic labels. See for exemple:
+
+ for (;;) {
+ l:break l;
+ l:break l;
+ l:break l;
+ l:break l;
+ }
+
+ Avoiding changing the target is just a workaround and might not
+ suffice to completely fix the problem. */
+ label = label0;
done:
*pop = op;
update_label(s, label, +1);
@@ -31008,7 +33374,7 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
label_slots = s->label_slots;
- line_num = s->line_num;
+ line_num = s->source_pos;
cc.bc_buf = bc_buf = s->byte_code.buf;
cc.bc_len = bc_len = s->byte_code.size;
@@ -31022,11 +33388,11 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
}
#endif
/* XXX: Should skip this phase if not generating SHORT_OPCODES */
- if (s->line_number_size && !(s->js_mode & JS_MODE_STRIP)) {
+ if (s->line_number_size && !s->strip_debug) {
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 = s->source_pos;
s->line_number_last_pc = 0;
}
@@ -31175,7 +33541,7 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
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;
+ //if (line1 != -1) line_num = line1;
update_label(s, label, -1);
add_pc2line_info(s, bc_out.size, line_num);
dbuf_putc(&bc_out, op1);
@@ -31223,7 +33589,7 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
int pos1 = cc.pos;
int line1 = cc.line_num;
if (code_has_label(&cc, pos1, label)) {
- if (line1 >= 0) line_num = line1;
+ if (line1 != -1) line_num = line1;
pos_next = pos1;
update_label(s, label, -1);
label = cc.label;
@@ -31296,7 +33662,6 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
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;
@@ -31423,6 +33788,26 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
}
goto no_change;
+ case OP_push_bigint_i32:
+ if (OPTIMIZE) {
+ /* transform i32(val) neg -> i32(-val) */
+ val = get_i32(bc_buf + pos + 1);
+ if (val != INT32_MIN
+ && 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);
+ dbuf_putc(&bc_out, OP_push_bigint_i32);
+ dbuf_put_u32(&bc_out, -val);
+ }
+ pos_next = cc.pos;
+ break;
+ }
+ }
+ goto no_change;
+
#if SHORT_OPCODES
case OP_push_const:
case OP_fclosure:
@@ -31471,9 +33856,8 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
goto no_change;
case OP_to_propkey:
- case OP_to_propkey2:
if (OPTIMIZE) {
- /* remove redundant to_propkey/to_propkey2 opcodes when storing simple data */
+ /* remove redundant to_propkey 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)) {
@@ -31880,6 +34264,7 @@ typedef struct StackSizeState {
int bc_len;
int stack_len_max;
uint16_t *stack_level_tab;
+ int32_t *catch_pos_tab;
int *pc_stack;
int pc_stack_len;
int pc_stack_size;
@@ -31887,7 +34272,7 @@ typedef struct StackSizeState {
/* 'op' is only used for error indication */
static __exception int ss_check(JSContext *ctx, StackSizeState *s,
- int pos, int op, int stack_len)
+ int pos, int op, int stack_len, int catch_pos)
{
if ((unsigned)pos >= s->bc_len) {
JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
@@ -31906,6 +34291,10 @@ static __exception int ss_check(JSContext *ctx, StackSizeState *s,
JS_ThrowInternalError(ctx, "inconsistent stack size: %d %d (pc=%d)",
s->stack_level_tab[pos], stack_len, pos);
return -1;
+ } else if (s->catch_pos_tab[pos] != catch_pos) {
+ JS_ThrowInternalError(ctx, "inconsistent catch position: %d %d (pc=%d)",
+ s->catch_pos_tab[pos], catch_pos, pos);
+ return -1;
} else {
return 0;
}
@@ -31913,6 +34302,7 @@ static __exception int ss_check(JSContext *ctx, StackSizeState *s,
/* mark as explored and store the stack size */
s->stack_level_tab[pos] = stack_len;
+ s->catch_pos_tab[pos] = catch_pos;
/* queue the new PC to explore */
if (js_resize_array(ctx, (void **)&s->pc_stack, sizeof(s->pc_stack[0]),
@@ -31927,7 +34317,7 @@ static __exception int compute_stack_size(JSContext *ctx,
int *pstack_size)
{
StackSizeState s_s, *s = &s_s;
- int i, diff, n_pop, pos_next, stack_len, pos, op;
+ int i, diff, n_pop, pos_next, stack_len, pos, op, catch_pos, catch_level;
const JSOpCode *oi;
const uint8_t *bc_buf;
@@ -31940,24 +34330,33 @@ static __exception int compute_stack_size(JSContext *ctx,
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->catch_pos_tab = js_malloc(ctx, sizeof(s->catch_pos_tab[0]) *
+ s->bc_len);
+ if (!s->catch_pos_tab)
+ goto fail;
+
+ s->stack_len_max = 0;
s->pc_stack_len = 0;
s->pc_stack_size = 0;
/* breadth-first graph exploration */
- if (ss_check(ctx, s, 0, OP_invalid, 0))
+ if (ss_check(ctx, s, 0, OP_invalid, 0, -1))
goto fail;
while (s->pc_stack_len > 0) {
pos = s->pc_stack[--s->pc_stack_len];
stack_len = s->stack_level_tab[pos];
+ catch_pos = s->catch_pos_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);
+#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 64)
+ printf("%5d: %10s %5d %5d\n", pos, oi->name, stack_len, catch_pos);
+#endif
pos_next = pos + oi->size;
if (pos_next > s->bc_len) {
JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
@@ -32013,55 +34412,103 @@ static __exception int compute_stack_size(JSContext *ctx,
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))
+ if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))
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))
+ if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))
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))
+ if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1, catch_pos))
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))
+ if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1, catch_pos))
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))
+ if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2, catch_pos))
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))
+ if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1, catch_pos))
goto fail;
break;
-
+ case OP_catch:
+ diff = get_u32(bc_buf + pos + 1);
+ if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))
+ goto fail;
+ catch_pos = pos;
+ break;
+ case OP_for_of_start:
+ case OP_for_await_of_start:
+ catch_pos = pos;
+ break;
+ /* we assume the catch offset entry is only removed with
+ some op codes */
+ case OP_drop:
+ catch_level = stack_len;
+ goto check_catch;
+ case OP_nip:
+ catch_level = stack_len - 1;
+ goto check_catch;
+ case OP_nip1:
+ catch_level = stack_len - 1;
+ goto check_catch;
+ case OP_iterator_close:
+ catch_level = stack_len + 2;
+ check_catch:
+ /* Note: for for_of_start/for_await_of_start we consider
+ the catch offset is on the first stack entry instead of
+ the thirst */
+ if (catch_pos >= 0) {
+ int level;
+ level = s->stack_level_tab[catch_pos];
+ if (bc_buf[catch_pos] != OP_catch)
+ level++; /* for_of_start, for_wait_of_start */
+ /* catch_level = stack_level before op_catch is executed ? */
+ if (catch_level == level) {
+ catch_pos = s->catch_pos_tab[catch_pos];
+ }
+ }
+ break;
+ case OP_nip_catch:
+ if (catch_pos < 0) {
+ JS_ThrowInternalError(ctx, "nip_catch: no catch op (pc=%d)", pos);
+ goto fail;
+ }
+ stack_len = s->stack_level_tab[catch_pos];
+ if (bc_buf[catch_pos] != OP_catch)
+ stack_len++; /* for_of_start, for_wait_of_start */
+ stack_len++; /* no stack overflow is possible by construction */
+ catch_pos = s->catch_pos_tab[catch_pos];
+ break;
default:
break;
}
- if (ss_check(ctx, s, pos_next, op, stack_len))
+ if (ss_check(ctx, s, pos_next, op, stack_len, catch_pos))
goto fail;
done_insn: ;
}
- js_free(ctx, s->stack_level_tab);
js_free(ctx, s->pc_stack);
+ js_free(ctx, s->catch_pos_tab);
+ js_free(ctx, s->stack_level_tab);
*pstack_size = s->stack_len_max;
return 0;
fail:
- js_free(ctx, s->stack_level_tab);
js_free(ctx, s->pc_stack);
+ js_free(ctx, s->catch_pos_tab);
+ js_free(ctx, s->stack_level_tab);
*pstack_size = 0;
return -1;
}
@@ -32167,12 +34614,12 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
}
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 4)
- if (!(fd->js_mode & JS_MODE_STRIP)) {
+ if (!fd->strip_debug) {
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->cpool, fd->cpool_count, fd->source,
fd->label_slots, NULL);
printf("\n");
}
@@ -32182,12 +34629,12 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
goto fail;
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 2)
- if (!(fd->js_mode & JS_MODE_STRIP)) {
+ if (!fd->strip_debug) {
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->cpool, fd->cpool_count, fd->source,
fd->label_slots, NULL);
printf("\n");
}
@@ -32199,7 +34646,7 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
if (compute_stack_size(ctx, fd, &stack_size) < 0)
goto fail;
- if (fd->js_mode & JS_MODE_STRIP) {
+ if (fd->strip_debug) {
function_size = offsetof(JSFunctionBytecode, debug);
} else {
function_size = sizeof(*b);
@@ -32207,7 +34654,7 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
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) {
+ if (!fd->strip_debug || fd->has_eval_call) {
function_size += (fd->arg_count + fd->var_count) * sizeof(*b->vardefs);
}
closure_var_offset = function_size;
@@ -32228,7 +34675,7 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
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) {
+ if (fd->strip_debug && !fd->has_eval_call) {
/* Strip variable definitions not needed at runtime */
int i;
for(i = 0; i < fd->var_count; i++) {
@@ -32243,8 +34690,8 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
}
} else {
b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
- memcpy(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0]));
- memcpy(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0]));
+ memcpy_no_ub(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0]));
+ memcpy_no_ub(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;
@@ -32262,7 +34709,7 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
b->stack_size = stack_size;
- if (fd->js_mode & JS_MODE_STRIP) {
+ if (fd->strip_debug) {
JS_FreeAtom(ctx, fd->filename);
dbuf_free(&fd->pc2line); // probably useless
} else {
@@ -32271,7 +34718,6 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
*/
b->has_debug = 1;
b->debug.filename = fd->filename;
- b->debug.line_num = fd->line_num;
//DynBuf pc2line;
//compute_pc2line_info(fd, &pc2line);
@@ -32305,13 +34751,14 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
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->is_direct_or_indirect_eval = (fd->eval_type == JS_EVAL_TYPE_DIRECT ||
+ fd->eval_type == JS_EVAL_TYPE_INDIRECT);
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)) {
+ if (!fd->strip_debug) {
js_dump_function_bytecode(ctx, b);
}
#endif
@@ -32453,20 +34900,16 @@ static __exception int js_parse_directives(JSParseState *s)
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);
}
+/* return TRUE if the keyword is forbidden only in strict mode */
+static BOOL is_strict_future_keyword(JSAtom atom)
+{
+ return (atom >= JS_ATOM_LAST_KEYWORD + 1 && atom <= JS_ATOM_LAST_STRICT_KEYWORD);
+}
+
static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd,
JSAtom func_name)
{
@@ -32477,13 +34920,15 @@ static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd,
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) {
+ if (func_name == JS_ATOM_eval || func_name == JS_ATOM_arguments ||
+ is_strict_future_keyword(func_name)) {
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) {
+ if (name == JS_ATOM_eval || name == JS_ATOM_arguments ||
+ is_strict_future_keyword(name)) {
return js_parse_error(s, "invalid argument name in strict code");
}
}
@@ -32521,15 +34966,16 @@ static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd,
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);
+ s->filename, s->buf_start,
+ &s->get_line_col_cache);
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;
@@ -32537,7 +34983,7 @@ static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s)
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;
@@ -32550,7 +34996,6 @@ static __exception int js_parse_function_decl2(JSParseState *s,
JSFunctionKindEnum func_kind,
JSAtom func_name,
const uint8_t *ptr,
- int function_line_num,
JSParseExportEnum export_flag,
JSFunctionDef **pfd)
{
@@ -32588,8 +35033,9 @@ static __exception int js_parse_function_decl2(JSParseState *s,
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))) {
+ ((func_type == JS_PARSE_FUNC_EXPR &&
+ (func_kind & JS_FUNC_ASYNC)) ||
+ func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))) {
return js_parse_error_reserved_identifier(s);
}
}
@@ -32664,7 +35110,8 @@ static __exception int js_parse_function_decl2(JSParseState *s,
}
fd = js_new_function_def(ctx, fd, FALSE, is_expr,
- s->filename, function_line_num);
+ s->filename, ptr,
+ &s->get_line_col_cache);
if (!fd) {
JS_FreeAtom(ctx, func_name);
return -1;
@@ -32683,7 +35130,8 @@ static __exception int js_parse_function_decl2(JSParseState *s,
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_arguments_binding = (func_type != JS_PARSE_FUNC_ARROW &&
+ func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT);
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) {
@@ -32691,6 +35139,11 @@ static __exception int js_parse_function_decl2(JSParseState *s,
fd->super_call_allowed = fd->parent->super_call_allowed;
fd->super_allowed = fd->parent->super_allowed;
fd->arguments_allowed = fd->parent->arguments_allowed;
+ } else if (func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) {
+ fd->new_target_allowed = TRUE; // although new.target === undefined
+ fd->super_call_allowed = FALSE;
+ fd->super_allowed = TRUE;
+ fd->arguments_allowed = FALSE;
} else {
fd->new_target_allowed = TRUE;
fd->super_call_allowed = fd->is_derived_class_constructor;
@@ -32713,7 +35166,7 @@ static __exception int js_parse_function_decl2(JSParseState *s,
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;
@@ -32728,7 +35181,7 @@ static __exception int js_parse_function_decl2(JSParseState *s,
if (add_arg(ctx, fd, name) < 0)
goto fail;
fd->defined_arg_count = 1;
- } else {
+ } else if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) {
if (s->token.val == '(') {
int skip_bits;
/* if there is an '=' inside the parameter list, we
@@ -32748,13 +35201,15 @@ static __exception int js_parse_function_decl2(JSParseState *s,
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) {
+ if (func_type == JS_PARSE_FUNC_SETTER)
+ goto fail_accessor;
fd->has_simple_parameter_list = FALSE;
rest = TRUE;
if (next_token(s))
@@ -32771,7 +35226,7 @@ static __exception int js_parse_function_decl2(JSParseState *s,
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);
+ has_initializer = js_parse_destructuring_element(s, fd->has_parameter_expressions ? TOK_LET : TOK_VAR, 1, TRUE, -1, TRUE, FALSE);
if (has_initializer < 0)
goto fail;
if (has_initializer)
@@ -32789,6 +35244,8 @@ static __exception int js_parse_function_decl2(JSParseState *s,
goto fail;
}
if (fd->has_parameter_expressions) {
+ if (js_parse_check_duplicate_parameter(s, name))
+ goto fail;
if (define_var(s, fd, name, JS_VAR_DEF_LET) < 0)
goto fail;
}
@@ -32813,7 +35270,7 @@ static __exception int js_parse_function_decl2(JSParseState *s,
has_opt_arg = TRUE;
} else if (s->token.val == '=') {
int label;
-
+
fd->has_simple_parameter_list = FALSE;
has_opt_arg = TRUE;
@@ -32866,6 +35323,7 @@ static __exception int js_parse_function_decl2(JSParseState *s,
}
if ((func_type == JS_PARSE_FUNC_GETTER && fd->arg_count != 0) ||
(func_type == JS_PARSE_FUNC_SETTER && fd->arg_count != 1)) {
+ fail_accessor:
js_parse_error(s, "invalid number of arguments for getter or setter");
goto fail;
}
@@ -32896,7 +35354,7 @@ static __exception int js_parse_function_decl2(JSParseState *s,
}
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);
@@ -32905,7 +35363,7 @@ static __exception int js_parse_function_decl2(JSParseState *s,
fd->scope_level = 0;
fd->scope_first = fd->scopes[fd->scope_level].first;
}
-
+
if (next_token(s))
goto fail;
@@ -32920,7 +35378,7 @@ static __exception int js_parse_function_decl2(JSParseState *s,
push_scope(s); /* enter body scope */
fd->body_scope = fd->scope_level;
- if (s->token.val == TOK_ARROW) {
+ if (s->token.val == TOK_ARROW && func_type == JS_PARSE_FUNC_ARROW) {
if (next_token(s))
goto fail;
@@ -32936,7 +35394,7 @@ static __exception int js_parse_function_decl2(JSParseState *s,
else
emit_op(s, OP_return);
- if (!(fd->js_mode & JS_MODE_STRIP)) {
+ if (!fd->strip_source) {
/* 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 */
@@ -32949,8 +35407,10 @@ static __exception int js_parse_function_decl2(JSParseState *s,
}
}
- if (js_parse_expect(s, '{'))
- goto fail;
+ if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) {
+ if (js_parse_expect(s, '{'))
+ goto fail;
+ }
if (js_parse_directives(s))
goto fail;
@@ -32963,7 +35423,7 @@ static __exception int js_parse_function_decl2(JSParseState *s,
if (js_parse_source_element(s))
goto fail;
}
- if (!(fd->js_mode & JS_MODE_STRIP)) {
+ if (!fd->strip_source) {
/* save the function source code */
fd->source_len = s->buf_ptr - ptr;
fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);
@@ -32980,9 +35440,15 @@ static __exception int js_parse_function_decl2(JSParseState *s,
if (js_is_live_code(s)) {
emit_return(s, FALSE);
}
-done:
+ done:
s->cur_func = fd->parent;
+ /* Reparse identifiers after the function is terminated so that
+ the token is parsed in the englobing function. It could be done
+ by just using next_token() here for normal functions, but it is
+ necessary for arrow functions with an expression body. */
+ reparse_ident_token(s);
+
/* create the function object */
{
int idx;
@@ -33019,7 +35485,7 @@ static __exception int js_parse_function_decl2(JSParseState *s,
/* 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->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);
@@ -33097,12 +35563,10 @@ 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)
+ const uint8_t *ptr)
{
return js_parse_function_decl2(s, func_type, func_kind, func_name, ptr,
- function_line_num, JS_PARSE_EXPORT_NONE,
- NULL);
+ JS_PARSE_EXPORT_NONE, NULL);
}
static __exception int js_parse_program(JSParseState *s)
@@ -33134,12 +35598,24 @@ static __exception int js_parse_program(JSParseState *s)
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);
+ if (fd->func_kind == JS_FUNC_ASYNC) {
+ /* wrap the return value in an object so that promises can
+ be safely returned */
+ emit_op(s, OP_object);
+ emit_op(s, OP_dup);
- emit_op(s, OP_return);
+ emit_op(s, OP_get_loc);
+ emit_u16(s, fd->eval_ret_idx);
+
+ emit_op(s, OP_put_field);
+ emit_atom(s, JS_ATOM_value);
+ } else {
+ emit_op(s, OP_get_loc);
+ emit_u16(s, fd->eval_ret_idx);
+ }
+ emit_return(s, TRUE);
} else {
- emit_op(s, OP_return_undef);
+ emit_return(s, FALSE);
}
return 0;
@@ -33152,11 +35628,15 @@ static void js_parse_init(JSContext *ctx, JSParseState *s,
memset(s, 0, sizeof(*s));
s->ctx = ctx;
s->filename = filename;
- s->line_num = 1;
- s->buf_ptr = (const uint8_t *)input;
+ s->buf_start = s->buf_ptr = (const uint8_t *)input;
s->buf_end = s->buf_ptr + input_len;
s->token.val = ' ';
- s->token.line_num = 1;
+ s->token.ptr = s->buf_ptr;
+
+ s->get_line_col_cache.ptr = s->buf_start;
+ s->get_line_col_cache.buf_start = s->buf_start;
+ s->get_line_col_cache.line_num = 0;
+ s->get_line_col_cache.col_num = 0;
}
static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj,
@@ -33182,7 +35662,6 @@ static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj,
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 {
@@ -33197,31 +35676,6 @@ 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,
@@ -33237,7 +35691,7 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
JSModuleDef *m;
js_parse_init(ctx, s, input, input_len, filename);
- skip_shebang(s);
+ skip_shebang(&s->buf_ptr, s->buf_end);
eval_type = flags & JS_EVAL_TYPE_MASK;
m = NULL;
@@ -33258,8 +35712,6 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
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)
@@ -33270,13 +35722,13 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
js_mode |= JS_MODE_STRICT;
}
}
- fd = js_new_function_def(ctx, NULL, TRUE, FALSE, filename, 1);
+ fd = js_new_function_def(ctx, NULL, TRUE, FALSE, filename,
+ s->buf_start, &s->get_line_col_cache);
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;
@@ -33295,12 +35747,16 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
goto fail;
}
fd->module = m;
+ if (m != NULL || (flags & JS_EVAL_FLAG_ASYNC)) {
+ fd->in_function_body = TRUE;
+ fd->func_kind = JS_FUNC_ASYNC;
+ }
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:
@@ -33309,6 +35765,9 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
goto fail1;
}
+ if (m != NULL)
+ m->has_tla = fd->has_await;
+
/* create the function object and all the enclosed functions */
fun_obj = js_create_function(ctx, fd);
if (JS_IsException(fun_obj))
@@ -33318,7 +35777,7 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
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));
+ fun_obj = JS_NewModuleValue(ctx, m);
}
if (flags & JS_EVAL_FLAG_COMPILE_ONLY) {
ret_val = fun_obj;
@@ -33338,11 +35797,22 @@ static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
const char *input, size_t input_len,
const char *filename, int flags, int scope_idx)
{
+ BOOL backtrace_barrier = ((flags & JS_EVAL_FLAG_BACKTRACE_BARRIER) != 0);
+ int saved_js_mode = 0;
+ JSValue ret;
+
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);
+ if (backtrace_barrier && ctx->rt->current_stack_frame) {
+ saved_js_mode = ctx->rt->current_stack_frame->js_mode;
+ ctx->rt->current_stack_frame->js_mode |= JS_MODE_BACKTRACE_BARRIER;
+ }
+ ret = ctx->eval_internal(ctx, this_obj, input, input_len, filename,
+ flags, scope_idx);
+ if (backtrace_barrier && ctx->rt->current_stack_frame)
+ ctx->rt->current_stack_frame->js_mode = saved_js_mode;
+ return ret;
}
static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
@@ -33435,13 +35905,13 @@ static int js_object_list_resize_hash(JSContext *ctx, JSObjectList *s,
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);
+ h = js_object_list_get_hash(e->obj, s->hash_size);
e->hash_next = s->hash_table[h];
s->hash_table[h] = i;
}
@@ -33454,7 +35924,7 @@ 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))
@@ -33467,7 +35937,7 @@ static int js_object_list_add(JSContext *ctx, JSObjectList *s, JSObject *obj)
return -1;
}
e = &s->object_tab[s->object_count++];
- h = js_object_list_get_hash(obj, s->hash_size);
+ 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;
@@ -33483,7 +35953,7 @@ static int js_object_list_find(JSContext *ctx, JSObjectList *s, JSObject *obj)
/* 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);
+ h = js_object_list_get_hash(obj, s->hash_size);
p = s->hash_table[h];
while (p != -1) {
e = &s->object_tab[p];
@@ -33514,8 +35984,6 @@ typedef enum BCTagEnum {
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,
@@ -33527,22 +35995,11 @@ typedef enum BCTagEnum {
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
+#define BC_VERSION 5
typedef struct BCWriterState {
JSContext *ctx;
DynBuf dbuf;
- BOOL byte_swap : 8;
BOOL allow_bytecode : 8;
BOOL allow_sab : 8;
BOOL allow_reference : 8;
@@ -33572,8 +36029,6 @@ static const char * const bc_tag_str[] = {
"object",
"array",
"bigint",
- "bigfloat",
- "bigdecimal",
"template",
"function",
"module",
@@ -33586,6 +36041,15 @@ static const char * const bc_tag_str[] = {
};
#endif
+static inline BOOL is_be(void)
+{
+ union {
+ uint16_t a;
+ uint8_t b;
+ } u = {0x100};
+ return u.b;
+}
+
static void bc_put_u8(BCWriterState *s, uint8_t v)
{
dbuf_putc(&s->dbuf, v);
@@ -33593,21 +36057,21 @@ static void bc_put_u8(BCWriterState *s, uint8_t v)
static void bc_put_u16(BCWriterState *s, uint16_t v)
{
- if (s->byte_swap)
+ if (is_be())
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)
+ if (is_be())
v = bswap32(v);
dbuf_put_u32(&s->dbuf, v);
}
static void bc_put_u64(BCWriterState *s, uint64_t v)
{
- if (s->byte_swap)
+ if (is_be())
v = bswap64(v);
dbuf_put(&s->dbuf, (uint8_t *)&v, sizeof(v));
}
@@ -33777,7 +36241,7 @@ static int JS_WriteFunctionBytecode(BCWriterState *s,
pos += len;
}
- if (s->byte_swap)
+ if (is_be())
bc_byte_swap(bc_buf, bc_len);
dbuf_put(&s->dbuf, bc_buf, bc_len);
@@ -33801,138 +36265,50 @@ static void JS_WriteString(BCWriterState *s, JSString *p)
}
}
-static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj)
+static int JS_WriteBigInt(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;
-#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_FLOAT:
- tag1 = BC_TAG_BIG_FLOAT;
- break;
- case JS_TAG_BIG_DECIMAL:
- tag1 = BC_TAG_BIG_DECIMAL;
- break;
-#endif
- default:
- abort();
- }
- bc_put_u8(s, tag1);
+ JSBigIntBuf buf;
+ JSBigInt *p;
+ uint32_t len, i;
+ js_limb_t v, b;
+ int shift;
+
+ bc_put_u8(s, BC_TAG_BIG_INT);
- /* 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;
+ if (JS_VALUE_GET_TAG(obj) == JS_TAG_SHORT_BIG_INT)
+ p = js_bigint_set_short(&buf, obj);
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;
+ p = JS_VALUE_GET_PTR(obj);
+ if (p->len == 1 && p->tab[0] == 0) {
+ /* zero case */
+ len = 0;
+ } else {
+ /* compute the length of the two's complement representation
+ in bytes */
+ len = p->len * (JS_LIMB_BITS / 8);
+ v = p->tab[p->len - 1];
+ shift = JS_LIMB_BITS - 8;
+ while (shift > 0) {
+ b = (v >> shift) & 0xff;
+ if (b != 0x00 && b != 0xff)
+ break;
+ if ((b & 1) != ((v >> (shift - 1)) & 1))
+ break;
+ shift -= 8;
+ len--;
+ }
}
- 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);
+ bc_put_leb128(s, len);
+ if (len > 0) {
+ for(i = 0; i < (len / (JS_LIMB_BITS / 8)); i++) {
+#if JS_LIMB_BITS == 32
+ bc_put_u32(s, p->tab[i]);
#else
-#ifdef WORDS_BIGENDIAN
- v = bswap64(v);
-#endif
- dbuf_put_u64(&s->dbuf, v);
+ bc_put_u64(s, p->tab[i]);
#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);
- }
+ }
+ for(i = 0; i < len % (JS_LIMB_BITS / 8); i++) {
+ bc_put_u8(s, (p->tab[p->len - 1] >> (i * 8)) & 0xff);
}
}
return 0;
@@ -33945,7 +36321,7 @@ 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);
@@ -33958,12 +36334,12 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj)
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);
+ bc_set_flags(&flags, &idx, b->is_direct_or_indirect_eval, 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);
@@ -33990,7 +36366,7 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj)
} 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);
@@ -34004,17 +36380,22 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj)
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);
+ if (b->debug.source) {
+ bc_put_leb128(s, b->debug.source_len);
+ dbuf_put(&s->dbuf, (uint8_t *)b->debug.source, b->debug.source_len);
+ } else {
+ bc_put_leb128(s, 0);
+ }
}
-
+
for(i = 0; i < b->cpool_count; i++) {
if (JS_WriteObjectRec(s, b->cpool[i]))
goto fail;
@@ -34028,16 +36409,18 @@ 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);
+ if (JS_WriteObjectRec(s, rme->attributes))
+ goto fail;
}
-
+
bc_put_leb128(s, m->export_entries_count);
for(i = 0; i < m->export_entries_count; i++) {
JSExportEntry *me = &m->export_entries[i];
@@ -34050,21 +36433,24 @@ static int JS_WriteModule(BCWriterState *s, JSValueConst obj)
}
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_u8(s, mi->is_star);
bc_put_atom(s, mi->import_name);
bc_put_leb128(s, mi->req_module_idx);
}
-
+
+ bc_put_u8(s, m->has_tla);
+
if (JS_WriteObjectRec(s, m->func_obj))
goto fail;
return 0;
@@ -34079,7 +36465,7 @@ static int JS_WriteArray(BCWriterState *s, JSValueConst obj)
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 */
@@ -34237,6 +36623,16 @@ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj)
JS_WriteString(s, p);
}
break;
+ case JS_TAG_STRING_ROPE:
+ {
+ JSValue str;
+ str = JS_ToString(s->ctx, obj);
+ if (JS_IsException(str))
+ goto fail;
+ JS_WriteObjectRec(s, str);
+ JS_FreeValue(s->ctx, str);
+ }
+ break;
case JS_TAG_FUNCTION_BYTECODE:
if (!s->allow_bytecode)
goto invalid_tag;
@@ -34253,7 +36649,7 @@ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj)
{
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) {
@@ -34294,10 +36690,6 @@ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj)
case JS_CLASS_STRING:
case JS_CLASS_BOOLEAN:
case JS_CLASS_BIG_INT:
-#ifdef CONFIG_BIGNUM
- 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;
@@ -34316,12 +36708,9 @@ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj)
goto fail;
}
break;
+ case JS_TAG_SHORT_BIG_INT:
case JS_TAG_BIG_INT:
-#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_FLOAT:
- case JS_TAG_BIG_DECIMAL:
-#endif
- if (JS_WriteBigNum(s, obj))
+ if (JS_WriteBigInt(s, obj))
goto fail;
break;
default:
@@ -34341,15 +36730,10 @@ 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_u8(s, BC_VERSION);
bc_put_leb128(s, s->idx_to_atom_count);
for(i = 0; i < s->idx_to_atom_count; i++) {
@@ -34382,8 +36766,6 @@ uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,
memset(s, 0, 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);
@@ -34394,7 +36776,7 @@ uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,
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))
@@ -34442,7 +36824,7 @@ typedef struct BCReaderState {
JSObject **objects;
int objects_count;
int objects_size;
-
+
#ifdef DUMP_READ_OBJECT
const uint8_t *ptr_last;
int level;
@@ -34504,33 +36886,45 @@ static int bc_get_u8(BCReaderState *s, uint8_t *pval)
static int bc_get_u16(BCReaderState *s, uint16_t *pval)
{
+ uint16_t v;
if (unlikely(s->buf_end - s->ptr < 2)) {
*pval = 0; /* avoid warning */
return bc_read_error_end(s);
}
- *pval = get_u16(s->ptr);
+ v = get_u16(s->ptr);
+ if (is_be())
+ v = bswap16(v);
+ *pval = v;
s->ptr += 2;
return 0;
}
static __maybe_unused int bc_get_u32(BCReaderState *s, uint32_t *pval)
{
+ uint32_t v;
if (unlikely(s->buf_end - s->ptr < 4)) {
*pval = 0; /* avoid warning */
return bc_read_error_end(s);
}
- *pval = get_u32(s->ptr);
+ v = get_u32(s->ptr);
+ if (is_be())
+ v = bswap32(v);
+ *pval = v;
s->ptr += 4;
return 0;
}
static int bc_get_u64(BCReaderState *s, uint64_t *pval)
{
+ uint64_t v;
if (unlikely(s->buf_end - s->ptr < 8)) {
*pval = 0; /* avoid warning */
return bc_read_error_end(s);
}
- *pval = get_u64(s->ptr);
+ v = get_u64(s->ptr);
+ if (is_be())
+ v = bswap64(v);
+ *pval = v;
s->ptr += 8;
return 0;
}
@@ -34629,6 +37023,10 @@ static JSString *JS_ReadString(BCReaderState *s)
return NULL;
is_wide_char = len & 1;
len >>= 1;
+ if (len > JS_STRING_LEN_MAX) {
+ JS_ThrowInternalError(s->ctx, "string too long");
+ return NULL;
+ }
p = js_alloc_string(s->ctx, len, is_wide_char);
if (!p) {
s->error_state = -1;
@@ -34642,7 +37040,13 @@ static JSString *JS_ReadString(BCReaderState *s)
}
memcpy(p->u.str8, s->ptr, size);
s->ptr += size;
- if (!is_wide_char) {
+ if (is_wide_char) {
+ if (is_be()) {
+ uint32_t i;
+ for (i = 0; i < len; i++)
+ p->u.str16[i] = bswap16(p->u.str16[i]);
+ }
+ } else {
p->u.str8[size] = '\0'; /* add the trailing zero for 8 bit strings */
}
#ifdef DUMP_READ_OBJECT
@@ -34681,6 +37085,9 @@ static int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b,
}
b->byte_code_buf = bc_buf;
+ if (is_be())
+ bc_byte_swap(bc_buf, bc_len);
+
pos = 0;
while (pos < bc_len) {
op = bc_buf[pos];
@@ -34715,135 +37122,53 @@ static int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b,
return 0;
}
-static JSValue JS_ReadBigNum(BCReaderState *s, int tag)
+static JSValue JS_ReadBigInt(BCReaderState *s)
{
JSValue obj = JS_UNDEFINED;
+ uint32_t len, i, n;
+ JSBigInt *p;
+ js_limb_t v;
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)
+ if (bc_get_leb128(s, &len))
goto fail;
- switch(tag) {
- case BC_TAG_BIG_INT:
- obj = JS_MKPTR(JS_TAG_BIG_INT, p);
- break;
-#ifdef CONFIG_BIGNUM
- 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;
-#endif
- default:
- abort();
+ bc_read_trace(s, "len=%" PRId64 "\n", (int64_t)len);
+ if (len == 0) {
+ /* zero case */
+ bc_read_trace(s, "}\n");
+ return __JS_NewShortBigInt(s->ctx, 0);
}
-
- /* sign + exponent */
- if (bc_get_sleb128(s, &e))
+ p = js_bigint_new(s->ctx, (len - 1) / (JS_LIMB_BITS / 8) + 1);
+ if (!p)
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);
+ for(i = 0; i < len / (JS_LIMB_BITS / 8); i++) {
+#if JS_LIMB_BITS == 32
+ if (bc_get_u32(s, &v))
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
+ if (bc_get_u64(s, &v))
+ goto fail;
#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;
- }
+ p->tab[i] = v;
+ }
+ n = len % (JS_LIMB_BITS / 8);
+ if (n != 0) {
+ int shift;
+ v = 0;
+ for(i = 0; i < n; i++) {
+ if (bc_get_u8(s, &v8))
+ goto fail;
+ v |= (js_limb_t)v8 << (i * 8);
}
+ shift = JS_LIMB_BITS - n * 8;
+ /* extend the sign */
+ if (shift != 0) {
+ v = (js_slimb_t)(v << shift) >> shift;
+ }
+ p->tab[p->len - 1] = v;
}
bc_read_trace(s, "}\n");
- return obj;
+ return JS_CompactBigInt(s->ctx, p);
fail:
JS_FreeValue(s->ctx, obj);
return JS_EXCEPTION;
@@ -34896,7 +37221,7 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
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.is_direct_or_indirect_eval = bc_get_flags(v16, &idx, 1);
bc.read_only_bytecode = s->is_rom_data;
if (bc_get_u8(s, &v8))
goto fail;
@@ -34939,7 +37264,7 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
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) {
@@ -34951,9 +37276,9 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
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
@@ -35024,8 +37349,9 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
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;
+#ifdef DUMP_READ_OBJECT
+ bc_read_trace(s, "filename: "); print_atom(s->ctx, b->debug.filename); printf("\n");
+#endif
if (bc_get_leb128_int(s, &b->debug.pc2line_len))
goto fail;
if (b->debug.pc2line_len) {
@@ -35035,9 +37361,16 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
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
+ if (bc_get_leb128_int(s, &b->debug.source_len))
+ goto fail;
+ if (b->debug.source_len) {
+ bc_read_trace(s, "source: %d bytes\n", b->source_len);
+ b->debug.source = js_mallocz(ctx, b->debug.source_len);
+ if (!b->debug.source)
+ goto fail;
+ if (bc_get_buf(s, (uint8_t *)b->debug.source, b->debug.source_len))
+ goto fail;
+ }
bc_read_trace(s, "}\n");
}
if (b->cpool_count != 0) {
@@ -35066,7 +37399,7 @@ static JSValue JS_ReadModule(BCReaderState *s)
JSAtom module_name;
int i;
uint8_t v8;
-
+
if (bc_get_atom(s, &module_name))
goto fail;
#ifdef DUMP_READ_OBJECT
@@ -35075,7 +37408,7 @@ static JSValue JS_ReadModule(BCReaderState *s)
m = js_new_module_def(ctx, module_name);
if (!m)
goto fail;
- obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
+ obj = JS_NewModuleValue(ctx, m);
if (bc_get_leb128_int(s, &m->req_module_entries_count))
goto fail;
if (m->req_module_entries_count != 0) {
@@ -35085,8 +37418,13 @@ static JSValue JS_ReadModule(BCReaderState *s)
goto fail;
for(i = 0; i < m->req_module_entries_count; i++) {
JSReqModuleEntry *rme = &m->req_module_entries[i];
+ JSValue val;
if (bc_get_atom(s, &rme->module_name))
goto fail;
+ val = JS_ReadObjectRec(s);
+ if (JS_IsException(val))
+ goto fail;
+ rme->attributes = val;
}
}
@@ -35139,8 +37477,12 @@ static JSValue JS_ReadModule(BCReaderState *s)
goto fail;
for(i = 0; i < m->import_entries_count; i++) {
JSImportEntry *mi = &m->import_entries[i];
+ uint8_t v8;
if (bc_get_leb128_int(s, &mi->var_idx))
goto fail;
+ if (bc_get_u8(s, &v8))
+ goto fail;
+ mi->is_star = (v8 != 0);
if (bc_get_atom(s, &mi->import_name))
goto fail;
if (bc_get_leb128_int(s, &mi->req_module_idx))
@@ -35148,6 +37490,10 @@ static JSValue JS_ReadModule(BCReaderState *s)
}
}
+ if (bc_get_u8(s, &v8))
+ goto fail;
+ m->has_tla = (v8 != 0);
+
m->func_obj = JS_ReadObjectRec(s);
if (JS_IsException(m->func_obj))
goto fail;
@@ -35167,7 +37513,7 @@ static JSValue JS_ReadObjectTag(BCReaderState *s)
JSAtom atom;
JSValue val;
int ret;
-
+
obj = JS_NewObject(ctx);
if (BC_add_object_ref(s, obj))
goto fail;
@@ -35247,7 +37593,7 @@ static JSValue JS_ReadTypedArray(BCReaderState *s)
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)
@@ -35292,7 +37638,7 @@ 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)) {
@@ -35318,7 +37664,7 @@ static JSValue JS_ReadSharedArrayBuffer(BCReaderState *s)
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))
@@ -35473,11 +37819,7 @@ static JSValue JS_ReadObjectRec(BCReaderState *s)
obj = JS_ReadObjectValue(s);
break;
case BC_TAG_BIG_INT:
-#ifdef CONFIG_BIGNUM
- case BC_TAG_BIG_FLOAT:
- case BC_TAG_BIG_DECIMAL:
-#endif
- obj = JS_ReadBigNum(s, tag);
+ obj = JS_ReadBigInt(s);
break;
case BC_TAG_OBJECT_REFERENCE:
{
@@ -35512,7 +37854,6 @@ static int JS_ReadObjectAtoms(BCReaderState *s)
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);
@@ -35751,17 +38092,22 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj,
return 0;
}
-void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
- const JSCFunctionListEntry *tab, int len)
+int JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
+ const JSCFunctionListEntry *tab, int len)
{
- int i;
+ int i, ret;
for (i = 0; i < len; i++) {
const JSCFunctionListEntry *e = &tab[i];
JSAtom atom = find_atom(ctx, e->name);
- JS_InstantiateFunctionListItem(ctx, obj, atom, e);
+ if (atom == JS_ATOM_NULL)
+ return -1;
+ ret = JS_InstantiateFunctionListItem(ctx, obj, atom, e);
JS_FreeAtom(ctx, atom);
+ if (ret)
+ return -1;
}
+ return 0;
}
int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m,
@@ -35828,7 +38174,7 @@ static void JS_SetConstructor2(JSContext *ctx,
set_cycle_flag(ctx, proto);
}
-void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj,
+void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj,
JSValueConst proto)
{
JS_SetConstructor2(ctx, func_obj, proto,
@@ -35878,7 +38224,6 @@ static JSValue js_global_isNaN(JSContext *ctx, JSValueConst this_val,
{
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));
@@ -35887,12 +38232,10 @@ static JSValue js_global_isNaN(JSContext *ctx, JSValueConst this_val,
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);
+ return JS_NewBool(ctx, isfinite(d));
}
/* Object class */
@@ -35910,29 +38253,31 @@ static JSValue JS_ToObject(JSContext *ctx, JSValueConst val)
case JS_TAG_OBJECT:
case JS_TAG_EXCEPTION:
return JS_DupValue(ctx, val);
+ case JS_TAG_SHORT_BIG_INT:
case JS_TAG_BIG_INT:
obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT);
goto set_value;
-#ifdef CONFIG_BIGNUM
- 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:
+ case JS_TAG_STRING_ROPE:
/* XXX: should call the string constructor */
{
- JSString *p1 = JS_VALUE_GET_STRING(val);
+ JSValue str;
+ str = JS_ToString(ctx, val); /* ensure that we never store a rope */
+ if (JS_IsException(str))
+ return JS_EXCEPTION;
obj = JS_NewObjectClass(ctx, JS_CLASS_STRING);
- JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0);
+ if (!JS_IsException(obj)) {
+ JS_DefinePropertyValue(ctx, obj, JS_ATOM_length,
+ JS_NewInt32(ctx, JS_VALUE_GET_STRING(str)->len), 0);
+ JS_SetObjectData(ctx, obj, JS_DupValue(ctx, str));
+ }
+ JS_FreeValue(ctx, str);
+ return obj;
}
- goto set_value;
case JS_TAG_BOOL:
obj = JS_NewObjectClass(ctx, JS_CLASS_BOOLEAN);
goto set_value;
@@ -35966,6 +38311,14 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
val = JS_UNDEFINED;
getter = JS_UNDEFINED;
setter = JS_UNDEFINED;
+ 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_configurable)) {
JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_configurable);
if (JS_IsException(prop))
@@ -35974,6 +38327,12 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
if (JS_ToBoolFree(ctx, prop))
flags |= JS_PROP_CONFIGURABLE;
}
+ 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_writable)) {
JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_writable);
if (JS_IsException(prop))
@@ -35982,20 +38341,6 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
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);
@@ -36066,6 +38411,7 @@ static __exception int JS_ObjectDefineProperties(JSContext *ctx,
if (JS_IsException(props))
return -1;
p = JS_VALUE_GET_OBJ(props);
+ /* XXX: not done in the same order as the spec */
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++) {
@@ -36079,7 +38425,7 @@ static __exception int JS_ObjectDefineProperties(JSContext *ctx,
ret = 0;
exception:
- js_free_prop_enum(ctx, atoms, len);
+ JS_FreePropertyEnum(ctx, atoms, len);
JS_FreeValue(ctx, props);
JS_FreeValue(ctx, desc);
return ret;
@@ -36286,13 +38632,13 @@ static JSValue js_object_getOwnPropertyDescriptor(JSContext *ctx, JSValueConst t
} 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)
+ JS_NewBool(ctx, desc.flags & JS_PROP_WRITABLE), flags) < 0)
goto exception1;
}
if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
- JS_NewBool(ctx, (desc.flags & JS_PROP_ENUMERABLE) != 0), flags) < 0
+ JS_NewBool(ctx, desc.flags & JS_PROP_ENUMERABLE), flags) < 0
|| JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
- JS_NewBool(ctx, (desc.flags & JS_PROP_CONFIGURABLE) != 0), flags) < 0)
+ JS_NewBool(ctx, desc.flags & JS_PROP_CONFIGURABLE), flags) < 0)
goto exception1;
js_free_desc(ctx, &desc);
}
@@ -36350,12 +38696,12 @@ static JSValue js_object_getOwnPropertyDescriptors(JSContext *ctx, JSValueConst
goto exception;
}
}
- js_free_prop_enum(ctx, props, len);
+ JS_FreePropertyEnum(ctx, props, len);
JS_FreeValue(ctx, obj);
return r;
exception:
- js_free_prop_enum(ctx, props, len);
+ JS_FreePropertyEnum(ctx, props, len);
JS_FreeValue(ctx, obj);
JS_FreeValue(ctx, r);
return JS_EXCEPTION;
@@ -36435,7 +38781,7 @@ static JSValue JS_GetOwnPropertyNames2(JSContext *ctx, JSValueConst obj1,
JS_FreeValue(ctx, r);
r = JS_EXCEPTION;
done:
- js_free_prop_enum(ctx, atoms, len);
+ JS_FreePropertyEnum(ctx, atoms, len);
JS_FreeValue(ctx, obj);
return r;
}
@@ -36573,9 +38919,9 @@ static JSValue js_object_toString(JSContext *ctx, JSValueConst this_val,
JSObject *p;
if (JS_IsNull(this_val)) {
- tag = JS_NewString(ctx, "Null");
+ tag = js_new_string8(ctx, "Null");
} else if (JS_IsUndefined(this_val)) {
- tag = JS_NewString(ctx, "Undefined");
+ tag = js_new_string8(ctx, "Undefined");
} else {
obj = JS_ToObject(ctx, this_val);
if (JS_IsException(obj))
@@ -36671,7 +39017,7 @@ static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val,
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))
@@ -36696,11 +39042,11 @@ static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val,
JS_UNDEFINED, JS_UNDEFINED, desc_flags) < 0)
goto exception;
}
- js_free_prop_enum(ctx, props, len);
+ JS_FreePropertyEnum(ctx, props, len);
return JS_DupValue(ctx, obj);
exception:
- js_free_prop_enum(ctx, props, len);
+ JS_FreePropertyEnum(ctx, props, len);
return JS_EXCEPTION;
}
@@ -36712,7 +39058,7 @@ static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val,
JSPropertyEnum *props;
uint32_t len, i;
int flags, res;
-
+
if (!JS_IsObject(obj))
return JS_TRUE;
@@ -36741,12 +39087,12 @@ static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val,
if (res < 0)
return JS_EXCEPTION;
res ^= 1;
-done:
- js_free_prop_enum(ctx, props, len);
+done:
+ JS_FreePropertyEnum(ctx, props, len);
return JS_NewBool(ctx, res);
exception:
- js_free_prop_enum(ctx, props, len);
+ JS_FreePropertyEnum(ctx, props, len);
return JS_EXCEPTION;
}
@@ -36764,24 +39110,22 @@ static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val,
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);
+ if (done)
break;
- }
-
+
key = JS_UNDEFINED;
value = JS_UNDEFINED;
if (!JS_IsObject(item)) {
@@ -37024,23 +39368,23 @@ static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val,
static JSValue js_object_propertyIsEnumerable(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
- JSValue obj, res = JS_EXCEPTION;
- JSAtom prop = JS_ATOM_NULL;
+ JSValue obj = JS_UNDEFINED, res = JS_EXCEPTION;
+ JSAtom prop;
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;
+ obj = JS_ToObject(ctx, this_val);
+ if (JS_IsException(obj))
+ 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);
+ res = JS_NewBool(ctx, desc.flags & JS_PROP_ENUMERABLE);
js_free_desc(ctx, &desc);
} else {
res = JS_FALSE;
@@ -37105,6 +39449,7 @@ static const JSCFunctionListEntry js_object_funcs[] = {
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("groupBy", 2, js_object_groupBy, 0 ),
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 ),
@@ -37166,7 +39511,7 @@ static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target,
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 ");
}
@@ -37264,6 +39609,7 @@ static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
JSValueConst array_arg)
{
uint32_t len, i;
+ int64_t len64;
JSValue *tab, ret;
JSObject *p;
@@ -37271,12 +39617,15 @@ static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
JS_ThrowTypeError(ctx, "not a object");
return NULL;
}
- if (js_get_length32(ctx, &len, array_arg))
+ if (js_get_length64(ctx, &len64, array_arg))
return NULL;
- if (len > JS_MAX_LOCAL_VARS) {
- JS_ThrowInternalError(ctx, "too many arguments");
+ if (len64 > JS_MAX_LOCAL_VARS) {
+ // XXX: check for stack overflow?
+ JS_ThrowRangeError(ctx, "too many arguments in function call (only %d allowed)",
+ JS_MAX_LOCAL_VARS);
return NULL;
}
+ len = len64;
/* avoid allocating 0 bytes */
tab = js_mallocz(ctx, sizeof(tab[0]) * max_uint32(1, len));
if (!tab)
@@ -37488,7 +39837,8 @@ static const JSCFunctionListEntry js_function_proto_funcs[] = {
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 ),
+ JS_CGETSET_MAGIC_DEF("lineNumber", js_function_proto_lineNumber, NULL, 0 ),
+ JS_CGETSET_MAGIC_DEF("columnNumber", js_function_proto_lineNumber, NULL, 1 ),
};
/* Error class */
@@ -37499,7 +39849,7 @@ static JSValue iterator_to_array(JSContext *ctx, JSValueConst items)
JSValue v, r = JS_UNDEFINED;
int64_t k;
BOOL done;
-
+
iter = JS_GetIterator(ctx, items, FALSE);
if (JS_IsException(iter))
goto exception;
@@ -37535,7 +39885,8 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,
int argc, JSValueConst *argv, int magic)
{
JSValue obj, msg, proto;
- JSValueConst message;
+ JSValueConst message, options;
+ int arg_index;
if (JS_IsUndefined(new_target))
new_target = JS_GetActiveFunction(ctx);
@@ -37545,7 +39896,7 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,
if (!JS_IsObject(proto)) {
JSContext *realm;
JSValueConst proto1;
-
+
JS_FreeValue(ctx, proto);
realm = JS_GetFunctionRealm(ctx, new_target);
if (!realm)
@@ -37561,12 +39912,9 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,
JS_FreeValue(ctx, proto);
if (JS_IsException(obj))
return obj;
- if (magic == JS_AGGREGATE_ERROR) {
- message = argv[1];
- } else {
- message = argv[0];
- }
+ arg_index = (magic == JS_AGGREGATE_ERROR);
+ message = argv[arg_index++];
if (!JS_IsUndefined(message)) {
msg = JS_ToString(ctx, message);
if (unlikely(JS_IsException(msg)))
@@ -37575,6 +39923,22 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
}
+ if (arg_index < argc) {
+ options = argv[arg_index];
+ if (JS_IsObject(options)) {
+ int present = JS_HasProperty(ctx, options, JS_ATOM_cause);
+ if (present < 0)
+ goto exception;
+ if (present) {
+ JSValue cause = JS_GetProperty(ctx, options, JS_ATOM_cause);
+ if (JS_IsException(cause))
+ goto exception;
+ JS_DefinePropertyValue(ctx, obj, JS_ATOM_cause, cause,
+ 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))
@@ -37584,7 +39948,7 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,
}
/* skip the Error() function in the backtrace */
- build_backtrace(ctx, obj, NULL, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL);
+ build_backtrace(ctx, obj, NULL, 0, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL);
return obj;
exception:
JS_FreeValue(ctx, obj);
@@ -37633,7 +39997,7 @@ 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);
@@ -37699,7 +40063,7 @@ static int JS_CopySubArray(JSContext *ctx,
fromPresent = JS_TryGetPropertyInt64(ctx, obj, from, &val);
if (fromPresent < 0)
goto exception;
-
+
if (fromPresent) {
if (JS_SetPropertyInt64(ctx, obj, to, val) < 0)
goto exception;
@@ -37749,8 +40113,7 @@ static JSValue js_array_from(JSContext *ctx, JSValueConst this_val,
// 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;
+ JSValue iter, r, v, v2, arrayLike, next_method, enum_obj;
int64_t k, len;
int done, mapping;
@@ -37759,8 +40122,9 @@ static JSValue js_array_from(JSContext *ctx, JSValueConst this_val,
this_arg = JS_UNDEFINED;
r = JS_UNDEFINED;
arrayLike = JS_UNDEFINED;
- stack[0] = JS_UNDEFINED;
- stack[1] = JS_UNDEFINED;
+ iter = JS_UNDEFINED;
+ enum_obj = JS_UNDEFINED;
+ next_method = JS_UNDEFINED;
if (argc > 1) {
mapfn = argv[1];
@@ -37775,21 +40139,27 @@ static JSValue js_array_from(JSContext *ctx, JSValueConst this_val,
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_IsUndefined(iter) && !JS_IsNull(iter)) {
+ if (!JS_IsFunction(ctx, iter)) {
+ JS_ThrowTypeError(ctx, "value is not iterable");
+ goto exception;
+ }
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))
+ enum_obj = JS_GetIterator2(ctx, items, iter);
+ if (JS_IsException(enum_obj))
+ goto exception;
+ next_method = JS_GetProperty(ctx, enum_obj, JS_ATOM_next);
+ if (JS_IsException(next_method))
goto exception;
for (k = 0;; k++) {
- v = JS_IteratorNext(ctx, stack[0], stack[1], 0, NULL, &done);
+ v = JS_IteratorNext(ctx, enum_obj, next_method, 0, NULL, &done);
if (JS_IsException(v))
- goto exception_close;
+ goto exception;
if (done)
break;
if (mapping) {
@@ -37844,15 +40214,15 @@ static JSValue js_array_from(JSContext *ctx, JSValueConst this_val,
goto done;
exception_close:
- if (!JS_IsUndefined(stack[0]))
- JS_IteratorClose(ctx, stack[0], TRUE);
+ JS_IteratorClose(ctx, enum_obj, TRUE);
exception:
JS_FreeValue(ctx, r);
r = JS_EXCEPTION;
done:
JS_FreeValue(ctx, arrayLike);
- JS_FreeValue(ctx, stack[0]);
- JS_FreeValue(ctx, stack[1]);
+ JS_FreeValue(ctx, iter);
+ JS_FreeValue(ctx, enum_obj);
+ JS_FreeValue(ctx, next_method);
return r;
}
@@ -37907,7 +40277,7 @@ static JSValue JS_ArraySpeciesCreate(JSContext *ctx, JSValueConst obj,
JSValue ctor, ret, species;
int res;
JSContext *realm;
-
+
res = JS_IsArray(ctx, obj);
if (res < 0)
return JS_EXCEPTION;
@@ -37975,7 +40345,7 @@ static JSValue js_array_at(JSContext *ctx, JSValueConst this_val,
int64_t len, idx;
JSValue *arrp;
uint32_t count;
-
+
obj = JS_ToObject(ctx, this_val);
if (js_get_length64(ctx, &len, obj))
goto exception;
@@ -38003,6 +40373,71 @@ static JSValue js_array_at(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
}
+static JSValue js_array_with(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue arr, obj, ret, *arrp, *pval;
+ JSObject *p;
+ int64_t i, len, idx;
+ uint32_t count32;
+
+ ret = JS_EXCEPTION;
+ arr = JS_UNDEFINED;
+ obj = JS_ToObject(ctx, this_val);
+ if (js_get_length64(ctx, &len, obj))
+ goto exception;
+
+ if (JS_ToInt64Sat(ctx, &idx, argv[0]))
+ goto exception;
+
+ if (idx < 0)
+ idx = len + idx;
+
+ if (idx < 0 || idx >= len) {
+ JS_ThrowRangeError(ctx, "invalid array index: %" PRId64, idx);
+ goto exception;
+ }
+
+ arr = js_allocate_fast_array(ctx, len);
+ if (JS_IsException(arr))
+ goto exception;
+
+ p = JS_VALUE_GET_OBJ(arr);
+ i = 0;
+ pval = p->u.array.u.values;
+ if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
+ for (; i < idx; i++, pval++)
+ *pval = JS_DupValue(ctx, arrp[i]);
+ *pval = JS_DupValue(ctx, argv[1]);
+ for (i++, pval++; i < len; i++, pval++)
+ *pval = JS_DupValue(ctx, arrp[i]);
+ } else {
+ for (; i < idx; i++, pval++)
+ if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
+ goto fill_and_fail;
+ *pval = JS_DupValue(ctx, argv[1]);
+ for (i++, pval++; i < len; i++, pval++) {
+ if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) {
+ fill_and_fail:
+ for (; i < len; i++, pval++)
+ *pval = JS_UNDEFINED;
+ goto exception;
+ }
+ }
+ }
+
+ if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0)
+ goto exception;
+
+ ret = arr;
+ arr = JS_UNDEFINED;
+
+exception:
+ JS_FreeValue(ctx, arr);
+ JS_FreeValue(ctx, obj);
+ return ret;
+}
+
static JSValue js_array_concat(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
@@ -38107,7 +40542,7 @@ static JSValue js_array_every(JSContext *ctx, JSValueConst this_val,
this_arg = JS_UNDEFINED;
if (argc > 1)
this_arg = argv[1];
-
+
if (check_function(ctx, func))
goto exception;
@@ -38368,9 +40803,10 @@ static JSValue js_array_includes(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSValue obj, val;
- int64_t len, n, res;
+ int64_t len, n;
JSValue *arrp;
uint32_t count;
+ int res;
obj = JS_ToObject(ctx, this_val);
if (js_get_length64(ctx, &len, obj))
@@ -38502,10 +40938,10 @@ static JSValue js_array_lastIndexOf(JSContext *ctx, JSValueConst this_val,
}
enum {
- special_find,
- special_findIndex,
- special_findLast,
- special_findLastIndex,
+ ArrayFind,
+ ArrayFindIndex,
+ ArrayFindLast,
+ ArrayFindLastIndex,
};
static JSValue js_array_find(JSContext *ctx, JSValueConst this_val,
@@ -38531,14 +40967,13 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val,
if (argc > 1)
this_arg = argv[1];
- if (mode == special_findLast || mode == special_findLastIndex) {
+ k = 0;
+ dir = 1;
+ end = len;
+ if (mode == ArrayFindLast || mode == ArrayFindLastIndex) {
k = len - 1;
dir = -1;
end = -1;
- } else {
- k = 0;
- dir = 1;
- end = len;
}
// TODO(bnoordhuis) add fast path for fast arrays
@@ -38556,7 +40991,7 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val,
if (JS_IsException(res))
goto exception;
if (JS_ToBoolFree(ctx, res)) {
- if (mode == special_findIndex || mode == special_findLastIndex) {
+ if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) {
JS_FreeValue(ctx, val);
JS_FreeValue(ctx, obj);
return index_val;
@@ -38570,7 +41005,7 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val,
JS_FreeValue(ctx, index_val);
}
JS_FreeValue(ctx, obj);
- if (mode == special_findIndex || mode == special_findLastIndex)
+ if (mode == ArrayFindIndex || mode == ArrayFindLastIndex)
return JS_NewInt32(ctx, -1);
else
return JS_UNDEFINED;
@@ -38821,6 +41256,61 @@ static JSValue js_array_reverse(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
}
+// Note: a.toReversed() is a.slice().reverse() with the twist that a.slice()
+// leaves holes in sparse arrays intact whereas a.toReversed() replaces them
+// with undefined, thus in effect creating a dense array.
+// Does not use Array[@@species], always returns a base Array.
+static JSValue js_array_toReversed(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue arr, obj, ret, *arrp, *pval;
+ JSObject *p;
+ int64_t i, len;
+ uint32_t count32;
+
+ ret = JS_EXCEPTION;
+ arr = JS_UNDEFINED;
+ obj = JS_ToObject(ctx, this_val);
+ if (js_get_length64(ctx, &len, obj))
+ goto exception;
+
+ arr = js_allocate_fast_array(ctx, len);
+ if (JS_IsException(arr))
+ goto exception;
+
+ if (len > 0) {
+ p = JS_VALUE_GET_OBJ(arr);
+
+ i = len - 1;
+ pval = p->u.array.u.values;
+ if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
+ for (; i >= 0; i--, pval++)
+ *pval = JS_DupValue(ctx, arrp[i]);
+ } else {
+ // Query order is observable; test262 expects descending order.
+ for (; i >= 0; i--, pval++) {
+ if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) {
+ // Exception; initialize remaining elements.
+ for (; i >= 0; i--, pval++)
+ *pval = JS_UNDEFINED;
+ goto exception;
+ }
+ }
+ }
+
+ if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0)
+ goto exception;
+ }
+
+ ret = arr;
+ arr = JS_UNDEFINED;
+
+exception:
+ JS_FreeValue(ctx, arr);
+ JS_FreeValue(ctx, obj);
+ return ret;
+}
+
static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int splice)
{
@@ -38928,6 +41418,92 @@ static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
}
+static JSValue js_array_toSpliced(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue arr, obj, ret, *arrp, *pval, *last;
+ JSObject *p;
+ int64_t i, j, len, newlen, start, add, del;
+ uint32_t count32;
+
+ pval = NULL;
+ last = NULL;
+ ret = JS_EXCEPTION;
+ arr = JS_UNDEFINED;
+
+ obj = JS_ToObject(ctx, this_val);
+ if (js_get_length64(ctx, &len, obj))
+ goto exception;
+
+ start = 0;
+ if (argc > 0)
+ if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
+ goto exception;
+
+ del = 0;
+ if (argc > 0)
+ del = len - start;
+ if (argc > 1)
+ if (JS_ToInt64Clamp(ctx, &del, argv[1], 0, del, 0))
+ goto exception;
+
+ add = 0;
+ if (argc > 2)
+ add = argc - 2;
+
+ newlen = len + add - del;
+ if (newlen > MAX_SAFE_INTEGER) {
+ JS_ThrowTypeError(ctx, "invalid array length");
+ goto exception;
+ }
+
+ arr = js_allocate_fast_array(ctx, newlen);
+ if (JS_IsException(arr))
+ goto exception;
+
+ if (newlen <= 0)
+ goto done;
+
+ p = JS_VALUE_GET_OBJ(arr);
+ pval = &p->u.array.u.values[0];
+ last = &p->u.array.u.values[newlen];
+
+ if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
+ for (i = 0; i < start; i++, pval++)
+ *pval = JS_DupValue(ctx, arrp[i]);
+ for (j = 0; j < add; j++, pval++)
+ *pval = JS_DupValue(ctx, argv[2 + j]);
+ for (i += del; i < len; i++, pval++)
+ *pval = JS_DupValue(ctx, arrp[i]);
+ } else {
+ for (i = 0; i < start; i++, pval++)
+ if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
+ goto exception;
+ for (j = 0; j < add; j++, pval++)
+ *pval = JS_DupValue(ctx, argv[2 + j]);
+ for (i += del; i < len; i++, pval++)
+ if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
+ goto exception;
+ }
+
+ assert(pval == last);
+
+ if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, newlen)) < 0)
+ goto exception;
+
+done:
+ ret = arr;
+ arr = JS_UNDEFINED;
+
+exception:
+ while (pval != last)
+ *pval++ = JS_UNDEFINED;
+
+ JS_FreeValue(ctx, arr);
+ JS_FreeValue(ctx, obj);
+ return ret;
+}
+
static JSValue js_array_copyWithin(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
@@ -38987,8 +41563,8 @@ static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target,
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]);
+ JS_FreeValue(ctx, args[0]);
+ JS_FreeValue(ctx, args[1]);
if (JS_IsException(element))
return -1;
}
@@ -39231,6 +41807,68 @@ static JSValue js_array_sort(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
}
+// Note: a.toSorted() is a.slice().sort() with the twist that a.slice()
+// leaves holes in sparse arrays intact whereas a.toSorted() replaces them
+// with undefined, thus in effect creating a dense array.
+// Does not use Array[@@species], always returns a base Array.
+static JSValue js_array_toSorted(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue arr, obj, ret, *arrp, *pval;
+ JSObject *p;
+ int64_t i, len;
+ uint32_t count32;
+ int ok;
+
+ ok = JS_IsUndefined(argv[0]) || JS_IsFunction(ctx, argv[0]);
+ if (!ok)
+ return JS_ThrowTypeError(ctx, "not a function");
+
+ ret = JS_EXCEPTION;
+ arr = JS_UNDEFINED;
+ obj = JS_ToObject(ctx, this_val);
+ if (js_get_length64(ctx, &len, obj))
+ goto exception;
+
+ arr = js_allocate_fast_array(ctx, len);
+ if (JS_IsException(arr))
+ goto exception;
+
+ if (len > 0) {
+ p = JS_VALUE_GET_OBJ(arr);
+ i = 0;
+ pval = p->u.array.u.values;
+ if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
+ for (; i < len; i++, pval++)
+ *pval = JS_DupValue(ctx, arrp[i]);
+ } else {
+ for (; i < len; i++, pval++) {
+ if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) {
+ for (; i < len; i++, pval++)
+ *pval = JS_UNDEFINED;
+ goto exception;
+ }
+ }
+ }
+
+ if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0)
+ goto exception;
+ }
+
+ ret = js_array_sort(ctx, arr, argc, argv);
+ if (JS_IsException(ret))
+ goto exception;
+ JS_FreeValue(ctx, ret);
+
+ ret = arr;
+ arr = JS_UNDEFINED;
+
+exception:
+ JS_FreeValue(ctx, arr);
+ JS_FreeValue(ctx, obj);
+ return ret;
+}
+
typedef struct JSArrayIteratorData {
JSValue obj;
JSIteratorKindEnum kind;
@@ -39384,6 +42022,7 @@ static const JSCFunctionListEntry js_iterator_proto_funcs[] = {
static const JSCFunctionListEntry js_array_proto_funcs[] = {
JS_CFUNC_DEF("at", 1, js_array_at ),
+ JS_CFUNC_DEF("with", 2, js_array_with ),
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 ),
@@ -39393,10 +42032,10 @@ static const JSCFunctionListEntry js_array_proto_funcs[] = {
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, special_find ),
- JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, special_findIndex ),
- JS_CFUNC_MAGIC_DEF("findLast", 1, js_array_find, special_findLast ),
- JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_array_find, special_findLastIndex ),
+ JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, ArrayFind ),
+ JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, ArrayFindIndex ),
+ JS_CFUNC_MAGIC_DEF("findLast", 1, js_array_find, ArrayFindLast ),
+ JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_array_find, ArrayFindLastIndex ),
JS_CFUNC_DEF("indexOf", 1, js_array_indexOf ),
JS_CFUNC_DEF("lastIndexOf", 1, js_array_lastIndexOf ),
JS_CFUNC_DEF("includes", 1, js_array_includes ),
@@ -39408,9 +42047,12 @@ static const JSCFunctionListEntry js_array_proto_funcs[] = {
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("toReversed", 0, js_array_toReversed ),
JS_CFUNC_DEF("sort", 1, js_array_sort ),
+ JS_CFUNC_DEF("toSorted", 1, js_array_toSorted ),
JS_CFUNC_MAGIC_DEF("slice", 2, js_array_slice, 0 ),
JS_CFUNC_MAGIC_DEF("splice", 2, js_array_slice, 1 ),
+ JS_CFUNC_DEF("toSpliced", 2, js_array_toSpliced ),
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 ),
@@ -39438,28 +42080,20 @@ static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target,
if (JS_IsException(val))
return val;
switch(JS_VALUE_GET_TAG(val)) {
+ case JS_TAG_SHORT_BIG_INT:
+ val = JS_NewInt64(ctx, JS_VALUE_GET_SHORT_BIG_INT(val));
+ if (JS_IsException(val))
+ return val;
+ break;
case JS_TAG_BIG_INT:
-#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_FLOAT:
-#endif
{
- JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ JSBigInt *p = JS_VALUE_GET_PTR(val);
double d;
- bf_get_float64(&p->num, &d, BF_RNDN);
+ d = js_bigint_to_float64(ctx, p);
JS_FreeValue(ctx, val);
- val = __JS_NewFloat64(ctx, d);
+ val = JS_NewFloat64(ctx, d);
}
break;
-#ifdef CONFIG_BIGNUM
- 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;
}
@@ -39539,9 +42173,9 @@ static const JSCFunctionListEntry js_number_funcs[] = {
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("NaN", (0.0 / 0.0), 0 ),
+ JS_PROP_DOUBLE_DEF("NEGATIVE_INFINITY", (-1.0 / 0.0), 0 ),
+ JS_PROP_DOUBLE_DEF("POSITIVE_INFINITY", (1.0 / 0.0), 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 */
@@ -39586,7 +42220,7 @@ static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
JSValue val;
- int base;
+ int base, flags;
double d;
val = js_thisNumberValue(ctx, this_val);
@@ -39599,9 +42233,18 @@ static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val,
if (base < 0)
goto fail;
}
+ if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) {
+ char buf1[70];
+ int len;
+ len = i64toa_radix(buf1, JS_VALUE_GET_INT(val), base);
+ return js_new_string8_len(ctx, buf1, len);
+ }
if (JS_ToFloat64Free(ctx, &d, val))
return JS_EXCEPTION;
- return js_dtoa(ctx, d, base, 0, JS_DTOA_VAR_FORMAT);
+ flags = JS_DTOA_FORMAT_FREE;
+ if (base != 10)
+ flags |= JS_DTOA_EXP_DISABLED;
+ return js_dtoa2(ctx, d, base, 0, flags);
fail:
JS_FreeValue(ctx, val);
return JS_EXCEPTION;
@@ -39611,7 +42254,7 @@ static JSValue js_number_toFixed(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSValue val;
- int f;
+ int f, flags;
double d;
val = js_thisNumberValue(ctx, this_val);
@@ -39623,11 +42266,11 @@ static JSValue js_number_toFixed(JSContext *ctx, JSValueConst this_val,
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);
- }
+ if (fabs(d) >= 1e21)
+ flags = JS_DTOA_FORMAT_FREE;
+ else
+ flags = JS_DTOA_FORMAT_FRAC;
+ return js_dtoa2(ctx, d, 10, f, flags);
}
static JSValue js_number_toExponential(JSContext *ctx, JSValueConst this_val,
@@ -39648,15 +42291,15 @@ static JSValue js_number_toExponential(JSContext *ctx, JSValueConst this_val,
return JS_ToStringFree(ctx, __JS_NewFloat64(ctx, d));
}
if (JS_IsUndefined(argv[0])) {
- flags = 0;
+ flags = JS_DTOA_FORMAT_FREE;
f = 0;
} else {
if (f < 0 || f > 100)
return JS_ThrowRangeError(ctx, "invalid number of digits");
f++;
- flags = JS_DTOA_FIXED_FORMAT;
+ flags = JS_DTOA_FORMAT_FIXED;
}
- return js_dtoa(ctx, d, 10, f, flags | JS_DTOA_FORCE_EXP);
+ return js_dtoa2(ctx, d, 10, f, flags | JS_DTOA_EXP_ENABLED);
}
static JSValue js_number_toPrecision(JSContext *ctx, JSValueConst this_val,
@@ -39681,7 +42324,7 @@ static JSValue js_number_toPrecision(JSContext *ctx, JSValueConst this_val,
}
if (p < 1 || p > 100)
return JS_ThrowRangeError(ctx, "invalid number of digits");
- return js_dtoa(ctx, d, 10, p, JS_DTOA_FIXED_FORMAT);
+ return js_dtoa2(ctx, d, 10, p, JS_DTOA_FORMAT_FIXED);
}
static const JSCFunctionListEntry js_number_proto_funcs[] = {
@@ -39805,10 +42448,7 @@ static int js_string_get_own_property(JSContext *ctx,
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];
+ ch = string_get(p1, idx);
desc->flags = JS_PROP_ENUMERABLE;
desc->value = js_new_string_char(ctx, ch);
desc->getter = JS_UNDEFINED;
@@ -39830,7 +42470,7 @@ static int js_string_define_own_property(JSContext *ctx,
uint32_t idx;
JSObject *p;
JSString *p1, *p2;
-
+
if (__JS_AtomIsTaggedInt(prop)) {
idx = __JS_AtomToUInt32(prop);
p = JS_VALUE_GET_OBJ(this_obj);
@@ -39901,7 +42541,9 @@ static JSValue js_string_constructor(JSContext *ctx, JSValueConst new_target,
JSString *p1 = JS_VALUE_GET_STRING(val);
obj = js_create_from_ctor(ctx, new_target, JS_CLASS_STRING);
- if (!JS_IsException(obj)) {
+ if (JS_IsException(obj)) {
+ JS_FreeValue(ctx, val);
+ } else {
JS_SetObjectData(ctx, obj, val);
JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0);
}
@@ -39913,7 +42555,8 @@ static JSValue js_string_constructor(JSContext *ctx, JSValueConst new_target,
static JSValue js_thisStringValue(JSContext *ctx, JSValueConst this_val)
{
- if (JS_VALUE_GET_TAG(this_val) == JS_TAG_STRING)
+ if (JS_VALUE_GET_TAG(this_val) == JS_TAG_STRING ||
+ JS_VALUE_GET_TAG(this_val) == JS_TAG_STRING_ROPE)
return JS_DupValue(ctx, this_val);
if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
@@ -39963,7 +42606,7 @@ static JSValue js_string_fromCodePoint(JSContext *ctx, JSValueConst this_val,
} else {
if (JS_ToFloat64(ctx, &d, argv[i]))
goto fail;
- if (d < 0 || d > 0x10ffff || (c = (int)d) != d)
+ if (isnan(d) || d < 0 || d > 0x10ffff || (c = (int)d) != d)
goto range_error;
}
if (string_buffer_putc(b, c))
@@ -39996,7 +42639,7 @@ static JSValue js_string_raw(JSContext *ctx, JSValueConst this_val,
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))
@@ -40074,10 +42717,7 @@ static JSValue js_string_charCodeAt(JSContext *ctx, JSValueConst this_val,
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];
+ c = string_get(p, idx);
ret = JS_NewInt32(ctx, c);
}
JS_FreeValue(ctx, val);
@@ -40105,12 +42745,9 @@ static JSValue js_string_charAt(JSContext *ctx, JSValueConst this_val,
if (is_at)
ret = JS_UNDEFINED;
else
- ret = js_new_string8(ctx, NULL, 0);
+ ret = JS_AtomToString(ctx, JS_ATOM_empty_string);
} else {
- if (p->is_wide_char)
- c = p->u.str16[idx];
- else
- c = p->u.str8[idx];
+ c = string_get(p, idx);
ret = js_new_string_char(ctx, c);
}
JS_FreeValue(ctx, val);
@@ -40218,6 +42855,80 @@ static int64_t string_advance_index(JSString *p, int64_t index, BOOL unicode)
return index;
}
+/* return the position of the first invalid character in the string or
+ -1 if none */
+static int js_string_find_invalid_codepoint(JSString *p)
+{
+ int i;
+ if (!p->is_wide_char)
+ return -1;
+ for(i = 0; i < p->len; i++) {
+ uint32_t c = p->u.str16[i];
+ if (is_surrogate(c)) {
+ if (is_hi_surrogate(c) && (i + 1) < p->len
+ && is_lo_surrogate(p->u.str16[i + 1])) {
+ i++;
+ } else {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+static JSValue js_string_isWellFormed(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue str;
+ JSString *p;
+ BOOL ret;
+
+ str = JS_ToStringCheckObject(ctx, this_val);
+ if (JS_IsException(str))
+ return JS_EXCEPTION;
+ p = JS_VALUE_GET_STRING(str);
+ ret = (js_string_find_invalid_codepoint(p) < 0);
+ JS_FreeValue(ctx, str);
+ return JS_NewBool(ctx, ret);
+}
+
+static JSValue js_string_toWellFormed(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue str, ret;
+ JSString *p;
+ int i;
+
+ str = JS_ToStringCheckObject(ctx, this_val);
+ if (JS_IsException(str))
+ return JS_EXCEPTION;
+
+ p = JS_VALUE_GET_STRING(str);
+ /* avoid reallocating the string if it is well-formed */
+ i = js_string_find_invalid_codepoint(p);
+ if (i < 0)
+ return str;
+
+ ret = js_new_string16_len(ctx, p->u.str16, p->len);
+ JS_FreeValue(ctx, str);
+ if (JS_IsException(ret))
+ return JS_EXCEPTION;
+
+ p = JS_VALUE_GET_STRING(ret);
+ for (; i < p->len; i++) {
+ uint32_t c = p->u.str16[i];
+ if (is_surrogate(c)) {
+ if (is_hi_surrogate(c) && (i + 1) < p->len
+ && is_lo_surrogate(p->u.str16[i + 1])) {
+ i++;
+ } else {
+ p->u.str16[i] = 0xFFFD;
+ }
+ }
+ }
+ return ret;
+}
+
static JSValue js_string_indexOf(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int lastIndexOf)
{
@@ -40300,7 +43011,7 @@ static JSValue js_string_includes(JSContext *ctx, JSValueConst this_val,
ret = js_is_regexp(ctx, argv[0]);
if (ret) {
if (ret > 0)
- JS_ThrowTypeError(ctx, "regex not supported");
+ JS_ThrowTypeError(ctx, "regexp not supported");
goto fail;
}
v = JS_ToString(ctx, argv[0]);
@@ -40354,7 +43065,7 @@ 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;
@@ -40412,10 +43123,10 @@ static JSValue js_string_match(JSContext *ctx, JSValueConst this_val,
args[0] = regexp;
str = JS_UNDEFINED;
if (atom == JS_ATOM_Symbol_matchAll) {
- str = JS_NewString(ctx, "g");
+ str = js_new_string8(ctx, "g");
if (JS_IsException(str))
goto fail;
- args[args_len++] = (JSValueConst)str;
+ args[args_len++] = str;
}
rx = JS_CallConstructor(ctx, ctx->regexp_ctor, args_len, args);
JS_FreeValue(ctx, str);
@@ -40628,7 +43339,7 @@ static JSValue js_string_replace(JSContext *ctx, JSValueConst this_val,
}
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;
@@ -40862,8 +43573,8 @@ static JSValue js_string_pad(JSContext *ctx, JSValueConst this_val,
}
}
if (n > JS_STRING_LEN_MAX) {
- JS_ThrowInternalError(ctx, "string too long");
- goto fail2;
+ JS_ThrowRangeError(ctx, "invalid string length");
+ goto fail3;
}
if (string_buffer_init(ctx, b, n))
goto fail3;
@@ -40924,8 +43635,9 @@ static JSValue js_string_repeat(JSContext *ctx, JSValueConst this_val,
len = p->len;
if (len == 0 || n == 1)
return str;
+ // XXX: potential arithmetic overflow
if (val * len > JS_STRING_LEN_MAX) {
- JS_ThrowInternalError(ctx, "string too long");
+ JS_ThrowRangeError(ctx, "invalid string length");
goto fail;
}
if (string_buffer_init2(ctx, b, n * len, p->is_wide_char))
@@ -40988,10 +43700,10 @@ static int string_prevc(JSString *p, int *pidx)
idx--;
if (p->is_wide_char) {
c = p->u.str16[idx];
- if (c >= 0xdc00 && c < 0xe000 && idx > 0) {
+ if (is_lo_surrogate(c) && idx > 0) {
c1 = p->u.str16[idx - 1];
- if (c1 >= 0xd800 && c1 <= 0xdc00) {
- c = (((c1 & 0x3ff) << 10) | (c & 0x3ff)) + 0x10000;
+ if (is_hi_surrogate(c1)) {
+ c = from_surrogate(c1, c);
idx--;
}
}
@@ -41030,26 +43742,6 @@ static BOOL test_final_sigma(JSString *p, int sigma_pos)
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)
{
@@ -41135,23 +43827,38 @@ static JSValue JS_NewUTF32String(JSContext *ctx, const uint32_t *buf, int len)
return JS_EXCEPTION;
}
+static int js_string_normalize1(JSContext *ctx, uint32_t **pout_buf,
+ JSValueConst val,
+ UnicodeNormalizationEnum n_type)
+{
+ int buf_len, out_len;
+ uint32_t *buf, *out_buf;
+
+ buf_len = JS_ToUTF32String(ctx, &buf, val);
+ if (buf_len < 0)
+ return -1;
+ 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 -1;
+ *pout_buf = out_buf;
+ return out_len;
+}
+
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;
+ int is_compat, out_len;
UnicodeNormalizationEnum n_type;
JSValue val;
- uint32_t *buf, *out_buf;
+ uint32_t *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;
@@ -41177,22 +43884,96 @@ static JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val,
JS_FreeCString(ctx, form);
JS_ThrowRangeError(ctx, "bad normalization form");
fail1:
- js_free(ctx, buf);
+ JS_FreeValue(ctx, val);
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);
+ out_len = js_string_normalize1(ctx, &out_buf, val, n_type);
+ JS_FreeValue(ctx, val);
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 */
+
+/* return < 0, 0 or > 0 */
+static int js_UTF32_compare(const uint32_t *buf1, int buf1_len,
+ const uint32_t *buf2, int buf2_len)
+{
+ int i, len, c, res;
+ len = min_int(buf1_len, buf2_len);
+ for(i = 0; i < len; i++) {
+ /* Note: range is limited so a subtraction is valid */
+ c = buf1[i] - buf2[i];
+ if (c != 0)
+ return c;
+ }
+ if (buf1_len == buf2_len)
+ res = 0;
+ else if (buf1_len < buf2_len)
+ res = -1;
+ else
+ res = 1;
+ return res;
+}
+
+static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue a, b;
+ int cmp, a_len, b_len;
+ uint32_t *a_buf, *b_buf;
+
+ 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;
+ }
+ a_len = js_string_normalize1(ctx, &a_buf, a, UNICODE_NFC);
+ JS_FreeValue(ctx, a);
+ if (a_len < 0) {
+ JS_FreeValue(ctx, b);
+ return JS_EXCEPTION;
+ }
+
+ b_len = js_string_normalize1(ctx, &b_buf, b, UNICODE_NFC);
+ JS_FreeValue(ctx, b);
+ if (b_len < 0) {
+ js_free(ctx, a_buf);
+ return JS_EXCEPTION;
+ }
+ cmp = js_UTF32_compare(a_buf, a_len, b_buf, b_len);
+ js_free(ctx, a_buf);
+ js_free(ctx, b_buf);
+ return JS_NewInt32(ctx, cmp);
+}
+#else /* CONFIG_ALL_UNICODE */
+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);
+}
+#endif /* !CONFIG_ALL_UNICODE */
/* also used for String.prototype.valueOf */
static JSValue js_string_toString(JSContext *ctx, JSValueConst this_val,
@@ -41276,7 +44057,7 @@ static JSValue js_string_iterator_next(JSContext *ctx, JSValueConst this_val,
if (c <= 0xffff) {
return js_new_string_char(ctx, c);
} else {
- return js_new_string16(ctx, p->u.str16 + start, 2);
+ return js_new_string16_len(ctx, p->u.str16 + start, 2);
}
}
@@ -41306,7 +44087,7 @@ static JSValue js_string_CreateHTML(JSContext *ctx, JSValueConst this_val,
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 },
+ { "a", "href" }, { "small", NULL }, { "strike", NULL },
{ "sub", NULL }, { "sup", NULL },
};
@@ -41369,6 +44150,8 @@ static const JSCFunctionListEntry js_string_proto_funcs[] = {
JS_CFUNC_MAGIC_DEF("charAt", 1, js_string_charAt, 0 ),
JS_CFUNC_DEF("concat", 1, js_string_concat ),
JS_CFUNC_DEF("codePointAt", 1, js_string_codePointAt ),
+ JS_CFUNC_DEF("isWellFormed", 0, js_string_isWellFormed ),
+ JS_CFUNC_DEF("toWellFormed", 0, js_string_toWellFormed ),
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 ),
@@ -41394,7 +44177,6 @@ static const JSCFunctionListEntry js_string_proto_funcs[] = {
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 ),
@@ -41421,18 +44203,17 @@ static const JSCFunctionListEntry js_string_iterator_proto_funcs[] = {
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "String Iterator", JS_PROP_CONFIGURABLE ),
};
-#ifdef CONFIG_ALL_UNICODE
static const JSCFunctionListEntry js_string_proto_normalize[] = {
+#ifdef CONFIG_ALL_UNICODE
JS_CFUNC_DEF("normalize", 0, js_string_normalize ),
-};
#endif
+ JS_CFUNC_DEF("localeCompare", 1, js_string_localeCompare ),
+};
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
}
/* Math */
@@ -41474,7 +44255,7 @@ static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
uint32_t tag;
if (unlikely(argc == 0)) {
- return __JS_NewFloat64(ctx, is_max ? -1.0 / 0.0 : 1.0 / 0.0);
+ return __JS_NewFloat64(ctx, is_max ? -INFINITY : INFINITY);
}
tag = JS_VALUE_GET_TAG(argv[0]);
@@ -41580,6 +44361,11 @@ static JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val,
return JS_NewFloat64(ctx, r);
}
+static double js_math_f16round(double a)
+{
+ return fromfp16(tofp16(a));
+}
+
static double js_math_fround(double a)
{
return (float)a;
@@ -41588,14 +44374,16 @@ static double js_math_fround(double a)
static JSValue js_math_imul(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
- int a, b;
+ uint32_t a, b, c;
+ int32_t d;
- if (JS_ToInt32(ctx, &a, argv[0]))
+ if (JS_ToUint32(ctx, &a, argv[0]))
return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &b, argv[1]))
+ if (JS_ToUint32(ctx, &b, argv[1]))
return JS_EXCEPTION;
- /* purposely ignoring overflow */
- return JS_NewInt32(ctx, a * b);
+ c = a * b;
+ memcpy(&d, &c, sizeof(d));
+ return JS_NewInt32(ctx, d);
}
static JSValue js_math_clz32(JSContext *ctx, JSValueConst this_val,
@@ -41681,6 +44469,7 @@ static const JSCFunctionListEntry js_math_funcs[] = {
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("f16round", 1, f_f, js_math_f16round ),
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 ),
@@ -41701,39 +44490,12 @@ static const JSCFunctionListEntry js_math_obj[] = {
/* Date */
-#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. */
-static 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
+static int getTimezoneOffset(int64_t time)
+{
time_t ti;
- struct tm tm;
+ int res;
time /= 1000; /* convert to seconds */
if (sizeof(time_t) == 4) {
@@ -41757,9 +44519,31 @@ static int getTimezoneOffset(int64_t time) {
}
}
ti = time;
- localtime_r(&ti, &tm);
- return -tm.tm_gmtoff / 60;
+#if defined(_WIN32)
+ {
+ struct tm *tm;
+ time_t gm_ti, loc_ti;
+
+ tm = gmtime(&ti);
+ if (!tm)
+ return 0;
+ gm_ti = mktime(tm);
+
+ tm = localtime(&ti);
+ if (!tm)
+ return 0;
+ loc_ti = mktime(tm);
+
+ res = (gm_ti - loc_ti) / 60;
+ }
+#else
+ {
+ struct tm tm;
+ localtime_r(&ti, &tm);
+ res = -tm.tm_gmtoff / 60;
+ }
#endif
+ return res;
}
#if 0
@@ -41836,6 +44620,9 @@ static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
/* XXX: re_flags = LRE_FLAG_OCTAL unless strict mode? */
for (i = 0; i < len; i++) {
switch(str[i]) {
+ case 'd':
+ mask = LRE_FLAG_INDICES;
+ break;
case 'g':
mask = LRE_FLAG_GLOBAL;
break;
@@ -41849,7 +44636,10 @@ static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
mask = LRE_FLAG_DOTALL;
break;
case 'u':
- mask = LRE_FLAG_UTF16;
+ mask = LRE_FLAG_UNICODE;
+ break;
+ case 'v':
+ mask = LRE_FLAG_UNICODE_SETS;
break;
case 'y':
mask = LRE_FLAG_STICKY;
@@ -41860,14 +44650,20 @@ static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
if ((re_flags & mask) != 0) {
bad_flags:
JS_FreeCString(ctx, str);
- return JS_ThrowSyntaxError(ctx, "invalid regular expression flags");
+ goto bad_flags1;
}
re_flags |= mask;
}
JS_FreeCString(ctx, str);
}
- str = JS_ToCStringLen2(ctx, &len, pattern, !(re_flags & LRE_FLAG_UTF16));
+ /* 'u' and 'v' cannot be both set */
+ if ((re_flags & LRE_FLAG_UNICODE_SETS) && (re_flags & LRE_FLAG_UNICODE)) {
+ bad_flags1:
+ return JS_ThrowSyntaxError(ctx, "invalid regular expression flags");
+ }
+
+ str = JS_ToCStringLen2(ctx, &len, pattern, !(re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)));
if (!str)
return JS_EXCEPTION;
re_bytecode_buf = lre_compile(&re_bytecode_len, error_msg,
@@ -41878,7 +44674,7 @@ static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
return JS_EXCEPTION;
}
- ret = js_new_string8(ctx, re_bytecode_buf, re_bytecode_len);
+ ret = js_new_string8_len(ctx, (const char *)re_bytecode_buf, re_bytecode_len);
js_free(ctx, re_bytecode_buf);
return ret;
}
@@ -42106,8 +44902,8 @@ static JSValue js_regexp_get_source(JSContext *ctx, JSValueConst this_val)
if (p->len == 0) {
empty_regex:
- return JS_NewString(ctx, "(?:)");
- }
+ return js_new_string8(ctx, "(?:)");
+ }
string_buffer_init2(ctx, b, p->len, p->is_wide_char);
/* Escape '/' and newline sequences as needed */
@@ -42166,49 +44962,39 @@ static JSValue js_regexp_get_flag(JSContext *ctx, JSValueConst this_val, int mas
else
return JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);
}
-
+
flags = lre_get_flags(re->bytecode->u.str8);
- return JS_NewBool(ctx, (flags & mask) != 0);
+ return JS_NewBool(ctx, flags & mask);
}
+#define RE_FLAG_COUNT 8
+
static JSValue js_regexp_get_flags(JSContext *ctx, JSValueConst this_val)
{
- char str[8], *p = str;
- int res;
-
+ char str[RE_FLAG_COUNT], *p = str;
+ int res, i;
+ static const int flag_atom[RE_FLAG_COUNT] = {
+ JS_ATOM_hasIndices,
+ JS_ATOM_global,
+ JS_ATOM_ignoreCase,
+ JS_ATOM_multiline,
+ JS_ATOM_dotAll,
+ JS_ATOM_unicode,
+ JS_ATOM_unicodeSets,
+ JS_ATOM_sticky,
+ };
+ static const char flag_char[RE_FLAG_COUNT] = { 'd', 'g', 'i', 'm', 's', 'u', 'v', 'y' };
+
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';
+ for(i = 0; i < RE_FLAG_COUNT; i++) {
+ res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, flag_atom[i]));
+ if (res < 0)
+ goto exception;
+ if (res)
+ *p++ = flag_char[i];
+ }
return JS_NewStringLen(ctx, str, p - str);
exception:
@@ -42240,12 +45026,20 @@ static JSValue js_regexp_toString(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
}
-BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size)
+int lre_check_stack_overflow(void *opaque, size_t alloca_size)
{
JSContext *ctx = opaque;
return js_check_stack_overflow(ctx->rt, alloca_size);
}
+int lre_check_timeout(void *opaque)
+{
+ JSContext *ctx = opaque;
+ JSRuntime *rt = ctx->rt;
+ return (rt->interrupt_handler &&
+ rt->interrupt_handler(rt, rt->interrupt_opaque));
+}
+
void *lre_realloc(void *opaque, void *ptr, size_t size)
{
JSContext *ctx = opaque;
@@ -42253,30 +45047,89 @@ void *lre_realloc(void *opaque, void *ptr, size_t size)
return js_realloc_rt(ctx->rt, ptr, size);
}
+static JSValue js_regexp_escape(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue str;
+ StringBuffer b_s, *b = &b_s;
+ JSString *p;
+ uint32_t c, i;
+ char s[16];
+
+ if (!JS_IsString(argv[0]))
+ return JS_ThrowTypeError(ctx, "not a string");
+ str = JS_ToString(ctx, argv[0]); /* must call it to linearlize ropes */
+ if (JS_IsException(str))
+ return JS_EXCEPTION;
+ p = JS_VALUE_GET_STRING(str);
+ string_buffer_init2(ctx, b, 0, p->is_wide_char);
+ for (i = 0; i < p->len; i++) {
+ c = string_get(p, i);
+ if (c < 33) {
+ if (c >= 9 && c <= 13) {
+ string_buffer_putc8(b, '\\');
+ string_buffer_putc8(b, "tnvfr"[c - 9]);
+ } else {
+ goto hex2;
+ }
+ } else if (c < 128) {
+ if ((c >= '0' && c <= '9')
+ || (c >= 'A' && c <= 'Z')
+ || (c >= 'a' && c <= 'z')) {
+ if (i == 0)
+ goto hex2;
+ } else if (strchr(",-=<>#&!%:;@~'`\"", c)) {
+ goto hex2;
+ } else if (c != '_') {
+ string_buffer_putc8(b, '\\');
+ }
+ string_buffer_putc8(b, c);
+ } else if (c < 256) {
+ hex2:
+ snprintf(s, sizeof(s), "\\x%02x", c);
+ string_buffer_puts8(b, s);
+ } else if (is_surrogate(c) || lre_is_space(c)) {
+ snprintf(s, sizeof(s), "\\u%04x", c);
+ string_buffer_puts8(b, s);
+ } else {
+ string_buffer_putc16(b, c);
+ }
+ }
+ JS_FreeValue(ctx, str);
+ return string_buffer_end(b);
+}
+
static 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;
+ JSValue t, ret, str_val, obj, val, groups;
+ JSValue indices, indices_groups;
uint8_t *re_bytecode;
- int ret;
uint8_t **capture, *str_buf;
- int capture_count, shift, i, re_flags;
+ int rc, 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;
- }
+
+ ret = JS_EXCEPTION;
+ obj = JS_NULL;
+ groups = JS_UNDEFINED;
+ indices = JS_UNDEFINED;
+ indices_groups = JS_UNDEFINED;
+ capture = NULL;
+
+ val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex);
+ if (JS_IsException(val) || JS_ToLengthFree(ctx, &last_index, val))
+ goto fail;
+
re_bytecode = re->bytecode->u.str8;
re_flags = lre_get_flags(re_bytecode);
if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {
@@ -42284,36 +45137,35 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val,
}
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;
- }
+ if (!capture)
+ goto fail;
}
shift = str->is_wide_char;
str_buf = str->u.str8;
if (last_index > str->len) {
- ret = 2;
+ rc = 2;
} else {
- ret = lre_exec(capture, re_bytecode,
- str_buf, last_index, str->len,
- shift, ctx);
+ rc = 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 (rc != 1) {
+ if (rc >= 0) {
+ if (rc == 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");
+ if (rc == LRE_RET_TIMEOUT) {
+ JS_ThrowInterrupted(ctx);
+ } 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)) {
@@ -42331,52 +45183,124 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val,
if (JS_IsException(groups))
goto fail;
}
+ if (re_flags & LRE_FLAG_INDICES) {
+ indices = JS_NewArray(ctx);
+ if (JS_IsException(indices))
+ goto fail;
+ if (group_name_ptr) {
+ indices_groups = JS_NewObjectProto(ctx, JS_NULL);
+ if (JS_IsException(indices_groups))
+ goto fail;
+ }
+ }
for(i = 0; i < capture_count; i++) {
- int start, end;
+ const char *name = NULL;
+ uint8_t **match = &capture[2 * i];
+ int start = -1;
+ int end = -1;
JSValue val;
- if (capture[2 * i] == NULL ||
- capture[2 * i + 1] == NULL) {
+
+ if (group_name_ptr && i > 0) {
+ if (*group_name_ptr) name = group_name_ptr;
+ group_name_ptr += strlen(group_name_ptr) + 1;
+ }
+
+ if (match[0] && match[1]) {
+ start = (match[0] - str_buf) >> shift;
+ end = (match[1] - str_buf) >> shift;
+ }
+
+ if (!JS_IsUndefined(indices)) {
val = JS_UNDEFINED;
- } else {
- start = (capture[2 * i] - str_buf) >> shift;
- end = (capture[2 * i + 1] - str_buf) >> shift;
+ if (start != -1) {
+ val = JS_NewArray(ctx);
+ if (JS_IsException(val))
+ goto fail;
+ if (JS_DefinePropertyValueUint32(ctx, val, 0,
+ JS_NewInt32(ctx, start),
+ prop_flags) < 0) {
+ JS_FreeValue(ctx, val);
+ goto fail;
+ }
+ if (JS_DefinePropertyValueUint32(ctx, val, 1,
+ JS_NewInt32(ctx, end),
+ prop_flags) < 0) {
+ JS_FreeValue(ctx, val);
+ goto fail;
+ }
+ }
+ if (name && !JS_IsUndefined(indices_groups)) {
+ val = JS_DupValue(ctx, val);
+ if (JS_DefinePropertyValueStr(ctx, indices_groups,
+ name, val, prop_flags) < 0) {
+ JS_FreeValue(ctx, val);
+ goto fail;
+ }
+ }
+ if (JS_DefinePropertyValueUint32(ctx, indices, i, val,
+ prop_flags) < 0) {
+ goto fail;
+ }
+ }
+
+ val = JS_UNDEFINED;
+ if (start != -1) {
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;
- }
+
+ if (name) {
+ if (JS_DefinePropertyValueStr(ctx, groups, name,
+ 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)
+
+ t = JS_NewInt32(ctx, (capture[0] - str_buf) >> shift);
+ if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_index, t, prop_flags) < 0)
+ goto fail;
+
+ t = str_val, str_val = JS_UNDEFINED;
+ if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_input, t, prop_flags) < 0)
goto fail;
- if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_index,
- JS_NewInt32(ctx, (capture[0] - str_buf) >> shift), prop_flags) < 0)
+
+ t = groups, groups = JS_UNDEFINED;
+ if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_groups,
+ t, prop_flags) < 0) {
goto fail;
- if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_input, str_val, prop_flags) < 0)
- goto fail1;
+ }
+
+ if (!JS_IsUndefined(indices)) {
+ t = indices_groups, indices_groups = JS_UNDEFINED;
+ if (JS_DefinePropertyValue(ctx, indices, JS_ATOM_groups,
+ t, prop_flags) < 0) {
+ goto fail;
+ }
+ t = indices, indices = JS_UNDEFINED;
+ if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_indices,
+ t, prop_flags) < 0) {
+ goto fail;
+ }
+ }
}
- js_free(ctx, capture);
- return obj;
+ ret = obj;
+ obj = JS_UNDEFINED;
fail:
- JS_FreeValue(ctx, groups);
+ JS_FreeValue(ctx, indices_groups);
+ JS_FreeValue(ctx, indices);
JS_FreeValue(ctx, str_val);
-fail1:
+ JS_FreeValue(ctx, groups);
JS_FreeValue(ctx, obj);
js_free(ctx, capture);
- return JS_EXCEPTION;
+ return ret;
}
/* delete portions of a string that match a given regex */
@@ -42435,7 +45359,11 @@ static JSValue JS_RegExpDelete(JSContext *ctx, JSValueConst this_val, JSValueCon
goto fail;
}
} else {
- JS_ThrowInternalError(ctx, "out of memory in regexp execution");
+ if (ret == LRE_RET_TIMEOUT) {
+ JS_ThrowInterrupted(ctx);
+ } else {
+ JS_ThrowInternalError(ctx, "out of memory in regexp execution");
+ }
goto fail;
}
break;
@@ -42455,7 +45383,7 @@ static JSValue JS_RegExpDelete(JSContext *ctx, JSValueConst this_val, JSValueCon
break;
}
if (end == start) {
- if (!(re_flags & LRE_FLAG_UTF16) || (unsigned)end >= str->len || !str->is_wide_char) {
+ if (!(re_flags & LRE_FLAG_UNICODE) || (unsigned)end >= str->len || !str->is_wide_char) {
end++;
} else {
string_getc(str, &end);
@@ -42551,14 +45479,12 @@ static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val,
goto exception;
p = JS_VALUE_GET_STRING(flags);
- // TODO(bnoordhuis) query 'u' flag the same way?
global = (-1 != string_indexof_char(p, 'g', 0));
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;
+ fullUnicode = (string_indexof_char(p, 'u', 0) >= 0 ||
+ string_indexof_char(p, 'v', 0) >= 0);
if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0)
goto exception;
@@ -42577,7 +45503,7 @@ static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val,
if (JS_IsException(matchStr))
goto exception;
isEmpty = JS_IsEmptyString(matchStr);
- if (JS_SetPropertyInt64(ctx, A, n++, matchStr) < 0)
+ if (JS_DefinePropertyValueInt64(ctx, A, n++, matchStr, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
goto exception;
if (isEmpty) {
int64_t thisIndex, nextIndex;
@@ -42702,7 +45628,7 @@ static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val,
JSString *strp;
int64_t lastIndex;
JSRegExpStringIteratorData *it;
-
+
if (!JS_IsObject(R))
return JS_ThrowTypeErrorNotAnObject(ctx);
@@ -42710,7 +45636,7 @@ static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val,
flags = JS_UNDEFINED;
matcher = JS_UNDEFINED;
iter = JS_UNDEFINED;
-
+
S = JS_ToString(ctx, argv[0]);
if (JS_IsException(S))
goto exception;
@@ -42731,7 +45657,7 @@ static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val,
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;
@@ -42742,7 +45668,8 @@ static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val,
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->unicode = (string_indexof_char(strp, 'u', 0) >= 0 ||
+ string_indexof_char(strp, 'v', 0) >= 0);
it->done = FALSE;
JS_SetOpaque(iter, it);
@@ -42870,7 +45797,7 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
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);
@@ -42889,13 +45816,11 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
goto exception;
p = JS_VALUE_GET_STRING(flags);
- // TODO(bnoordhuis) query 'u' flag the same way?
fullUnicode = 0;
is_global = (-1 != string_indexof_char(p, 'g', 0));
if (is_global) {
- fullUnicode = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_unicode));
- if (fullUnicode < 0)
- goto exception;
+ fullUnicode = (string_indexof_char(p, 'u', 0) >= 0 ||
+ string_indexof_char(p, 'v', 0) >= 0);
if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0)
goto exception;
}
@@ -43121,7 +46046,8 @@ static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val,
if (JS_IsException(flags))
goto exception;
strp = JS_VALUE_GET_STRING(flags);
- unicodeMatching = string_indexof_char(strp, 'u', 0) >= 0;
+ unicodeMatching = (string_indexof_char(strp, 'u', 0) >= 0 ||
+ string_indexof_char(strp, 'v', 0) >= 0);
if (string_indexof_char(strp, 'y', 0) < 0) {
flags = JS_ConcatString3(ctx, "", flags, "y");
if (JS_IsException(flags))
@@ -43158,7 +46084,7 @@ static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val,
while (q < size) {
if (JS_SetProperty(ctx, splitter, JS_ATOM_lastIndex, JS_NewInt32(ctx, q)) < 0)
goto exception;
- JS_FreeValue(ctx, z);
+ JS_FreeValue(ctx, z);
z = JS_RegExpExec(ctx, splitter, str);
if (JS_IsException(z))
goto exception;
@@ -43184,7 +46110,7 @@ static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val,
if (js_get_length64(ctx, &numberOfCaptures, z))
goto exception;
for(i = 1; i < numberOfCaptures; i++) {
- sub = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, z, i));
+ sub = 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)
@@ -43213,11 +46139,12 @@ static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val,
JS_FreeValue(ctx, ctor);
JS_FreeValue(ctx, splitter);
JS_FreeValue(ctx, flags);
- JS_FreeValue(ctx, z);
+ JS_FreeValue(ctx, z);
return A;
}
static const JSCFunctionListEntry js_regexp_funcs[] = {
+ JS_CFUNC_DEF("escape", 1, js_regexp_escape ),
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 ),
@@ -43226,12 +46153,14 @@ static const JSCFunctionListEntry js_regexp_funcs[] = {
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_CGETSET_MAGIC_DEF("global", js_regexp_get_flag, NULL, LRE_FLAG_GLOBAL ),
+ JS_CGETSET_MAGIC_DEF("ignoreCase", js_regexp_get_flag, NULL, LRE_FLAG_IGNORECASE ),
+ JS_CGETSET_MAGIC_DEF("multiline", js_regexp_get_flag, NULL, LRE_FLAG_MULTILINE ),
+ JS_CGETSET_MAGIC_DEF("dotAll", js_regexp_get_flag, NULL, LRE_FLAG_DOTALL ),
+ JS_CGETSET_MAGIC_DEF("unicode", js_regexp_get_flag, NULL, LRE_FLAG_UNICODE ),
+ JS_CGETSET_MAGIC_DEF("unicodeSets", js_regexp_get_flag, NULL, LRE_FLAG_UNICODE_SETS ),
+ JS_CGETSET_MAGIC_DEF("sticky", js_regexp_get_flag, NULL, LRE_FLAG_STICKY ),
+ JS_CGETSET_MAGIC_DEF("hasIndices", js_regexp_get_flag, NULL, LRE_FLAG_INDICES ),
JS_CFUNC_DEF("exec", 1, js_regexp_exec ),
JS_CFUNC_DEF("compile", 2, js_regexp_compile ),
JS_CFUNC_DEF("test", 1, js_regexp_test ),
@@ -43298,7 +46227,7 @@ static JSValue json_parse_value(JSParseState *s)
{
JSValue prop_val;
JSAtom prop_name;
-
+
if (json_next_token(s))
goto fail;
val = JS_NewObject(ctx);
@@ -43389,9 +46318,15 @@ static JSValue json_parse_value(JSParseState *s)
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));
+ 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 if (s->token.u.ident.atom == JS_ATOM_NaN && s->ext_json) {
+ /* Note: json5 identifier handling is ambiguous e.g. is
+ '{ NaN: 1 }' a valid JSON5 production ? */
+ val = JS_NewFloat64(s->ctx, NAN);
+ } else if (s->token.u.ident.atom == JS_ATOM_Infinity && s->ext_json) {
+ val = JS_NewFloat64(s->ctx, INFINITY);
} else {
goto def_token;
}
@@ -43401,7 +46336,7 @@ static JSValue json_parse_value(JSParseState *s)
default:
def_token:
if (s->token.val == TOK_EOF) {
- js_parse_error(s, "unexpected end of input");
+ js_parse_error(s, "Unexpected end of JSON input");
} else {
js_parse_error(s, "unexpected token: '%.*s'",
(int)(s->buf_ptr - s->token.ptr), s->token.ptr);
@@ -43441,7 +46376,7 @@ JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
const char *filename)
{
- return JS_ParseJSON2(ctx, buf, buf_len, filename, 0);
+ return JS_ParseJSON2(ctx, buf, buf_len, filename, 0);
}
static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
@@ -43496,7 +46431,7 @@ static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
goto fail;
}
}
- js_free_prop_enum(ctx, atoms, len);
+ JS_FreePropertyEnum(ctx, atoms, len);
atoms = NULL;
name_val = JS_AtomToValue(ctx, name);
if (JS_IsException(name_val))
@@ -43508,7 +46443,7 @@ static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
JS_FreeValue(ctx, val);
return res;
fail:
- js_free_prop_enum(ctx, atoms, len);
+ JS_FreePropertyEnum(ctx, atoms, len);
JS_FreeValue(ctx, val);
return JS_EXCEPTION;
}
@@ -43568,22 +46503,22 @@ static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,
JSValue v;
JSValueConst args[2];
- if (JS_IsObject(val) ||
- JS_IsBigInt(ctx, val) /* XXX: probably useless */
- ) {
- JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON);
- if (JS_IsException(f))
+ /* check for object.toJSON method */
+ /* ECMA specifies this is done only for Object and BigInt */
+ if (JS_IsObject(val) || JS_IsBigInt(ctx, val)) {
+ 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;
- 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);
- }
+ } else {
+ JS_FreeValue(ctx, f);
}
+ }
if (!JS_IsUndefined(jsc->replacer_func)) {
args[0] = key;
@@ -43600,13 +46535,12 @@ static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,
if (JS_IsFunction(ctx, val))
break;
case JS_TAG_STRING:
+ case JS_TAG_STRING_ROPE:
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:
+ case JS_TAG_SHORT_BIG_INT:
case JS_TAG_BIG_INT:
case JS_TAG_EXCEPTION:
return val;
@@ -43630,43 +46564,36 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
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:
+ if (js_check_stack_overflow(ctx->rt, 0)) {
+ JS_ThrowStackOverflow(ctx);
+ goto exception;
+ }
+
+ if (JS_IsObject(val)) {
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);
+ goto concat_primitive;
} 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;
- } else
-#ifdef CONFIG_BIGNUM
- if (cl == JS_CLASS_BIG_FLOAT) {
- return string_buffer_concat_value_free(jsc->b, val);
- } else
-#endif
- if (cl == JS_CLASS_BIG_INT) {
- JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify");
- goto exception;
+ goto concat_primitive;
+ } else if (cl == JS_CLASS_BOOLEAN || cl == JS_CLASS_BIG_INT)
+ {
+ /* This will thow the same error as for the primitive object */
+ set_value(ctx, &val, JS_DupValue(ctx, p->u.object_data));
+ goto concat_primitive;
}
v = js_array_includes(ctx, jsc->stack, 1, (JSValueConst *)&val);
if (JS_IsException(v))
@@ -43682,7 +46609,7 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
sep = JS_ConcatString3(ctx, "\n", JS_DupValue(ctx, indent1), "");
if (JS_IsException(sep))
goto exception;
- sep1 = JS_NewString(ctx, " ");
+ sep1 = js_new_string8(ctx, " ");
if (JS_IsException(sep1))
goto exception;
} else {
@@ -43764,7 +46691,7 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
has_content = TRUE;
}
}
- if (has_content && JS_VALUE_GET_STRING(jsc->gap)->len != 0) {
+ if (has_content && !JS_IsEmptyString(jsc->gap)) {
string_buffer_putc8(jsc->b, '\n');
string_buffer_concat_value(jsc->b, indent);
}
@@ -43779,7 +46706,11 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
JS_FreeValue(ctx, indent1);
JS_FreeValue(ctx, prop);
return 0;
+ }
+ concat_primitive:
+ switch (JS_VALUE_GET_NORM_TAG(val)) {
case JS_TAG_STRING:
+ case JS_TAG_STRING_ROPE:
val = JS_ToQuotedStringFree(ctx, val);
if (JS_IsException(val))
goto exception;
@@ -43790,21 +46721,20 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
}
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);
+ case JS_TAG_SHORT_BIG_INT:
case JS_TAG_BIG_INT:
- JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify");
+ /* reject big numbers: use toJSON method to override */
+ JS_ThrowTypeError(ctx, "Do not know how to serialize a BigInt");
goto exception;
default:
JS_FreeValue(ctx, val);
return 0;
}
-
+
exception:
JS_FreeValue(ctx, val);
JS_FreeValue(ctx, tab);
@@ -43905,7 +46835,7 @@ JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
int n;
if (JS_ToInt32Clamp(ctx, &n, space, 0, 10, 0))
goto exception;
- jsc->gap = JS_NewStringLen(ctx, " ", n);
+ jsc->gap = js_new_string8_len(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));
@@ -43922,7 +46852,7 @@ JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
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;
@@ -44178,7 +47108,7 @@ static JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod,
JS_ThrowStackOverflow(ctx);
return NULL;
}
-
+
/* 's' should never be NULL */
if (s->is_revoked) {
JS_ThrowTypeErrorRevokedProxy(ctx);
@@ -44193,7 +47123,7 @@ static JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod,
return s;
}
-static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj)
+static JSValue js_proxy_get_prototype(JSContext *ctx, JSValueConst obj)
{
JSProxyData *s;
JSValue method, ret, proto1;
@@ -44223,7 +47153,7 @@ static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj)
JS_FreeValue(ctx, ret);
return JS_EXCEPTION;
}
- if (JS_VALUE_GET_OBJ(proto1) != JS_VALUE_GET_OBJ(ret)) {
+ if (!js_same_value(ctx, proto1, ret)) {
JS_FreeValue(ctx, proto1);
fail:
JS_FreeValue(ctx, ret);
@@ -44234,8 +47164,8 @@ static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj)
return ret;
}
-static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
- JSValueConst proto_val, BOOL throw_flag)
+static int js_proxy_set_prototype(JSContext *ctx, JSValueConst obj,
+ JSValueConst proto_val)
{
JSProxyData *s;
JSValue method, ret, proto1;
@@ -44247,21 +47177,15 @@ static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
if (!s)
return -1;
if (JS_IsUndefined(method))
- return JS_SetPrototypeInternal(ctx, s->target, proto_val, throw_flag);
+ return JS_SetPrototypeInternal(ctx, s->target, proto_val, FALSE);
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;
- }
- }
+ if (!res)
+ return FALSE;
res2 = JS_IsExtensible(ctx, s->target);
if (res2 < 0)
return -1;
@@ -44269,7 +47193,7 @@ static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
proto1 = JS_GetPrototype(ctx, s->target);
if (JS_IsException(proto1))
return -1;
- if (JS_VALUE_GET_OBJ(proto_val) != JS_VALUE_GET_OBJ(proto1)) {
+ if (!js_same_value(ctx, proto_val, proto1)) {
JS_FreeValue(ctx, proto1);
JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
return -1;
@@ -44279,7 +47203,7 @@ static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
return TRUE;
}
-static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj)
+static int js_proxy_is_extensible(JSContext *ctx, JSValueConst obj)
{
JSProxyData *s;
JSValue method, ret;
@@ -44305,7 +47229,7 @@ static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj)
return res;
}
-static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj)
+static int js_proxy_prevent_extensions(JSContext *ctx, JSValueConst obj)
{
JSProxyData *s;
JSValue method, ret;
@@ -44405,8 +47329,10 @@ static JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom,
if (JS_IsException(ret))
return JS_EXCEPTION;
res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
- if (res < 0)
+ if (res < 0) {
+ JS_FreeValue(ctx, ret);
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)) {
@@ -44505,17 +47431,17 @@ static JSValue js_create_desc(JSContext *ctx, JSValueConst val,
}
if (flags & JS_PROP_HAS_WRITABLE) {
JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
- JS_NewBool(ctx, (flags & JS_PROP_WRITABLE) != 0),
+ JS_NewBool(ctx, flags & JS_PROP_WRITABLE),
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_NewBool(ctx, flags & JS_PROP_ENUMERABLE),
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_NewBool(ctx, flags & JS_PROP_CONFIGURABLE),
JS_PROP_C_W_E);
}
return ret;
@@ -44577,6 +47503,14 @@ static int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc
JS_FreeValue(ctx, trap_result_obj);
if (res < 0)
return -1;
+
+ /* convert the result_desc.flags to property flags */
+ if (result_desc.flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
+ result_desc.flags |= JS_PROP_GETSET;
+ } else {
+ result_desc.flags |= JS_PROP_NORMAL;
+ }
+ result_desc.flags &= (JS_PROP_C_W_E | JS_PROP_TMASK);
if (target_desc_ret) {
/* convert result_desc.flags to defineProperty flags */
@@ -44676,13 +47610,11 @@ static int js_proxy_define_own_property(JSContext *ctx, JSValueConst obj,
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)) {
+ if (!check_define_prop_flags(desc.flags, flags))
goto fail1;
- }
- if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
- if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) ==
- JS_PROP_GETSET) {
+ /* do the missing check from check_define_prop_flags() */
+ if (!(desc.flags & JS_PROP_CONFIGURABLE)) {
+ if ((desc.flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
if ((flags & JS_PROP_HAS_GET) &&
!js_same_value(ctx, getter, desc.getter)) {
goto fail1;
@@ -44691,27 +47623,26 @@ static int js_proxy_define_own_property(JSContext *ctx, JSValueConst obj,
!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;
+ } else if (!(desc.flags & JS_PROP_WRITABLE)) {
+ if ((flags & JS_PROP_HAS_VALUE) &&
+ !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;
- }
+
+ /* additional checks */
+ if ((desc.flags & JS_PROP_CONFIGURABLE) && setting_not_configurable)
+ goto fail1;
+
+ if ((desc.flags & JS_PROP_TMASK) != JS_PROP_GETSET &&
+ (desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == JS_PROP_WRITABLE &&
+ (flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) {
+ fail1:
+ js_free_desc(ctx, &desc);
+ fail:
+ JS_ThrowTypeError(ctx, "proxy: inconsistent defineProperty");
+ return -1;
}
js_free_desc(ctx, &desc);
}
@@ -44886,14 +47817,14 @@ static int js_proxy_get_own_property_names(JSContext *ctx,
}
}
- js_free_prop_enum(ctx, tab2, len2);
+ JS_FreePropertyEnum(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_FreePropertyEnum(ctx, tab2, len2);
+ JS_FreePropertyEnum(ctx, tab, len);
JS_FreeValue(ctx, prop_array);
return -1;
}
@@ -44942,7 +47873,7 @@ static JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj,
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;
@@ -44967,20 +47898,35 @@ static JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj,
return ret;
}
-static 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;
+/* `js_resolve_proxy`: resolve the proxy chain
+ `*pval` is updated with to ultimate proxy target
+ `throw_exception` controls whether exceptions are thown or not
+ - return -1 in case of error
+ - otherwise return 0
+ */
+static int js_resolve_proxy(JSContext *ctx, JSValueConst *pval, BOOL throw_exception) {
+ int depth = 0;
+ JSObject *p;
+ JSProxyData *s;
+
+ while (JS_VALUE_GET_TAG(*pval) == JS_TAG_OBJECT) {
+ p = JS_VALUE_GET_OBJ(*pval);
+ if (p->class_id != JS_CLASS_PROXY)
+ break;
+ if (depth++ > 1000) {
+ if (throw_exception)
+ JS_ThrowStackOverflow(ctx);
+ return -1;
+ }
+ s = p->u.opaque;
+ if (s->is_revoked) {
+ if (throw_exception)
+ JS_ThrowTypeErrorRevokedProxy(ctx);
+ return -1;
+ }
+ *pval = s->target;
}
- return JS_IsArray(ctx, s->target);
+ return 0;
}
static const JSClassExoticMethods js_proxy_exotic_methods = {
@@ -44991,6 +47937,10 @@ static const JSClassExoticMethods js_proxy_exotic_methods = {
.has_property = js_proxy_has,
.get_property = js_proxy_get,
.set_property = js_proxy_set,
+ .get_prototype = js_proxy_get_prototype,
+ .set_prototype = js_proxy_set_prototype,
+ .is_extensible = js_proxy_is_extensible,
+ .prevent_extensions = js_proxy_prevent_extensions,
};
static JSValue js_proxy_constructor(JSContext *ctx, JSValueConst this_val,
@@ -45210,26 +48160,78 @@ static const JSCFunctionListEntry js_symbol_funcs[] = {
/* Set/Map/WeakSet/WeakMap */
-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;
+static BOOL js_weakref_is_target(JSValueConst val)
+{
+ switch (JS_VALUE_GET_TAG(val)) {
+ case JS_TAG_OBJECT:
+ return TRUE;
+ case JS_TAG_SYMBOL:
+ {
+ JSAtomStruct *p = JS_VALUE_GET_PTR(val);
+ if (p->atom_type == JS_ATOM_TYPE_SYMBOL &&
+ p->hash != JS_ATOM_HASH_PRIVATE)
+ return TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ return FALSE;
+}
-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;
+/* JS_UNDEFINED is considered as a live weakref */
+/* XXX: add a specific JSWeakRef value type ? */
+static BOOL js_weakref_is_live(JSValueConst val)
+{
+ int *pref_count;
+ if (JS_IsUndefined(val))
+ return TRUE;
+ pref_count = JS_VALUE_GET_PTR(val);
+ return (*pref_count != 0);
+}
+
+/* 'val' can be JS_UNDEFINED */
+static void js_weakref_free(JSRuntime *rt, JSValue val)
+{
+ if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {
+ JSObject *p = JS_VALUE_GET_OBJ(val);
+ assert(p->weakref_count >= 1);
+ p->weakref_count--;
+ /* 'mark' is tested to avoid freeing the object structure when
+ it is about to be freed in a cycle or in
+ free_zero_refcount() */
+ if (p->weakref_count == 0 && p->header.ref_count == 0 &&
+ p->header.mark == 0) {
+ js_free_rt(rt, p);
+ }
+ } else if (JS_VALUE_GET_TAG(val) == JS_TAG_SYMBOL) {
+ JSString *p = JS_VALUE_GET_STRING(val);
+ assert(p->hash >= 1);
+ p->hash--;
+ if (p->hash == 0 && p->header.ref_count == 0) {
+ /* can remove the dummy structure */
+ js_free_rt(rt, p);
+ }
+ }
+}
+
+/* val must be an object, a symbol or undefined (see
+ js_weakref_is_target). */
+static JSValue js_weakref_new(JSContext *ctx, JSValueConst val)
+{
+ if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {
+ JSObject *p = JS_VALUE_GET_OBJ(val);
+ p->weakref_count++;
+ } else if (JS_VALUE_GET_TAG(val) == JS_TAG_SYMBOL) {
+ JSString *p = JS_VALUE_GET_STRING(val);
+ /* XXX: could return an exception if too many references */
+ assert(p->hash < JS_ATOM_HASH_MASK - 2);
+ p->hash++;
+ } else {
+ assert(JS_IsUndefined(val));
+ }
+ return val;
+}
#define MAGIC_SET (1 << 0)
#define MAGIC_WEAK (1 << 1)
@@ -45252,12 +48254,16 @@ static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target,
goto fail;
init_list_head(&s->records);
s->is_weak = is_weak;
+ if (is_weak) {
+ s->weakref_header.weakref_type = JS_WEAKREF_TYPE_MAP;
+ list_add_tail(&s->weakref_header.link, &ctx->rt->weakref_list);
+ }
JS_SetOpaque(obj, s);
- s->hash_size = 1;
- s->hash_table = js_malloc(ctx, sizeof(s->hash_table[0]) * s->hash_size);
+ s->hash_bits = 1;
+ s->hash_size = 1U << s->hash_bits;
+ s->hash_table = js_mallocz(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;
@@ -45286,15 +48292,13 @@ static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target,
item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
if (JS_IsException(item))
goto fail;
- if (done) {
- JS_FreeValue(ctx, item);
+ if (done)
break;
- }
if (is_set) {
ret = JS_Call(ctx, adder, obj, 1, (JSValueConst *)&item);
if (JS_IsException(ret)) {
JS_FreeValue(ctx, item);
- goto fail;
+ goto fail_close;
}
} else {
JSValue key, value;
@@ -45319,7 +48323,7 @@ static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target,
JS_FreeValue(ctx, item);
JS_FreeValue(ctx, key);
JS_FreeValue(ctx, value);
- goto fail;
+ goto fail_close;
}
JS_FreeValue(ctx, key);
JS_FreeValue(ctx, value);
@@ -45332,11 +48336,10 @@ static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target,
JS_FreeValue(ctx, adder);
}
return obj;
+ fail_close:
+ /* close the iterator object, preserving pending exception */
+ JS_IteratorClose(ctx, iter, TRUE);
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);
@@ -45355,27 +48358,56 @@ static JSValueConst map_normalize_key(JSContext *ctx, JSValueConst key)
return key;
}
+/* hash multipliers, same as the Linux kernel (see Knuth vol 3,
+ section 6.4, exercise 9) */
+#define HASH_MUL32 0x61C88647
+#define HASH_MUL64 UINT64_C(0x61C8864680B583EB)
+
+static uint32_t map_hash32(uint32_t a, int hash_bits)
+{
+ return (a * HASH_MUL32) >> (32 - hash_bits);
+}
+
+static uint32_t map_hash64(uint64_t a, int hash_bits)
+{
+ return (a * HASH_MUL64) >> (64 - hash_bits);
+}
+
+static uint32_t map_hash_pointer(uintptr_t a, int hash_bits)
+{
+#ifdef JS_PTR64
+ return map_hash64(a, hash_bits);
+#else
+ return map_hash32(a, hash_bits);
+#endif
+}
+
/* XXX: better hash ? */
-static uint32_t map_hash_key(JSContext *ctx, JSValueConst key)
+/* precondition: 1 <= hash_bits <= 32 */
+static uint32_t map_hash_key(JSValueConst key, int hash_bits)
{
uint32_t tag = JS_VALUE_GET_NORM_TAG(key);
uint32_t h;
double d;
- JSFloat64Union u;
-
+ JSBigInt *p;
+ JSBigIntBuf buf;
+
switch(tag) {
case JS_TAG_BOOL:
- h = JS_VALUE_GET_INT(key);
+ h = map_hash32(JS_VALUE_GET_INT(key) ^ JS_TAG_BOOL, hash_bits);
break;
case JS_TAG_STRING:
- h = hash_string(JS_VALUE_GET_STRING(key), 0);
+ h = map_hash32(hash_string(JS_VALUE_GET_STRING(key), 0) ^ JS_TAG_STRING, hash_bits);
+ break;
+ case JS_TAG_STRING_ROPE:
+ h = map_hash32(hash_string_rope(key, 0) ^ JS_TAG_STRING, hash_bits);
break;
case JS_TAG_OBJECT:
case JS_TAG_SYMBOL:
- h = (uintptr_t)JS_VALUE_GET_PTR(key) * 3163;
+ h = map_hash_pointer((uintptr_t)JS_VALUE_GET_PTR(key) ^ tag, hash_bits);
break;
case JS_TAG_INT:
- d = JS_VALUE_GET_INT(key) * 3163;
+ d = JS_VALUE_GET_INT(key);
goto hash_float64;
case JS_TAG_FLOAT64:
d = JS_VALUE_GET_FLOAT64(key);
@@ -45383,61 +48415,77 @@ static uint32_t map_hash_key(JSContext *ctx, JSValueConst key)
if (isnan(d))
d = JS_FLOAT64_NAN;
hash_float64:
- u.d = d;
- h = (u.u32[0] ^ u.u32[1]) * 3163;
+ h = map_hash64(float64_as_uint64(d) ^ JS_TAG_FLOAT64, hash_bits);
+ break;
+ case JS_TAG_SHORT_BIG_INT:
+ p = js_bigint_set_short(&buf, key);
+ goto hash_bigint;
+ case JS_TAG_BIG_INT:
+ p = JS_VALUE_GET_PTR(key);
+ hash_bigint:
+ {
+ int i;
+ h = 1;
+ for(i = p->len - 1; i >= 0; i--) {
+ h = h * 263 + p->tab[i];
+ }
+ /* the final step is necessary otherwise h mod n only
+ depends of p->tab[i] mod n */
+ h = map_hash32(h ^ JS_TAG_BIG_INT, hash_bits);
+ }
break;
default:
- h = 0; /* XXX: bignum support */
+ h = 0;
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;
+ h = map_hash_key(key, s->hash_bits);
+ for(mr = s->hash_table[h]; mr != NULL; mr = mr->hash_next) {
+ if (mr->empty || (s->is_weak && !js_weakref_is_live(mr->key))) {
+ /* cannot match */
+ } else {
+ 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;
+ uint32_t new_hash_size, h;
+ int new_hash_bits;
+ struct list_head *el;
+ JSMapRecord *mr, **new_hash_table;
/* 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);
+ new_hash_bits = min_int(s->hash_bits + 1, 31);
+ new_hash_size = 1U << new_hash_bits;
+ new_hash_table = js_realloc(ctx, s->hash_table,
+ sizeof(new_hash_table[0]) * new_hash_size);
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]);
+ memset(new_hash_table, 0, sizeof(new_hash_table[0]) * new_hash_size);
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]);
+ if (mr->empty || (s->is_weak && !js_weakref_is_live(mr->key))) {
+ } else {
+ h = map_hash_key(mr->key, new_hash_bits);
+ mr->hash_next = new_hash_table[h];
+ new_hash_table[h] = mr;
}
}
s->hash_table = new_hash_table;
+ s->hash_bits = new_hash_bits;
s->hash_size = new_hash_size;
s->record_count_threshold = new_hash_size * 2;
}
@@ -45452,19 +48500,15 @@ static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s,
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;
+ mr->key = js_weakref_new(ctx, key);
} else {
- JS_DupValue(ctx, key);
+ mr->key = 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]);
+ h = map_hash_key(key, s->hash_bits);
+ mr->hash_next = s->hash_table[h];
+ s->hash_table[h] = mr;
list_add_tail(&mr->link, &s->records);
s->record_count++;
if (s->record_count >= s->record_count_threshold) {
@@ -45473,34 +48517,14 @@ static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *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;
-}
-
+/* warning: the record must be removed from the hash table before */
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);
+ js_weakref_free(rt, mr->key);
} else {
JS_FreeValueRT(rt, mr->key);
}
@@ -45527,30 +48551,36 @@ static void map_decref_record(JSRuntime *rt, JSMapRecord *mr)
}
}
-static void reset_weak_ref(JSRuntime *rt, JSObject *p)
+static void map_delete_weakrefs(JSRuntime *rt, JSWeakRefHeader *wh)
{
- JSMapRecord *mr, *mr_next;
- JSMapState *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);
- }
+ JSMapState *s = container_of(wh, JSMapState, weakref_header);
+ struct list_head *el, *el1;
+ JSMapRecord *mr1, **pmr;
+ uint32_t h;
- p->first_weak_ref = NULL; /* fail safe */
+ list_for_each_safe(el, el1, &s->records) {
+ JSMapRecord *mr = list_entry(el, JSMapRecord, link);
+ if (!js_weakref_is_live(mr->key)) {
+
+ /* even if key is not live it can be hashed as a pointer */
+ h = map_hash_key(mr->key, s->hash_bits);
+ pmr = &s->hash_table[h];
+ for(;;) {
+ mr1 = *pmr;
+ /* the entry may already be removed from the hash
+ table if the map was resized */
+ if (mr1 == NULL)
+ goto done;
+ if (mr1 == mr)
+ break;
+ pmr = &mr1->hash_next;
+ }
+ /* remove from the hash table */
+ *pmr = mr1->hash_next;
+ done:
+ map_delete_record(rt, s, mr);
+ }
+ }
}
static JSValue js_map_set(JSContext *ctx, JSValueConst this_val,
@@ -45563,8 +48593,8 @@ static JSValue js_map_set(JSContext *ctx, JSValueConst this_val,
if (!s)
return JS_EXCEPTION;
key = map_normalize_key(ctx, argv[0]);
- if (s->is_weak && !JS_IsObject(key))
- return JS_ThrowTypeErrorNotAnObject(ctx);
+ if (s->is_weak && !js_weakref_is_target(key))
+ return JS_ThrowTypeError(ctx, "invalid value used as %s key", (magic & MAGIC_SET) ? "WeakSet" : "WeakMap");
if (magic & MAGIC_SET)
value = JS_UNDEFINED;
else
@@ -45609,22 +48639,39 @@ static JSValue js_map_has(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
key = map_normalize_key(ctx, argv[0]);
mr = map_find_record(ctx, s, key);
- return JS_NewBool(ctx, (mr != NULL));
+ 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;
+ JSMapRecord *mr, **pmr;
JSValueConst key;
+ uint32_t h;
if (!s)
return JS_EXCEPTION;
key = map_normalize_key(ctx, argv[0]);
- mr = map_find_record(ctx, s, key);
- if (!mr)
- return JS_FALSE;
+
+ h = map_hash_key(key, s->hash_bits);
+ pmr = &s->hash_table[h];
+ for(;;) {
+ mr = *pmr;
+ if (mr == NULL)
+ return JS_FALSE;
+ if (mr->empty || (s->is_weak && !js_weakref_is_live(mr->key))) {
+ /* not valid */
+ } else {
+ if (js_same_value_zero(ctx, mr->key, key))
+ break;
+ }
+ pmr = &mr->hash_next;
+ }
+
+ /* remove from the hash table */
+ *pmr = mr->hash_next;
+
map_delete_record(ctx->rt, s, mr);
return JS_TRUE;
}
@@ -45638,6 +48685,10 @@ static JSValue js_map_clear(JSContext *ctx, JSValueConst this_val,
if (!s)
return JS_EXCEPTION;
+
+ /* remove from the hash table */
+ memset(s->hash_table, 0, sizeof(s->hash_table[0]) * s->hash_size);
+
list_for_each_safe(el, el1, &s->records) {
mr = list_entry(el, JSMapRecord, link);
map_delete_record(ctx->rt, s, mr);
@@ -45684,7 +48735,7 @@ static JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val,
args[0] = args[1];
else
args[0] = JS_DupValue(ctx, mr->value);
- args[2] = (JSValue)this_val;
+ args[2] = this_val;
ret = JS_Call(ctx, func, this_arg, 3, (JSValueConst *)args);
JS_FreeValue(ctx, args[0]);
if (!magic)
@@ -45701,6 +48752,123 @@ static JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val,
return JS_UNDEFINED;
}
+static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int is_map)
+{
+ JSValueConst cb, args[2];
+ JSValue res, iter, next, groups, key, v, prop;
+ JSAtom key_atom = JS_ATOM_NULL;
+ int64_t idx;
+ BOOL done;
+
+ // "is function?" check must be observed before argv[0] is accessed
+ cb = argv[1];
+ if (check_function(ctx, cb))
+ return JS_EXCEPTION;
+
+ iter = JS_GetIterator(ctx, argv[0], /*is_async*/FALSE);
+ if (JS_IsException(iter))
+ return JS_EXCEPTION;
+
+ key = JS_UNDEFINED;
+ key_atom = JS_ATOM_NULL;
+ v = JS_UNDEFINED;
+ prop = JS_UNDEFINED;
+ groups = JS_UNDEFINED;
+
+ next = JS_GetProperty(ctx, iter, JS_ATOM_next);
+ if (JS_IsException(next))
+ goto exception;
+
+ if (is_map) {
+ groups = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, 0);
+ } else {
+ groups = JS_NewObjectProto(ctx, JS_NULL);
+ }
+ if (JS_IsException(groups))
+ goto exception;
+
+ for (idx = 0; ; idx++) {
+ if (idx >= MAX_SAFE_INTEGER) {
+ JS_ThrowTypeError(ctx, "too many elements");
+ goto iterator_close_exception;
+ }
+ v = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
+ if (JS_IsException(v))
+ goto exception;
+ if (done)
+ break; // v is JS_UNDEFINED
+
+ args[0] = v;
+ args[1] = JS_NewInt64(ctx, idx);
+ key = JS_Call(ctx, cb, ctx->global_obj, 2, args);
+ if (JS_IsException(key))
+ goto iterator_close_exception;
+
+ if (is_map) {
+ prop = js_map_get(ctx, groups, 1, (JSValueConst *)&key, 0);
+ } else {
+ key_atom = JS_ValueToAtom(ctx, key);
+ JS_FreeValue(ctx, key);
+ key = JS_UNDEFINED;
+ if (key_atom == JS_ATOM_NULL)
+ goto iterator_close_exception;
+ prop = JS_GetProperty(ctx, groups, key_atom);
+ }
+ if (JS_IsException(prop))
+ goto exception;
+
+ if (JS_IsUndefined(prop)) {
+ prop = JS_NewArray(ctx);
+ if (JS_IsException(prop))
+ goto exception;
+ if (is_map) {
+ args[0] = key;
+ args[1] = prop;
+ res = js_map_set(ctx, groups, 2, args, 0);
+ if (JS_IsException(res))
+ goto exception;
+ JS_FreeValue(ctx, res);
+ } else {
+ prop = JS_DupValue(ctx, prop);
+ if (JS_DefinePropertyValue(ctx, groups, key_atom, prop,
+ JS_PROP_C_W_E) < 0) {
+ goto exception;
+ }
+ }
+ }
+ res = js_array_push(ctx, prop, 1, (JSValueConst *)&v, /*unshift*/0);
+ if (JS_IsException(res))
+ goto exception;
+ // res is an int64
+
+ JS_FreeValue(ctx, prop);
+ JS_FreeValue(ctx, key);
+ JS_FreeAtom(ctx, key_atom);
+ JS_FreeValue(ctx, v);
+ prop = JS_UNDEFINED;
+ key = JS_UNDEFINED;
+ key_atom = JS_ATOM_NULL;
+ v = JS_UNDEFINED;
+ }
+
+ JS_FreeValue(ctx, iter);
+ JS_FreeValue(ctx, next);
+ return groups;
+
+ iterator_close_exception:
+ JS_IteratorClose(ctx, iter, TRUE);
+ exception:
+ JS_FreeAtom(ctx, key_atom);
+ JS_FreeValue(ctx, prop);
+ JS_FreeValue(ctx, key);
+ JS_FreeValue(ctx, v);
+ JS_FreeValue(ctx, groups);
+ JS_FreeValue(ctx, iter);
+ JS_FreeValue(ctx, next);
+ return JS_EXCEPTION;
+}
+
static void js_map_finalizer(JSRuntime *rt, JSValue val)
{
JSObject *p;
@@ -45717,7 +48885,7 @@ static void js_map_finalizer(JSRuntime *rt, JSValue val)
mr = list_entry(el, JSMapRecord, link);
if (!mr->empty) {
if (s->is_weak)
- delete_weak_ref(rt, mr);
+ js_weakref_free(rt, mr->key);
else
JS_FreeValueRT(rt, mr->key);
JS_FreeValueRT(rt, mr->value);
@@ -45725,6 +48893,9 @@ static void js_map_finalizer(JSRuntime *rt, JSValue val)
js_free_rt(rt, mr);
}
js_free_rt(rt, s->hash_table);
+ if (s->is_weak) {
+ list_del(&s->weakref_header.link);
+ }
js_free_rt(rt, s);
}
}
@@ -45881,6 +49052,7 @@ static JSValue js_map_iterator_next(JSContext *ctx, JSValueConst this_val,
}
static const JSCFunctionListEntry js_map_funcs[] = {
+ JS_CFUNC_MAGIC_DEF("groupBy", 2, js_object_groupBy, 1 ),
JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
};
@@ -46001,12 +49173,6 @@ static const JSCFunctionListEntry js_generator_proto_funcs[] = {
/* Promise */
-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 */
@@ -46032,6 +49198,22 @@ typedef struct JSPromiseReactionData {
JSValue handler;
} JSPromiseReactionData;
+JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise)
+{
+ JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
+ if (!s)
+ return -1;
+ return s->promise_state;
+}
+
+JSValue JS_PromiseResult(JSContext *ctx, JSValue promise)
+{
+ JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
+ if (!s)
+ return JS_UNDEFINED;
+ return JS_DupValue(ctx, s->promise_result);
+}
+
static int js_create_resolving_functions(JSContext *ctx, JSValue *args,
JSValueConst promise);
@@ -46267,8 +49449,8 @@ static JSValue js_promise_resolve_function_call(JSContext *ctx,
else
resolution = JS_UNDEFINED;
#ifdef DUMP_PROMISE
- printf("js_promise_resolving_function_call: is_reject=%d resolution=", is_reject);
- JS_DumpValue(ctx, resolution);
+ printf("js_promise_resolving_function_call: is_reject=%d ", is_reject);
+ JS_DumpValue(ctx, "resolution", resolution);
printf("\n");
#endif
if (is_reject || !JS_IsObject(resolution)) {
@@ -46494,17 +49676,14 @@ static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
return result_promise;
}
-#if 0
-static JSValue js_promise___newPromiseCapability(JSContext *ctx,
- JSValueConst this_val,
- int argc, JSValueConst *argv)
+static JSValue js_promise_withResolvers(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))
+ if (!JS_IsObject(this_val))
return JS_ThrowTypeErrorNotAnObject(ctx);
- result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor);
+ result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
if (JS_IsException(result_promise))
return result_promise;
obj = JS_NewObject(ctx);
@@ -46519,7 +49698,34 @@ static JSValue js_promise___newPromiseCapability(JSContext *ctx,
JS_DefinePropertyValue(ctx, obj, JS_ATOM_reject, resolving_funcs[1], JS_PROP_C_W_E);
return obj;
}
-#endif
+
+static JSValue js_promise_try(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue result_promise, resolving_funcs[2], ret, ret2;
+ BOOL is_reject = 0;
+
+ 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;
+ ret = JS_Call(ctx, argv[0], JS_UNDEFINED, argc - 1, argv + 1);
+ if (JS_IsException(ret)) {
+ is_reject = 1;
+ ret = JS_GetException(ctx);
+ }
+ ret2 = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED, 1, (JSValueConst *)&ret);
+ JS_FreeValue(ctx, resolving_funcs[0]);
+ JS_FreeValue(ctx, resolving_funcs[1]);
+ JS_FreeValue(ctx, ret);
+ if (JS_IsException(ret2)) {
+ JS_FreeValue(ctx, result_promise);
+ return ret2;
+ }
+ JS_FreeValue(ctx, ret2);
+ return result_promise;
+}
static __exception int remainingElementsCount_add(JSContext *ctx,
JSValueConst resolve_element_env,
@@ -46558,7 +49764,7 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx,
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)
@@ -46567,11 +49773,11 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx,
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");
+ str = js_new_string8(ctx, is_reject ? "rejected" : "fulfilled");
if (JS_IsException(str))
goto fail1;
if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_status,
@@ -46592,7 +49798,7 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx,
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;
@@ -46625,7 +49831,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
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);
@@ -46661,7 +49867,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
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'
@@ -46671,7 +49877,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
goto fail_reject;
if (done)
break;
- next_promise = JS_Call(ctx, promise_resolve,
+ next_promise = JS_Call(ctx, promise_resolve,
this_val, 1, (JSValueConst *)&item);
JS_FreeValue(ctx, item);
if (JS_IsException(next_promise)) {
@@ -46680,7 +49886,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
goto fail_reject;
}
resolve_element_data[0] = JS_NewBool(ctx, FALSE);
- resolve_element_data[1] = (JSValueConst)JS_NewInt32(ctx, index);
+ resolve_element_data[1] = 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;
@@ -46691,7 +49897,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
JS_FreeValue(ctx, next_promise);
goto fail_reject1;
}
-
+
if (magic == PROMISE_MAGIC_allSettled) {
reject_element =
JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,
@@ -47008,8 +50214,9 @@ static const JSCFunctionListEntry js_promise_funcs[] = {
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("try", 1, js_promise_try ),
JS_CFUNC_DEF("race", 1, js_promise_race ),
- //JS_CFUNC_DEF("__newPromiseCapability", 1, js_promise___newPromiseCapability ),
+ JS_CFUNC_DEF("withResolvers", 0, js_promise_withResolvers ),
JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL),
};
@@ -47025,25 +50232,6 @@ static const JSCFunctionListEntry js_async_function_proto_funcs[] = {
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncFunction", JS_PROP_CONFIGURABLE ),
};
-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);
-}
-
/* AsyncIteratorPrototype */
static const JSCFunctionListEntry js_async_iterator_proto_funcs[] = {
@@ -47105,6 +50293,41 @@ static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx,
return async_iter;
}
+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] = 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_close_wrap(JSContext *ctx,
+ JSValueConst this_val,
+ int argc, JSValueConst *argv,
+ int magic, JSValue *func_data)
+{
+ JS_Throw(ctx, JS_DupValue(ctx, argv[0]));
+ JS_IteratorClose(ctx, func_data[0], TRUE);
+ return JS_EXCEPTION;
+}
+
+static JSValue js_async_from_sync_iterator_close_wrap_func_create(JSContext *ctx, JSValueConst sync_iter)
+{
+ return JS_NewCFunctionData(ctx, js_async_from_sync_iterator_close_wrap,
+ 1, 0, 1, &sync_iter);
+}
+
static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv,
int magic)
@@ -47135,11 +50358,13 @@ static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst thi
if (magic == GEN_MAGIC_RETURN) {
err = js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]), TRUE);
is_reject = 0;
+ goto done_resolve;
} else {
- err = JS_DupValue(ctx, argv[0]);
- is_reject = 1;
+ if (JS_IteratorClose(ctx, s->sync_iter, FALSE))
+ goto reject;
+ JS_ThrowTypeError(ctx, "throw is not a method");
+ goto reject;
}
- goto done_resolve;
}
}
value = JS_IteratorNext2(ctx, s->sync_iter, method,
@@ -47154,21 +50379,9 @@ static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst thi
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;
- }
+
+ if (JS_IsException(value))
+ goto reject;
{
JSValue value_wrapper_promise, resolve_reject[2];
int res;
@@ -47176,8 +50389,22 @@ static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst thi
value_wrapper_promise = js_promise_resolve(ctx, ctx->promise_ctor,
1, (JSValueConst *)&value, 0);
if (JS_IsException(value_wrapper_promise)) {
+ JSValue res2;
JS_FreeValue(ctx, value);
- goto reject;
+ if (magic != GEN_MAGIC_RETURN && !done) {
+ JS_IteratorClose(ctx, s->sync_iter, TRUE);
+ }
+ 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;
}
resolve_reject[0] =
@@ -47186,13 +50413,23 @@ static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst thi
JS_FreeValue(ctx, value_wrapper_promise);
goto fail;
}
+ if (done || magic == GEN_MAGIC_RETURN) {
+ resolve_reject[1] = JS_UNDEFINED;
+ } else {
+ resolve_reject[1] =
+ js_async_from_sync_iterator_close_wrap_func_create(ctx, s->sync_iter);
+ if (JS_IsException(resolve_reject[1])) {
+ JS_FreeValue(ctx, value_wrapper_promise);
+ JS_FreeValue(ctx, resolve_reject[0]);
+ 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, resolve_reject[1]);
JS_FreeValue(ctx, value_wrapper_promise);
JS_FreeValue(ctx, resolving_funcs[0]);
JS_FreeValue(ctx, resolving_funcs[1]);
@@ -47422,8 +50659,7 @@ static JSValue js_global_decodeURI(JSContext *ctx, JSValueConst this_val,
}
c = (c << 6) | (c1 & 0x3f);
}
- if (c < c_min || c > 0x10FFFF ||
- (c >= 0xd800 && c < 0xe000)) {
+ if (c < c_min || c > 0x10FFFF || is_surrogate(c)) {
js_throw_URIError(ctx, "malformed UTF-8");
goto fail;
}
@@ -47498,21 +50734,21 @@ static JSValue js_global_encodeURI(JSContext *ctx, JSValueConst this_val,
if (isURIUnescaped(c, isComponent)) {
string_buffer_putc16(b, c);
} else {
- if (c >= 0xdc00 && c <= 0xdfff) {
+ if (is_lo_surrogate(c)) {
js_throw_URIError(ctx, "invalid character");
goto fail;
- } else if (c >= 0xd800 && c <= 0xdbff) {
+ } else if (is_hi_surrogate(c)) {
if (k >= p->len) {
js_throw_URIError(ctx, "expecting surrogate pair");
goto fail;
}
c1 = string_get(p, k);
k++;
- if (c1 < 0xdc00 || c1 > 0xdfff) {
+ if (!is_lo_surrogate(c1)) {
js_throw_URIError(ctx, "expecting surrogate pair");
goto fail;
}
- c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
+ c = from_surrogate(c, c1);
}
if (c < 0x80) {
encodeURI_hex(b, c);
@@ -47617,15 +50853,10 @@ static const JSCFunctionListEntry js_global_funcs[] = {
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_DOUBLE_DEF("Infinity", (1.0 / 0.0), 0 ),
+ JS_PROP_DOUBLE_DEF("NaN", (0.0 / 0.0), 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 ),
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "global", JS_PROP_CONFIGURABLE ),
};
/* Date */
@@ -47706,7 +50937,7 @@ 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 fields[minimum_length(9)], int is_local, int force)
{
double dval;
int64_t d, days, wd, y, i, md, h, m, s, ms, tz = 0;
@@ -47719,7 +50950,7 @@ static __exception int get_date_fields(JSContext *ctx, JSValueConst obj,
return FALSE; /* NaN */
d = 0; /* initialize all fields to 0 */
} else {
- d = dval;
+ d = dval; /* assuming -8.64e15 <= dval <= -8.64e15 */
if (is_local) {
tz = -getTimezoneOffset(d);
d += tz * 60000;
@@ -47765,33 +50996,63 @@ static double time_clip(double t) {
return NAN;
}
-/* The spec mandates the use of 'double' and it fixes the order
+/* The spec mandates the use of 'double' and it specifies 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];
+static double set_date_fields(double fields[minimum_length(7)], int is_local) {
+ double y, m, dt, ym, mn, day, h, s, milli, time, tv;
+ int yi, mi, i;
+ int64_t days;
+ volatile double temp; /* enforce evaluation order */
+
+ /* emulate 21.4.1.15 MakeDay ( year, month, date ) */
+ y = fields[0];
+ m = fields[1];
+ dt = fields[2];
+ ym = y + floor(m / 12);
+ mn = fmod(m, 12);
+ if (mn < 0)
+ mn += 12;
+ if (ym < -271821 || ym > 275760)
+ return NAN;
+
+ yi = ym;
+ mi = mn;
+ days = days_from_year(yi);
+ for(i = 0; i < mi; i++) {
+ days += month_days[i];
if (i == 1)
- md += days_in_year(y) - 365;
- days += md;
+ days += days_in_year(yi) - 365;
+ }
+ day = days + dt - 1;
+
+ /* emulate 21.4.1.14 MakeTime ( hour, min, sec, ms ) */
+ h = fields[3];
+ m = fields[4];
+ s = fields[5];
+ milli = fields[6];
+ /* Use a volatile intermediary variable to ensure order of evaluation
+ * as specified in ECMA. This fixes a test262 error on
+ * test262/test/built-ins/Date/UTC/fp-evaluation-order.js.
+ * Without the volatile qualifier, the compile can generate code
+ * that performs the computation in a different order or with instructions
+ * that produce a different result such as FMA (float multiply and add).
+ */
+ time = h * 3600000;
+ time += (temp = m * 60000);
+ time += (temp = s * 1000);
+ time += milli;
+
+ /* emulate 21.4.1.16 MakeDate ( day, time ) */
+ tv = (temp = day * 86400000) + time; /* prevent generation of FMA */
+ if (!isfinite(tv))
+ return NAN;
+
+ /* adjust for local time and clip */
+ if (is_local) {
+ int64_t ti = tv < INT64_MIN ? INT64_MIN : tv >= 0x1p63 ? INT64_MAX : (int64_t)tv;
+ tv += getTimezoneOffset(ti) * 60000;
}
- 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);
+ return time_clip(tv);
}
static JSValue get_date_field(JSContext *ctx, JSValueConst this_val,
@@ -47820,7 +51081,7 @@ static JSValue set_date_field(JSContext *ctx, JSValueConst this_val,
{
// _field(obj, first_field, end_field, args, is_local)
double fields[9];
- int res, first_field, end_field, is_local, i, n;
+ int res, first_field, end_field, is_local, i, n, res1;
double d, a;
d = NAN;
@@ -47831,7 +51092,8 @@ static JSValue set_date_field(JSContext *ctx, JSValueConst this_val,
res = get_date_fields(ctx, this_val, fields, is_local, first_field == 0);
if (res < 0)
return JS_EXCEPTION;
-
+ res1 = res;
+
// Argument coercion is observable and must be done unconditionally.
n = min_int(argc, end_field - first_field);
for(i = 0; i < n; i++) {
@@ -47841,9 +51103,13 @@ static JSValue set_date_field(JSContext *ctx, JSValueConst this_val,
res = FALSE;
fields[first_field + i] = trunc(a);
}
- if (res && argc > 0) {
+
+ if (!res1)
+ return JS_NAN; /* thisTimeValue is NaN */
+
+ if (res && argc > 0)
d = set_date_fields(fields, is_local);
- }
+
return JS_SetThisTimeValue(ctx, this_val, d);
}
@@ -47874,7 +51140,7 @@ static JSValue get_date_string(JSContext *ctx, JSValueConst this_val,
if (fmt == 2)
return JS_ThrowRangeError(ctx, "Date value is NaN");
else
- return JS_NewString(ctx, "Invalid Date");
+ return js_new_string8(ctx, "Invalid Date");
}
y = fields[0];
@@ -47953,7 +51219,7 @@ static JSValue get_date_string(JSContext *ctx, JSValueConst this_val,
break;
case 3:
pos += snprintf(buf + pos, sizeof(buf) - pos,
- "%02d:%02d:%02d %cM", (h + 1) % 12 - 1, m, s,
+ "%02d:%02d:%02d %cM", (h + 11) % 12 + 1, m, s,
(h < 12) ? 'A' : 'P');
break;
}
@@ -48029,2484 +51295,813 @@ static JSValue js_date_constructor(JSContext *ctx, JSValueConst 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 == '-') {
- if (*pval == 0)
- return -1; // reject negative zero
- *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));
-}
-
-/* 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;
- memset(ent, 0, 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 */
-
-/* BigInt */
-
-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:
-#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_FLOAT:
-#endif
- {
- bf_t *a, a_s;
-
- a = JS_ToBigFloat(ctx, &a_s, val);
- if (!a) {
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- 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;
-#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_DECIMAL:
- val = JS_ToStringFree(ctx, val);
- if (JS_IsException(val))
- break;
- goto redo;
-#endif
- 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);
-}
-
-#ifdef CONFIG_BIGNUM
-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;
+#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;
}
- fail:
- JS_FreeValue(ctx, q_val);
- JS_FreeValue(ctx, r_val);
- return JS_EXCEPTION;
+ return rv;
}
-static JSValue js_bigint_sqrt(JSContext *ctx,
- JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
+static JSValue js_Date_UTC(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
{
- 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);
+ // UTC(y, mon, d, h, m, s, ms)
+ double fields[] = { 0, 0, 1, 0, 0, 0, 0 };
+ int i, n;
+ double a;
- 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;
+ 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;
}
- fail:
- JS_FreeValue(ctx, r_val);
- JS_FreeValue(ctx, rem_val);
- return JS_EXCEPTION;
+ return JS_NewFloat64(ctx, set_date_fields(fields, 0));
}
-static JSValue js_bigint_op1(JSContext *ctx,
- JSValueConst this_val,
- int argc, JSValueConst *argv,
- int magic)
-{
- bf_t a_s, *a;
- int64_t res;
+/* Date string parsing */
- 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();
+static BOOL string_skip_char(const uint8_t *sp, int *pp, int c) {
+ if (sp[*pp] == c) {
+ *pp += 1;
+ return TRUE;
+ } else {
+ return FALSE;
}
- JS_FreeBigInt(ctx, a, &a_s);
- return JS_NewBigInt64(ctx, res);
}
-#endif
-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);
+/* skip spaces, update offset, return next char */
+static int string_skip_spaces(const uint8_t *sp, int *pp) {
+ int c;
+ while ((c = sp[*pp]) == ' ')
+ *pp += 1;
+ return c;
}
-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 ),
-#ifdef CONFIG_BIGNUM
- /* 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 ),
-#endif
-};
-
-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 ),
-};
-
-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));
+/* skip dashes dots and commas */
+static int string_skip_separators(const uint8_t *sp, int *pp) {
+ int c;
+ while ((c = sp[*pp]) == '-' || c == '/' || c == '.' || c == ',')
+ *pp += 1;
+ return c;
}
-#ifdef CONFIG_BIGNUM
-
-/* BigFloat */
+/* skip a word, stop on spaces, digits and separators, update offset */
+static int string_skip_until(const uint8_t *sp, int *pp, const char *stoplist) {
+ int c;
+ while (!strchr(stoplist, c = sp[*pp]))
+ *pp += 1;
+ return c;
+}
-static JSValue js_thisBigFloatValue(JSContext *ctx, JSValueConst this_val)
+/* parse a numeric field (max_digits = 0 -> no maximum) */
+static BOOL string_get_digits(const uint8_t *sp, int *pp, int *pval,
+ int min_digits, int max_digits)
{
- if (JS_IsBigFloat(this_val))
- return JS_DupValue(ctx, this_val);
+ int v = 0;
+ int c, p = *pp, p_start;
- 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);
- }
+ p_start = p;
+ while ((c = sp[p]) >= '0' && c <= '9') {
+ /* arbitrary limit to 9 digits */
+ if (v >= 100000000)
+ return FALSE;
+ v = v * 10 + c - '0';
+ p++;
+ if (p - p_start == max_digits)
+ break;
}
- return JS_ThrowTypeError(ctx, "not a bigfloat");
+ if (p - p_start < min_digits)
+ return FALSE;
+ *pval = v;
+ *pp = p;
+ return TRUE;
}
-static JSValue js_bigfloat_toString(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
-{
- JSValue val;
- int base;
- JSValue ret;
+static BOOL string_get_milliseconds(const uint8_t *sp, int *pp, int *pval) {
+ /* parse optional fractional part as milliseconds and truncate. */
+ /* spec does not indicate which rounding should be used */
+ int mul = 100, ms = 0, c, p_start, p = *pp;
- 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;
+ c = sp[p];
+ if (c == '.' || c == ',') {
+ p++;
+ p_start = p;
+ while ((c = sp[p]) >= '0' && c <= '9') {
+ ms += (c - '0') * mul;
+ mul /= 10;
+ p++;
+ if (p - p_start == 9)
+ break;
+ }
+ if (p > p_start) {
+ /* only consume the separator if digits are present */
+ *pval = ms;
+ *pp = p;
+ }
}
- 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;
+ return TRUE;
}
-static JSValue js_bigfloat_valueOf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
-{
- return js_thisBigFloatValue(ctx, this_val);
+static uint8_t upper_ascii(uint8_t c) {
+ return c >= 'a' && c <= 'z' ? c - 'a' + 'A' : c;
}
-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;
+static BOOL string_get_tzoffset(const uint8_t *sp, int *pp, int *tzp, BOOL strict) {
+ int tz = 0, sgn, hh, mm, p = *pp;
+
+ sgn = sp[p++];
+ if (sgn == '+' || sgn == '-') {
+ int n = p;
+ if (!string_get_digits(sp, &p, &hh, 1, 0))
+ return FALSE;
+ n = p - n;
+ if (strict && n != 2 && n != 4)
+ return FALSE;
+ while (n > 4) {
+ n -= 2;
+ hh /= 100;
+ }
+ if (n > 2) {
+ mm = hh % 100;
+ hh = hh / 100;
+ } else {
+ mm = 0;
+ if (string_skip_char(sp, &p, ':') /* optional separator */
+ && !string_get_digits(sp, &p, &mm, 2, 2))
+ return FALSE;
+ }
+ if (hh > 23 || mm > 59)
+ return FALSE;
+ tz = hh * 60 + mm;
+ if (sgn != '+')
+ tz = -tz;
+ } else
+ if (sgn != 'Z') {
+ return FALSE;
}
- return rnd_mode;
+ *pp = p;
+ *tzp = tz;
+ return TRUE;
}
-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;
+static BOOL string_match(const uint8_t *sp, int *pp, const char *s) {
+ int p = *pp;
+ while (*s != '\0') {
+ if (upper_ascii(sp[p]) != upper_ascii(*s++))
+ return FALSE;
+ p++;
}
- 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;
+ *pp = p;
+ return TRUE;
}
-static BOOL js_bigfloat_is_finite(JSContext *ctx, JSValueConst val)
-{
- BOOL res;
- uint32_t tag;
+static int find_abbrev(const uint8_t *sp, int p, const char *list, int count) {
+ int n, i;
- 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);
+ for (n = 0; n < count; n++) {
+ for (i = 0;; i++) {
+ if (upper_ascii(sp[p + i]) != upper_ascii(list[n * 3 + i]))
+ break;
+ if (i == 2)
+ return n;
}
- break;
- default:
- res = FALSE;
- break;
}
- return res;
+ return -1;
}
-static JSValue js_bigfloat_toExponential(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
-{
- JSValue val, ret;
- int64_t f;
- int rnd_mode, radix;
+static BOOL string_get_month(const uint8_t *sp, int *pp, int *pval) {
+ int n;
- 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;
+ n = find_abbrev(sp, *pp, month_names, 12);
+ if (n < 0)
+ return FALSE;
+
+ *pval = n + 1;
+ *pp += 3;
+ return TRUE;
}
-static JSValue js_bigfloat_toPrecision(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
-{
- JSValue val, ret;
- int64_t p;
- int rnd_mode, radix;
+/* parse toISOString format */
+static BOOL js_date_parse_isostring(const uint8_t *sp, int fields[9], BOOL *is_local) {
+ int sgn, i, p = 0;
- 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);
+ /* initialize fields to the beginning of the Epoch */
+ for (i = 0; i < 9; i++) {
+ fields[i] = (i == 2);
+ }
+ *is_local = FALSE;
+
+ /* year is either yyyy digits or [+-]yyyyyy */
+ sgn = sp[p];
+ if (sgn == '-' || sgn == '+') {
+ p++;
+ if (!string_get_digits(sp, &p, &fields[0], 6, 6))
+ return FALSE;
+ if (sgn == '-') {
+ if (fields[0] == 0)
+ return FALSE; // reject -000000
+ fields[0] = -fields[0];
+ }
} else {
- if (p < 1 || p > BF_PREC_MAX) {
- JS_ThrowRangeError(ctx, "invalid number of digits");
- goto fail;
+ if (!string_get_digits(sp, &p, &fields[0], 4, 4))
+ return FALSE;
+ }
+ if (string_skip_char(sp, &p, '-')) {
+ if (!string_get_digits(sp, &p, &fields[1], 2, 2)) /* month */
+ return FALSE;
+ if (fields[1] < 1)
+ return FALSE;
+ fields[1] -= 1;
+ if (string_skip_char(sp, &p, '-')) {
+ if (!string_get_digits(sp, &p, &fields[2], 2, 2)) /* day */
+ return FALSE;
+ if (fields[2] < 1)
+ return FALSE;
}
- 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 (string_skip_char(sp, &p, 'T')) {
+ *is_local = TRUE;
+ if (!string_get_digits(sp, &p, &fields[3], 2, 2) /* hour */
+ || !string_skip_char(sp, &p, ':')
+ || !string_get_digits(sp, &p, &fields[4], 2, 2)) { /* minute */
+ fields[3] = 100; // reject unconditionally
+ return TRUE;
}
- if (argc > 2) {
- radix = js_get_radix(ctx, argv[2]);
- if (radix < 0)
- goto fail;
+ if (string_skip_char(sp, &p, ':')) {
+ if (!string_get_digits(sp, &p, &fields[5], 2, 2)) /* second */
+ return FALSE;
+ string_get_milliseconds(sp, &p, &fields[6]);
}
- 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 ),
+ /* parse the time zone offset if present: [+-]HH:mm or [+-]HHmm */
+ if (sp[p]) {
+ *is_local = FALSE;
+ if (!string_get_tzoffset(sp, &p, &fields[8], TRUE))
+ return FALSE;
+ }
+ /* error if extraneous characters */
+ return sp[p] == '\0';
+}
+
+static struct {
+ char name[6];
+ int16_t offset;
+} const js_tzabbr[] = {
+ { "GMT", 0 }, // Greenwich Mean Time
+ { "UTC", 0 }, // Coordinated Universal Time
+ { "UT", 0 }, // Universal Time
+ { "Z", 0 }, // Zulu Time
+ { "EDT", -4 * 60 }, // Eastern Daylight Time
+ { "EST", -5 * 60 }, // Eastern Standard Time
+ { "CDT", -5 * 60 }, // Central Daylight Time
+ { "CST", -6 * 60 }, // Central Standard Time
+ { "MDT", -6 * 60 }, // Mountain Daylight Time
+ { "MST", -7 * 60 }, // Mountain Standard Time
+ { "PDT", -7 * 60 }, // Pacific Daylight Time
+ { "PST", -8 * 60 }, // Pacific Standard Time
+ { "WET", +0 * 60 }, // Western European Time
+ { "WEST", +1 * 60 }, // Western European Summer Time
+ { "CET", +1 * 60 }, // Central European Time
+ { "CEST", +2 * 60 }, // Central European Summer Time
+ { "EET", +2 * 60 }, // Eastern European Time
+ { "EEST", +3 * 60 }, // Eastern European Summer Time
};
-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;
+static BOOL string_get_tzabbr(const uint8_t *sp, int *pp, int *offset) {
+ for (size_t i = 0; i < countof(js_tzabbr); i++) {
+ if (string_match(sp, pp, js_tzabbr[i].name)) {
+ *offset = js_tzabbr[i].offset;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
- 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;
+/* parse toString, toUTCString and other formats */
+static BOOL js_date_parse_otherstring(const uint8_t *sp,
+ int fields[minimum_length(9)],
+ BOOL *is_local) {
+ int c, i, val, p = 0, p_start;
+ int num[3];
+ BOOL has_year = FALSE;
+ BOOL has_mon = FALSE;
+ BOOL has_time = FALSE;
+ int num_index = 0;
+
+ /* initialize fields to the beginning of 2001-01-01 */
+ fields[0] = 2001;
+ fields[1] = 1;
+ fields[2] = 1;
+ for (i = 3; i < 9; i++) {
+ fields[i] = 0;
+ }
+ *is_local = TRUE;
+
+ while (string_skip_spaces(sp, &p)) {
+ p_start = p;
+ if ((c = sp[p]) == '+' || c == '-') {
+ if (has_time && string_get_tzoffset(sp, &p, &fields[8], FALSE)) {
+ *is_local = FALSE;
+ } else {
+ p++;
+ if (string_get_digits(sp, &p, &val, 1, 0)) {
+ if (c == '-') {
+ if (val == 0)
+ return FALSE;
+ val = -val;
}
- p += skip_spaces(p);
- err = ((p - str) != len);
+ fields[0] = val;
+ has_year = TRUE;
}
- JS_FreeCString(ctx, str);
- if (err) {
- JS_FreeValue(ctx, val);
- return JS_ThrowSyntaxError(ctx, "invalid bigfloat literal");
+ }
+ } else
+ if (string_get_digits(sp, &p, &val, 1, 0)) {
+ if (string_skip_char(sp, &p, ':')) {
+ /* time part */
+ fields[3] = val;
+ if (!string_get_digits(sp, &p, &fields[4], 1, 2))
+ return FALSE;
+ if (string_skip_char(sp, &p, ':')) {
+ if (!string_get_digits(sp, &p, &fields[5], 1, 2))
+ return FALSE;
+ string_get_milliseconds(sp, &p, &fields[6]);
+ }
+ has_time = TRUE;
+ } else {
+ if (p - p_start > 2) {
+ fields[0] = val;
+ has_year = TRUE;
+ } else
+ if (val < 1 || val > 31) {
+ fields[0] = val + (val < 100) * 1900 + (val < 50) * 100;
+ has_year = TRUE;
+ } else {
+ if (num_index == 3)
+ return FALSE;
+ num[num_index++] = 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 bigfloat");
+ } else
+ if (string_get_month(sp, &p, &fields[1])) {
+ has_mon = TRUE;
+ string_skip_until(sp, &p, "0123456789 -/(");
+ } else
+ if (has_time && string_match(sp, &p, "PM")) {
+ if (fields[3] < 12)
+ fields[3] += 12;
+ continue;
+ } else
+ if (has_time && string_match(sp, &p, "AM")) {
+ if (fields[3] == 12)
+ fields[3] -= 12;
+ continue;
+ } else
+ if (string_get_tzabbr(sp, &p, &fields[8])) {
+ *is_local = FALSE;
+ continue;
+ } else
+ if (c == '(') { /* skip parenthesized phrase */
+ int level = 0;
+ while ((c = sp[p]) != '\0') {
+ p++;
+ level += (c == '(');
+ level -= (c == ')');
+ if (!level)
+ break;
+ }
+ if (level > 0)
+ return FALSE;
+ } else
+ if (c == ')') {
+ return FALSE;
+ } else {
+ if (has_year + has_mon + has_time + num_index)
+ return FALSE;
+ /* skip a word */
+ string_skip_until(sp, &p, " -/(");
}
+ string_skip_separators(sp, &p);
}
- return val;
- fail:
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
-}
+ if (num_index + has_year + has_mon > 3)
+ return FALSE;
-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);
+ switch (num_index) {
+ case 0:
+ if (!has_year)
+ return FALSE;
break;
- case 1: /* LN2 */
- bf_const_log2(r, ctx->fp_env.prec, ctx->fp_env.flags);
+ case 1:
+ if (has_mon)
+ fields[2] = num[0];
+ else
+ fields[1] = num[0];
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);
- }
+ case 2:
+ if (has_year) {
+ fields[1] = num[0];
+ fields[2] = num[1];
+ } else
+ if (has_mon) {
+ fields[0] = num[1] + (num[1] < 100) * 1900 + (num[1] < 50) * 100;
+ fields[2] = num[0];
+ } else {
+ fields[1] = num[0];
+ fields[2] = num[1];
}
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);
+ case 3:
+ fields[0] = num[2] + (num[2] < 100) * 1900 + (num[2] < 50) * 100;
+ fields[1] = num[0];
+ fields[2] = num[1];
break;
default:
- abort();
+ return FALSE;
}
- return val;
+ if (fields[1] < 1 || fields[2] < 1)
+ return FALSE;
+ fields[1] -= 1;
+ return TRUE;
}
-static JSValue js_bigfloat_parseFloat(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
+static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
{
- bf_t *a;
- const char *str;
- JSValue ret;
- int radix;
- JSFloatEnv *fe;
+ JSValue s, rv;
+ int fields[9];
+ double fields1[9];
+ double d;
+ int i, c;
+ JSString *sp;
+ uint8_t buf[128];
+ BOOL is_local;
- str = JS_ToCString(ctx, argv[0]);
- if (!str)
- return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &radix, argv[1])) {
- fail:
- JS_FreeCString(ctx, str);
+ rv = JS_NAN;
+
+ s = JS_ToString(ctx, argv[0]);
+ if (JS_IsException(s))
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));
+ sp = JS_VALUE_GET_STRING(s);
+ /* convert the string as a byte array */
+ for (i = 0; i < sp->len && i < (int)countof(buf) - 1; i++) {
+ c = string_get(sp, i);
+ if (c > 255)
+ c = (c == 0x2212) ? '-' : 'x';
+ buf[i] = c;
+ }
+ buf[i] = '\0';
+ if (js_date_parse_isostring(buf, fields, &is_local)
+ || js_date_parse_otherstring(buf, fields, &is_local)) {
+ static int const field_max[6] = { 0, 11, 31, 24, 59, 59 };
+ BOOL valid = TRUE;
+ /* check field maximum values */
+ for (i = 1; i < 6; i++) {
+ if (fields[i] > field_max[i])
+ valid = FALSE;
+ }
+ /* special case 24:00:00.000 */
+ if (fields[3] == 24 && (fields[4] | fields[5] | fields[6]))
+ valid = FALSE;
+ if (valid) {
+ for(i = 0; i < 7; i++)
+ fields1[i] = fields[i];
+ d = set_date_fields(fields1, is_local) - fields[8] * 60000;
+ rv = JS_NewFloat64(ctx, d);
+ }
+ }
+ JS_FreeValue(ctx, s);
+ return rv;
}
-static JSValue js_bigfloat_isNaN(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
+static JSValue js_Date_now(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));
+ // now()
+ return JS_NewInt64(ctx, date_now());
}
-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,
-};
-
-static JSValue js_bigfloat_fop(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
+static JSValue js_date_Symbol_toPrimitive(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
{
- 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);
- if (!a) {
- JS_FreeValue(ctx, op1);
- return JS_EXCEPTION;
- }
- 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;
-}
+ // Symbol_toPrimitive(hint)
+ JSValueConst obj = this_val;
+ JSAtom hint = JS_ATOM_NULL;
+ int hint_num;
-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;
+ if (!JS_IsObject(obj))
+ return JS_ThrowTypeErrorNotAnObject(ctx);
- 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);
- if (!a)
- goto fail1;
- b = JS_ToBigFloat(ctx, &b_s, op2);
- if (!b)
- goto fail2;
- 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 (b == &b_s)
- bf_delete(b);
- fail2:
- if (a == &a_s)
- bf_delete(a);
- fail1:
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- return JS_EXCEPTION;
+ if (JS_IsString(argv[0])) {
+ hint = JS_ValueToAtom(ctx, argv[0]);
+ if (hint == JS_ATOM_NULL)
+ return JS_EXCEPTION;
+ JS_FreeAtom(ctx, hint);
}
- 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);
+ switch (hint) {
+ case JS_ATOM_number:
+ case JS_ATOM_integer:
+ hint_num = HINT_NUMBER;
break;
- case MATH_OP_DIV:
- fe->status |= bf_div(r, a, b, fe->prec, fe->flags);
+ case JS_ATOM_string:
+ case JS_ATOM_default:
+ hint_num = HINT_STRING;
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;
+ return JS_ThrowTypeError(ctx, "invalid hint");
+ }
+ return JS_ToPrimitive(ctx, obj, hint_num | HINT_FORCE_ORDINARY);
}
-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 ),
-};
-
-/* FloatEnv */
-
-static JSValue js_float_env_constructor(JSContext *ctx,
- JSValueConst new_target,
- int argc, JSValueConst *argv)
+static JSValue js_date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val,
+ 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;
- }
- }
+ // getTimezoneOffset()
+ double v;
- obj = JS_NewObjectClass(ctx, JS_CLASS_FLOAT_ENV);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- fe = js_malloc(ctx, sizeof(*fe));
- if (!fe)
+ if (JS_ThisTimeValue(ctx, &v, this_val))
return JS_EXCEPTION;
- fe->prec = prec;
- fe->flags = flags;
- fe->status = 0;
- JS_SetOpaque(obj, fe);
- return obj;
+ if (isnan(v))
+ return JS_NAN;
+ else
+ /* assuming -8.64e15 <= v <= -8.64e15 */
+ return JS_NewInt64(ctx, getTimezoneOffset((int64_t)trunc(v)));
}
-static void js_float_env_finalizer(JSRuntime *rt, JSValue val)
+static JSValue js_date_getTime(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
{
- JSFloatEnv *fe = JS_GetOpaque(val, JS_CLASS_FLOAT_ENV);
- js_free_rt(rt, fe);
-}
+ // getTime()
+ double v;
-static JSValue js_float_env_get_prec(JSContext *ctx, JSValueConst this_val)
-{
- return JS_NewInt64(ctx, ctx->fp_env.prec);
+ if (JS_ThisTimeValue(ctx, &v, this_val))
+ return JS_EXCEPTION;
+ return JS_NewFloat64(ctx, v);
}
-static JSValue js_float_env_get_expBits(JSContext *ctx, JSValueConst this_val)
+static JSValue js_date_setTime(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
{
- return JS_NewInt32(ctx, bf_get_exp_bits(ctx->fp_env.flags));
+ // 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_float_env_setPrec(JSContext *ctx,
- JSValueConst this_val,
- int argc, JSValueConst *argv)
+static JSValue js_date_setYear(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;
+ // setYear(y)
+ double y;
+ JSValueConst args[1];
- func = argv[0];
- if (JS_ToInt64Sat(ctx, &prec, argv[1]))
+ if (JS_ThisTimeValue(ctx, &y, this_val) || JS_ToFloat64(ctx, &y, argv[0]))
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");
+ 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);
+}
- flags = BF_RNDN | BF_FLAG_SUBNORMAL | bf_set_exp_bits(exp_bits);
-
- saved_prec = ctx->fp_env.prec;
- saved_flags = ctx->fp_env.flags;
+static JSValue js_date_toJSON(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ // toJSON(key)
+ JSValue obj, tv, method, rv;
+ double d;
- ctx->fp_env.prec = prec;
- ctx->fp_env.flags = flags;
+ rv = JS_EXCEPTION;
+ tv = JS_UNDEFINED;
- 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;
+ 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;
}
-#define FE_PREC (-1)
-#define FE_EXP (-2)
-#define FE_RNDMODE (-3)
-#define FE_SUBNORMAL (-4)
+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 ),
+};
-static JSValue js_float_env_proto_get_status(JSContext *ctx, JSValueConst this_val, int magic)
+JSValue JS_NewDate(JSContext *ctx, double epoch_ms)
{
- JSFloatEnv *fe;
- fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV);
- if (!fe)
+ JSValue obj = js_create_from_ctor(ctx, JS_UNDEFINED, JS_CLASS_DATE);
+ if (JS_IsException(obj))
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);
- }
+ JS_SetObjectData(ctx, obj, __JS_NewFloat64(ctx, time_clip(epoch_ms)));
+ return obj;
}
-static JSValue js_float_env_proto_set_status(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic)
+void JS_AddIntrinsicDate(JSContext *ctx)
{
- JSFloatEnv *fe;
- int b;
- int64_t prec;
+ JSValueConst obj;
- 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;
+ /* 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));
}
-static JSValue js_float_env_clearStatus(JSContext *ctx,
- JSValueConst this_val,
- int argc, JSValueConst *argv)
+/* eval */
+
+void JS_AddIntrinsicEval(JSContext *ctx)
{
- JSFloatEnv *fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV);
- if (!fe)
- return JS_EXCEPTION;
- fe->status = 0;
- return JS_UNDEFINED;
+ ctx->eval_internal = __JS_EvalInternal;
}
-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 ),
-};
+/* BigInt */
-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));
-}
-
-/* BigDecimal */
-
-static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
- BOOL allow_null_or_undefined)
+static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)
{
+ uint32_t tag;
+
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:
+ tag = JS_VALUE_GET_NORM_TAG(val);
+ switch(tag) {
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;
- }
- }
+ case JS_TAG_BOOL:
+ val = JS_NewBigInt64(ctx, JS_VALUE_GET_INT(val));
break;
- case JS_TAG_FLOAT64:
+ case JS_TAG_SHORT_BIG_INT:
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:
+ break;
+ case JS_TAG_FLOAT64:
{
- 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;
+ double d = JS_VALUE_GET_FLOAT64(val);
+ JSBigInt *r;
+ int res;
+ r = js_bigint_from_float64(ctx, &res, d);
+ if (!r) {
+ if (res == 0) {
+ val = JS_EXCEPTION;
+ } else if (res == 1) {
+ val = JS_ThrowRangeError(ctx, "cannot convert to BigInt: not an integer");
+ } else {
+ val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to BigInt"); }
} 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");
+ val = JS_CompactBigInt(ctx, r);
}
}
break;
+ case JS_TAG_STRING:
+ case JS_TAG_STRING_ROPE:
+ 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:
- {
- 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 JS_ThrowTypeError(ctx, "cannot convert to BigInt");
}
return val;
}
-static JSValue js_bigdecimal_constructor(JSContext *ctx,
- JSValueConst new_target,
- int argc, JSValueConst *argv)
+static JSValue js_bigint_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;
+ return JS_ToBigIntCtorFree(ctx, JS_DupValue(ctx, argv[0]));
}
-static JSValue js_thisBigDecimalValue(JSContext *ctx, JSValueConst this_val)
+static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val)
{
- if (JS_IsBigDecimal(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_DECIMAL) {
- if (JS_IsBigDecimal(p->u.object_data))
+ 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 bigdecimal");
+ return JS_ThrowTypeError(ctx, "not a BigInt");
}
-static JSValue js_bigdecimal_toString(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
+static JSValue js_bigint_toString(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
{
JSValue val;
+ int base;
+ JSValue ret;
- val = js_thisBigDecimalValue(ctx, this_val);
+ val = js_thisBigIntValue(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);
+ if (argc == 0 || JS_IsUndefined(argv[0])) {
+ base = 10;
} 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)
+ base = js_get_radix(ctx, argv[0]);
+ if (base < 0)
goto fail;
}
- ret = js_bigdecimal_to_string1(ctx, val, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
+ ret = js_bigint_to_string1(ctx, val, base);
JS_FreeValue(ctx, val);
return ret;
fail:
@@ -50514,123 +52109,100 @@ static JSValue js_bigdecimal_toFixed(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
}
-static JSValue js_bigdecimal_toExponential(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
+static JSValue js_bigint_valueOf(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;
+ return js_thisBigIntValue(ctx, this_val);
}
-static JSValue js_bigdecimal_toPrecision(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
+static JSValue js_bigint_asUintN(JSContext *ctx,
+ JSValueConst this_val,
+ int argc, JSValueConst *argv, int asIntN)
{
- 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;
+ uint64_t bits;
+ JSValue res, a;
+
+ if (JS_ToIndex(ctx, &bits, argv[0]))
+ return JS_EXCEPTION;
+ a = JS_ToBigInt(ctx, argv[1]);
+ if (JS_IsException(a))
+ return JS_EXCEPTION;
+ if (bits == 0) {
+ JS_FreeValue(ctx, a);
+ res = __JS_NewShortBigInt(ctx, 0);
+ } else if (JS_VALUE_GET_TAG(a) == JS_TAG_SHORT_BIG_INT) {
+ /* fast case */
+ if (bits >= JS_SHORT_BIG_INT_BITS) {
+ res = a;
+ } else {
+ uint64_t v;
+ int shift;
+ shift = 64 - bits;
+ v = JS_VALUE_GET_SHORT_BIG_INT(a);
+ v = v << shift;
+ if (asIntN)
+ v = (int64_t)v >> shift;
+ else
+ v = v >> shift;
+ res = __JS_NewShortBigInt(ctx, v);
+ }
+ } else {
+ JSBigInt *r, *p = JS_VALUE_GET_PTR(a);
+ if (bits >= p->len * JS_LIMB_BITS) {
+ res = a;
+ } else {
+ int len, shift, i;
+ js_limb_t v;
+ len = (bits + JS_LIMB_BITS - 1) / JS_LIMB_BITS;
+ r = js_bigint_new(ctx, len);
+ if (!r) {
+ JS_FreeValue(ctx, a);
+ return JS_EXCEPTION;
+ }
+ r->len = len;
+ for(i = 0; i < len - 1; i++)
+ r->tab[i] = p->tab[i];
+ shift = (-bits) & (JS_LIMB_BITS - 1);
+ /* 0 <= shift <= JS_LIMB_BITS - 1 */
+ v = p->tab[len - 1] << shift;
+ if (asIntN)
+ v = (js_slimb_t)v >> shift;
+ else
+ v = v >> shift;
+ r->tab[len - 1] = v;
+ r = js_bigint_normalize(ctx, r);
+ JS_FreeValue(ctx, a);
+ res = JS_CompactBigInt(ctx, r);
+ }
}
- 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;
+ return res;
}
-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_bigint_funcs[] = {
+ JS_CFUNC_MAGIC_DEF("asUintN", 2, js_bigint_asUintN, 0 ),
+ JS_CFUNC_MAGIC_DEF("asIntN", 2, js_bigint_asUintN, 1 ),
};
-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 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 ),
};
-void JS_AddIntrinsicBigDecimal(JSContext *ctx)
+static void JS_AddIntrinsicBigInt(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;
+ 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));
}
-#endif /* CONFIG_BIGNUM */
-
static const char * const native_error_name[JS_NATIVE_ERROR_COUNT] = {
"EvalError", "RangeError", "ReferenceError",
"SyntaxError", "TypeError", "URIError",
@@ -50645,6 +52217,8 @@ static void JS_AddIntrinsicBasicObjects(JSContext *ctx)
int i;
ctx->class_proto[JS_CLASS_OBJECT] = JS_NewObjectProto(ctx, JS_NULL);
+ JS_SetImmutablePrototype(ctx, ctx->class_proto[JS_CLASS_OBJECT]);
+
ctx->function_proto = JS_NewCFunction3(ctx, js_function_proto, "", 0,
JS_CFUNC_generic, 0,
ctx->class_proto[JS_CLASS_OBJECT]);
@@ -50702,16 +52276,14 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
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,
+ ctx->throw_type_error, 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,
+ ctx->throw_type_error, 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);
@@ -50738,11 +52310,13 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
JS_NewGlobalCConstructor2(ctx, obj1,
"Error", ctx->class_proto[JS_CLASS_ERROR]);
+ /* Used to squelch a -Wcast-function-type warning. */
+ JSCFunctionType ft = { .generic_magic = js_error_constructor };
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,
+ func_obj = JS_NewCFunction3(ctx, ft.generic,
native_error_name[i], n_args,
JS_CFUNC_constructor_or_func_magic, i, obj1);
JS_NewGlobalCConstructor2(ctx, func_obj, native_error_name[i],
@@ -50769,7 +52343,8 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
/* XXX: create auto_initializer */
{
/* initialize Array.prototype[Symbol.unscopables] */
- char const unscopables[] =
+ static const char unscopables[] =
+ "at" "\0"
"copyWithin" "\0"
"entries" "\0"
"fill" "\0"
@@ -50781,6 +52356,9 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
"flatMap" "\0"
"includes" "\0"
"keys" "\0"
+ "toReversed" "\0"
+ "toSorted" "\0"
+ "toSpliced" "\0"
"values" "\0";
const char *p = unscopables;
obj1 = JS_NewObjectProto(ctx, JS_NULL);
@@ -50876,9 +52454,10 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
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);
+ obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor,
+ "GeneratorFunction", 1,
+ JS_CFUNC_constructor_or_func_magic, JS_FUNC_GENERATOR,
+ ctx->function_ctor);
JS_SetPropertyFunctionList(ctx,
ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
js_generator_function_proto_funcs,
@@ -50899,14 +52478,17 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_globalThis,
JS_DupValue(ctx, ctx->global_obj),
JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
+
+ /* BigInt */
+ JS_AddIntrinsicBigInt(ctx);
}
/* Typed Arrays */
static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT] = {
0, 0, 0, 1, 1, 2, 2,
- 3, 3, /* BigInt64Array, BigUint64Array */
- 2, 3
+ 3, 3, // BigInt64Array, BigUint64Array
+ 1, 2, 3 // Float16Array, Float32Array, Float64Array
};
static JSValue js_array_buffer_constructor3(JSContext *ctx,
@@ -51035,11 +52617,26 @@ static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val)
{
JSObject *p = JS_VALUE_GET_OBJ(val);
JSArrayBuffer *abuf = p->u.array_buffer;
+ struct list_head *el, *el1;
+
if (abuf) {
/* The ArrayBuffer finalizer may be called before the typed
array finalizers using it, so abuf->array_list is not
necessarily empty. */
- // assert(list_empty(&abuf->array_list));
+ list_for_each_safe(el, el1, &abuf->array_list) {
+ JSTypedArray *ta;
+ JSObject *p1;
+
+ ta = list_entry(el, JSTypedArray, link);
+ ta->link.prev = NULL;
+ ta->link.next = NULL;
+ p1 = ta->obj;
+ /* Note: the typed array length and offset fields are not modified */
+ if (p1->class_id != JS_CLASS_DATAVIEW) {
+ p1->u.array.count = 0;
+ p1->u.array.u.ptr = NULL;
+ }
+ }
if (abuf->shared && rt->sab_funcs.sab_free) {
rt->sab_funcs.sab_free(rt->sab_funcs.sab_opaque, abuf->data);
} else {
@@ -51349,6 +52946,16 @@ static JSValue js_typed_array_get_byteOffset(JSContext *ctx,
return JS_NewInt32(ctx, ta->offset);
}
+JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv,
+ JSTypedArrayEnum type)
+{
+ if (type < JS_TYPED_ARRAY_UINT8C || type > JS_TYPED_ARRAY_FLOAT64)
+ return JS_ThrowRangeError(ctx, "invalid typed array type");
+
+ return js_typed_array_constructor(ctx, JS_UNDEFINED, argc, argv,
+ JS_CLASS_UINT8C_ARRAY + type);
+}
+
/* Return the buffer associated to the typed array or an exception if
it is not a typed array or if the buffer is detached. pbyte_offset,
pbyte_length or pbytes_per_element can be NULL. */
@@ -51374,7 +52981,7 @@ JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,
}
return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
}
-
+
static JSValue js_typed_array_get_toStringTag(JSContext *ctx,
JSValueConst this_val)
{
@@ -51492,6 +53099,46 @@ static JSValue js_typed_array_at(JSContext *ctx, JSValueConst this_val,
return JS_GetPropertyInt64(ctx, this_val, idx);
}
+static JSValue js_typed_array_with(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue arr, val;
+ JSObject *p;
+ int64_t idx, len;
+
+ p = get_typed_array(ctx, this_val, /*is_dataview*/0);
+ if (!p)
+ return JS_EXCEPTION;
+ if (typed_array_is_detached(ctx, p))
+ return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+
+ if (JS_ToInt64Sat(ctx, &idx, argv[0]))
+ return JS_EXCEPTION;
+
+ len = p->u.array.count;
+ if (idx < 0)
+ idx = len + idx;
+
+ val = JS_ToPrimitive(ctx, argv[1], HINT_NUMBER);
+ if (JS_IsException(val))
+ return JS_EXCEPTION;
+
+ if (typed_array_is_detached(ctx, p) || idx < 0 || idx >= len)
+ return JS_ThrowRangeError(ctx, "invalid array index");
+
+ arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,
+ p->class_id);
+ if (JS_IsException(arr)) {
+ JS_FreeValue(ctx, val);
+ return JS_EXCEPTION;
+ }
+ if (JS_SetPropertyInt64(ctx, arr, idx, val) < 0) {
+ JS_FreeValue(ctx, arr);
+ return JS_EXCEPTION;
+ }
+ return arr;
+}
+
static JSValue js_typed_array_set(JSContext *ctx,
JSValueConst this_val,
int argc, JSValueConst *argv)
@@ -51616,18 +53263,16 @@ static JSValue js_typed_array_from(JSContext *ctx, JSValueConst this_val,
// from(items, mapfn = void 0, this_arg = void 0)
JSValueConst items = argv[0], mapfn, this_arg;
JSValueConst args[2];
- JSValue stack[2];
JSValue iter, arr, r, v, v2;
int64_t k, len;
- int done, mapping;
+ int mapping;
mapping = FALSE;
mapfn = JS_UNDEFINED;
this_arg = JS_UNDEFINED;
r = JS_UNDEFINED;
arr = JS_UNDEFINED;
- stack[0] = JS_UNDEFINED;
- stack[1] = JS_UNDEFINED;
+ iter = JS_UNDEFINED;
if (argc > 1) {
mapfn = argv[1];
@@ -51642,30 +53287,23 @@ static JSValue js_typed_array_from(JSContext *ctx, JSValueConst this_val,
iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator);
if (JS_IsException(iter))
goto exception;
- if (!JS_IsUndefined(iter)) {
- JS_FreeValue(ctx, iter);
- arr = JS_NewArray(ctx);
- if (JS_IsException(arr))
- goto exception;
- stack[0] = JS_DupValue(ctx, items);
- if (js_for_of_start(ctx, &stack[1], FALSE))
+ if (!JS_IsUndefined(iter) && !JS_IsNull(iter)) {
+ uint32_t len1;
+ if (!JS_IsFunction(ctx, iter)) {
+ JS_ThrowTypeError(ctx, "value is not iterable");
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 (JS_DefinePropertyValueInt64(ctx, arr, k, v, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- goto exception_close;
}
+ arr = js_array_from_iterator(ctx, &len1, items, iter);
+ if (JS_IsException(arr))
+ goto exception;
+ len = len1;
} else {
arr = JS_ToObject(ctx, items);
if (JS_IsException(arr))
goto exception;
+ if (js_get_length64(ctx, &len, arr) < 0)
+ goto exception;
}
- if (js_get_length64(ctx, &len, arr) < 0)
- goto exception;
v = JS_NewInt64(ctx, len);
args[0] = v;
r = js_typed_array_create(ctx, this_val, 1, args);
@@ -51689,17 +53327,12 @@ static JSValue js_typed_array_from(JSContext *ctx, JSValueConst this_val,
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, arr);
- JS_FreeValue(ctx, stack[0]);
- JS_FreeValue(ctx, stack[1]);
+ JS_FreeValue(ctx, iter);
return r;
}
@@ -51788,7 +53421,9 @@ static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val,
double d;
if (JS_ToFloat64(ctx, &d, argv[0]))
return JS_EXCEPTION;
- if (p->class_id == JS_CLASS_FLOAT32_ARRAY) {
+ if (p->class_id == JS_CLASS_FLOAT16_ARRAY) {
+ v64 = tofp16(d);
+ } else if (p->class_id == JS_CLASS_FLOAT32_ARRAY) {
union {
float f;
uint32_t u32;
@@ -51816,7 +53451,7 @@ static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val,
if (typed_array_is_detached(ctx, p))
return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-
+
shift = typed_array_size_log2(p->class_id);
switch(shift) {
case 0:
@@ -51867,14 +53502,13 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val,
if (argc > 1)
this_arg = argv[1];
- if (mode == special_findLast || mode == special_findLastIndex) {
+ k = 0;
+ dir = 1;
+ end = len;
+ if (mode == ArrayFindLast || mode == ArrayFindLastIndex) {
k = len - 1;
dir = -1;
end = -1;
- } else {
- k = 0;
- dir = 1;
- end = len;
}
for(; k != end; k += dir) {
@@ -51889,7 +53523,7 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val,
if (JS_IsException(res))
goto exception;
if (JS_ToBoolFree(ctx, res)) {
- if (mode == special_findIndex || mode == special_findLastIndex) {
+ if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) {
JS_FreeValue(ctx, val);
return index_val;
} else {
@@ -51898,7 +53532,7 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val,
}
JS_FreeValue(ctx, val);
}
- if (mode == special_findIndex || mode == special_findLastIndex)
+ if (mode == ArrayFindIndex || mode == ArrayFindLastIndex)
return JS_NewInt32(ctx, -1);
else
return JS_UNDEFINED;
@@ -51920,6 +53554,7 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
int64_t v64;
double d;
float f;
+ uint16_t hf;
len = js_typed_array_get_length_internal(ctx, this_val);
if (len < 0)
@@ -51968,7 +53603,7 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
res = 0;
goto done;
}
-
+
is_bigint = 0;
is_int = 0; /* avoid warning */
v64 = 0; /* avoid warning */
@@ -51980,20 +53615,37 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
} else
if (tag == JS_TAG_FLOAT64) {
d = JS_VALUE_GET_FLOAT64(argv[0]);
- v64 = d;
- is_int = (v64 == d);
- } else if (tag == JS_TAG_BIG_INT) {
- JSBigFloat *p1 = JS_VALUE_GET_PTR(argv[0]);
+ if (d >= INT64_MIN && d < 0x1p63) {
+ v64 = d;
+ is_int = (v64 == d);
+ }
+ } else if (tag == JS_TAG_BIG_INT || tag == JS_TAG_SHORT_BIG_INT) {
+ JSBigIntBuf buf1;
+ JSBigInt *p1;
+ int sz = (64 / JS_LIMB_BITS);
+ if (tag == JS_TAG_SHORT_BIG_INT)
+ p1 = js_bigint_set_short(&buf1, argv[0]);
+ else
+ p1 = JS_VALUE_GET_PTR(argv[0]);
if (p->class_id == JS_CLASS_BIG_INT64_ARRAY) {
- if (bf_get_int64(&v64, &p1->num, 0) != 0)
- goto done;
+ if (p1->len > sz)
+ goto done; /* does not fit an int64 : cannot be found */
} else if (p->class_id == JS_CLASS_BIG_UINT64_ARRAY) {
- if (bf_get_uint64((uint64_t *)&v64, &p1->num) != 0)
+ if (js_bigint_sign(p1))
+ goto done; /* v < 0 */
+ if (p1->len <= sz) {
+ /* OK */
+ } else if (p1->len == sz + 1 && p1->tab[sz] == 0) {
+ /* 2^63 <= v <= 2^64-1 */
+ } else {
goto done;
+ }
} else {
goto done;
}
+ if (JS_ToBigInt64(ctx, &v64, argv[0]))
+ goto exception;
d = 0;
is_bigint = 1;
} else {
@@ -52065,6 +53717,39 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
}
}
break;
+ case JS_CLASS_FLOAT16_ARRAY:
+ if (is_bigint)
+ break;
+ if (isnan(d)) {
+ const uint16_t *pv = p->u.array.u.fp16_ptr;
+ /* special case: indexOf returns -1, includes finds NaN */
+ if (special != special_includes)
+ goto done;
+ for (; k != stop; k += inc) {
+ if (isfp16nan(pv[k])) {
+ res = k;
+ break;
+ }
+ }
+ } else if (d == 0) {
+ // special case: includes also finds negative zero
+ const uint16_t *pv = p->u.array.u.fp16_ptr;
+ for (; k != stop; k += inc) {
+ if (isfp16zero(pv[k])) {
+ res = k;
+ break;
+ }
+ }
+ } else if (hf = tofp16(d), d == fromfp16(hf)) {
+ const uint16_t *pv = p->u.array.u.fp16_ptr;
+ for (; k != stop; k += inc) {
+ if (pv[k] == hf) {
+ res = k;
+ break;
+ }
+ }
+ }
+ break;
case JS_CLASS_FLOAT32_ARRAY:
if (is_bigint)
break;
@@ -52114,15 +53799,12 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
}
break;
case JS_CLASS_BIG_INT64_ARRAY:
- if (is_bigint || (is_math_mode(ctx) && is_int &&
- v64 >= -MAX_SAFE_INTEGER &&
- v64 <= MAX_SAFE_INTEGER)) {
+ if (is_bigint) {
goto scan64;
}
break;
case JS_CLASS_BIG_UINT64_ARRAY:
- if (is_bigint || (is_math_mode(ctx) && is_int &&
- v64 >= 0 && v64 <= MAX_SAFE_INTEGER)) {
+ if (is_bigint) {
const uint64_t *pv;
uint64_t v;
scan64:
@@ -52270,6 +53952,36 @@ static JSValue js_typed_array_reverse(JSContext *ctx, JSValueConst this_val,
return JS_DupValue(ctx, this_val);
}
+static JSValue js_typed_array_toReversed(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue arr, ret;
+ JSObject *p;
+
+ p = get_typed_array(ctx, this_val, /*is_dataview*/0);
+ if (!p)
+ return JS_EXCEPTION;
+ arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,
+ p->class_id);
+ if (JS_IsException(arr))
+ return JS_EXCEPTION;
+ ret = js_typed_array_reverse(ctx, arr, argc, argv);
+ JS_FreeValue(ctx, arr);
+ return ret;
+}
+
+static void slice_memcpy(uint8_t *dst, const uint8_t *src, size_t len)
+{
+ if (dst + len <= src || dst >= src + len) {
+ /* no overlap: can use memcpy */
+ memcpy(dst, src, len);
+ } else {
+ /* otherwise the spec mandates byte copy */
+ while (len-- != 0)
+ *dst++ = *src++;
+ }
+}
+
static JSValue js_typed_array_slice(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
@@ -52312,9 +54024,9 @@ static JSValue js_typed_array_slice(JSContext *ctx, JSValueConst this_val,
if (p1 != NULL && p->class_id == p1->class_id &&
typed_array_get_length(ctx, p1) >= count &&
typed_array_get_length(ctx, p) >= start + count) {
- memcpy(p1->u.array.u.uint8_ptr,
- p->u.array.u.uint8_ptr + (start << shift),
- count << shift);
+ slice_memcpy(p1->u.array.u.uint8_ptr,
+ p->u.array.u.uint8_ptr + (start << shift),
+ count << shift);
} else {
for (n = 0; n < count; n++) {
val = JS_GetPropertyValue(ctx, this_val, JS_NewInt32(ctx, start + n));
@@ -52428,6 +54140,11 @@ static int js_TA_cmp_uint64(const void *a, const void *b, void *opaque) {
return (y < x) - (y > x);
}
+static int js_TA_cmp_float16(const void *a, const void *b, void *opaque) {
+ return js_cmp_doubles(fromfp16(*(const uint16_t *)a),
+ fromfp16(*(const uint16_t *)b));
+}
+
static int js_TA_cmp_float32(const void *a, const void *b, void *opaque) {
return js_cmp_doubles(*(const float *)a, *(const float *)b);
}
@@ -52468,6 +54185,10 @@ static JSValue js_TA_get_uint64(JSContext *ctx, const void *a) {
return JS_NewBigUint64(ctx, *(uint64_t *)a);
}
+static JSValue js_TA_get_float16(JSContext *ctx, const void *a) {
+ return __JS_NewFloat64(ctx, fromfp16(*(const uint16_t *)a));
+}
+
static JSValue js_TA_get_float32(JSContext *ctx, const void *a) {
return __JS_NewFloat64(ctx, *(const float *)a);
}
@@ -52478,7 +54199,7 @@ static JSValue js_TA_get_float64(JSContext *ctx, const void *a) {
struct TA_sort_context {
JSContext *ctx;
- int exception;
+ int exception; /* 1 = exception, 2 = detached typed array */
JSValueConst arr;
JSValueConst cmp;
JSValue (*getfun)(JSContext *ctx, const void *a);
@@ -52496,6 +54217,8 @@ static int js_TA_cmp_generic(const void *a, const void *b, void *opaque) {
cmp = 0;
if (!psc->exception) {
+ /* Note: the typed array can be detached without causing an
+ error */
a_idx = *(uint32_t *)a;
b_idx = *(uint32_t *)b;
argv[0] = psc->getfun(ctx, psc->array_ptr +
@@ -52523,12 +54246,13 @@ static int js_TA_cmp_generic(const void *a, const void *b, void *opaque) {
/* make sort stable: compare array offsets */
cmp = (a_idx > b_idx) - (a_idx < b_idx);
}
- if (validate_typed_array(ctx, psc->arr) < 0) {
- psc->exception = 1;
+ if (unlikely(typed_array_is_detached(ctx,
+ JS_VALUE_GET_PTR(psc->arr)))) {
+ psc->exception = 2;
}
done:
- JS_FreeValue(ctx, (JSValue)argv[0]);
- JS_FreeValue(ctx, (JSValue)argv[1]);
+ JS_FreeValue(ctx, argv[0]);
+ JS_FreeValue(ctx, argv[1]);
}
return cmp;
}
@@ -52548,11 +54272,11 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val,
tsc.arr = this_val;
tsc.cmp = argv[0];
+ if (!JS_IsUndefined(tsc.cmp) && check_function(ctx, tsc.cmp))
+ return JS_EXCEPTION;
len = js_typed_array_get_length_internal(ctx, this_val);
if (len < 0)
return JS_EXCEPTION;
- if (!JS_IsUndefined(tsc.cmp) && check_function(ctx, tsc.cmp))
- return JS_EXCEPTION;
if (len > 1) {
p = JS_VALUE_GET_OBJ(this_val);
@@ -52590,6 +54314,10 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val,
tsc.getfun = js_TA_get_uint64;
cmpfun = js_TA_cmp_uint64;
break;
+ case JS_CLASS_FLOAT16_ARRAY:
+ tsc.getfun = js_TA_get_float16;
+ cmpfun = js_TA_cmp_float16;
+ break;
case JS_CLASS_FLOAT32_ARRAY:
tsc.getfun = js_TA_get_float32;
cmpfun = js_TA_cmp_float32;
@@ -52607,7 +54335,7 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val,
uint32_t *array_idx;
void *array_tmp;
size_t i, j;
-
+
/* XXX: a stable sort would use less memory */
array_idx = js_malloc(ctx, len * sizeof(array_idx[0]));
if (!array_idx)
@@ -52618,44 +54346,48 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val,
tsc.elt_size = elt_size;
rqsort(array_idx, len, sizeof(array_idx[0]),
js_TA_cmp_generic, &tsc);
- if (tsc.exception)
- goto fail;
- array_tmp = js_malloc(ctx, len * elt_size);
- if (!array_tmp) {
- fail:
- js_free(ctx, array_idx);
- return JS_EXCEPTION;
- }
- memcpy(array_tmp, array_ptr, len * elt_size);
- switch(elt_size) {
- case 1:
- for(i = 0; i < len; i++) {
- j = array_idx[i];
- ((uint8_t *)array_ptr)[i] = ((uint8_t *)array_tmp)[j];
- }
- break;
- case 2:
- for(i = 0; i < len; i++) {
- j = array_idx[i];
- ((uint16_t *)array_ptr)[i] = ((uint16_t *)array_tmp)[j];
- }
- break;
- case 4:
- for(i = 0; i < len; i++) {
- j = array_idx[i];
- ((uint32_t *)array_ptr)[i] = ((uint32_t *)array_tmp)[j];
+ if (tsc.exception) {
+ if (tsc.exception == 1)
+ goto fail;
+ /* detached typed array during the sort: no error */
+ } else {
+ array_tmp = js_malloc(ctx, len * elt_size);
+ if (!array_tmp) {
+ fail:
+ js_free(ctx, array_idx);
+ return JS_EXCEPTION;
}
- break;
- case 8:
- for(i = 0; i < len; i++) {
- j = array_idx[i];
- ((uint64_t *)array_ptr)[i] = ((uint64_t *)array_tmp)[j];
+ memcpy(array_tmp, array_ptr, len * elt_size);
+ switch(elt_size) {
+ case 1:
+ for(i = 0; i < len; i++) {
+ j = array_idx[i];
+ ((uint8_t *)array_ptr)[i] = ((uint8_t *)array_tmp)[j];
+ }
+ break;
+ case 2:
+ for(i = 0; i < len; i++) {
+ j = array_idx[i];
+ ((uint16_t *)array_ptr)[i] = ((uint16_t *)array_tmp)[j];
+ }
+ break;
+ case 4:
+ for(i = 0; i < len; i++) {
+ j = array_idx[i];
+ ((uint32_t *)array_ptr)[i] = ((uint32_t *)array_tmp)[j];
+ }
+ break;
+ case 8:
+ for(i = 0; i < len; i++) {
+ j = array_idx[i];
+ ((uint64_t *)array_ptr)[i] = ((uint64_t *)array_tmp)[j];
+ }
+ break;
+ default:
+ abort();
}
- break;
- default:
- abort();
+ js_free(ctx, array_tmp);
}
- js_free(ctx, array_tmp);
js_free(ctx, array_idx);
} else {
rqsort(array_ptr, len, elt_size, cmpfun, &tsc);
@@ -52666,6 +54398,24 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val,
return JS_DupValue(ctx, this_val);
}
+static JSValue js_typed_array_toSorted(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue arr, ret;
+ JSObject *p;
+
+ p = get_typed_array(ctx, this_val, /*is_dataview*/0);
+ if (!p)
+ return JS_EXCEPTION;
+ arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,
+ p->class_id);
+ if (JS_IsException(arr))
+ return JS_EXCEPTION;
+ ret = js_typed_array_sort(ctx, arr, argc, argv);
+ JS_FreeValue(ctx, arr);
+ return ret;
+}
+
static const JSCFunctionListEntry js_typed_array_base_funcs[] = {
JS_CFUNC_DEF("from", 1, js_typed_array_from ),
JS_CFUNC_DEF("of", 0, js_typed_array_of ),
@@ -52678,6 +54428,7 @@ static const JSCFunctionListEntry js_typed_array_base_funcs[] = {
static const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = {
JS_CGETSET_DEF("length", js_typed_array_get_length, NULL ),
JS_CFUNC_DEF("at", 1, js_typed_array_at ),
+ JS_CFUNC_DEF("with", 2, js_typed_array_with ),
JS_CGETSET_MAGIC_DEF("buffer", js_typed_array_get_buffer, NULL, 0 ),
JS_CGETSET_MAGIC_DEF("byteLength", js_typed_array_get_byteLength, NULL, 0 ),
JS_CGETSET_MAGIC_DEF("byteOffset", js_typed_array_get_byteOffset, NULL, 0 ),
@@ -52696,14 +54447,16 @@ static const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = {
JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce | special_TA ),
JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight | special_TA ),
JS_CFUNC_DEF("fill", 1, js_typed_array_fill ),
- JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, special_find ),
- JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, special_findIndex ),
- JS_CFUNC_MAGIC_DEF("findLast", 1, js_typed_array_find, special_findLast ),
- JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_typed_array_find, special_findLastIndex ),
+ JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, ArrayFind ),
+ JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, ArrayFindIndex ),
+ JS_CFUNC_MAGIC_DEF("findLast", 1, js_typed_array_find, ArrayFindLast ),
+ JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_typed_array_find, ArrayFindLastIndex ),
JS_CFUNC_DEF("reverse", 0, js_typed_array_reverse ),
+ JS_CFUNC_DEF("toReversed", 0, js_typed_array_toReversed ),
JS_CFUNC_DEF("slice", 2, js_typed_array_slice ),
JS_CFUNC_DEF("subarray", 2, js_typed_array_subarray ),
JS_CFUNC_DEF("sort", 1, js_typed_array_sort ),
+ JS_CFUNC_DEF("toSorted", 1, js_typed_array_toSorted ),
JS_CFUNC_MAGIC_DEF("join", 1, js_typed_array_join, 0 ),
JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_typed_array_join, 1 ),
JS_CFUNC_MAGIC_DEF("indexOf", 1, js_typed_array_indexOf, special_indexOf ),
@@ -52771,10 +54524,8 @@ static JSValue js_array_from_iterator(JSContext *ctx, uint32_t *plen,
val = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
if (JS_IsException(val))
goto fail;
- if (done) {
- JS_FreeValue(ctx, val);
+ if (done)
break;
- }
if (JS_CreateDataPropertyUint32(ctx, arr, k, val, JS_PROP_THROW) < 0)
goto fail;
k++;
@@ -52975,7 +54726,7 @@ static void js_typed_array_finalizer(JSRuntime *rt, JSValue val)
if (ta) {
/* during the GC the finalizers are called in an arbitrary
order so the ArrayBuffer finalizer may have been called */
- if (JS_IsLiveObject(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer))) {
+ if (ta->link.next) {
list_del(&ta->link);
}
JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
@@ -53058,7 +54809,8 @@ static JSValue js_dataview_getValue(JSContext *ctx,
{
JSTypedArray *ta;
JSArrayBuffer *abuf;
- int is_swap, size;
+ BOOL littleEndian, is_swap;
+ int size;
uint8_t *ptr;
uint32_t v;
uint64_t pos;
@@ -53069,12 +54821,8 @@ static JSValue js_dataview_getValue(JSContext *ctx,
size = 1 << typed_array_size_log2(class_id);
if (JS_ToIndex(ctx, &pos, argv[0]))
return JS_EXCEPTION;
- is_swap = FALSE;
- if (argc > 1)
- is_swap = JS_ToBool(ctx, argv[1]);
-#ifndef WORDS_BIGENDIAN
- is_swap ^= 1;
-#endif
+ littleEndian = argc > 1 && JS_ToBool(ctx, argv[1]);
+ is_swap = littleEndian ^ !is_be();
abuf = ta->buffer->u.array_buffer;
if (abuf->detached)
return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
@@ -53125,6 +54873,14 @@ static JSValue js_dataview_getValue(JSContext *ctx,
return JS_NewBigUint64(ctx, v);
}
break;
+ case JS_CLASS_FLOAT16_ARRAY:
+ {
+ uint16_t v;
+ v = get_u16(ptr);
+ if (is_swap)
+ v = bswap16(v);
+ return __JS_NewFloat64(ctx, fromfp16(v));
+ }
case JS_CLASS_FLOAT32_ARRAY:
{
union {
@@ -53159,7 +54915,8 @@ static JSValue js_dataview_setValue(JSContext *ctx,
{
JSTypedArray *ta;
JSArrayBuffer *abuf;
- int is_swap, size;
+ BOOL littleEndian, is_swap;
+ int size;
uint8_t *ptr;
uint64_t v64;
uint32_t v;
@@ -53185,7 +54942,9 @@ static JSValue js_dataview_setValue(JSContext *ctx,
double d;
if (JS_ToFloat64(ctx, &d, val))
return JS_EXCEPTION;
- if (class_id == JS_CLASS_FLOAT32_ARRAY) {
+ if (class_id == JS_CLASS_FLOAT16_ARRAY) {
+ v = tofp16(d);
+ } else if (class_id == JS_CLASS_FLOAT32_ARRAY) {
union {
float f;
uint32_t i;
@@ -53198,12 +54957,8 @@ static JSValue js_dataview_setValue(JSContext *ctx,
v64 = u.u64;
}
}
- is_swap = FALSE;
- if (argc > 2)
- is_swap = JS_ToBool(ctx, argv[2]);
-#ifndef WORDS_BIGENDIAN
- is_swap ^= 1;
-#endif
+ littleEndian = argc > 2 && JS_ToBool(ctx, argv[2]);
+ is_swap = littleEndian ^ !is_be();
abuf = ta->buffer->u.array_buffer;
if (abuf->detached)
return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
@@ -53218,6 +54973,7 @@ static JSValue js_dataview_setValue(JSContext *ctx,
break;
case JS_CLASS_INT16_ARRAY:
case JS_CLASS_UINT16_ARRAY:
+ case JS_CLASS_FLOAT16_ARRAY:
if (is_swap)
v = bswap16(v);
put_u16(ptr, v);
@@ -53254,6 +55010,7 @@ static const JSCFunctionListEntry js_dataview_proto_funcs[] = {
JS_CFUNC_MAGIC_DEF("getUint32", 1, js_dataview_getValue, JS_CLASS_UINT32_ARRAY ),
JS_CFUNC_MAGIC_DEF("getBigInt64", 1, js_dataview_getValue, JS_CLASS_BIG_INT64_ARRAY ),
JS_CFUNC_MAGIC_DEF("getBigUint64", 1, js_dataview_getValue, JS_CLASS_BIG_UINT64_ARRAY ),
+ JS_CFUNC_MAGIC_DEF("getFloat16", 1, js_dataview_getValue, JS_CLASS_FLOAT16_ARRAY ),
JS_CFUNC_MAGIC_DEF("getFloat32", 1, js_dataview_getValue, JS_CLASS_FLOAT32_ARRAY ),
JS_CFUNC_MAGIC_DEF("getFloat64", 1, js_dataview_getValue, JS_CLASS_FLOAT64_ARRAY ),
JS_CFUNC_MAGIC_DEF("setInt8", 2, js_dataview_setValue, JS_CLASS_INT8_ARRAY ),
@@ -53264,6 +55021,7 @@ static const JSCFunctionListEntry js_dataview_proto_funcs[] = {
JS_CFUNC_MAGIC_DEF("setUint32", 2, js_dataview_setValue, JS_CLASS_UINT32_ARRAY ),
JS_CFUNC_MAGIC_DEF("setBigInt64", 2, js_dataview_setValue, JS_CLASS_BIG_INT64_ARRAY ),
JS_CFUNC_MAGIC_DEF("setBigUint64", 2, js_dataview_setValue, JS_CLASS_BIG_UINT64_ARRAY ),
+ JS_CFUNC_MAGIC_DEF("setFloat16", 2, js_dataview_setValue, JS_CLASS_FLOAT16_ARRAY ),
JS_CFUNC_MAGIC_DEF("setFloat32", 2, js_dataview_setValue, JS_CLASS_FLOAT32_ARRAY ),
JS_CFUNC_MAGIC_DEF("setFloat64", 2, js_dataview_setValue, JS_CLASS_FLOAT64_ARRAY ),
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "DataView", JS_PROP_CONFIGURABLE ),
@@ -53326,6 +55084,11 @@ static void *js_atomics_get_ptr(JSContext *ctx,
if (JS_ToIndex(ctx, &idx, idx_val)) {
return NULL;
}
+ /* RevalidateAtomicAccess(): must test again detached after JS_ToIndex() */
+ if (abuf->detached) {
+ JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+ 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");
@@ -53387,7 +55150,7 @@ static JSValue js_atomics_op(JSContext *ctx,
}
switch(op | (size_log2 << 3)) {
-
+
#define OP(op_name, func_name) \
case ATOMICS_OP_ ## op_name | (0 << 3): \
a = func_name((_Atomic(uint8_t) *)ptr, v); \
@@ -53401,7 +55164,7 @@ static JSValue js_atomics_op(JSContext *ctx,
case ATOMICS_OP_ ## op_name | (3 << 3): \
a = func_name((_Atomic(uint64_t) *)ptr, v); \
break;
-
+
OP(ADD, atomic_fetch_add)
OP(AND, atomic_fetch_and)
OP(OR, atomic_fetch_or)
@@ -53422,7 +55185,7 @@ static JSValue js_atomics_op(JSContext *ctx,
case ATOMICS_OP_LOAD | (3 << 3):
a = atomic_load((_Atomic(uint64_t) *)ptr);
break;
-
+
case ATOMICS_OP_COMPARE_EXCHANGE | (0 << 3):
{
uint8_t v1 = v;
@@ -53502,7 +55265,7 @@ static JSValue js_atomics_store(JSContext *ctx,
return JS_EXCEPTION;
if (size_log2 == 3) {
int64_t v64;
- ret = JS_ToBigIntValueFree(ctx, JS_DupValue(ctx, argv[2]));
+ ret = JS_ToBigIntFree(ctx, JS_DupValue(ctx, argv[2]));
if (JS_IsException(ret))
return ret;
if (JS_ToBigInt64(ctx, &v64, ret)) {
@@ -53583,14 +55346,15 @@ static JSValue js_atomics_wait(JSContext *ctx,
if (size_log2 == 3) {
if (JS_ToBigInt64(ctx, &v, argv[2]))
return JS_EXCEPTION;
- } else {
+ } else {
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)
+ /* must use INT64_MAX + 1 because INT64_MAX cannot be exactly represented as a double */
+ if (isnan(d) || d >= 0x1p63)
timeout = INT64_MAX;
else if (d < 0)
timeout = 0;
@@ -53761,13 +55525,15 @@ void JS_AddIntrinsicTypedArrays(JSContext *ctx)
JS_DefinePropertyValue(ctx, typed_array_base_proto, JS_ATOM_toString, obj,
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- typed_array_base_func = JS_NewCFunction(ctx, js_typed_array_base_constructor,
- "TypedArray", 0);
+ typed_array_base_func = JS_NewCFunction2(ctx, js_typed_array_base_constructor,
+ "TypedArray", 0, JS_CFUNC_constructor_or_func, 0);
JS_SetPropertyFunctionList(ctx, typed_array_base_func,
js_typed_array_base_funcs,
countof(js_typed_array_base_funcs));
JS_SetConstructor(ctx, typed_array_base_func, typed_array_base_proto);
+ /* Used to squelch a -Wcast-function-type warning. */
+ JSCFunctionType ft = { .generic_magic = js_typed_array_constructor };
for(i = JS_CLASS_UINT8C_ARRAY; i < JS_CLASS_UINT8C_ARRAY + JS_TYPED_ARRAY_COUNT; i++) {
JSValue func_obj;
char buf[ATOM_GET_STR_BUF_SIZE];
@@ -53780,7 +55546,7 @@ void JS_AddIntrinsicTypedArrays(JSContext *ctx)
0);
name = JS_AtomGetStr(ctx, buf, sizeof(buf),
JS_ATOM_Uint8ClampedArray + i - JS_CLASS_UINT8C_ARRAY);
- func_obj = JS_NewCFunction3(ctx, (JSCFunction *)js_typed_array_constructor,
+ func_obj = JS_NewCFunction3(ctx, ft.generic,
name, 3, JS_CFUNC_constructor_magic, i,
typed_array_base_func);
JS_NewGlobalCConstructor2(ctx, func_obj, name, ctx->class_proto[i]);
@@ -53806,13 +55572,279 @@ void JS_AddIntrinsicTypedArrays(JSContext *ctx)
#endif
}
-JSClassID JS_GetClassID(JSValueConst v)
+/* WeakRef */
+
+typedef struct JSWeakRefData {
+ JSWeakRefHeader weakref_header;
+ JSValue target;
+} JSWeakRefData;
+
+static void js_weakref_finalizer(JSRuntime *rt, JSValue val)
{
- JSObject *p;
+ JSWeakRefData *wrd = JS_GetOpaque(val, JS_CLASS_WEAK_REF);
+ if (!wrd)
+ return;
+ js_weakref_free(rt, wrd->target);
+ list_del(&wrd->weakref_header.link);
+ js_free_rt(rt, wrd);
+}
- if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT)
- return 0;
- p = JS_VALUE_GET_OBJ(v);
- assert(p != 0);
- return p->class_id;
+static void weakref_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh)
+{
+ JSWeakRefData *wrd = container_of(wh, JSWeakRefData, weakref_header);
+
+ if (!js_weakref_is_live(wrd->target)) {
+ js_weakref_free(rt, wrd->target);
+ wrd->target = JS_UNDEFINED;
+ }
+}
+
+static JSValue js_weakref_constructor(JSContext *ctx, JSValueConst new_target,
+ int argc, JSValueConst *argv)
+{
+ JSValueConst arg;
+ JSValue obj;
+
+ if (JS_IsUndefined(new_target))
+ return JS_ThrowTypeError(ctx, "constructor requires 'new'");
+ arg = argv[0];
+ if (!js_weakref_is_target(arg))
+ return JS_ThrowTypeError(ctx, "invalid target");
+ obj = js_create_from_ctor(ctx, new_target, JS_CLASS_WEAK_REF);
+ if (JS_IsException(obj))
+ return JS_EXCEPTION;
+ JSWeakRefData *wrd = js_mallocz(ctx, sizeof(*wrd));
+ if (!wrd) {
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+ }
+ wrd->target = js_weakref_new(ctx, arg);
+ wrd->weakref_header.weakref_type = JS_WEAKREF_TYPE_WEAKREF;
+ list_add_tail(&wrd->weakref_header.link, &ctx->rt->weakref_list);
+ JS_SetOpaque(obj, wrd);
+ return obj;
+}
+
+static JSValue js_weakref_deref(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
+{
+ JSWeakRefData *wrd = JS_GetOpaque2(ctx, this_val, JS_CLASS_WEAK_REF);
+ if (!wrd)
+ return JS_EXCEPTION;
+ if (js_weakref_is_live(wrd->target))
+ return JS_DupValue(ctx, wrd->target);
+ else
+ return JS_UNDEFINED;
+}
+
+static const JSCFunctionListEntry js_weakref_proto_funcs[] = {
+ JS_CFUNC_DEF("deref", 0, js_weakref_deref ),
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakRef", JS_PROP_CONFIGURABLE ),
+};
+
+static const JSClassShortDef js_weakref_class_def[] = {
+ { JS_ATOM_WeakRef, js_weakref_finalizer, NULL }, /* JS_CLASS_WEAK_REF */
+};
+
+typedef struct JSFinRecEntry {
+ struct list_head link;
+ JSValue target;
+ JSValue held_val;
+ JSValue token;
+} JSFinRecEntry;
+
+typedef struct JSFinalizationRegistryData {
+ JSWeakRefHeader weakref_header;
+ struct list_head entries; /* list of JSFinRecEntry.link */
+ JSContext *ctx;
+ JSValue cb;
+} JSFinalizationRegistryData;
+
+static void js_finrec_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSFinalizationRegistryData *frd = JS_GetOpaque(val, JS_CLASS_FINALIZATION_REGISTRY);
+ if (frd) {
+ struct list_head *el, *el1;
+ list_for_each_safe(el, el1, &frd->entries) {
+ JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);
+ js_weakref_free(rt, fre->target);
+ js_weakref_free(rt, fre->token);
+ JS_FreeValueRT(rt, fre->held_val);
+ js_free_rt(rt, fre);
+ }
+ JS_FreeValueRT(rt, frd->cb);
+ list_del(&frd->weakref_header.link);
+ js_free_rt(rt, frd);
+ }
+}
+
+static void js_finrec_mark(JSRuntime *rt, JSValueConst val,
+ JS_MarkFunc *mark_func)
+{
+ JSFinalizationRegistryData *frd = JS_GetOpaque(val, JS_CLASS_FINALIZATION_REGISTRY);
+ struct list_head *el;
+ if (frd) {
+ list_for_each(el, &frd->entries) {
+ JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);
+ JS_MarkValue(rt, fre->held_val, mark_func);
+ }
+ JS_MarkValue(rt, frd->cb, mark_func);
+ }
+}
+
+static JSValue js_finrec_job(JSContext *ctx, int argc, JSValueConst *argv)
+{
+ return JS_Call(ctx, argv[0], JS_UNDEFINED, 1, &argv[1]);
+}
+
+static void finrec_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh)
+{
+ JSFinalizationRegistryData *frd = container_of(wh, JSFinalizationRegistryData, weakref_header);
+ struct list_head *el, *el1;
+
+ list_for_each_safe(el, el1, &frd->entries) {
+ JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);
+
+ if (!js_weakref_is_live(fre->token)) {
+ js_weakref_free(rt, fre->token);
+ fre->token = JS_UNDEFINED;
+ }
+
+ if (!js_weakref_is_live(fre->target)) {
+ JSValueConst args[2];
+ args[0] = frd->cb;
+ args[1] = fre->held_val;
+ JS_EnqueueJob(frd->ctx, js_finrec_job, 2, args);
+
+ js_weakref_free(rt, fre->target);
+ js_weakref_free(rt, fre->token);
+ JS_FreeValueRT(rt, fre->held_val);
+ list_del(&fre->link);
+ js_free_rt(rt, fre);
+ }
+ }
+}
+
+static JSValue js_finrec_constructor(JSContext *ctx, JSValueConst new_target,
+ int argc, JSValueConst *argv)
+{
+ JSValueConst cb;
+ JSValue obj;
+ JSFinalizationRegistryData *frd;
+
+ if (JS_IsUndefined(new_target))
+ return JS_ThrowTypeError(ctx, "constructor requires 'new'");
+ cb = argv[0];
+ if (!JS_IsFunction(ctx, cb))
+ return JS_ThrowTypeError(ctx, "argument must be a function");
+
+ obj = js_create_from_ctor(ctx, new_target, JS_CLASS_FINALIZATION_REGISTRY);
+ if (JS_IsException(obj))
+ return JS_EXCEPTION;
+ frd = js_mallocz(ctx, sizeof(*frd));
+ if (!frd) {
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+ }
+ frd->weakref_header.weakref_type = JS_WEAKREF_TYPE_FINREC;
+ list_add_tail(&frd->weakref_header.link, &ctx->rt->weakref_list);
+ init_list_head(&frd->entries);
+ frd->ctx = ctx; /* XXX: JS_DupContext() ? */
+ frd->cb = JS_DupValue(ctx, cb);
+ JS_SetOpaque(obj, frd);
+ return obj;
+}
+
+static JSValue js_finrec_register(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValueConst target, held_val, token;
+ JSFinalizationRegistryData *frd;
+ JSFinRecEntry *fre;
+
+ frd = JS_GetOpaque2(ctx, this_val, JS_CLASS_FINALIZATION_REGISTRY);
+ if (!frd)
+ return JS_EXCEPTION;
+ target = argv[0];
+ held_val = argv[1];
+ token = argc > 2 ? argv[2] : JS_UNDEFINED;
+
+ if (!js_weakref_is_target(target))
+ return JS_ThrowTypeError(ctx, "invalid target");
+ if (js_same_value(ctx, target, held_val))
+ return JS_ThrowTypeError(ctx, "held value cannot be the target");
+ if (!JS_IsUndefined(token) && !js_weakref_is_target(token))
+ return JS_ThrowTypeError(ctx, "invalid unregister token");
+ fre = js_malloc(ctx, sizeof(*fre));
+ if (!fre)
+ return JS_EXCEPTION;
+ fre->target = js_weakref_new(ctx, target);
+ fre->held_val = JS_DupValue(ctx, held_val);
+ fre->token = js_weakref_new(ctx, token);
+ list_add_tail(&fre->link, &frd->entries);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_finrec_unregister(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
+{
+ JSFinalizationRegistryData *frd = JS_GetOpaque2(ctx, this_val, JS_CLASS_FINALIZATION_REGISTRY);
+ JSValueConst token;
+ BOOL removed;
+ struct list_head *el, *el1;
+
+ if (!frd)
+ return JS_EXCEPTION;
+ token = argv[0];
+ if (!js_weakref_is_target(token))
+ return JS_ThrowTypeError(ctx, "invalid unregister token");
+
+ removed = FALSE;
+ list_for_each_safe(el, el1, &frd->entries) {
+ JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);
+ if (js_weakref_is_live(fre->token) && js_same_value(ctx, fre->token, token)) {
+ js_weakref_free(ctx->rt, fre->target);
+ js_weakref_free(ctx->rt, fre->token);
+ JS_FreeValue(ctx, fre->held_val);
+ list_del(&fre->link);
+ js_free(ctx, fre);
+ removed = TRUE;
+ }
+ }
+ return JS_NewBool(ctx, removed);
+}
+
+static const JSCFunctionListEntry js_finrec_proto_funcs[] = {
+ JS_CFUNC_DEF("register", 2, js_finrec_register ),
+ JS_CFUNC_DEF("unregister", 1, js_finrec_unregister ),
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "FinalizationRegistry", JS_PROP_CONFIGURABLE ),
+};
+
+static const JSClassShortDef js_finrec_class_def[] = {
+ { JS_ATOM_FinalizationRegistry, js_finrec_finalizer, js_finrec_mark }, /* JS_CLASS_FINALIZATION_REGISTRY */
+};
+
+void JS_AddIntrinsicWeakRef(JSContext *ctx)
+{
+ JSRuntime *rt = ctx->rt;
+
+ /* WeakRef */
+ if (!JS_IsRegisteredClass(rt, JS_CLASS_WEAK_REF)) {
+ init_class_range(rt, js_weakref_class_def, JS_CLASS_WEAK_REF,
+ countof(js_weakref_class_def));
+ }
+ ctx->class_proto[JS_CLASS_WEAK_REF] = JS_NewObject(ctx);
+ JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_WEAK_REF],
+ js_weakref_proto_funcs,
+ countof(js_weakref_proto_funcs));
+ JS_NewGlobalCConstructor(ctx, "WeakRef", js_weakref_constructor, 1, ctx->class_proto[JS_CLASS_WEAK_REF]);
+
+ /* FinalizationRegistry */
+ if (!JS_IsRegisteredClass(rt, JS_CLASS_FINALIZATION_REGISTRY)) {
+ init_class_range(rt, js_finrec_class_def, JS_CLASS_FINALIZATION_REGISTRY,
+ countof(js_finrec_class_def));
+ }
+ ctx->class_proto[JS_CLASS_FINALIZATION_REGISTRY] = JS_NewObject(ctx);
+ JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_FINALIZATION_REGISTRY],
+ js_finrec_proto_funcs,
+ countof(js_finrec_proto_funcs));
+ JS_NewGlobalCConstructor(ctx, "FinalizationRegistry", js_finrec_constructor, 1, ctx->class_proto[JS_CLASS_FINALIZATION_REGISTRY]);
}
diff --git a/quickjs/quickjs.h b/quickjs/quickjs.h
index 296137e741..ce3350e00a 100644
--- a/quickjs/quickjs.h
+++ b/quickjs/quickjs.h
@@ -27,6 +27,7 @@
#include
#include
+#include
#ifdef __cplusplus
extern "C" {
@@ -48,7 +49,6 @@ extern "C" {
typedef struct JSRuntime JSRuntime;
typedef struct JSContext JSContext;
-typedef struct JSObject JSObject;
typedef struct JSClass JSClass;
typedef uint32_t JSClassID;
typedef uint32_t JSAtom;
@@ -64,14 +64,21 @@ typedef uint32_t JSAtom;
#define JS_NAN_BOXING
#endif
+#if defined(__SIZEOF_INT128__) && (INTPTR_MAX >= INT64_MAX)
+#define JS_LIMB_BITS 64
+#else
+#define JS_LIMB_BITS 32
+#endif
+
+#define JS_SHORT_BIG_INT_BITS JS_LIMB_BITS
+
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_FIRST = -9, /* first negative tag */
+ JS_TAG_BIG_INT = -9,
JS_TAG_SYMBOL = -8,
JS_TAG_STRING = -7,
+ JS_TAG_STRING_ROPE = -6,
JS_TAG_MODULE = -3, /* used internally */
JS_TAG_FUNCTION_BYTECODE = -2, /* used internally */
JS_TAG_OBJECT = -1,
@@ -83,7 +90,8 @@ enum {
JS_TAG_UNINITIALIZED = 4,
JS_TAG_CATCH_OFFSET = 5,
JS_TAG_EXCEPTION = 6,
- JS_TAG_FLOAT64 = 7,
+ JS_TAG_SHORT_BIG_INT = 7,
+ JS_TAG_FLOAT64 = 8,
/* any larger tag is FLOAT64 if JS_NAN_BOXING */
};
@@ -108,6 +116,7 @@ typedef const struct __JSValue *JSValueConst;
#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_SHORT_BIG_INT(v) 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))
@@ -126,7 +135,12 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
{
return 0;
}
-
+
+static inline JSValue __JS_NewShortBigInt(JSContext *ctx, int32_t d)
+{
+ return JS_MKVAL(JS_TAG_SHORT_BIG_INT, d);
+}
+
#elif defined(JS_NAN_BOXING)
typedef uint64_t JSValue;
@@ -136,6 +150,7 @@ typedef uint64_t 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_SHORT_BIG_INT(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))
@@ -191,13 +206,23 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
tag = JS_VALUE_GET_TAG(v);
return tag == (JS_NAN >> 32);
}
-
+
+static inline JSValue __JS_NewShortBigInt(JSContext *ctx, int32_t d)
+{
+ return JS_MKVAL(JS_TAG_SHORT_BIG_INT, d);
+}
+
#else /* !JS_NAN_BOXING */
typedef union JSValueUnion {
int32_t int32;
double float64;
void *ptr;
+#if JS_SHORT_BIG_INT_BITS == 32
+ int32_t short_big_int;
+#else
+ int64_t short_big_int;
+#endif
} JSValueUnion;
typedef struct JSValue {
@@ -213,14 +238,24 @@ typedef struct JSValue {
#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_SHORT_BIG_INT(v) ((v).u.short_big_int)
#define JS_VALUE_GET_PTR(v) ((v).u.ptr)
+#ifdef __cplusplus
+#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 }
+#else // __cplusplus
#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 }
+#endif // __cplusplus
static inline JSValue __JS_NewFloat64(JSContext *ctx, double d)
{
@@ -242,13 +277,19 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
return (u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000;
}
+static inline JSValue __JS_NewShortBigInt(JSContext *ctx, int64_t d)
+{
+ JSValue v;
+ v.tag = JS_TAG_SHORT_BIG_INT;
+ v.u.short_big_int = d;
+ return v;
+}
+
#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 */
@@ -290,7 +331,9 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
#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)
+#ifndef JS_DEFAULT_STACK_SIZE
+#define JS_DEFAULT_STACK_SIZE (1024 * 1024)
+#endif
/* JS_Eval() flags */
#define JS_EVAL_TYPE_GLOBAL (0 << 0) /* global code (default) */
@@ -300,13 +343,15 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
#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)
+/* allow top-level await in normal script. JS_Eval() returns a
+ promise. Only allowed with JS_EVAL_TYPE_GLOBAL */
+#define JS_EVAL_FLAG_ASYNC (1 << 7)
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);
@@ -370,13 +415,7 @@ 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);
+void JS_AddIntrinsicWeakRef(JSContext *ctx);
JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv);
@@ -426,7 +465,11 @@ 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);
+const char *JS_AtomToCStringLen(JSContext *ctx, size_t *plen, JSAtom atom);
+static inline const char *JS_AtomToCString(JSContext *ctx, JSAtom atom)
+{
+ return JS_AtomToCStringLen(ctx, NULL, atom);
+}
JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val);
/* object class support */
@@ -471,6 +514,17 @@ typedef struct JSClassExoticMethods {
/* return < 0 if exception or TRUE/FALSE */
int (*set_property)(JSContext *ctx, JSValueConst obj, JSAtom atom,
JSValueConst value, JSValueConst receiver, int flags);
+
+ /* To get a consistent object behavior when get_prototype != NULL,
+ get_property, set_property and set_prototype must be != NULL
+ and the object must be created with a JS_NULL prototype. */
+ JSValue (*get_prototype)(JSContext *ctx, JSValueConst obj);
+ /* return < 0 if exception or TRUE/FALSE */
+ int (*set_prototype)(JSContext *ctx, JSValueConst obj, JSValueConst proto_val);
+ /* return < 0 if exception or TRUE/FALSE */
+ int (*is_extensible)(JSContext *ctx, JSValueConst obj);
+ /* return < 0 if exception or TRUE/FALSE */
+ int (*prevent_extensions)(JSContext *ctx, JSValueConst obj);
} JSClassExoticMethods;
typedef void JSClassFinalizer(JSRuntime *rt, JSValue val);
@@ -496,8 +550,10 @@ typedef struct JSClassDef {
JSClassExoticMethods *exotic;
} JSClassDef;
+#define JS_INVALID_CLASS_ID 0
JSClassID JS_NewClassID(JSClassID *pclass_id);
-JSClassID JS_GetClassID(JSValueConst v);
+/* Returns the class ID if `v` is an object, otherwise returns JS_INVALID_CLASS_ID. */
+JSClassID JS_GetClassID(JSValue v);
int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def);
int JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id);
@@ -545,23 +601,21 @@ JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v);
static js_force_inline 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);
+ if (d >= INT32_MIN && d <= INT32_MAX) {
+ 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)
+ return JS_MKVAL(JS_TAG_INT, val);
}
- return v;
+ return __JS_NewFloat64(ctx, d);
}
static inline JS_BOOL JS_IsNumber(JSValueConst v)
@@ -573,19 +627,7 @@ static inline JS_BOOL JS_IsNumber(JSValueConst v)
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;
+ return tag == JS_TAG_BIG_INT || tag == JS_TAG_SHORT_BIG_INT;
}
static inline JS_BOOL JS_IsBool(JSValueConst v)
@@ -615,7 +657,8 @@ static inline JS_BOOL JS_IsUninitialized(JSValueConst v)
static inline JS_BOOL JS_IsString(JSValueConst v)
{
- return JS_VALUE_GET_TAG(v) == JS_TAG_STRING;
+ return JS_VALUE_GET_TAG(v) == JS_TAG_STRING ||
+ JS_VALUE_GET_TAG(v) == JS_TAG_STRING_ROPE;
}
static inline JS_BOOL JS_IsSymbol(JSValueConst v)
@@ -629,9 +672,10 @@ static inline JS_BOOL JS_IsObject(JSValueConst v)
}
JSValue JS_Throw(JSContext *ctx, JSValue obj);
+void JS_SetUncatchableException(JSContext *ctx, JS_BOOL flag);
JSValue JS_GetException(JSContext *ctx);
+JS_BOOL JS_HasException(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, ...);
@@ -667,7 +711,7 @@ static inline JSValue JS_DupValue(JSContext *ctx, JSValueConst v)
JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
p->ref_count++;
}
- return (JSValue)v;
+ return v;
}
static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v)
@@ -676,9 +720,13 @@ static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v)
JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
p->ref_count++;
}
- return (JSValue)v;
+ return v;
}
+JS_BOOL JS_StrictEq(JSContext *ctx, JSValueConst op1, JSValueConst op2);
+JS_BOOL JS_SameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2);
+JS_BOOL JS_SameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2);
+
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)
@@ -694,7 +742,10 @@ int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val);
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);
+static inline JSValue JS_NewString(JSContext *ctx, const char *str)
+{
+ return JS_NewStringLen(ctx, str, strlen(str));
+}
JSValue JS_NewAtomString(JSContext *ctx, const char *str);
JSValue JS_ToString(JSContext *ctx, JSValueConst val);
JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val);
@@ -721,6 +772,8 @@ JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, JS_BOOL val)
JSValue JS_NewArray(JSContext *ctx);
int JS_IsArray(JSContext *ctx, JSValueConst val);
+JSValue JS_NewDate(JSContext *ctx, double epoch_ms);
+
JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
JSAtom prop, JSValueConst receiver,
JS_BOOL throw_ref_error);
@@ -765,6 +818,8 @@ JSValue JS_GetPrototype(JSContext *ctx, JSValueConst val);
int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab,
uint32_t *plen, JSValueConst obj, int flags);
+void JS_FreePropertyEnum(JSContext *ctx, JSPropertyEnum *tab,
+ uint32_t len);
int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc,
JSValueConst obj, JSAtom prop);
@@ -802,6 +857,7 @@ int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj,
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);
+void *JS_GetAnyOpaque(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,
@@ -819,6 +875,24 @@ JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len,
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);
+
+typedef enum JSTypedArrayEnum {
+ JS_TYPED_ARRAY_UINT8C = 0,
+ JS_TYPED_ARRAY_INT8,
+ JS_TYPED_ARRAY_UINT8,
+ JS_TYPED_ARRAY_INT16,
+ JS_TYPED_ARRAY_UINT16,
+ JS_TYPED_ARRAY_INT32,
+ JS_TYPED_ARRAY_UINT32,
+ JS_TYPED_ARRAY_BIG_INT64,
+ JS_TYPED_ARRAY_BIG_UINT64,
+ JS_TYPED_ARRAY_FLOAT16,
+ JS_TYPED_ARRAY_FLOAT32,
+ JS_TYPED_ARRAY_FLOAT64,
+} JSTypedArrayEnum;
+
+JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv,
+ JSTypedArrayEnum array_type);
JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,
size_t *pbyte_offset,
size_t *pbyte_length,
@@ -832,7 +906,15 @@ typedef struct {
void JS_SetSharedArrayBufferFunctions(JSRuntime *rt,
const JSSharedArrayBufferFunctions *sf);
+typedef enum JSPromiseStateEnum {
+ JS_PROMISE_PENDING,
+ JS_PROMISE_FULFILLED,
+ JS_PROMISE_REJECTED,
+} JSPromiseStateEnum;
+
JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs);
+JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise);
+JSValue JS_PromiseResult(JSContext *ctx, JSValue promise);
/* is_handled = TRUE means that the rejection is handled */
typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise,
@@ -846,6 +928,12 @@ 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);
+/* select which debug info is stripped from the compiled code */
+#define JS_STRIP_SOURCE (1 << 0) /* strip source code */
+#define JS_STRIP_DEBUG (1 << 1) /* strip all debug info including source code */
+void JS_SetStripInfo(JSRuntime *rt, int flags);
+int JS_GetStripInfo(JSRuntime *rt);
+
/* set the [IsHTMLDDA] internal slot */
void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj);
@@ -858,15 +946,29 @@ typedef char *JSModuleNormalizeFunc(JSContext *ctx,
const char *module_name, void *opaque);
typedef JSModuleDef *JSModuleLoaderFunc(JSContext *ctx,
const char *module_name, void *opaque);
-
+typedef JSModuleDef *JSModuleLoaderFunc2(JSContext *ctx,
+ const char *module_name, void *opaque,
+ JSValueConst attributes);
+/* return -1 if exception, 0 if OK */
+typedef int JSModuleCheckSupportedImportAttributes(JSContext *ctx, void *opaque,
+ JSValueConst attributes);
+
/* 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);
+/* same as JS_SetModuleLoaderFunc but with attributes. if
+ module_check_attrs = NULL, no attribute checking is done. */
+void JS_SetModuleLoaderFunc2(JSRuntime *rt,
+ JSModuleNormalizeFunc *module_normalize,
+ JSModuleLoaderFunc2 *module_loader,
+ JSModuleCheckSupportedImportAttributes *module_check_attrs,
+ void *opaque);
/* return the import.meta object of a module */
JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m);
JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m);
+JSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m);
/* JS Job support */
@@ -904,8 +1006,8 @@ 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);
+JSValue JS_LoadModule(JSContext *ctx, const char *basename,
+ const char *filename);
/* C function definition */
typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */
@@ -959,7 +1061,7 @@ static inline JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *fun
{
return JS_NewCFunction2(ctx, (JSCFunction *)func, name, length, cproto, magic);
}
-void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj,
+void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj,
JSValueConst proto);
/* C property definition */
@@ -1021,9 +1123,9 @@ typedef struct JSCFunctionListEntry {
#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);
+int JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
+ const JSCFunctionListEntry *tab,
+ int len);
/* C module definition */
@@ -1040,6 +1142,29 @@ 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);
+/* associate a JSValue to a C module */
+int JS_SetModulePrivateValue(JSContext *ctx, JSModuleDef *m, JSValue val);
+JSValue JS_GetModulePrivateValue(JSContext *ctx, JSModuleDef *m);
+
+/* debug value output */
+
+typedef struct {
+ JS_BOOL show_hidden : 8; /* only show enumerable properties */
+ JS_BOOL raw_dump : 8; /* avoid doing autoinit and avoid any malloc() call (for internal use) */
+ uint32_t max_depth; /* recurse up to this depth, 0 = no limit */
+ uint32_t max_string_length; /* print no more than this length for
+ strings, 0 = no limit */
+ uint32_t max_item_count; /* print no more than this count for
+ arrays or objects, 0 = no limit */
+} JSPrintValueOptions;
+
+typedef void JSPrintValueWrite(void *opaque, const char *buf, size_t len);
+
+void JS_PrintValueSetDefaultOptions(JSPrintValueOptions *options);
+void JS_PrintValueRT(JSRuntime *rt, JSPrintValueWrite *write_func, void *write_opaque,
+ JSValueConst val, const JSPrintValueOptions *options);
+void JS_PrintValue(JSContext *ctx, JSPrintValueWrite *write_func, void *write_opaque,
+ JSValueConst val, const JSPrintValueOptions *options);
#undef js_unlikely
#undef js_force_inline
diff --git a/quickjs/win/dirent.h b/quickjs/win/dirent.h
new file mode 100644
index 0000000000..077674e45c
--- /dev/null
+++ b/quickjs/win/dirent.h
@@ -0,0 +1,1166 @@
+/*
+ * Dirent interface for Microsoft Visual Studio
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent. Dirent may be freely distributed
+ * under the MIT license. For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+#ifndef DIRENT_H
+#define DIRENT_H
+
+/* Hide warnings about unreferenced local functions */
+#if defined(__clang__)
+# pragma clang diagnostic ignored "-Wunused-function"
+#elif defined(_MSC_VER)
+# pragma warning(disable:4505)
+#elif defined(__GNUC__)
+# pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+/*
+ * Include windows.h without Windows Sockets 1.1 to prevent conflicts with
+ * Windows Sockets 2.0.
+ */
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Indicates that d_type field is available in dirent structure */
+#define _DIRENT_HAVE_D_TYPE
+
+/* Indicates that d_namlen field is available in dirent structure */
+#define _DIRENT_HAVE_D_NAMLEN
+
+/* Entries missing from MSVC 6.0 */
+#if !defined(FILE_ATTRIBUTE_DEVICE)
+# define FILE_ATTRIBUTE_DEVICE 0x40
+#endif
+
+/* File type and permission flags for stat(), general mask */
+#if !defined(S_IFMT)
+# define S_IFMT _S_IFMT
+#endif
+
+/* Directory bit */
+#if !defined(S_IFDIR)
+# define S_IFDIR _S_IFDIR
+#endif
+
+/* Character device bit */
+#if !defined(S_IFCHR)
+# define S_IFCHR _S_IFCHR
+#endif
+
+/* Pipe bit */
+#if !defined(S_IFFIFO)
+# define S_IFFIFO _S_IFFIFO
+#endif
+
+/* Regular file bit */
+#if !defined(S_IFREG)
+# define S_IFREG _S_IFREG
+#endif
+
+/* Read permission */
+#if !defined(S_IREAD)
+# define S_IREAD _S_IREAD
+#endif
+
+/* Write permission */
+#if !defined(S_IWRITE)
+# define S_IWRITE _S_IWRITE
+#endif
+
+/* Execute permission */
+#if !defined(S_IEXEC)
+# define S_IEXEC _S_IEXEC
+#endif
+
+/* Pipe */
+#if !defined(S_IFIFO)
+# define S_IFIFO _S_IFIFO
+#endif
+
+/* Block device */
+#if !defined(S_IFBLK)
+# define S_IFBLK 0
+#endif
+
+/* Link */
+#if !defined(S_IFLNK)
+# define S_IFLNK 0
+#endif
+
+/* Socket */
+#if !defined(S_IFSOCK)
+# define S_IFSOCK 0
+#endif
+
+/* Read user permission */
+#if !defined(S_IRUSR)
+# define S_IRUSR S_IREAD
+#endif
+
+/* Write user permission */
+#if !defined(S_IWUSR)
+# define S_IWUSR S_IWRITE
+#endif
+
+/* Execute user permission */
+#if !defined(S_IXUSR)
+# define S_IXUSR 0
+#endif
+
+/* Read group permission */
+#if !defined(S_IRGRP)
+# define S_IRGRP 0
+#endif
+
+/* Write group permission */
+#if !defined(S_IWGRP)
+# define S_IWGRP 0
+#endif
+
+/* Execute group permission */
+#if !defined(S_IXGRP)
+# define S_IXGRP 0
+#endif
+
+/* Read others permission */
+#if !defined(S_IROTH)
+# define S_IROTH 0
+#endif
+
+/* Write others permission */
+#if !defined(S_IWOTH)
+# define S_IWOTH 0
+#endif
+
+/* Execute others permission */
+#if !defined(S_IXOTH)
+# define S_IXOTH 0
+#endif
+
+/* Maximum length of file name */
+#if !defined(PATH_MAX)
+# define PATH_MAX MAX_PATH
+#endif
+#if !defined(FILENAME_MAX)
+# define FILENAME_MAX MAX_PATH
+#endif
+#if !defined(NAME_MAX)
+# define NAME_MAX FILENAME_MAX
+#endif
+
+/* File type flags for d_type */
+#define DT_UNKNOWN 0
+#define DT_REG S_IFREG
+#define DT_DIR S_IFDIR
+#define DT_FIFO S_IFIFO
+#define DT_SOCK S_IFSOCK
+#define DT_CHR S_IFCHR
+#define DT_BLK S_IFBLK
+#define DT_LNK S_IFLNK
+
+/* Macros for converting between st_mode and d_type */
+#define IFTODT(mode) ((mode) & S_IFMT)
+#define DTTOIF(type) (type)
+
+/*
+ * File type macros. Note that block devices, sockets and links cannot be
+ * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
+ * only defined for compatibility. These macros should always return false
+ * on Windows.
+ */
+#if !defined(S_ISFIFO)
+# define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISDIR)
+# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG)
+# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISLNK)
+# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK)
+# define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISCHR)
+# define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISBLK)
+# define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
+#endif
+
+/* Return the exact length of the file name without zero terminator */
+#define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
+
+/* Return the maximum size of a file name */
+#define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1)
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Wide-character version */
+struct _wdirent {
+ /* Always zero */
+ long d_ino;
+
+ /* File position within stream */
+ long d_off;
+
+ /* Structure size */
+ unsigned short d_reclen;
+
+ /* Length of name without \0 */
+ size_t d_namlen;
+
+ /* File type */
+ int d_type;
+
+ /* File name */
+ wchar_t d_name[PATH_MAX+1];
+};
+typedef struct _wdirent _wdirent;
+
+struct _WDIR {
+ /* Current directory entry */
+ struct _wdirent ent;
+
+ /* Private file data */
+ WIN32_FIND_DATAW data;
+
+ /* True if data is valid */
+ int cached;
+
+ /* Win32 search handle */
+ HANDLE handle;
+
+ /* Initial directory name */
+ wchar_t *patt;
+};
+typedef struct _WDIR _WDIR;
+
+/* Multi-byte character version */
+struct dirent {
+ /* Always zero */
+ long d_ino;
+
+ /* File position within stream */
+ long d_off;
+
+ /* Structure size */
+ unsigned short d_reclen;
+
+ /* Length of name without \0 */
+ size_t d_namlen;
+
+ /* File type */
+ int d_type;
+
+ /* File name */
+ char d_name[PATH_MAX+1];
+};
+typedef struct dirent dirent;
+
+struct DIR {
+ struct dirent ent;
+ struct _WDIR *wdirp;
+};
+typedef struct DIR DIR;
+
+
+/* Dirent functions */
+static DIR *opendir (const char *dirname);
+static _WDIR *_wopendir (const wchar_t *dirname);
+
+static struct dirent *readdir (DIR *dirp);
+static struct _wdirent *_wreaddir (_WDIR *dirp);
+
+static int readdir_r(
+ DIR *dirp, struct dirent *entry, struct dirent **result);
+static int _wreaddir_r(
+ _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result);
+
+static int closedir (DIR *dirp);
+static int _wclosedir (_WDIR *dirp);
+
+static void rewinddir (DIR* dirp);
+static void _wrewinddir (_WDIR* dirp);
+
+static int scandir (const char *dirname, struct dirent ***namelist,
+ int (*filter)(const struct dirent*),
+ int (*compare)(const struct dirent**, const struct dirent**));
+
+static int alphasort (const struct dirent **a, const struct dirent **b);
+
+static int versionsort (const struct dirent **a, const struct dirent **b);
+
+
+/* For compatibility with Symbian */
+#define wdirent _wdirent
+#define WDIR _WDIR
+#define wopendir _wopendir
+#define wreaddir _wreaddir
+#define wclosedir _wclosedir
+#define wrewinddir _wrewinddir
+
+
+/* Internal utility functions */
+static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp);
+static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp);
+
+static int dirent_mbstowcs_s(
+ size_t *pReturnValue,
+ wchar_t *wcstr,
+ size_t sizeInWords,
+ const char *mbstr,
+ size_t count);
+
+static int dirent_wcstombs_s(
+ size_t *pReturnValue,
+ char *mbstr,
+ size_t sizeInBytes,
+ const wchar_t *wcstr,
+ size_t count);
+
+static void dirent_set_errno (int error);
+
+
+/*
+ * Open directory stream DIRNAME for read and return a pointer to the
+ * internal working area that is used to retrieve individual directory
+ * entries.
+ */
+static _WDIR*
+_wopendir(
+ const wchar_t *dirname)
+{
+ _WDIR *dirp;
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+ /* Desktop */
+ DWORD n;
+#else
+ /* WinRT */
+ size_t n;
+#endif
+ wchar_t *p;
+
+ /* Must have directory name */
+ if (dirname == NULL || dirname[0] == '\0') {
+ dirent_set_errno (ENOENT);
+ return NULL;
+ }
+
+ /* Allocate new _WDIR structure */
+ dirp = (_WDIR*) malloc (sizeof (struct _WDIR));
+ if (!dirp) {
+ return NULL;
+ }
+
+ /* Reset _WDIR structure */
+ dirp->handle = INVALID_HANDLE_VALUE;
+ dirp->patt = NULL;
+ dirp->cached = 0;
+
+ /*
+ * Compute the length of full path plus zero terminator
+ *
+ * Note that on WinRT there's no way to convert relative paths
+ * into absolute paths, so just assume it is an absolute path.
+ */
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+ /* Desktop */
+ n = GetFullPathNameW (dirname, 0, NULL, NULL);
+#else
+ /* WinRT */
+ n = wcslen (dirname);
+#endif
+
+ /* Allocate room for absolute directory name and search pattern */
+ dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16);
+ if (dirp->patt == NULL) {
+ goto exit_closedir;
+ }
+
+ /*
+ * Convert relative directory name to an absolute one. This
+ * allows rewinddir() to function correctly even when current
+ * working directory is changed between opendir() and rewinddir().
+ *
+ * Note that on WinRT there's no way to convert relative paths
+ * into absolute paths, so just assume it is an absolute path.
+ */
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+ /* Desktop */
+ n = GetFullPathNameW (dirname, n, dirp->patt, NULL);
+ if (n <= 0) {
+ goto exit_closedir;
+ }
+#else
+ /* WinRT */
+ wcsncpy_s (dirp->patt, n+1, dirname, n);
+#endif
+
+ /* Append search pattern \* to the directory name */
+ p = dirp->patt + n;
+ switch (p[-1]) {
+ case '\\':
+ case '/':
+ case ':':
+ /* Directory ends in path separator, e.g. c:\temp\ */
+ /*NOP*/;
+ break;
+
+ default:
+ /* Directory name doesn't end in path separator */
+ *p++ = '\\';
+ }
+ *p++ = '*';
+ *p = '\0';
+
+ /* Open directory stream and retrieve the first entry */
+ if (!dirent_first (dirp)) {
+ goto exit_closedir;
+ }
+
+ /* Success */
+ return dirp;
+
+ /* Failure */
+exit_closedir:
+ _wclosedir (dirp);
+ return NULL;
+}
+
+/*
+ * Read next directory entry.
+ *
+ * Returns pointer to static directory entry which may be overwritten by
+ * subsequent calls to _wreaddir().
+ */
+static struct _wdirent*
+_wreaddir(
+ _WDIR *dirp)
+{
+ struct _wdirent *entry;
+
+ /*
+ * Read directory entry to buffer. We can safely ignore the return value
+ * as entry will be set to NULL in case of error.
+ */
+ (void) _wreaddir_r (dirp, &dirp->ent, &entry);
+
+ /* Return pointer to statically allocated directory entry */
+ return entry;
+}
+
+/*
+ * Read next directory entry.
+ *
+ * Returns zero on success. If end of directory stream is reached, then sets
+ * result to NULL and returns zero.
+ */
+static int
+_wreaddir_r(
+ _WDIR *dirp,
+ struct _wdirent *entry,
+ struct _wdirent **result)
+{
+ WIN32_FIND_DATAW *datap;
+
+ /* Read next directory entry */
+ datap = dirent_next (dirp);
+ if (datap) {
+ size_t n;
+ DWORD attr;
+
+ /*
+ * Copy file name as wide-character string. If the file name is too
+ * long to fit in to the destination buffer, then truncate file name
+ * to PATH_MAX characters and zero-terminate the buffer.
+ */
+ n = 0;
+ while (n < PATH_MAX && datap->cFileName[n] != 0) {
+ entry->d_name[n] = datap->cFileName[n];
+ n++;
+ }
+ entry->d_name[n] = 0;
+
+ /* Length of file name excluding zero terminator */
+ entry->d_namlen = n;
+
+ /* File type */
+ attr = datap->dwFileAttributes;
+ if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
+ entry->d_type = DT_CHR;
+ } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+ entry->d_type = DT_DIR;
+ } else {
+ entry->d_type = DT_REG;
+ }
+
+ /* Reset dummy fields */
+ entry->d_ino = 0;
+ entry->d_off = 0;
+ entry->d_reclen = sizeof (struct _wdirent);
+
+ /* Set result address */
+ *result = entry;
+
+ } else {
+
+ /* Return NULL to indicate end of directory */
+ *result = NULL;
+
+ }
+
+ return /*OK*/0;
+}
+
+/*
+ * Close directory stream opened by opendir() function. This invalidates the
+ * DIR structure as well as any directory entry read previously by
+ * _wreaddir().
+ */
+static int
+_wclosedir(
+ _WDIR *dirp)
+{
+ int ok;
+ if (dirp) {
+
+ /* Release search handle */
+ if (dirp->handle != INVALID_HANDLE_VALUE) {
+ FindClose (dirp->handle);
+ }
+
+ /* Release search pattern */
+ free (dirp->patt);
+
+ /* Release directory structure */
+ free (dirp);
+ ok = /*success*/0;
+
+ } else {
+
+ /* Invalid directory stream */
+ dirent_set_errno (EBADF);
+ ok = /*failure*/-1;
+
+ }
+ return ok;
+}
+
+/*
+ * Rewind directory stream such that _wreaddir() returns the very first
+ * file name again.
+ */
+static void
+_wrewinddir(
+ _WDIR* dirp)
+{
+ if (dirp) {
+ /* Release existing search handle */
+ if (dirp->handle != INVALID_HANDLE_VALUE) {
+ FindClose (dirp->handle);
+ }
+
+ /* Open new search handle */
+ dirent_first (dirp);
+ }
+}
+
+/* Get first directory entry (internal) */
+static WIN32_FIND_DATAW*
+dirent_first(
+ _WDIR *dirp)
+{
+ WIN32_FIND_DATAW *datap;
+ DWORD error;
+
+ /* Open directory and retrieve the first entry */
+ dirp->handle = FindFirstFileExW(
+ dirp->patt, FindExInfoStandard, &dirp->data,
+ FindExSearchNameMatch, NULL, 0);
+ if (dirp->handle != INVALID_HANDLE_VALUE) {
+
+ /* a directory entry is now waiting in memory */
+ datap = &dirp->data;
+ dirp->cached = 1;
+
+ } else {
+
+ /* Failed to open directory: no directory entry in memory */
+ dirp->cached = 0;
+ datap = NULL;
+
+ /* Set error code */
+ error = GetLastError ();
+ switch (error) {
+ case ERROR_ACCESS_DENIED:
+ /* No read access to directory */
+ dirent_set_errno (EACCES);
+ break;
+
+ case ERROR_DIRECTORY:
+ /* Directory name is invalid */
+ dirent_set_errno (ENOTDIR);
+ break;
+
+ case ERROR_PATH_NOT_FOUND:
+ default:
+ /* Cannot find the file */
+ dirent_set_errno (ENOENT);
+ }
+
+ }
+ return datap;
+}
+
+/*
+ * Get next directory entry (internal).
+ *
+ * Returns
+ */
+static WIN32_FIND_DATAW*
+dirent_next(
+ _WDIR *dirp)
+{
+ WIN32_FIND_DATAW *p;
+
+ /* Get next directory entry */
+ if (dirp->cached != 0) {
+
+ /* A valid directory entry already in memory */
+ p = &dirp->data;
+ dirp->cached = 0;
+
+ } else if (dirp->handle != INVALID_HANDLE_VALUE) {
+
+ /* Get the next directory entry from stream */
+ if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) {
+ /* Got a file */
+ p = &dirp->data;
+ } else {
+ /* The very last entry has been processed or an error occurred */
+ FindClose (dirp->handle);
+ dirp->handle = INVALID_HANDLE_VALUE;
+ p = NULL;
+ }
+
+ } else {
+
+ /* End of directory stream reached */
+ p = NULL;
+
+ }
+
+ return p;
+}
+
+/*
+ * Open directory stream using plain old C-string.
+ */
+static DIR*
+opendir(
+ const char *dirname)
+{
+ struct DIR *dirp;
+
+ /* Must have directory name */
+ if (dirname == NULL || dirname[0] == '\0') {
+ dirent_set_errno (ENOENT);
+ return NULL;
+ }
+
+ /* Allocate memory for DIR structure */
+ dirp = (DIR*) malloc (sizeof (struct DIR));
+ if (!dirp) {
+ return NULL;
+ }
+ {
+ int error;
+ wchar_t wname[PATH_MAX + 1];
+ size_t n;
+
+ /* Convert directory name to wide-character string */
+ error = dirent_mbstowcs_s(
+ &n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1);
+ if (error) {
+ /*
+ * Cannot convert file name to wide-character string. This
+ * occurs if the string contains invalid multi-byte sequences or
+ * the output buffer is too small to contain the resulting
+ * string.
+ */
+ goto exit_free;
+ }
+
+
+ /* Open directory stream using wide-character name */
+ dirp->wdirp = _wopendir (wname);
+ if (!dirp->wdirp) {
+ goto exit_free;
+ }
+
+ }
+
+ /* Success */
+ return dirp;
+
+ /* Failure */
+exit_free:
+ free (dirp);
+ return NULL;
+}
+
+/*
+ * Read next directory entry.
+ */
+static struct dirent*
+readdir(
+ DIR *dirp)
+{
+ struct dirent *entry;
+
+ /*
+ * Read directory entry to buffer. We can safely ignore the return value
+ * as entry will be set to NULL in case of error.
+ */
+ (void) readdir_r (dirp, &dirp->ent, &entry);
+
+ /* Return pointer to statically allocated directory entry */
+ return entry;
+}
+
+/*
+ * Read next directory entry into called-allocated buffer.
+ *
+ * Returns zero on success. If the end of directory stream is reached, then
+ * sets result to NULL and returns zero.
+ */
+static int
+readdir_r(
+ DIR *dirp,
+ struct dirent *entry,
+ struct dirent **result)
+{
+ WIN32_FIND_DATAW *datap;
+
+ /* Read next directory entry */
+ datap = dirent_next (dirp->wdirp);
+ if (datap) {
+ size_t n;
+ int error;
+
+ /* Attempt to convert file name to multi-byte string */
+ error = dirent_wcstombs_s(
+ &n, entry->d_name, PATH_MAX + 1, datap->cFileName, PATH_MAX + 1);
+
+ /*
+ * If the file name cannot be represented by a multi-byte string,
+ * then attempt to use old 8+3 file name. This allows traditional
+ * Unix-code to access some file names despite of unicode
+ * characters, although file names may seem unfamiliar to the user.
+ *
+ * Be ware that the code below cannot come up with a short file
+ * name unless the file system provides one. At least
+ * VirtualBox shared folders fail to do this.
+ */
+ if (error && datap->cAlternateFileName[0] != '\0') {
+ error = dirent_wcstombs_s(
+ &n, entry->d_name, PATH_MAX + 1,
+ datap->cAlternateFileName, PATH_MAX + 1);
+ }
+
+ if (!error) {
+ DWORD attr;
+
+ /* Length of file name excluding zero terminator */
+ entry->d_namlen = n - 1;
+
+ /* File attributes */
+ attr = datap->dwFileAttributes;
+ if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
+ entry->d_type = DT_CHR;
+ } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+ entry->d_type = DT_DIR;
+ } else {
+ entry->d_type = DT_REG;
+ }
+
+ /* Reset dummy fields */
+ entry->d_ino = 0;
+ entry->d_off = 0;
+ entry->d_reclen = sizeof (struct dirent);
+
+ } else {
+
+ /*
+ * Cannot convert file name to multi-byte string so construct
+ * an erroneous directory entry and return that. Note that
+ * we cannot return NULL as that would stop the processing
+ * of directory entries completely.
+ */
+ entry->d_name[0] = '?';
+ entry->d_name[1] = '\0';
+ entry->d_namlen = 1;
+ entry->d_type = DT_UNKNOWN;
+ entry->d_ino = 0;
+ entry->d_off = -1;
+ entry->d_reclen = 0;
+
+ }
+
+ /* Return pointer to directory entry */
+ *result = entry;
+
+ } else {
+
+ /* No more directory entries */
+ *result = NULL;
+
+ }
+
+ return /*OK*/0;
+}
+
+/*
+ * Close directory stream.
+ */
+static int
+closedir(
+ DIR *dirp)
+{
+ int ok;
+ if (dirp) {
+
+ /* Close wide-character directory stream */
+ ok = _wclosedir (dirp->wdirp);
+ dirp->wdirp = NULL;
+
+ /* Release multi-byte character version */
+ free (dirp);
+
+ } else {
+
+ /* Invalid directory stream */
+ dirent_set_errno (EBADF);
+ ok = /*failure*/-1;
+
+ }
+ return ok;
+}
+
+/*
+ * Rewind directory stream to beginning.
+ */
+static void
+rewinddir(
+ DIR* dirp)
+{
+ /* Rewind wide-character string directory stream */
+ _wrewinddir (dirp->wdirp);
+}
+
+/*
+ * Scan directory for entries.
+ */
+static int
+scandir(
+ const char *dirname,
+ struct dirent ***namelist,
+ int (*filter)(const struct dirent*),
+ int (*compare)(const struct dirent**, const struct dirent**))
+{
+ struct dirent **files = NULL;
+ size_t size = 0;
+ size_t allocated = 0;
+ const size_t init_size = 1;
+ DIR *dir = NULL;
+ struct dirent *entry;
+ struct dirent *tmp = NULL;
+ size_t i;
+ int result = 0;
+
+ /* Open directory stream */
+ dir = opendir (dirname);
+ if (dir) {
+
+ /* Read directory entries to memory */
+ while (1) {
+
+ /* Enlarge pointer table to make room for another pointer */
+ if (size >= allocated) {
+ void *p;
+ size_t num_entries;
+
+ /* Compute number of entries in the enlarged pointer table */
+ if (size < init_size) {
+ /* Allocate initial pointer table */
+ num_entries = init_size;
+ } else {
+ /* Double the size */
+ num_entries = size * 2;
+ }
+
+ /* Allocate first pointer table or enlarge existing table */
+ p = realloc (files, sizeof (void*) * num_entries);
+ if (p != NULL) {
+ /* Got the memory */
+ files = (dirent**) p;
+ allocated = num_entries;
+ } else {
+ /* Out of memory */
+ result = -1;
+ break;
+ }
+
+ }
+
+ /* Allocate room for temporary directory entry */
+ if (tmp == NULL) {
+ tmp = (struct dirent*) malloc (sizeof (struct dirent));
+ if (tmp == NULL) {
+ /* Cannot allocate temporary directory entry */
+ result = -1;
+ break;
+ }
+ }
+
+ /* Read directory entry to temporary area */
+ if (readdir_r (dir, tmp, &entry) == /*OK*/0) {
+
+ /* Did we get an entry? */
+ if (entry != NULL) {
+ int pass;
+
+ /* Determine whether to include the entry in result */
+ if (filter) {
+ /* Let the filter function decide */
+ pass = filter (tmp);
+ } else {
+ /* No filter function, include everything */
+ pass = 1;
+ }
+
+ if (pass) {
+ /* Store the temporary entry to pointer table */
+ files[size++] = tmp;
+ tmp = NULL;
+
+ /* Keep up with the number of files */
+ result++;
+ }
+
+ } else {
+
+ /*
+ * End of directory stream reached => sort entries and
+ * exit.
+ */
+ qsort (files, size, sizeof (void*),
+ (int (*) (const void*, const void*)) compare);
+ break;
+
+ }
+
+ } else {
+ /* Error reading directory entry */
+ result = /*Error*/ -1;
+ break;
+ }
+
+ }
+
+ } else {
+ /* Cannot open directory */
+ result = /*Error*/ -1;
+ }
+
+ /* Release temporary directory entry */
+ free (tmp);
+
+ /* Release allocated memory on error */
+ if (result < 0) {
+ for (i = 0; i < size; i++) {
+ free (files[i]);
+ }
+ free (files);
+ files = NULL;
+ }
+
+ /* Close directory stream */
+ if (dir) {
+ closedir (dir);
+ }
+
+ /* Pass pointer table to caller */
+ if (namelist) {
+ *namelist = files;
+ }
+ return result;
+}
+
+/* Alphabetical sorting */
+static int
+alphasort(
+ const struct dirent **a, const struct dirent **b)
+{
+ return strcoll ((*a)->d_name, (*b)->d_name);
+}
+
+/* Sort versions */
+static int
+versionsort(
+ const struct dirent **a, const struct dirent **b)
+{
+ /* FIXME: implement strverscmp and use that */
+ return alphasort (a, b);
+}
+
+/* Convert multi-byte string to wide character string */
+static int
+dirent_mbstowcs_s(
+ size_t *pReturnValue,
+ wchar_t *wcstr,
+ size_t sizeInWords,
+ const char *mbstr,
+ size_t count)
+{
+ int error;
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+
+ /* Microsoft Visual Studio 2005 or later */
+ error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count);
+
+#else
+
+ /* Older Visual Studio or non-Microsoft compiler */
+ size_t n;
+
+ /* Convert to wide-character string (or count characters) */
+ n = mbstowcs (wcstr, mbstr, sizeInWords);
+ if (!wcstr || n < count) {
+
+ /* Zero-terminate output buffer */
+ if (wcstr && sizeInWords) {
+ if (n >= sizeInWords) {
+ n = sizeInWords - 1;
+ }
+ wcstr[n] = 0;
+ }
+
+ /* Length of resulting multi-byte string WITH zero terminator */
+ if (pReturnValue) {
+ *pReturnValue = n + 1;
+ }
+
+ /* Success */
+ error = 0;
+
+ } else {
+
+ /* Could not convert string */
+ error = 1;
+
+ }
+
+#endif
+ return error;
+}
+
+/* Convert wide-character string to multi-byte string */
+static int
+dirent_wcstombs_s(
+ size_t *pReturnValue,
+ char *mbstr,
+ size_t sizeInBytes, /* max size of mbstr */
+ const wchar_t *wcstr,
+ size_t count)
+{
+ int error;
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+
+ /* Microsoft Visual Studio 2005 or later */
+ error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count);
+
+#else
+
+ /* Older Visual Studio or non-Microsoft compiler */
+ size_t n;
+
+ /* Convert to multi-byte string (or count the number of bytes needed) */
+ n = wcstombs (mbstr, wcstr, sizeInBytes);
+ if (!mbstr || n < count) {
+
+ /* Zero-terminate output buffer */
+ if (mbstr && sizeInBytes) {
+ if (n >= sizeInBytes) {
+ n = sizeInBytes - 1;
+ }
+ mbstr[n] = '\0';
+ }
+
+ /* Length of resulting multi-bytes string WITH zero-terminator */
+ if (pReturnValue) {
+ *pReturnValue = n + 1;
+ }
+
+ /* Success */
+ error = 0;
+
+ } else {
+
+ /* Cannot convert string */
+ error = 1;
+
+ }
+
+#endif
+ return error;
+}
+
+/* Set errno variable */
+static void
+dirent_set_errno(
+ int error)
+{
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+
+ /* Microsoft Visual Studio 2005 and later */
+ _set_errno (error);
+
+#else
+
+ /* Non-Microsoft compiler or older Microsoft compiler */
+ errno = error;
+
+#endif
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*DIRENT_H*/
\ No newline at end of file
diff --git a/quickjs/win/getopt.h b/quickjs/win/getopt.h
new file mode 100644
index 0000000000..d78b753b2b
--- /dev/null
+++ b/quickjs/win/getopt.h
@@ -0,0 +1,653 @@
+#ifndef __GETOPT_H__
+/**
+ * DISCLAIMER
+ * This file is part of the mingw-w64 runtime package.
+ *
+ * The mingw-w64 runtime package and its code is distributed in the hope that it
+ * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR
+ * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to
+ * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+ /*
+ * Copyright (c) 2002 Todd C. Miller
+ *
+ * Permission to use, copy, modify, and 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.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma warning(disable:4996)
+
+#define __GETOPT_H__
+
+/* All the headers include this file. */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
+
+#ifdef REPLACE_GETOPT
+int opterr = 1; /* if error message should be printed */
+int optind = 1; /* index into parent argv vector */
+int optopt = '?'; /* character checked for validity */
+#undef optreset /* see getopt.h */
+#define optreset __mingw_optreset
+int optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+#endif
+
+//extern int optind; /* index of first non-option in argv */
+//extern int optopt; /* single option character, as parsed */
+//extern int opterr; /* flag to enable built-in diagnostics... */
+// /* (user may set to zero, to suppress) */
+//
+//extern char *optarg; /* pointer to argument of current option */
+
+#define PRINT_ERROR ((opterr) && (*options != ':'))
+
+#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
+#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
+#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
+
+/* return values */
+#define BADCH (int)'?'
+#define BADARG ((*options == ':') ? (int)':' : (int)'?')
+#define INORDER (int)1
+
+#ifndef __CYGWIN__
+#define __progname __argv[0]
+#else
+extern char __declspec(dllimport) *__progname;
+#endif
+
+#ifdef __CYGWIN__
+static char EMSG[] = "";
+#else
+#define EMSG ""
+#endif
+
+static int getopt_internal(int, char * const *, const char *,
+ const struct option *, int *, int);
+static int parse_long_options(char * const *, const char *,
+ const struct option *, int *, int);
+static int gcd(int, int);
+static void permute_args(int, int, int, char * const *);
+
+static char *place = EMSG; /* option letter processing */
+
+/* XXX: set optreset to 1 rather than these two */
+static int nonopt_start = -1; /* first non option argument (for permute) */
+static int nonopt_end = -1; /* first option after non options (for permute) */
+
+/* Error messages */
+static const char recargchar[] = "option requires an argument -- %c";
+static const char recargstring[] = "option requires an argument -- %s";
+static const char ambig[] = "ambiguous option -- %.*s";
+static const char noarg[] = "option doesn't take an argument -- %.*s";
+static const char illoptchar[] = "unknown option -- %c";
+static const char illoptstring[] = "unknown option -- %s";
+
+static void
+_vwarnx(const char *fmt,va_list ap)
+{
+ (void)fprintf(stderr,"%s: ",__progname);
+ if (fmt != NULL)
+ (void)vfprintf(stderr,fmt,ap);
+ (void)fprintf(stderr,"\n");
+}
+
+static void
+warnx(const char *fmt,...)
+{
+ va_list ap;
+ va_start(ap,fmt);
+ _vwarnx(fmt,ap);
+ va_end(ap);
+}
+
+/*
+ * Compute the greatest common divisor of a and b.
+ */
+static int
+gcd(int a, int b)
+{
+ int c;
+
+ c = a % b;
+ while (c != 0) {
+ a = b;
+ b = c;
+ c = a % b;
+ }
+
+ return (b);
+}
+
+/*
+ * Exchange the block from nonopt_start to nonopt_end with the block
+ * from nonopt_end to opt_end (keeping the same order of arguments
+ * in each block).
+ */
+static void
+permute_args(int panonopt_start, int panonopt_end, int opt_end,
+ char * const *nargv)
+{
+ int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+ char *swap;
+
+ /*
+ * compute lengths of blocks and number and size of cycles
+ */
+ nnonopts = panonopt_end - panonopt_start;
+ nopts = opt_end - panonopt_end;
+ ncycle = gcd(nnonopts, nopts);
+ cyclelen = (opt_end - panonopt_start) / ncycle;
+
+ for (i = 0; i < ncycle; i++) {
+ cstart = panonopt_end+i;
+ pos = cstart;
+ for (j = 0; j < cyclelen; j++) {
+ if (pos >= panonopt_end)
+ pos -= nnonopts;
+ else
+ pos += nopts;
+ swap = nargv[pos];
+ /* LINTED const cast */
+ ((char **) nargv)[pos] = nargv[cstart];
+ /* LINTED const cast */
+ ((char **)nargv)[cstart] = swap;
+ }
+ }
+}
+
+#ifdef REPLACE_GETOPT
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ *
+ * [eventually this will replace the BSD getopt]
+ */
+int
+getopt(int nargc, char * const *nargv, const char *options)
+{
+
+ /*
+ * We don't pass FLAG_PERMUTE to getopt_internal() since
+ * the BSD getopt(3) (unlike GNU) has never done this.
+ *
+ * Furthermore, since many privileged programs call getopt()
+ * before dropping privileges it makes sense to keep things
+ * as simple (and bug-free) as possible.
+ */
+ return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
+}
+#endif /* REPLACE_GETOPT */
+
+//extern int getopt(int nargc, char * const *nargv, const char *options);
+
+#ifdef _BSD_SOURCE
+/*
+ * BSD adds the non-standard `optreset' feature, for reinitialisation
+ * of `getopt' parsing. We support this feature, for applications which
+ * proclaim their BSD heritage, before including this header; however,
+ * to maintain portability, developers are advised to avoid it.
+ */
+# define optreset __mingw_optreset
+extern int optreset;
+#endif
+#ifdef __cplusplus
+}
+#endif
+/*
+ * POSIX requires the `getopt' API to be specified in `unistd.h';
+ * thus, `unistd.h' includes this header. However, we do not want
+ * to expose the `getopt_long' or `getopt_long_only' APIs, when
+ * included in this manner. Thus, close the standard __GETOPT_H__
+ * declarations block, and open an additional __GETOPT_LONG_H__
+ * specific block, only when *not* __UNISTD_H_SOURCED__, in which
+ * to declare the extended API.
+ */
+#endif /* !defined(__GETOPT_H__) */
+
+#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
+#define __GETOPT_LONG_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct option /* specification for a long form option... */
+{
+ const char *name; /* option name, without leading hyphens */
+ int has_arg; /* does it take an argument? */
+ int *flag; /* where to save its status, or NULL */
+ int val; /* its associated status value */
+};
+
+enum /* permitted values for its `has_arg' field... */
+{
+ no_argument = 0, /* option never takes an argument */
+ required_argument, /* option always requires an argument */
+ optional_argument /* option may take an argument */
+};
+
+/*
+ * parse_long_options --
+ * Parse long options in argc/argv argument vector.
+ * Returns -1 if short_too is set and the option does not match long_options.
+ */
+static int
+parse_long_options(char * const *nargv, const char *options,
+ const struct option *long_options, int *idx, int short_too)
+{
+ char *current_argv, *has_equal;
+ size_t current_argv_len;
+ int i, ambiguous, match;
+
+#define IDENTICAL_INTERPRETATION(_x, _y) \
+ (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
+ long_options[(_x)].flag == long_options[(_y)].flag && \
+ long_options[(_x)].val == long_options[(_y)].val)
+
+ current_argv = place;
+ match = -1;
+ ambiguous = 0;
+
+ optind++;
+
+ if ((has_equal = strchr(current_argv, '=')) != NULL) {
+ /* argument found (--option=arg) */
+ current_argv_len = has_equal - current_argv;
+ has_equal++;
+ } else
+ current_argv_len = strlen(current_argv);
+
+ for (i = 0; long_options[i].name; i++) {
+ /* find matching long option */
+ if (strncmp(current_argv, long_options[i].name,
+ current_argv_len))
+ continue;
+
+ if (strlen(long_options[i].name) == current_argv_len) {
+ /* exact match */
+ match = i;
+ ambiguous = 0;
+ break;
+ }
+ /*
+ * If this is a known short option, don't allow
+ * a partial match of a single character.
+ */
+ if (short_too && current_argv_len == 1)
+ continue;
+
+ if (match == -1) /* partial match */
+ match = i;
+ else if (!IDENTICAL_INTERPRETATION(i, match))
+ ambiguous = 1;
+ }
+ if (ambiguous) {
+ /* ambiguous abbreviation */
+ if (PRINT_ERROR)
+ warnx(ambig, (int)current_argv_len,
+ current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ if (match != -1) { /* option found */
+ if (long_options[match].has_arg == no_argument
+ && has_equal) {
+ if (PRINT_ERROR)
+ warnx(noarg, (int)current_argv_len,
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ return (BADARG);
+ }
+ if (long_options[match].has_arg == required_argument ||
+ long_options[match].has_arg == optional_argument) {
+ if (has_equal)
+ optarg = has_equal;
+ else if (long_options[match].has_arg ==
+ required_argument) {
+ /*
+ * optional argument doesn't use next nargv
+ */
+ optarg = nargv[optind++];
+ }
+ }
+ if ((long_options[match].has_arg == required_argument)
+ && (optarg == NULL)) {
+ /*
+ * Missing argument; leading ':' indicates no error
+ * should be generated.
+ */
+ if (PRINT_ERROR)
+ warnx(recargstring,
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ --optind;
+ return (BADARG);
+ }
+ } else { /* unknown option */
+ if (short_too) {
+ --optind;
+ return (-1);
+ }
+ if (PRINT_ERROR)
+ warnx(illoptstring, current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ if (idx)
+ *idx = match;
+ if (long_options[match].flag) {
+ *long_options[match].flag = long_options[match].val;
+ return (0);
+ } else
+ return (long_options[match].val);
+#undef IDENTICAL_INTERPRETATION
+}
+
+/*
+ * getopt_internal --
+ * Parse argc/argv argument vector. Called by user level routines.
+ */
+static int
+getopt_internal(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx, int flags)
+{
+ char *oli; /* option letter list index */
+ int optchar, short_too;
+ static int posixly_correct = -1;
+
+ if (options == NULL)
+ return (-1);
+
+ /*
+ * XXX Some GNU programs (like cvs) set optind to 0 instead of
+ * XXX using optreset. Work around this braindamage.
+ */
+ if (optind == 0)
+ optind = optreset = 1;
+
+ /*
+ * Disable GNU extensions if POSIXLY_CORRECT is set or options
+ * string begins with a '+'.
+ *
+ * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
+ * optreset != 0 for GNU compatibility.
+ */
+ if (posixly_correct == -1 || optreset != 0)
+ posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
+ if (*options == '-')
+ flags |= FLAG_ALLARGS;
+ else if (posixly_correct || *options == '+')
+ flags &= ~FLAG_PERMUTE;
+ if (*options == '+' || *options == '-')
+ options++;
+
+ optarg = NULL;
+ if (optreset)
+ nonopt_start = nonopt_end = -1;
+start:
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc) { /* end of argument vector */
+ place = EMSG;
+ if (nonopt_end != -1) {
+ /* do permutation, if we have to */
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ else if (nonopt_start != -1) {
+ /*
+ * If we skipped non-options, set optind
+ * to the first of them.
+ */
+ optind = nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ if (*(place = nargv[optind]) != '-' ||
+ (place[1] == '\0' && strchr(options, '-') == NULL)) {
+ place = EMSG; /* found non-option */
+ if (flags & FLAG_ALLARGS) {
+ /*
+ * GNU extension:
+ * return non-option as argument to option 1
+ */
+ optarg = nargv[optind++];
+ return (INORDER);
+ }
+ if (!(flags & FLAG_PERMUTE)) {
+ /*
+ * If no permutation wanted, stop parsing
+ * at first non-option.
+ */
+ return (-1);
+ }
+ /* do permutation */
+ if (nonopt_start == -1)
+ nonopt_start = optind;
+ else if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ nonopt_start = optind -
+ (nonopt_end - nonopt_start);
+ nonopt_end = -1;
+ }
+ optind++;
+ /* process next argument */
+ goto start;
+ }
+ if (nonopt_start != -1 && nonopt_end == -1)
+ nonopt_end = optind;
+
+ /*
+ * If we have "-" do nothing, if "--" we are done.
+ */
+ if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
+ optind++;
+ place = EMSG;
+ /*
+ * We found an option (--), so if we skipped
+ * non-options, we have to permute.
+ */
+ if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ }
+
+ /*
+ * Check long options if:
+ * 1) we were passed some
+ * 2) the arg is not just "-"
+ * 3) either the arg starts with -- we are getopt_long_only()
+ */
+ if (long_options != NULL && place != nargv[optind] &&
+ (*place == '-' || (flags & FLAG_LONGONLY))) {
+ short_too = 0;
+ if (*place == '-')
+ place++; /* --foo long option */
+ else if (*place != ':' && strchr(options, *place) != NULL)
+ short_too = 1; /* could be short option too */
+
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, short_too);
+ if (optchar != -1) {
+ place = EMSG;
+ return (optchar);
+ }
+ }
+
+ if ((optchar = (int)*place++) == (int)':' ||
+ (optchar == (int)'-' && *place != '\0') ||
+ (oli = (char*)strchr(options, optchar)) == NULL) {
+ /*
+ * If the user specified "-" and '-' isn't listed in
+ * options, return -1 (non-option) as per POSIX.
+ * Otherwise, it is an unknown option character (or ':').
+ */
+ if (optchar == (int)'-' && *place == '\0')
+ return (-1);
+ if (!*place)
+ ++optind;
+ if (PRINT_ERROR)
+ warnx(illoptchar, optchar);
+ optopt = optchar;
+ return (BADCH);
+ }
+ if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
+ /* -W long-option */
+ if (*place) /* no space */
+ /* NOTHING */;
+ else if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ } else /* white space */
+ place = nargv[optind];
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, 0);
+ place = EMSG;
+ return (optchar);
+ }
+ if (*++oli != ':') { /* doesn't take argument */
+ if (!*place)
+ ++optind;
+ } else { /* takes (optional) argument */
+ optarg = NULL;
+ if (*place) /* no white space */
+ optarg = place;
+ else if (oli[1] != ':') { /* arg not optional */
+ if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ } else
+ optarg = nargv[optind];
+ }
+ place = EMSG;
+ ++optind;
+ }
+ /* dump back option letter */
+ return (optchar);
+}
+
+/*
+ * getopt_long --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx)
+{
+
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE));
+}
+
+/*
+ * getopt_long_only --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long_only(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx)
+{
+
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE|FLAG_LONGONLY));
+}
+
+//extern int getopt_long(int nargc, char * const *nargv, const char *options,
+// const struct option *long_options, int *idx);
+//extern int getopt_long_only(int nargc, char * const *nargv, const char *options,
+// const struct option *long_options, int *idx);
+/*
+ * Previous MinGW implementation had...
+ */
+#ifndef HAVE_DECL_GETOPT
+/*
+ * ...for the long form API only; keep this for compatibility.
+ */
+# define HAVE_DECL_GETOPT 1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */
\ No newline at end of file
diff --git a/quickjspp.hpp b/quickjspp.hpp
index b1a2e3f25c..b158e92b0d 100644
--- a/quickjspp.hpp
+++ b/quickjspp.hpp
@@ -406,10 +406,10 @@ struct js_traits>
case JS_TAG_BOOL:
return is_boolean::value || std::is_integral_v || std::is_floating_point_v;
- case JS_TAG_BIG_DECIMAL:
- [[fallthrough]];
- case JS_TAG_BIG_FLOAT:
- [[fallthrough]];
+ //case JS_TAG_BIG_DECIMAL:
+ // [[fallthrough]];
+ //case JS_TAG_BIG_FLOAT:
+ // [[fallthrough]];
case JS_TAG_FLOAT64:
default: // >JS_TAG_FLOAT64 (JS_NAN_BOXING)
return is_double::value || std::is_floating_point_v;
@@ -474,10 +474,10 @@ struct js_traits>
case JS_TAG_EXCEPTION:
break;
- case JS_TAG_BIG_DECIMAL:
- [[fallthrough]];
- case JS_TAG_BIG_FLOAT:
- [[fallthrough]];
+ //case JS_TAG_BIG_DECIMAL:
+ // [[fallthrough]];
+ //case JS_TAG_BIG_FLOAT:
+ // [[fallthrough]];
case JS_TAG_FLOAT64:
[[fallthrough]];
@@ -908,7 +908,7 @@ struct js_traits>
assert(pptr);
const T * ptr = pptr->get();
assert(ptr);
- for(Value T::* member : markOffsets)
+ for(Value (T::*member) : markOffsets)
{
JS_MarkValue(rt, (*ptr.*member).v, mark_func);
}