packages feed

mquickjs-hs (empty) → 0.1.2.4

raw patch · 26 files changed

+29839/−0 lines, 26 filesdep +HUnitdep +QuickCheckdep +aesonsetup-changed

Dependencies added: HUnit, QuickCheck, aeson, base, bytestring, containers, exceptions, inline-c, mquickjs-hs, mtl, scientific, string-conv, tasty, tasty-hunit, tasty-quickcheck, text, time, transformers, unliftio-core, unordered-containers, vector

Files

+ LICENSE view
@@ -0,0 +1,21 @@+MIT License++Copyright (c) 2020 Samuel Balco++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.
+ README.md view
@@ -0,0 +1,55 @@+# mquickjs-hs++This package provides a Haskell wrapper for the [Micro QuickJS](https://github.com/bellard/mquickjs) JavaScript Engine.+It has been inspired by the [quickjs-rs](https://github.com/theduke/quickjs-rs)+and [ocaml-quickjs](https://github.com/dhcmrlchtdj/ocaml-quickjs) libraries.+++## Features++The functionality is quite basic and is currently limited to:+- Evaluating JS code+- Calling a JS function in the global scope+- Marshalling [Aeson Values](https://hackage.haskell.org/package/aeson-1.5.3.0/docs/Data-Aeson.html#t:Value)+    to and from JSValues.+++## Examples++Evaluate an expression:++```hs+import MQuickJS++one_plus_two = mquickjs $ do+  res <- eval "1+2"+  liftIO $ print res+```++Declare a function and call it on an argument:++```hs+call_f = mquickjs $ do+  _ <- eval_ "function f(x) { return x + 1; }"+  res <- eval "f(2)"+  liftIO $ print res+```++Pass a Haskell value+(which has a [ToJSON](https://hackage.haskell.org/package/aeson-1.5.3.0/docs/Data-Aeson.html#t:ToJSON) instance)+to the JS runtime:++```hs+aeson_marshall = mquickjs $ do+  _ <- eval_ "function f(x) { return x + 1; }"+  res <- withJSValue (3::Int) $ \x -> call "f" [x]+  liftIO $ print res+```+++## Contributing++Please feel free to report bugs/submit feature requests via the+[github issue tracker](https://github.com/ad-si/mquickjs-hs/issues)+and submit any pull requests to the+[git repository](https://github.com/ad-si/mquickjs-hs/).
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ changelog.md view
@@ -0,0 +1,6 @@+# Changelog for mquickjs-hs++## 2026-01-14 - 0.1++* Initial implementation based on+  [quickjs-hs](https://github.com/haskell-github-trust/quickjs-hs)
+ mquickjs-hs.cabal view
@@ -0,0 +1,88 @@+cabal-version:      1.12+name:               mquickjs-hs+version:            0.1.2.4+homepage:           https://github.com/ad-si/mquickjs-hs#readme+bug-reports:        https://github.com/ad-si/mquickjs-hs/issues+author:             Sam Balco, Adrian Sieber+maintainer:         haskell@ad-si.com+copyright:          2020 Sam Balco, 2026 Adrian Sieber+license:            MIT+license-file:       LICENSE+build-type:         Simple+extra-source-files:+  changelog.md+  README.md++category:           JavaScript+synopsis:           Wrapper for the Micro QuickJS JavaScript Engine+description:+  This library is a wrapper for+  [Micro QuickJS](https://github.com/bellard/mquickjs),+  a compact JavaScript Engine.+  .+  To get started, see the Readme below.++extra-source-files: mquickjs/*.h++source-repository head+  type:     git+  location: https://github.com/ad-si/mquickjs-hs++library+  exposed-modules:+    MQuickJS+    MQuickJS.Error+    MQuickJS.Types++  other-modules:    Paths_mquickjs_hs+  hs-source-dirs:   src+  build-depends:+      aeson                 >=2.0   && <2.3+    , base                  >=4.11  && <5+    , bytestring            >=0.10  && <0.13+    , containers            >=0.5   && <0.8+    , exceptions            >=0.8   && <0.11+    , inline-c              >=0.5   && <0.10+    , mtl                   >=2.2.2 && <2.4+    , scientific            >=0.3.5 && <0.4+    , string-conv           >=0.1.2 && <0.3+    , text                  >=1.2.0 && <2.2+    , time                  >=1.8   && <1.14+    , transformers          >=0.5   && <0.7+    , unliftio-core         >=0.1   && <0.3+    , unordered-containers  >=0.2.8 && <0.3+    , vector                >=0.12  && <0.14++  default-language: Haskell2010+  include-dirs:     mquickjs+  c-sources:+    mquickjs/cutils.c+    mquickjs/dtoa.c+    mquickjs/libm.c+    mquickjs/mquickjs.c+    mquickjs/stdlib_wrapper.c++  includes:         mquickjs/mquickjs.h+  install-includes: mquickjs/mquickjs.h+  cc-options:       -static -D_GNU_SOURCE -include stddef.h++test-suite mquickjs-hs-test+  type:             exitcode-stdio-1.0+  main-is:          Spec.hs+  hs-source-dirs:   test+  other-modules:    Paths_mquickjs_hs+  default-language: Haskell2010+  ghc-options:      -threaded -rtsopts -with-rtsopts=-N+  build-depends:+      aeson+    , base+    , exceptions+    , HUnit                 >=1.6.0.0+    , mquickjs-hs+    , QuickCheck            >=2.9+    , tasty                 >=1.0+    , tasty-hunit           >=0.10+    , tasty-quickcheck      >=0.9+    , text+    , unordered-containers+    , vector
+ mquickjs/cutils.c view
@@ -0,0 +1,178 @@+/*+ * C utilities+ * + * Copyright (c) 2017 Fabrice Bellard+ * Copyright (c) 2018 Charlie Gordon+ *+ * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ *+ * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+ * THE SOFTWARE.+ */+#include <stdlib.h>+#include <stdio.h>+#include <stdarg.h>+#include <string.h>++#include "cutils.h"++void pstrcpy(char *buf, int buf_size, const char *str)+{+    int c;+    char *q = buf;++    if (buf_size <= 0)+        return;++    for(;;) {+        c = *str++;+        if (c == 0 || q >= buf + buf_size - 1)+            break;+        *q++ = c;+    }+    *q = '\0';+}++/* strcat and truncate. */+char *pstrcat(char *buf, int buf_size, const char *s)+{+    int len;+    len = strlen(buf);+    if (len < buf_size)+        pstrcpy(buf + len, buf_size - len, s);+    return buf;+}++int strstart(const char *str, const char *val, const char **ptr)+{+    const char *p, *q;+    p = str;+    q = val;+    while (*q != '\0') {+        if (*p != *q)+            return 0;+        p++;+        q++;+    }+    if (ptr)+        *ptr = p;+    return 1;+}++int has_suffix(const char *str, const char *suffix)+{+    size_t len = strlen(str);+    size_t slen = strlen(suffix);+    return (len >= slen && !memcmp(str + len - slen, suffix, slen));+}++size_t __unicode_to_utf8(uint8_t *buf, unsigned int c)+{+    uint8_t *q = buf;++    if (c < 0x800) {+        *q++ = (c >> 6) | 0xc0;+    } else {+        if (c < 0x10000) {+            *q++ = (c >> 12) | 0xe0;+        } else {+            if (c < 0x00200000) {+                *q++ = (c >> 18) | 0xf0;+            } else {+                return 0;+            }+            *q++ = ((c >> 12) & 0x3f) | 0x80;+        }+        *q++ = ((c >> 6) & 0x3f) | 0x80;+    }+    *q++ = (c & 0x3f) | 0x80;+    return q - buf;+}++int __unicode_from_utf8(const uint8_t *p, size_t max_len, size_t *plen)+{+    size_t len = 1;+    int c;+    +    c = p[0];+    if (c < 0xc0) {+        goto fail;+    } else if (c < 0xe0) {+        if (unlikely(max_len < 2 || (p[1] & 0xc0) != 0x80))+            goto fail;+        c = ((p[0] & 0x1f) << 6) | (p[1] & 0x3f);+        len = 2;+        if (unlikely(c < 0x80))+            goto fail;+    } else if (c < 0xf0) {+        if (unlikely(max_len < 2 || (p[1] & 0xc0) != 0x80))+            goto fail;+        if (unlikely(max_len < 3 || (p[2] & 0xc0) != 0x80)) {+            len = 2;+            goto fail;+        }+        c = ((p[0] & 0x0f) << 12) | ((p[1] & 0x3f) << 6) | (p[2] & 0x3f);+        len = 3;+        if (unlikely(c < 0x800))+            goto fail;+    } else if (c < 0xf8) {+        if (unlikely(max_len < 2 || (p[1] & 0xc0) != 0x80))+            goto fail;+        if (unlikely(max_len < 3 || (p[2] & 0xc0) != 0x80)) {+            len = 2;+            goto fail;+        }+        if (unlikely(max_len < 4 || (p[3] & 0xc0) != 0x80)) {+            len = 3;+            goto fail;+        }+        c = ((p[0] & 0x07) << 18) | ((p[1] & 0x3f) << 12) | ((p[2] & 0x3f) << 6) | (p[3] & 0x3f);+        len = 4;+        /* We explicitly accept surrogate pairs */+        if (unlikely(c < 0x10000 || c > 0x10ffff))+            goto fail;+    } else {+    fail:+        *plen = len;+        return -1;+    }+    *plen = len;+    return c;+}++int __utf8_get(const uint8_t *p, size_t *plen)+{+    size_t len;+    int c;+    +    c = p[0];+    if (c < 0xc0) {+        len = 1;+    } else if (c < 0xe0) {+        c = ((p[0] & 0x1f) << 6) | (p[1] & 0x3f);+        len = 2;+    } else if (c < 0xf0) {+        c = ((p[0] & 0x0f) << 12) | ((p[1] & 0x3f) << 6) | (p[2] & 0x3f);+        len = 3;+    } else if (c < 0xf8) {+        c = ((p[0] & 0x07) << 18) | ((p[1] & 0x3f) << 12) | ((p[2] & 0x3f) << 6) | (p[3] & 0x3f);+        len = 4;+    } else {+        len = 1;+    }+    *plen = len;+    return c;+}
+ mquickjs/cutils.h view
@@ -0,0 +1,355 @@+/*+ * C utilities+ * + * Copyright (c) 2017 Fabrice Bellard+ * Copyright (c) 2018 Charlie Gordon+ *+ * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ *+ * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+ * THE SOFTWARE.+ */+#ifndef CUTILS_H+#define CUTILS_H++#include <stdlib.h>+#include <inttypes.h>++/* set if CPU is big endian */+#undef WORDS_BIGENDIAN++#define likely(x)       __builtin_expect(!!(x), 1)+#define unlikely(x)     __builtin_expect(!!(x), 0)+#define force_inline inline __attribute__((always_inline))+#define no_inline __attribute__((noinline))+#define __maybe_unused __attribute__((unused))++#define xglue(x, y) x ## y+#define glue(x, y) xglue(x, y)+#define stringify(s)    tostring(s)+#define tostring(s)     #s++#ifndef offsetof+#define offsetof(type, field) ((size_t) &((type *)0)->field)+#endif+#ifndef countof+#define countof(x) (sizeof(x) / sizeof((x)[0]))+#endif++/* return the pointer of type 'type *' containing 'ptr' as field 'member' */+#define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member)))++typedef int BOOL;++#ifndef FALSE+enum {+    FALSE = 0,+    TRUE = 1,+};+#endif++void pstrcpy(char *buf, int buf_size, const char *str);+char *pstrcat(char *buf, int buf_size, const char *s);+int strstart(const char *str, const char *val, const char **ptr);+int has_suffix(const char *str, const char *suffix);++static inline int max_int(int a, int b)+{+    if (a > b)+        return a;+    else+        return b;+}++static inline int min_int(int a, int b)+{+    if (a < b)+        return a;+    else+        return b;+}++static inline uint32_t max_uint32(uint32_t a, uint32_t b)+{+    if (a > b)+        return a;+    else+        return b;+}++static inline uint32_t min_uint32(uint32_t a, uint32_t b)+{+    if (a < b)+        return a;+    else+        return b;+}++static inline int64_t max_int64(int64_t a, int64_t b)+{+    if (a > b)+        return a;+    else+        return b;+}++static inline int64_t min_int64(int64_t a, int64_t b)+{+    if (a < b)+        return a;+    else+        return b;+}++static inline size_t max_size_t(size_t a, size_t b)+{+    if (a > b)+        return a;+    else+        return b;+}++static inline size_t min_size_t(size_t a, size_t b)+{+    if (a < b)+        return a;+    else+        return b;+}++/* WARNING: undefined if a = 0 */+static inline int clz32(unsigned int a)+{+    return __builtin_clz(a);+}++/* WARNING: undefined if a = 0 */+static inline int clz64(uint64_t a)+{+    return __builtin_clzll(a);+}++/* WARNING: undefined if a = 0 */+static inline int ctz32(unsigned int a)+{+    return __builtin_ctz(a);+}++/* WARNING: undefined if a = 0 */+static inline int ctz64(uint64_t a)+{+    return __builtin_ctzll(a);+}++struct __attribute__((packed)) packed_u64 {+    uint64_t v;+};++struct __attribute__((packed)) packed_u32 {+    uint32_t v;+};++struct __attribute__((packed)) packed_u16 {+    uint16_t v;+};++static inline uint64_t get_u64(const uint8_t *tab)+{+    return ((const struct packed_u64 *)tab)->v;+}++static inline int64_t get_i64(const uint8_t *tab)+{+    return (int64_t)((const struct packed_u64 *)tab)->v;+}++static inline void put_u64(uint8_t *tab, uint64_t val)+{+    ((struct packed_u64 *)tab)->v = val;+}++static inline uint32_t get_u32(const uint8_t *tab)+{+    return ((const struct packed_u32 *)tab)->v;+}++static inline int32_t get_i32(const uint8_t *tab)+{+    return (int32_t)((const struct packed_u32 *)tab)->v;+}++static inline void put_u32(uint8_t *tab, uint32_t val)+{+    ((struct packed_u32 *)tab)->v = val;+}++static inline uint32_t get_u16(const uint8_t *tab)+{+    return ((const struct packed_u16 *)tab)->v;+}++static inline int32_t get_i16(const uint8_t *tab)+{+    return (int16_t)((const struct packed_u16 *)tab)->v;+}++static inline void put_u16(uint8_t *tab, uint16_t val)+{+    ((struct packed_u16 *)tab)->v = val;+}++static inline uint32_t get_u8(const uint8_t *tab)+{+    return *tab;+}++static inline int32_t get_i8(const uint8_t *tab)+{+    return (int8_t)*tab;+}++static inline void put_u8(uint8_t *tab, uint8_t val)+{+    *tab = val;+}++static inline uint16_t bswap16(uint16_t x)+{+    return (x >> 8) | (x << 8);+}++static inline uint32_t bswap32(uint32_t v)+{+    return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >>  8) |+        ((v & 0x0000ff00) <<  8) | ((v & 0x000000ff) << 24);+}++static inline uint64_t bswap64(uint64_t v)+{+    return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) | +        ((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) | +        ((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) | +        ((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) | +        ((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) | +        ((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) | +        ((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) | +        ((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8));+}++static inline uint32_t get_be32(const uint8_t *d)+{+    return bswap32(get_u32(d));+}++static inline void put_be32(uint8_t *d, uint32_t v)+{+    put_u32(d, bswap32(v));+}++#define UTF8_CHAR_LEN_MAX 4++size_t __unicode_to_utf8(uint8_t *buf, unsigned int c);+int __unicode_from_utf8(const uint8_t *p, size_t max_len, size_t *plen);+int __utf8_get(const uint8_t *p, size_t *plen);++/* Note: at most 21 bits are encoded. At most UTF8_CHAR_LEN_MAX bytes+   are output. */+static inline size_t unicode_to_utf8(uint8_t *buf, unsigned int c)+{+    if (c < 0x80) {+        buf[0] = c;+        return 1;+    } else {+        return __unicode_to_utf8(buf, c);+    }+}++/* return -1 in case of error. Surrogates are accepted. max_len must+   be >= 1. *plen is set in case of error and always >= 1. */+static inline int unicode_from_utf8(const uint8_t *buf, size_t max_len, size_t *plen)+{+    if (buf[0] < 0x80) {+        *plen = 1;+        return buf[0];+    } else {+        return __unicode_from_utf8(buf, max_len, plen);+    }+}++/* Warning: no error checking is done so the UTF-8 encoding must be+   validated before. */+static force_inline int utf8_get(const uint8_t *buf, size_t *plen)+{+    if (likely(buf[0] < 0x80)) {+        *plen = 1;+        return buf[0];+    } else {+        return __utf8_get(buf, plen);+    }+}++static inline int from_hex(int c)+{+    if (c >= '0' && c <= '9')+        return c - '0';+    else if (c >= 'A' && c <= 'F')+        return c - 'A' + 10;+    else if (c >= 'a' && c <= 'f')+        return c - 'a' + 10;+    else+        return -1;+}++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;+}++typedef union {+    uint32_t u32;+    float f;+} f32_union;++static inline uint32_t float_as_uint(float f)+{+    f32_union u;+    u.f = f;+    return u.u32;+}++static inline float uint_as_float(uint32_t v)+{+    f32_union u;+    u.u32 = v;+    return u.f;+}++#endif  /* CUTILS_H */
+ mquickjs/dtoa.c view
@@ -0,0 +1,1620 @@+/*+ * Tiny float64 printing and parsing library+ *+ * Copyright (c) 2024-2025 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 <stdlib.h>+#include <stdio.h>+#include <stdarg.h>+#include <inttypes.h>+#include <string.h>+#include <assert.h>+#include <ctype.h>+#include <sys/time.h>+#include <math.h>+#include <setjmp.h>++#include "cutils.h"+#include "dtoa.h"++/* +   TODO:+   - test n_digits=101 instead of 100+   - simplify subnormal handling+   - reduce max memory usage+   - free format: could add shortcut if exact result+   - use 64 bit limb_t when possible+   - use another algorithm for free format dtoa in base 10 (ryu ?)+*/++#define USE_POW5_TABLE+/* use fast path to print small integers in free format */+#define USE_FAST_INT++#define LIMB_LOG2_BITS 5++#define LIMB_BITS (1 << LIMB_LOG2_BITS)++typedef int32_t slimb_t;+typedef uint32_t limb_t;+typedef uint64_t dlimb_t;++#define LIMB_DIGITS 9++#define JS_RADIX_MAX 36++#define DBIGNUM_LEN_MAX 52 /* ~ 2^(1072+53)*36^100 (dtoa) */+#define MANT_LEN_MAX 18 /* < 36^100 */++typedef intptr_t mp_size_t;++/* the represented number is sum(i, tab[i]*2^(LIMB_BITS * i)) */+typedef struct {+    int len; /* >= 1 */+    limb_t tab[];+} mpb_t;++static limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n)+{+    size_t i;+    limb_t k, a;++    k=b;+    for(i=0;i<n;i++) {+        if (k == 0)+            break;+        a = tab[i] + k;+        k = (a < k);+        tab[i] = a;+    }+    return k;+}++/* 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;+}++/* 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 guaranteed 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 guaranteed 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--;+            }+            /* guaranteed 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;+}
+ mquickjs/dtoa.h view
@@ -0,0 +1,83 @@+/*+ * Tiny float64 printing and parsing library+ *+ * Copyright (c) 2024-2025 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);
+ mquickjs/libm.c view
@@ -0,0 +1,2260 @@+/*+ * Tiny Math 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.+ */+/*+ * ====================================================+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.+ *+ * Permission to use, copy, modify, and distribute this+ * software is freely granted, provided that this notice + * is preserved.+ * ====================================================+ */+#include <stdio.h>+#include <inttypes.h>+#include <math.h>+#define NDEBUG+#include <assert.h>++#include "cutils.h"+#include "libm.h"++/* define to enable softfloat support */+//#define USE_SOFTFLOAT+/* use less code for tan() but currently less precise */+#define USE_TAN_SHORTCUT ++/* +  TODO:+  - smaller scalbn implementation ?+  - add all ES6 math functions+*/+/*+   tc32: +   - base: size libm+libgcc: 21368+   - size libm+libgcc: 11832++   x86:+   - size libm softfp: 18510+   - size libm hardfp: 10051++   TODO:+   - unify i32 bit and i64 bit conversions+   - unify comparisons operations+*/++typedef enum {+    RM_RNE, /* Round to Nearest, ties to Even */+    RM_RTZ, /* Round towards Zero */+    RM_RDN, /* Round Down (must be even) */+    RM_RUP, /* Round Up (must be odd) */+    RM_RMM, /* Round to Nearest, ties to Max Magnitude */+    RM_RMMUP, /* only for rint_sf64(): round to nearest, ties to +inf (must be odd) */+} RoundingModeEnum;++#define FFLAG_INVALID_OP  (1 << 4)+#define FFLAG_DIVIDE_ZERO (1 << 3)+#define FFLAG_OVERFLOW    (1 << 2)+#define FFLAG_UNDERFLOW   (1 << 1)+#define FFLAG_INEXACT     (1 << 0)++typedef enum {+    FMINMAX_PROP, /* min(1, qNaN/sNaN) -> qNaN */+    FMINMAX_IEEE754_2008, /* min(1, qNaN) -> 1, min(1, sNaN) -> qNaN */+    FMINMAX_IEEE754_201X, /* min(1, qNaN/sNaN) -> 1 */+} SoftFPMinMaxTypeEnum;++typedef uint32_t sfloat32;+typedef uint64_t sfloat64;++#define F_STATIC static __maybe_unused+#define F_USE_FFLAGS 0++#define F_SIZE 32+#define F_NORMALIZE_ONLY+#include "softfp_template.h"++#define F_SIZE 64+#include "softfp_template.h"++#ifdef USE_SOFTFLOAT++/* wrappers */+double __adddf3(double a, double b)+{+    return uint64_as_float64(add_sf64(float64_as_uint64(a),+                                     float64_as_uint64(b), RM_RNE));+}++double __subdf3(double a, double b)+{+    return uint64_as_float64(sub_sf64(float64_as_uint64(a),+                                      float64_as_uint64(b), RM_RNE));+}++double __muldf3(double a, double b)+{+    return uint64_as_float64(mul_sf64(float64_as_uint64(a),+                                      float64_as_uint64(b), RM_RNE));+}++double __divdf3(double a, double b)+{+    return uint64_as_float64(div_sf64(float64_as_uint64(a),+                                      float64_as_uint64(b), RM_RNE));+}++/* comparisons */++int __eqdf2(double a, double b)+{+    int ret = cmp_sf64(float64_as_uint64(a),+                       float64_as_uint64(b));+    return ret;+}++/* NaN: return 0 */+int __nedf2(double a, double b)+{+    int ret = cmp_sf64(float64_as_uint64(a),+                       float64_as_uint64(b));+    if (unlikely(ret == 2))+        return 0;+    else+        return ret;+}++int __ledf2(double a, double b)+{+    int ret = cmp_sf64(float64_as_uint64(a),+                       float64_as_uint64(b));+    return ret;+}++int __ltdf2(double a, double b)+{+    int ret = cmp_sf64(float64_as_uint64(a),+                       float64_as_uint64(b));+    return ret;+}++int __gedf2(double a, double b)+{+    int ret = cmp_sf64(float64_as_uint64(a),+                       float64_as_uint64(b));+    if (unlikely(ret == 2))+        return -1;+    else+        return ret;+}++int __gtdf2(double a, double b)+{+    int ret = cmp_sf64(float64_as_uint64(a),+                       float64_as_uint64(b));+    if (unlikely(ret == 2))+        return -1;+    else+        return ret;+}++int __unorddf2(double a, double b)+{+    return isnan_sf64(float64_as_uint64(a)) ||+        isnan_sf64(float64_as_uint64(b));+}++/* conversions */+double __floatsidf(int32_t a)+{+    return uint64_as_float64(cvt_i32_sf64(a, RM_RNE));+}++double __floatdidf(int64_t a)+{+    return uint64_as_float64(cvt_i64_sf64(a, RM_RNE));+}++double __floatunsidf(unsigned int a)+{+    return uint64_as_float64(cvt_u32_sf64(a, RM_RNE));+}++int32_t __fixdfsi(double a)+{+    return cvt_sf64_i32(float64_as_uint64(a), RM_RTZ);+}++double __extendsfdf2(float a)+{+    return uint64_as_float64(cvt_sf32_sf64(float_as_uint(a)));+}++float __truncdfsf2(double a)+{+    return uint_as_float(cvt_sf64_sf32(float64_as_uint64(a), RM_RNE));+}++double js_sqrt(double a)+{+    return uint64_as_float64(sqrt_sf64(float64_as_uint64(a), RM_RNE));+}++#if defined(__tc32__)+/* XXX: check */+int __fpclassifyd(double a)+{+    uint64_t u = float64_as_uint64(a);+    uint32_t h = u >> 32;+    uint32_t l = u;++    h &= 0x7fffffff;+    if (h >= 0x7ff00000) {+        if (h == 0x7ff00000 && l == 0)+            return FP_INFINITE;+        else+            return FP_NAN;+    } else if (h < 0x00100000) {+        if (h == 0 && l == 0)+            return FP_ZERO;+        else+            return FP_SUBNORMAL;+    } else {+        return FP_NORMAL;+    }+}+#endif++#endif /* USE_SOFTFLOAT */++int32_t js_lrint(double a)+{+    return cvt_sf64_i32(float64_as_uint64(a), RM_RNE);+}++double js_fmod(double a, double b)+{+    return uint64_as_float64(fmod_sf64(float64_as_uint64(a), float64_as_uint64(b)));+}++/* supported rounding modes: RM_UP, RM_DN, RM_RTZ, RM_RMMUP, RM_RMM */+static double rint_sf64(double a, RoundingModeEnum rm)+{+    uint64_t u = float64_as_uint64(a);+    uint64_t frac_mask, one, m, addend;+    int e;+    unsigned int s;++    e = ((u >> 52) & 0x7ff) - 0x3ff;+    s = u >> 63;+    if (e < 0) {+        m = u & (((uint64_t)1 << 52) - 1);+        if (e == -0x3ff && m == 0) {+            /* zero: nothing to do */+        } else {+            /* abs(a) < 1 */+            s = u >> 63;+            one = (uint64_t)0x3ff << 52;+            u = 0;+            switch(rm) {+            case RM_RUP:+            case RM_RDN:+                if (s ^ (rm & 1))+                    u = one;+                break;+            default:+            case RM_RMM:+            case RM_RMMUP:+                if (e == -1 && (m != 0 || (m == 0 && (!s || rm == RM_RMM))))+                    u = one;+                break;+            case RM_RTZ:+                break;+            }+            u |= (uint64_t)s << 63;+        }+    } else if (e < 52) {+        one = (uint64_t)1 << (52 - e);+        frac_mask = one - 1;+        addend = 0;+        switch(rm) {+        case RM_RMMUP:+            addend = (one >> 1) - s;+            break;+        default:+        case RM_RMM:+            addend = (one >> 1);+            break;+        case RM_RTZ:+            break;+        case RM_RUP:+        case RM_RDN:+            if (s ^ (rm & 1))+                addend = one - 1;+            break;+        }+        u += addend;+        u &= ~frac_mask; /* truncate to an integer */+    }+    /* otherwise: abs(a) >= 2^52, or NaN, +/-Infinity: no change */+    return uint64_as_float64(u);+}++double js_floor(double x)+{+    return rint_sf64(x, RM_RDN);+}++double js_ceil(double x)+{+    return rint_sf64(x, RM_RUP);+}++double js_trunc(double x)+{+    return rint_sf64(x, RM_RTZ);+}++double js_round_inf(double x)+{+    return rint_sf64(x, RM_RMMUP);+}++double js_fabs(double x)+{+    uint64_t a = float64_as_uint64(x);+    return uint64_as_float64(a & 0x7fffffffffffffff);+}++/************************************************************/+/* libm */++#define EXTRACT_WORDS(ix0,ix1,d)				\+    do {                                                        \+        uint64_t __u = float64_as_uint64(d);                    \+        (ix0) = (uint32_t)(__u >> 32);                          \+        (ix1) = (uint32_t)__u;                                  \+    } while (0)++static uint32_t get_high_word(double d)+{+    return float64_as_uint64(d) >> 32;+}++static double set_high_word(double d, uint32_t h)+{+    uint64_t u = float64_as_uint64(d);+    u = (u & 0xffffffff) | ((uint64_t)h << 32);+    return uint64_as_float64(u);+}++static uint32_t get_low_word(double d)+{+    return float64_as_uint64(d);+}++/* set the low 32 bits to zero */+static double zero_low(double x)+{+    uint64_t u = float64_as_uint64(x);+    u &= 0xffffffff00000000;+    return uint64_as_float64(u);+}++static double float64_from_u32(uint32_t h, uint32_t l)+{+    return uint64_as_float64(((uint64_t)h << 32) | l);+}++static const double zero   = 0.0;+static const double one    = 1.0;+static const double half =  5.00000000000000000000e-01;+static const double tiny = 1.0e-300;+static const double huge = 1.0e300;++/* @(#)s_scalbn.c 1.3 95/01/18 */+/*+ * ====================================================+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.+ *+ * Developed at SunSoft, a Sun Microsystems, Inc. business.+ * Permission to use, copy, modify, and distribute this+ * software is freely granted, provided that this notice + * is preserved.+ * ====================================================+ */++/* + * scalbn (double x, int n)+ * scalbn(x,n) returns x* 2**n  computed by  exponent  + * manipulation rather than by actually performing an + * exponentiation or a multiplication.+ */++static const double+    two54   =  1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */+    twom54  =  5.55111512312578270212e-17; /* 0x3C900000, 0x00000000 */++double js_scalbn(double x, int n)+{+	int  k,hx,lx;+	EXTRACT_WORDS(hx, lx, x);+        k = (hx&0x7ff00000)>>20;		/* extract exponent */+        if (k==0) {				/* 0 or subnormal x */+            if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */+	    x *= two54; +	    hx = get_high_word(x);+	    k = ((hx&0x7ff00000)>>20) - 54; +            if (n< -50000) return tiny*x; 	/*underflow*/+	    }+        if (k==0x7ff) return x+x;		/* NaN or Inf */+        k = k+n; +        if (k >  0x7fe) return huge*copysign(huge,x); /* overflow  */+        if (k > 0) 				/* normal result */+	    {x = set_high_word(x, (hx&0x800fffff)|(k<<20)); return x;}+        if (k <= -54) {+            if (n > 50000) 	/* in case integer overflow in n+k */+		return huge*copysign(huge,x);	/*overflow*/+	    else+                return tiny*copysign(tiny,x); 	/*underflow*/+        }+        k += 54;				/* subnormal result */+        x = set_high_word(x, (hx&0x800fffff)|(k<<20));+        return x*twom54;+}++#ifndef USE_SOFTFLOAT+/* @(#)e_sqrt.c 1.3 95/01/18 */+/*+ * ====================================================+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.+ *+ * Developed at SunSoft, a Sun Microsystems, Inc. business.+ * Permission to use, copy, modify, and distribute this+ * software is freely granted, provided that this notice + * is preserved.+ * ====================================================+ */++/* __ieee754_sqrt(x)+ * Return correctly rounded sqrt.+ *           ------------------------------------------+ *	     |  Use the hardware sqrt if you have one |+ *           ------------------------------------------+ * Method: + *   Bit by bit method using integer arithmetic. (Slow, but portable) + *   1. Normalization+ *	Scale x to y in [1,4) with even powers of 2: + *	find an integer k such that  1 <= (y=x*2^(2k)) < 4, then+ *		sqrt(x) = 2^k * sqrt(y)+ *   2. Bit by bit computation+ *	Let q  = sqrt(y) truncated to i bit after binary point (q = 1),+ *	     i							 0+ *                                     i+1         2+ *	    s  = 2*q , and	y  =  2   * ( y - q  ).		(1)+ *	     i      i            i                 i+ *                                                        + *	To compute q    from q , one checks whether + *		    i+1       i                       + *+ *			      -(i+1) 2+ *			(q + 2      ) <= y.			(2)+ *     			  i+ *							      -(i+1)+ *	If (2) is false, then q   = q ; otherwise q   = q  + 2      .+ *		 	       i+1   i             i+1   i+ *+ *	With some algebraic manipulation, it is not difficult to see+ *	that (2) is equivalent to + *                             -(i+1)+ *			s  +  2       <= y			(3)+ *			 i                i+ *+ *	The advantage of (3) is that s  and y  can be computed by + *				      i      i+ *	the following recurrence formula:+ *	    if (3) is false+ *+ *	    s     =  s  ,	y    = y   ;			(4)+ *	     i+1      i		 i+1    i+ *+ *	    otherwise,+ *                         -i                     -(i+1)+ *	    s	  =  s  + 2  ,  y    = y  -  s  - 2  		(5)+ *           i+1      i          i+1    i     i+ *				+ *	One may easily use induction to prove (4) and (5). + *	Note. Since the left hand side of (3) contain only i+2 bits,+ *	      it does not necessary to do a full (53-bit) comparison + *	      in (3).+ *   3. Final rounding+ *	After generating the 53 bits result, we compute one more bit.+ *	Together with the remainder, we can decide whether the+ *	result is exact, bigger than 1/2ulp, or less than 1/2ulp+ *	(it will never equal to 1/2ulp).+ *	The rounding mode can be detected by checking whether+ *	huge + tiny is equal to huge, and whether huge - tiny is+ *	equal to huge for some floating point number "huge" and "tiny".+ *		+ * Special cases:+ *	sqrt(+-0) = +-0 	... exact+ *	sqrt(inf) = inf+ *	sqrt(-ve) = NaN		... with invalid signal+ *	sqrt(NaN) = NaN		... with invalid signal for signaling NaN+ *+ * Other methods : see the appended file at the end of the program below.+ *---------------+ */++#if defined(__aarch64__) || defined(__x86_64__) || defined(__i386__)+/* hardware sqrt is available */+double js_sqrt(double x)+{+    return sqrt(x);+}+#else+double js_sqrt(double x)+{+	double z;+	int 	sign = (int)0x80000000; +	unsigned r,t1,s1,ix1,q1;+	int ix0,s0,q,m,t,i;++	EXTRACT_WORDS(ix0, ix1, x);++    /* take care of Inf and NaN */+	if((ix0&0x7ff00000)==0x7ff00000) {			+	    return x*x+x;		/* sqrt(NaN)=NaN, sqrt(+inf)=+inf+					   sqrt(-inf)=sNaN */+	} +    /* take care of zero */+	if(ix0<=0) {+	    if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */+	    else if(ix0<0)+		return (x-x)/(x-x);		/* sqrt(-ve) = sNaN */+	}+    /* normalize x */+	m = (ix0>>20);+	if(m==0) {				/* subnormal x */+	    while(ix0==0) {+		m -= 21;+		ix0 |= (ix1>>11); ix1 <<= 21;+	    }+	    for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1;+	    m -= i-1;+	    ix0 |= (ix1>>(32-i));+	    ix1 <<= i;+	}+	m -= 1023;	/* unbias exponent */+	ix0 = (ix0&0x000fffff)|0x00100000;+	if(m&1){	/* odd m, double x to make it even */+	    ix0 += ix0 + ((ix1&sign)>>31);+	    ix1 += ix1;+	}+	m >>= 1;	/* m = [m/2] */++    /* generate sqrt(x) bit by bit */+	ix0 += ix0 + ((ix1&sign)>>31);+	ix1 += ix1;+	q = q1 = s0 = s1 = 0;	/* [q,q1] = sqrt(x) */+	r = 0x00200000;		/* r = moving bit from right to left */++	while(r!=0) {+	    t = s0+r; +	    if(t<=ix0) { +		s0   = t+r; +		ix0 -= t; +		q   += r; +	    } +	    ix0 += ix0 + ((ix1&sign)>>31);+	    ix1 += ix1;+	    r>>=1;+	}++	r = sign;+	while(r!=0) {+	    t1 = s1+r; +	    t  = s0;+	    if((t<ix0)||((t==ix0)&&(t1<=ix1))) { +		s1  = t1+r;+		if(((t1&sign)==sign)&&(s1&sign)==0) s0 += 1;+		ix0 -= t;+		if (ix1 < t1) ix0 -= 1;+		ix1 -= t1;+		q1  += r;+	    }+	    ix0 += ix0 + ((ix1&sign)>>31);+	    ix1 += ix1;+	    r>>=1;+	}++    /* use floating add to find out rounding direction */+	if((ix0|ix1)!=0) {+	    z = one-tiny; /* trigger inexact flag */+	    if (z>=one) {+	        z = one+tiny;+	        if (q1==(unsigned)0xffffffff) { q1=0; q += 1;}+		else if (z>one) {+		    if (q1==(unsigned)0xfffffffe) q+=1;+		    q1+=2; +		} else+	            q1 += (q1&1);+	    }+	}+	ix0 = (q>>1)+0x3fe00000;+	ix1 =  q1>>1;+	if ((q&1)==1) ix1 |= sign;+	ix0 += (m <<20);+	return float64_from_u32(ix0, ix1);+}+#endif /* !hardware sqrt */+#endif /* USE_SOFTFLOAT */++/* to have smaller code */+/* n >= 1 */+/* return sum(x^i*coefs[i] with i = 0 ... n - 1 and n >= 1 using+   Horner algorithm. */+static double eval_poly(double x, const double *coefs, int n)+{+    double r;+    int i;+    r = coefs[n - 1];+    for(i = n - 2; i >= 0; i--) {+        r = r * x + coefs[i];+    }+    return r;+}++/* @(#)k_sin.c 1.3 95/01/18 */+/*+ * ====================================================+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.+ *+ * Developed at SunSoft, a Sun Microsystems, Inc. business.+ * Permission to use, copy, modify, and distribute this+ * software is freely granted, provided that this notice + * is preserved.+ * ====================================================+ */++/* __kernel_sin( x, y, iy)+ * kernel sin function on [-pi/4, pi/4], pi/4 ~ 0.7854+ * Input x is assumed to be bounded by ~pi/4 in magnitude.+ * Input y is the tail of x.+ * Input iy indicates whether y is 0. (if iy=0, y assume to be 0). + *+ * Algorithm+ *	1. Since sin(-x) = -sin(x), we need only to consider positive x. + *	2. if x < 2^-27 (hx<0x3e400000 0), return x with inexact if x!=0.+ *	3. sin(x) is approximated by a polynomial of degree 13 on+ *	   [0,pi/4]+ *		  	         3            13+ *	   	sin(x) ~ x + S1*x + ... + S6*x+ *	   where+ *	+ * 	|sin(x)         2     4     6     8     10     12  |     -58+ * 	|----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x  +S6*x   )| <= 2+ * 	|  x 					           | + * + *	4. sin(x+y) = sin(x) + sin'(x')*y+ *		    ~ sin(x) + (1-x*x/2)*y+ *	   For better accuracy, let + *		     3      2      2      2      2+ *		r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6))))+ *	   then                   3    2+ *		sin(x) = x + (S1*x + (x *(r-y/2)+y))+ */++static const double +S1  = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */+static const double S_tab[] = {+    /* S2 */  8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */+    /* S3 */ -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */+    /* S4 */  2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */+    /* S5 */ -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */+    /* S6 */  1.58969099521155010221e-10, /* 0x3DE5D93A, 0x5ACFD57C */+};++/* iy=0 if y is zero */+static double __kernel_sin(double x, double y, int iy)+{+	double z,r,v;+	int ix;+	ix = get_high_word(x)&0x7fffffff;	/* high word of x */+	if(ix<0x3e400000)			/* |x| < 2**-27 */+	   {if((int)x==0) return x;}		/* generate inexact */+	z	=  x*x;+	v	=  z*x;+	r	=  eval_poly(z, S_tab, 5);+	if(iy==0) return x+v*(S1+z*r);+	else      return x-((z*(half*y-v*r)-y)-v*S1);+}+++/* @(#)k_cos.c 1.3 95/01/18 */+/*+ * ====================================================+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.+ *+ * Developed at SunSoft, a Sun Microsystems, Inc. business.+ * Permission to use, copy, modify, and distribute this+ * software is freely granted, provided that this notice + * is preserved.+ * ====================================================+ */++/*+ * __kernel_cos( x,  y )+ * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164+ * Input x is assumed to be bounded by ~pi/4 in magnitude.+ * Input y is the tail of x. + *+ * Algorithm+ *	1. Since cos(-x) = cos(x), we need only to consider positive x.+ *	2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0.+ *	3. cos(x) is approximated by a polynomial of degree 14 on+ *	   [0,pi/4]+ *		  	                 4            14+ *	   	cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x+ *	   where the remez error is+ *	+ * 	|              2     4     6     8     10    12     14 |     -58+ * 	|cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  )| <= 2+ * 	|    					               | + * + * 	               4     6     8     10    12     14 + *	4. let r = C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  , then+ *	       cos(x) = 1 - x*x/2 + r+ *	   since cos(x+y) ~ cos(x) - sin(x)*y + *			  ~ cos(x) - x*y,+ *	   a correction term is necessary in cos(x) and hence+ *		cos(x+y) = 1 - (x*x/2 - (r - x*y))+ *	   For better accuracy when x > 0.3, let qx = |x|/4 with+ *	   the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125.+ *	   Then+ *		cos(x+y) = (1-qx) - ((x*x/2-qx) - (r-x*y)).+ *	   Note that 1-qx and (x*x/2-qx) is EXACT here, and the+ *	   magnitude of the latter is at least a quarter of x*x/2,+ *	   thus, reducing the rounding error in the subtraction.+ */++static const double C_tab[] = {+    /* C1 */  4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */+    /* C2 */ -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */+    /* C3 */  2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */+    /* C4 */ -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */+    /* C5 */  2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */+    /* C6 */ -1.13596475577881948265e-11, /* 0xBDA8FAE9, 0xBE8838D4 */+};++static double __kernel_cos(double x, double y)+{+	double a,hz,z,r,qx;+	int ix;+	ix = get_high_word(x)&0x7fffffff;	/* ix = |x|'s high word*/+	if(ix<0x3e400000) {			/* if x < 2**27 */+	    if(((int)x)==0) return one;		/* generate inexact */+	}+	z  = x*x;+	r  = z * eval_poly(z, C_tab, 6);+	if(ix < 0x3FD33333) 			/* if |x| < 0.3 */ +	    return one - (0.5*z - (z*r - x*y));+	else {+	    if(ix > 0x3fe90000) {		/* x > 0.78125 */+		qx = 0.28125;+	    } else {+	        qx = float64_from_u32(ix-0x00200000, 0);	/* x/4 */+	    }+	    hz = 0.5*z-qx;+	    a  = one-qx;+	    return a - (hz - (z*r-x*y));+	}+}++/* rem_pio2 */++#define T_LEN 19++/* T[i] = floor(2^(64*(T_LEN - i))/2pi) mod 2^64 */+static const uint64_t T[T_LEN] = {+    0x1580cc11bf1edaea,+    0x9afed7ec47e35742,+    0xcf41ce7de294a4ba,+    0x5d49eeb1faf97c5e,+    0xd3d18fd9a797fa8b,+    0xdb4d9fb3c9f2c26d,+    0xfbcbc462d6829b47,+    0xc7fe25fff7816603,+    0x272117e2ef7e4a0e,+    0x4e64758e60d4ce7d,+    0x3a671c09ad17df90,+    0xba208d7d4baed121,+    0x3f877ac72c4a69cf,+    0x01924bba82746487,+    0x6dc91b8e909374b8,+    0x7f9458eaf7aef158,+    0x36d8a5664f10e410,+    0x7f09d5f47d4d3770,+    0x28be60db9391054a, /* high part */+};++/* PIO2[i] = floor(2^(64*(2 - i))*PI/4) mod 2^64 */+static const uint64_t PIO4[2] = {+    0xc4c6628b80dc1cd1,+    0xc90fdaa22168c234,+};++static uint64_t get_u64_at_bit(const uint64_t *tab, uint32_t tab_len,+                               uint32_t pos)+{+    uint64_t v;+    uint32_t p = pos / 64;+    int shift = pos % 64;+    v = tab[p] >> shift;+    if (shift != 0 && (p + 1) < tab_len)+        v |= tab[p + 1] << (64 - shift);+    return v;+}++/* return n = round(x/(pi/2)) (only low 2 bits are valid) and+   (y[0], y[1]) = x - (pi/2) * n. +   'x' must be finite and such as abs(x) >= PI/4.+   The initial algorithm comes from the CORE-MATH project.+*/+static int rem_pio2_large(double x, double *y)+{+    uint64_t m;+    int e, sgn, n, rnd, j, i, y_sgn;+    uint64_t c[2], d[3];+    uint64_t r0, r1;+    uint32_t carry, carry1;++    m = float64_as_uint64(x);+    sgn = m >> 63;+    e = (m >> 52) & 0x7ff;+    /* 1022 <= e <= 2047 */+    m = (m & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);++    /* multiply m by T[j:j+192] */+    j = T_LEN * 64 - (e - 1075) - 192;+    /* 53 <= j <= 1077 */+    //    printf("m=0x%016" PRIx64 " e=%d j=%d\n", m, e, j);+    for(i = 0; i < 3; i++) {+        d[i] = get_u64_at_bit(T, T_LEN, j + i * 64);+    }+    r1 = mul_u64(&r0, m, d[0]);+    c[0] = r1;+    r1 = mul_u64(&r0, m, d[1]);+    c[0] += r0;+    carry = c[0] < r0;+    c[1] = r1 + carry;+    mul_u64(&r0, m, d[2]);+    c[1] += r0;++    //    printf("c0=%016" PRIx64 " %016" PRIx64 "\n", c[1], c[0]);++    /* n = round(c[1]/2^62) */+    n = c[1] >> 62;+    rnd = (c[1] >> 61) & 1;+    n += rnd;+    /* c = c * 4 - n */+    c[1] = (c[1] << 2) | (c[0] >> 62);+    c[0] = (c[0] << 2);+    y_sgn = sgn;+    if (rnd) {+        /* 'y' sign change */+        y_sgn ^= 1;+        c[0] = ~c[0];+        c[1] = ~c[1];+        if (++c[0] == 0)+            c[1]++;+    }+    //    printf("c1=%016" PRIx64 " %016" PRIx64 " n=%d sgn=%d\n", c[1], c[0], n, sgn);++    /* c = c * (PI/2) (high 128 bits of the product) */+    r1 = mul_u64(&r0, c[0], PIO4[1]);+    d[0] = r0;+    d[1] = r1;++    r1 = mul_u64(&r0, c[1], PIO4[0]);+    d[0] += r0;+    carry = d[0] < r0;+    d[1] += r1;+    carry1 = d[1] < r1;+    d[1] += carry;+    carry1 |= (d[1] < carry);+    d[2] = carry1;++    r1 = mul_u64(&r0, c[1], PIO4[1]);+    d[1] += r0;+    carry = d[1] < r0;+    d[2] += r1 + carry;+    +    /* convert d to two float64 */+    //    printf("d=%016" PRIx64 " %016" PRIx64 "\n", d[2], d[1]);+    if (d[2] == 0) {+        /* should never happen (see ARGUMENT REDUCTION FOR HUGE+           ARGUMENTS: Good to the Last Bit, K. C. Ng and the members+           of the FP group of SunPro */+        y[0] = y[1] = 0;+    } else {+        uint64_t m0, m1;+        int e1;+        +        e = clz64(d[2]);+        d[2] = (d[2] << e) | (d[1] >> (64 - e));+        d[1] = (d[1] << e);+        //        printf("d=%016" PRIx64 " %016" PRIx64 " e=%d\n", d[2], d[1], e);+        m0 = (d[2] >> 11) & (((uint64_t)1 << 52) - 1);+        m1 = ((d[2] & 0x7ff) << 42) | (d[1] >> (64 - 42));+        y[0] = uint64_as_float64(((uint64_t)y_sgn << 63) |+                                 ((uint64_t)(1023 - e) << 52) |+                                 m0);+        if (m1 == 0) {+            y[1] = 0;+        } else {+            e1 = clz64(m1) - 11;+            m1 = (m1 << e1) & (((uint64_t)1 << 52) - 1);+            y[1] = uint64_as_float64(((uint64_t)y_sgn << 63) |+                                     ((uint64_t)(1023 - e - 53 - e1) << 52) |+                                     m1);+        }+    }+    if (sgn)+        n = -n;+    return n;+}++#ifdef USE_SOFTFLOAT+/* when using softfloat, the FP reduction should be not much faster+   than the generic one */+int js_rem_pio2(double x, double *y)+{+    int ix,hx;++    hx = get_high_word(x);		/* high word of x */+    ix = hx&0x7fffffff;+    if(ix<=0x3fe921fb) {+        /* |x| ~<= pi/4 , no need for reduction */+        y[0] = x;+        y[1] = 0;+        return 0;+    }+    /* +     * all other (large) arguments+     */+    if(ix>=0x7ff00000) {		/* x is inf or NaN */+        y[0]=y[1]=x-x;+        return 0;+    }++    return rem_pio2_large(x, y);+}+#else+/*+ * invpio2:  53 bits of 2/pi+ * pio2_1:   first  33 bit of pi/2+ * pio2_1t:  pi/2 - pio2_1+ * pio2_2:   second 33 bit of pi/2+ * pio2_2t:  pi/2 - (pio2_1+pio2_2)+ * pio2_3:   third  33 bit of pi/2+ * pio2_3t:  pi/2 - (pio2_1+pio2_2+pio2_3)+ */++static const double +invpio2 =  6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */+static const double pio2_tab[3] = {+    /* pio2_1 */  1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */+    /* pio2_2 */ 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */+    /* pio2_3 */  2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */+};+static const double pio2_t_tab[3] = {+    /* pio2_1t */  6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */+    /* pio2_2t */  2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */+    /* pio2_3t */  8.47842766036889956997e-32, /* 0x397B839A, 0x252049C1 */+};+static uint8_t rem_pio2_emax[2] = { 16, 49 };++int js_rem_pio2(double x, double *y)+{+    double w,t,r,fn;+    int i,j,n,ix,hx,it;++    hx = get_high_word(x);		/* high word of x */+    ix = hx&0x7fffffff;+    if(ix<=0x3fe921fb) {+        /* |x| ~<= pi/4 , no need for reduction */+        y[0] = x;+        y[1] = 0;+        return 0;+    }+    if(ix<=0x413921fb) { /* |x| ~<= 2^19*(pi/2), medium size */+        t  = fabs(x);+        if (ix<0x4002d97c) {+            /* |x| < 3pi/4, special case with n=+-1 */+            n = 1;+            fn = 1;+        } else {+            n  = (int) (t*invpio2+half);+            fn = (double)n;+        }++        it = 0;+        for(;;) {+            /* 1st round good to 85 bit */+            /* 2nd iteration needed, good to 118 */+            /* 3rd iteration need, 151 bits acc */+            r  = t-fn*pio2_tab[it];+            w  = fn*pio2_t_tab[it];	+            y[0] = r-w;+            j  = ix>>20;+            i = j-(((get_high_word(y[0]))>>20)&0x7ff);+            if (it == 2 || i <= rem_pio2_emax[it])+                break;+            t = r;+            it++;+        }+        y[1] = (r-y[0])-w;+        if (hx<0) {+            y[0] = -y[0];+            y[1] = -y[1];+            return -n;+        } else {+            return n;+        }+    }+    /* +     * all other (large) arguments+     */+    if(ix>=0x7ff00000) {		/* x is inf or NaN */+        y[0]=y[1]=x-x;+        return 0;+    }++    return rem_pio2_large(x, y);+}+#endif /* !USE_SOFTFLOAT */++/* @(#)s_sin.c 1.3 95/01/18 */+/*+ * ====================================================+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.+ *+ * Developed at SunSoft, a Sun Microsystems, Inc. business.+ * Permission to use, copy, modify, and distribute this+ * software is freely granted, provided that this notice + * is preserved.+ * ====================================================+ */++/* sin(x)+ * Return sine function of x.+ *+ * kernel function:+ *	__kernel_sin		... sine function on [-pi/4,pi/4]+ *	__kernel_cos		... cose function on [-pi/4,pi/4]+ *	__ieee754_rem_pio2	... argument reduction routine+ *+ * Method.+ *      Let S,C and T denote the sin, cos and tan respectively on + *	[-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + *	in [-pi/4 , +pi/4], and let n = k mod 4.+ *	We have+ *+ *          n        sin(x)      cos(x)        tan(x)+ *     ----------------------------------------------------------+ *	    0	       S	   C		 T+ *	    1	       C	  -S		-1/T+ *	    2	      -S	  -C		 T+ *	    3	      -C	   S		-1/T+ *     ----------------------------------------------------------+ *+ * Special cases:+ *      Let trig be any of sin, cos, or tan.+ *      trig(+-INF)  is NaN, with signals;+ *      trig(NaN)    is that NaN;+ *+ * Accuracy:+ *	TRIG(x) returns trig(x) nearly rounded + */++/* flag = 0: sin()+   flag = 1: cos()+   flag = 3: tan()+*/+static double js_sin_cos(double x, int flag)+{+    double y[2], z, s, c;+    int ix;+    uint32_t n;+    +    /* High word of x. */+    ix = get_high_word(x);++    /* sin(Inf or NaN) is NaN */+    if (ix>=0x7ff00000)+        return x-x;+    +    n = js_rem_pio2(x,y);+    s = c = 0; /* avoid warning */+    if (flag == 3 || (n & 1) == flag) {+        s = __kernel_sin(y[0],y[1],1);+        if (flag != 3)+            goto done;+    }+    if (flag == 3 || (n & 1) != flag) {+        c = __kernel_cos(y[0],y[1]);+        if (flag != 3) {+            s = c;+            goto done;+        }+    }+    if (n & 1)+        z = -c / s;+    else+        z = s / c;+    return z;+done:+    if ((n + flag) & 2)+        s = -s;+    return s;+}++double js_sin(double x)+{+    return js_sin_cos(x, 0);+}++double js_cos(double x)+{+    return js_sin_cos(x, 1);+}++#ifdef USE_TAN_SHORTCUT+double js_tan(double x)+{+    return js_sin_cos(x, 3);+}+#endif++#ifndef USE_TAN_SHORTCUT+/*+ * ====================================================+ * Copyright 2004 Sun Microsystems, Inc.  All Rights Reserved.+ *+ * Permission to use, copy, modify, and distribute this+ * software is freely granted, provided that this notice+ * is preserved.+ * ====================================================+ */++/* INDENT OFF */+/* __kernel_tan( x, y, k )+ * kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854+ * Input x is assumed to be bounded by ~pi/4 in magnitude.+ * Input y is the tail of x.+ * Input k indicates whether tan (if k = 1) or -1/tan (if k = -1) is returned.+ *+ * Algorithm+ *	1. Since tan(-x) = -tan(x), we need only to consider positive x.+ *	2. if x < 2^-28 (hx<0x3e300000 0), return x with inexact if x!=0.+ *	3. tan(x) is approximated by a odd polynomial of degree 27 on+ *	   [0,0.67434]+ *		  	         3             27+ *	   	tan(x) ~ x + T1*x + ... + T13*x+ *	   where+ *+ * 	        |tan(x)         2     4            26   |     -59.2+ * 	        |----- - (1+T1*x +T2*x +.... +T13*x    )| <= 2+ * 	        |  x 					|+ *+ *	   Note: tan(x+y) = tan(x) + tan'(x)*y+ *		          ~ tan(x) + (1+x*x)*y+ *	   Therefore, for better accuracy in computing tan(x+y), let+ *		     3      2      2       2       2+ *		r = x *(T2+x *(T3+x *(...+x *(T12+x *T13))))+ *	   then+ *		 		    3    2+ *		tan(x+y) = x + (T1*x + (x *(r+y)+y))+ *+ *      4. For x in [0.67434,pi/4],  let y = pi/4 - x, then+ *		tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y))+ *		       = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y)))+ */++static const double T0 = 3.33333333333334091986e-01;	/* 3FD55555, 55555563 */+static const double T_even[] = {+    5.39682539762260521377e-02,	/* 3FABA1BA, 1BB341FE */+    8.86323982359930005737e-03,	/* 3F8226E3, E96E8493 */+    1.45620945432529025516e-03,	/* 3F57DBC8, FEE08315 */+    2.46463134818469906812e-04,	/* 3F3026F7, 1A8D1068 */+    7.14072491382608190305e-05,	/* 3F12B80F, 32F0A7E9 */+    2.59073051863633712884e-05,	/* 3EFB2A70, 74BF7AD4 */+};+static const double T_odd[] = {+    1.33333333333201242699e-01,	/* 3FC11111, 1110FE7A */+    2.18694882948595424599e-02,	/* 3F9664F4, 8406D637 */+    3.59207910759131235356e-03,	/* 3F6D6D22, C9560328 */+    5.88041240820264096874e-04,	/* 3F4344D8, F2F26501 */+    7.81794442939557092300e-05,	/* 3F147E88, A03792A6 */+    -1.85586374855275456654e-05,	/* BEF375CB, DB605373 */+};+static const double pio4 = 7.85398163397448278999e-01,	/* 3FE921FB, 54442D18 */+    pio4lo =  3.06161699786838301793e-17;	/* 3C81A626, 33145C07 */++/* compute -1 / (x+y) carefully */+static double minus_inv(double x, double y)+{+    double a, t, z, v, s, w;+    +    w = x + y;+    z = zero_low(w);+    v = y - (z - x);+    a = -one / w;+    t = zero_low(a);+    s = one + t * z;+    return t + a * (s + t * v);+}++static double+__kernel_tan(double x, double y, int iy) {+	double z, r, v, w, s;+	int ix, hx;++	hx = get_high_word(x);		/* high word of x */+	ix = hx & 0x7fffffff;			/* high word of |x| */+	if (ix < 0x3e300000) {			/* x < 2**-28 */+		if ((int) x == 0) {		/* generate inexact */+			if (((ix | get_low_word(x)) | (iy + 1)) == 0)+				return one / fabs(x);+			else {+				if (iy == 1)+                                    return x;+				else+                                    return minus_inv(x, y);+			}+		}+	}+	if (ix >= 0x3FE59428) {	/* |x| >= 0.6744 */+		if (hx < 0) {+			x = -x;+			y = -y;+		}+		z = pio4 - x;+		w = pio4lo - y;+		x = z + w;+		y = 0.0;+	}+	z = x * x;+	w = z * z;+	/*+	 * Break x^5*(T[1]+x^2*T[2]+...) into+	 * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) ++	 * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12]))+	 */+	r = eval_poly(w, T_odd, 6);+	v = z * eval_poly(w, T_even, 6);+	s = z * x;+	r = y + z * (s * (r + v) + y);+	r += T0 * s;+	w = x + r;+	if (ix >= 0x3FE59428) {+		v = (double) iy;+		return (double) (1 - ((hx >> 30) & 2)) *+			(v - 2.0 * (x - (w * w / (w + v) - r)));+	}+	if (iy == 1) {+		return w;+        } else {+		/*+		 * if allow error up to 2 ulp, simply return+		 * -1.0 / (x+r) here+		 */+            return minus_inv(x, r);+	}+}++/* @(#)s_tan.c 1.3 95/01/18 */+/*+ * ====================================================+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.+ *+ * Developed at SunSoft, a Sun Microsystems, Inc. business.+ * Permission to use, copy, modify, and distribute this+ * software is freely granted, provided that this notice + * is preserved.+ * ====================================================+ */++/* tan(x)+ * Return tangent function of x.+ *+ * kernel function:+ *	__kernel_tan		... tangent function on [-pi/4,pi/4]+ *	__ieee754_rem_pio2	... argument reduction routine+ *+ * Method.+ *      Let S,C and T denote the sin, cos and tan respectively on + *	[-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + *	in [-pi/4 , +pi/4], and let n = k mod 4.+ *	We have+ *+ *          n        sin(x)      cos(x)        tan(x)+ *     ----------------------------------------------------------+ *	    0	       S	   C		 T+ *	    1	       C	  -S		-1/T+ *	    2	      -S	  -C		 T+ *	    3	      -C	   S		-1/T+ *     ----------------------------------------------------------+ *+ * Special cases:+ *      Let trig be any of sin, cos, or tan.+ *      trig(+-INF)  is NaN, with signals;+ *      trig(NaN)    is that NaN;+ *+ * Accuracy:+ *	TRIG(x) returns trig(x) nearly rounded + */++double js_tan(double x) +{+	double y[2],z=0.0;+	int n, ix;++    /* High word of x. */+	ix = get_high_word(x);++    /* |x| ~< pi/4 */+	ix &= 0x7fffffff;+	if(ix <= 0x3fe921fb) return __kernel_tan(x,z,1);++    /* tan(Inf or NaN) is NaN */+	else if (ix>=0x7ff00000) return x-x;		/* NaN */++    /* argument reduction needed */+	else {+	    n = js_rem_pio2(x,y);+	    return __kernel_tan(y[0],y[1],1-((n&1)<<1)); /*   1 -- n even+							-1 -- n odd */+	}+}+#endif++/* @(#)e_asin.c 1.3 95/01/18 */+/*+ * ====================================================+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.+ *+ * Developed at SunSoft, a Sun Microsystems, Inc. business.+ * Permission to use, copy, modify, and distribute this+ * software is freely granted, provided that this notice + * is preserved.+ * ====================================================+ */++/* __ieee754_asin(x)+ * Method :                  + *	Since  asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ...+ *	we approximate asin(x) on [0,0.5] by+ *		asin(x) = x + x*x^2*R(x^2)+ *	where+ *		R(x^2) is a rational approximation of (asin(x)-x)/x^3 + *	and its remez error is bounded by+ *		|(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75)+ *+ *	For x in [0.5,1]+ *		asin(x) = pi/2-2*asin(sqrt((1-x)/2))+ *	Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2;+ *	then for x>0.98+ *		asin(x) = pi/2 - 2*(s+s*z*R(z))+ *			= pio2_hi - (2*(s+s*z*R(z)) - pio2_lo)+ *	For x<=0.98, let pio4_hi = pio2_hi/2, then+ *		f = hi part of s;+ *		c = sqrt(z) - f = (z-f*f)/(s+f) 	...f+c=sqrt(z)+ *	and+ *		asin(x) = pi/2 - 2*(s+s*z*R(z))+ *			= pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo)+ *			= pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c))+ *+ * Special cases:+ *	if x is NaN, return x itself;+ *	if |x|>1, return NaN with invalid signal.+ *+ */+++static const double +pio2_hi =  1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */+    pio2_lo =  6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */+    pio4_hi =  7.85398163397448278999e-01; /* 0x3FE921FB, 0x54442D18 */+/* coefficient for R(x^2) */+static const double pS[] = {    +    /* pS0 */  1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */+    /* pS1 */-3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */+    /* pS2 */ 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */+    /* pS3 */ -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */+    /* pS4 */  7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */+    /* pS5 */  3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */+};++static const double qS[] = {    +    /* qS1 */ -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */+    /* qS2 */  2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */+    /* qS3 */ -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */+    /* qS4 */  7.70381505559019352791e-02, /* 0x3FB3B8C5, 0xB12E9282 */+};++static double R(double t)+{+    double p, q, w;+    p = t * eval_poly(t, pS, 6);+    q = one + t * eval_poly(t, qS, 4);+    w = p/q;+    return w;+}++double js_asin(double x)+{+	double t,w,p,q,c,r,s;+	int hx,ix;+	hx = get_high_word(x);+	ix = hx&0x7fffffff;+	if(ix>= 0x3ff00000) {		/* |x|>= 1 */+	    if(((ix-0x3ff00000)|get_low_word(x))==0)+		    /* asin(1)=+-pi/2 with inexact */+		return x*pio2_hi+x*pio2_lo;	+	    return (x-x)/(x-x);		/* asin(|x|>1) is NaN */   +	} else if (ix<0x3fe00000) {	/* |x|<0.5 */+	    if(ix<0x3e400000) {		/* if |x| < 2**-27 */+		if(huge+x>one) return x;/* return x with inexact if x!=0*/+	    } else {+		t = x*x;+                w = R(t);+		return x+x*w;+            }+	}+	/* 1> |x|>= 0.5 */+	w = one-fabs(x);+	t = w*0.5;+	r = R(t);+	s = js_sqrt(t);+	if(ix>=0x3FEF3333) { 	/* if |x| > 0.975 */+	    w = r;+	    t = pio2_hi-(2.0*(s+s*w)-pio2_lo);+	} else {+	    w = zero_low(s);+	    c  = (t-w*w)/(s+w);+	    p  = 2.0*s*r-(pio2_lo-2.0*c);+	    q  = pio4_hi-2.0*w;+	    t  = pio4_hi-(p-q);+	}    +	if(hx>0) return t; else return -t;    +}+++/* @(#)e_acos.c 1.3 95/01/18 */+/*+ * ====================================================+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.+ *+ * Developed at SunSoft, a Sun Microsystems, Inc. business.+ * Permission to use, copy, modify, and distribute this+ * software is freely granted, provided that this notice + * is preserved.+ * ====================================================+ */++/* __ieee754_acos(x)+ * Method :                  + *	acos(x)  = pi/2 - asin(x)+ *	acos(-x) = pi/2 + asin(x)+ * For |x|<=0.5+ *	acos(x) = pi/2 - (x + x*x^2*R(x^2))	(see asin.c)+ * For x>0.5+ * 	acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2)))+ *		= 2asin(sqrt((1-x)/2))  + *		= 2s + 2s*z*R(z) 	...z=(1-x)/2, s=sqrt(z)+ *		= 2f + (2c + 2s*z*R(z))+ *     where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term+ *     for f so that f+c ~ sqrt(z).+ * For x<-0.5+ *	acos(x) = pi - 2asin(sqrt((1-|x|)/2))+ *		= pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z)+ *+ * Special cases:+ *	if x is NaN, return x itself;+ *	if |x|>1, return NaN with invalid signal.+ *+ * Function needed: sqrt+ */++static const double +pi =  3.14159265358979311600e+00; /* 0x400921FB, 0x54442D18 */++double js_acos(double x)+{+	double z,r,w,s,c,df;+	int hx,ix;+	hx = get_high_word(x);+	ix = hx&0x7fffffff;+	if(ix>=0x3ff00000) {	/* |x| >= 1 */+	    if(((ix-0x3ff00000)|get_low_word(x))==0) {	/* |x|==1 */+		if(hx>0) return 0.0;		/* acos(1) = 0  */+		else return pi+2.0*pio2_lo;	/* acos(-1)= pi */+	    }+	    return (x-x)/(x-x);		/* acos(|x|>1) is NaN */+	}+	if(ix<0x3fe00000) {	/* |x| < 0.5 */+	    if(ix<=0x3c600000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/+	    z = x*x;+            r = R(z);+	    return pio2_hi - (x - (pio2_lo-x*r));+	} else  {+	    z = (one-fabs(x))*0.5;+            r = R(z);+	    s = js_sqrt(z);+            if (hx<0) {		/* x < -0.5 */+                w = r*s-pio2_lo;+                return pi - 2.0*(s+w);+            } else {			/* x > 0.5 */+                df = zero_low(s);+                c  = (z-df*df)/(s+df);+                w = r*s+c;+                return 2.0*(df+w);+            }+        }+}+++/* @(#)s_atan.c 1.3 95/01/18 */+/*+ * ====================================================+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.+ *+ * Developed at SunSoft, a Sun Microsystems, Inc. business.+ * Permission to use, copy, modify, and distribute this+ * software is freely granted, provided that this notice + * is preserved.+ * ====================================================+ *+ */++/* atan(x)+ * Method+ *   1. Reduce x to positive by atan(x) = -atan(-x).+ *   2. According to the integer k=4t+0.25 chopped, t=x, the argument+ *      is further reduced to one of the following intervals and the+ *      arctangent of t is evaluated by the corresponding formula:+ *+ *      [0,7/16]      atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...)+ *      [7/16,11/16]  atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) )+ *      [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) )+ *      [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) )+ *      [39/16,INF]   atan(x) = atan(INF) + atan( -1/t )+ *+ * Constants:+ * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown.+ */++static const double atanhi[] = {+  4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */+  7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */+  9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */+  1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */+};++static const double atanlo[] = {+  2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */+  3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */+  1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */+  6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */+};++static const double aT_even[] = {+  3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */+  1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */+  9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */+  6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */+  4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */+  1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */+};+static const double aT_odd[] = {+  -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */+  -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */+  -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */+  -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */+  -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */+};++double js_atan(double x)+{+	double w,s1,s2,z;+	int ix,hx,id;++	hx = get_high_word(x);+	ix = hx&0x7fffffff;+	if(ix>=0x44100000) {	/* if |x| >= 2^66 */+	    if(ix>0x7ff00000||+		(ix==0x7ff00000&&(get_low_word(x)!=0)))+		return x+x;		/* NaN */+	    if(hx>0) return  atanhi[3]+atanlo[3];+	    else     return -atanhi[3]-atanlo[3];+	} if (ix < 0x3fdc0000) {	/* |x| < 0.4375 */+	    if (ix < 0x3e200000) {	/* |x| < 2^-29 */+		if(huge+x>one) return x;	/* raise inexact */+	    }+	    id = -1;+	} else {+	x = fabs(x);+	if (ix < 0x3ff30000) {		/* |x| < 1.1875 */+	    if (ix < 0x3fe60000) {	/* 7/16 <=|x|<11/16 */+		id = 0; x = (2.0*x-one)/(2.0+x); +	    } else {			/* 11/16<=|x|< 19/16 */+		id = 1; x  = (x-one)/(x+one); +	    }+	} else {+	    if (ix < 0x40038000) {	/* |x| < 2.4375 */+		id = 2; x  = (x-1.5)/(one+1.5*x);+	    } else {			/* 2.4375 <= |x| < 2^66 */+		id = 3; x  = -1.0/x;+	    }+	}}+    /* end of argument reduction */+	z = x*x;+	w = z*z;+    /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */+	s1 = z*eval_poly(w, aT_even, 6);+	s2 = w*eval_poly(w, aT_odd, 5);+	if (id<0) return x - x*(s1+s2);+	else {+	    z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x);+	    return (hx<0)? -z:z;+	}+}++/* @(#)e_atan2.c 1.3 95/01/18 */+/*+ * ====================================================+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.+ *+ * Developed at SunSoft, a Sun Microsystems, Inc. business.+ * Permission to use, copy, modify, and distribute this+ * software is freely granted, provided that this notice + * is preserved.+ * ====================================================+ *+ */++/* __ieee754_atan2(y,x)+ * Method :+ *	1. Reduce y to positive by atan2(y,x)=-atan2(-y,x).+ *	2. Reduce x to positive by (if x and y are unexceptional): + *		ARG (x+iy) = arctan(y/x)   	   ... if x > 0,+ *		ARG (x+iy) = pi - arctan[y/(-x)]   ... if x < 0,+ *+ * Special cases:+ *+ *	ATAN2((anything), NaN ) is NaN;+ *	ATAN2(NAN , (anything) ) is NaN;+ *	ATAN2(+-0, +(anything but NaN)) is +-0  ;+ *	ATAN2(+-0, -(anything but NaN)) is +-pi ;+ *	ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2;+ *	ATAN2(+-(anything but INF and NaN), +INF) is +-0 ;+ *	ATAN2(+-(anything but INF and NaN), -INF) is +-pi;+ *	ATAN2(+-INF,+INF ) is +-pi/4 ;+ *	ATAN2(+-INF,-INF ) is +-3pi/4;+ *	ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2;+ *+ * Constants:+ * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown.+ */++static const double +pi_o_4  = 7.8539816339744827900E-01, /* 0x3FE921FB, 0x54442D18 */+pi_o_2  = 1.5707963267948965580E+00, /* 0x3FF921FB, 0x54442D18 */+pi_lo   = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */++double js_atan2(double y, double x)+{  +	double z;+	int k,m,hx,hy,ix,iy;+	unsigned lx,ly;++        EXTRACT_WORDS(hx, lx, x);+        EXTRACT_WORDS(hy, ly, y);+	ix = hx&0x7fffffff;+	iy = hy&0x7fffffff;+	if(((ix|((lx|-lx)>>31))>0x7ff00000)||+	   ((iy|((ly|-ly)>>31))>0x7ff00000))	/* x or y is NaN */+	   return x+y;+	if(((hx-0x3ff00000)|lx)==0)+            return js_atan(y);   /* x=1.0 */+	m = ((hy>>31)&1)|((hx>>30)&2);	/* 2*sign(x)+sign(y) */++    /* when y = 0 */+	if((iy|ly)==0) {+            z = 0;+            goto done;+	}+    /* when x = 0 */+	if((ix|lx)==0) return (hy<0)?  -pi_o_2-tiny: pi_o_2+tiny;+	    +    /* when x is INF */+	if(ix==0x7ff00000) {+	    if(iy==0x7ff00000) {+                z = pi_o_4;+	    } else {+                z = 0;+	    }+            goto done;+	}+    /* when y is INF */+	if(iy==0x7ff00000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;++    /* compute y/x */+	k = (iy-ix)>>20;+	if(k > 60) {+            z=pi_o_2+0.5*pi_lo; 	/* |y/x| >  2**60 */+        } else if(hx<0&&k<-60) {+            z=0.0; 	/* |y|/x < -2**60 */+        } else {+            z=js_atan(fabs(y/x));		/* safe to do y/x */+        }+ done:+	switch (m) {+	    case 0:+                return       z  ;	/* atan(+,+) */+	    case 1:+                z = set_high_word(z, get_high_word(z) ^ 0x80000000);+                return       z  ;	/* atan(-,+) */+	    case 2:+                return  pi-(z-pi_lo);/* atan(+,-) */+	    default: /* case 3 */+                return  (z-pi_lo)-pi;/* atan(-,-) */+	}+}++/* @(#)e_exp.c 1.6 04/04/22 */+/*+ * ====================================================+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.+ *+ * Permission to use, copy, modify, and distribute this+ * software is freely granted, provided that this notice + * is preserved.+ * ====================================================+ */++/* __ieee754_exp(x)+ * Returns the exponential of x.+ *+ * Method+ *   1. Argument reduction:+ *      Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.+ *	Given x, find r and integer k such that+ *+ *               x = k*ln2 + r,  |r| <= 0.5*ln2.  + *+ *      Here r will be represented as r = hi-lo for better + *	accuracy.+ *+ *   2. Approximation of exp(r) by a special rational function on+ *	the interval [0,0.34658]:+ *	Write+ *	    R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...+ *      We use a special Remes algorithm on [0,0.34658] to generate + * 	a polynomial of degree 5 to approximate R. The maximum error + *	of this polynomial approximation is bounded by 2**-59. In+ *	other words,+ *	    R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5+ *  	(where z=r*r, and the values of P1 to P5 are listed below)+ *	and+ *	    |                  5          |     -59+ *	    | 2.0+P1*z+...+P5*z   -  R(z) | <= 2 + *	    |                             |+ *	The computation of exp(r) thus becomes+ *                             2*r+ *		exp(r) = 1 + -------+ *		              R - r+ *                                 r*R1(r)	+ *		       = 1 + r + ----------- (for better accuracy)+ *		                  2 - R1(r)+ *	where+ *			         2       4             10+ *		R1(r) = r - (P1*r  + P2*r  + ... + P5*r   ).+ *	+ *   3. Scale back to obtain exp(x):+ *	From step 1, we have+ *	   exp(x) = 2^k * exp(r)+ *+ * Special cases:+ *	exp(INF) is INF, exp(NaN) is NaN;+ *	exp(-INF) is 0, and+ *	for finite argument, only exp(0)=1 is exact.+ *+ * Accuracy:+ *	according to an error analysis, the error is always less than+ *	1 ulp (unit in the last place).+ *+ * Misc. info.+ *	For IEEE double + *	    if x >  7.09782712893383973096e+02 then exp(x) overflow+ *	    if x < -7.45133219101941108420e+02 then exp(x) underflow+ *+ * Constants:+ * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough+ * to produce the hexadecimal values shown.+ */++static const double+two	=  2.0,+halF[2]	= {0.5,-0.5,},+twom1000= 9.33263618503218878990e-302,     /* 2**-1000=0x01700000,0*/+o_threshold=  7.09782712893383973096e+02,  /* 0x40862E42, 0xFEFA39EF */+u_threshold= -7.45133219101941108420e+02,  /* 0xc0874910, 0xD52D3051 */+ln2HI[2]   ={ 6.93147180369123816490e-01,  /* 0x3fe62e42, 0xfee00000 */+	     -6.93147180369123816490e-01,},/* 0xbfe62e42, 0xfee00000 */+ln2LO[2]   ={ 1.90821492927058770002e-10,  /* 0x3dea39ef, 0x35793c76 */+	     -1.90821492927058770002e-10,},/* 0xbdea39ef, 0x35793c76 */+    invln2 =  1.44269504088896338700e+00; /* 0x3ff71547, 0x652b82fe */+static const double P[] = {+    /* P1 */  1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */+    /* P2 */ -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */+    /* P3 */  6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */+    /* P4 */ -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */+    /* P5 */  4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */+};++/* compute exp(z+w)*2^n */+static double kernel_exp(double z, double w, double lo, double hi, int n)+{+    int j;+    double t, t1, r;+    t  = z*z;+    t1  = z - t*eval_poly(t, P, 5);+    r  = (z*t1)/(t1-two) - (w+z*w);+    z  = one-((lo + r)-hi);+    j  = get_high_word(z);+    j += (n<<20);+    if((j>>20)<=0)+        z = js_scalbn(z,n);	/* subnormal output */+    else+        z = set_high_word(z, get_high_word(z) + (n<<20));+    return z;+}++double js_exp(double x)+{+	double hi,lo,t;+	int k,xsb;+	unsigned hx;++	hx  = get_high_word(x);	/* high word of x */+	xsb = (hx>>31)&1;		/* sign bit of x */+	hx &= 0x7fffffff;		/* high word of |x| */++    /* filter out non-finite argument */+	if(hx >= 0x40862E42) {			/* if |x|>=709.78... */+            if(hx>=0x7ff00000) {+		if(((hx&0xfffff)|get_low_word(x))!=0) +		     return x+x; 		/* NaN */+		else return (xsb==0)? x:0.0;	/* exp(+-inf)={inf,0} */+	    }+	    if(x > o_threshold) return huge*huge; /* overflow */+	    if(x < u_threshold) return twom1000*twom1000; /* underflow */+	}++    /* argument reduction */+	if(hx > 0x3fd62e42) {		/* if  |x| > 0.5 ln2 */ +	    if(hx < 0x3FF0A2B2) {	/* and |x| < 1.5 ln2 */+		hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb;+	    } else {+		k  = (int)(invln2*x+halF[xsb]);+		t  = k;+		hi = x - t*ln2HI[0];	/* t*ln2HI is exact here */+		lo = t*ln2LO[0];+	    }+	    x  = hi - lo;+	} +	else if(hx < 0x3e300000)  {	/* when |x|<2**-28 */+	    if(huge+x>one) return one+x;/* trigger inexact */+            k = 0; /* avoid warning */+	}+	else k = 0;++        /* x is now in primary range */+        if (k == 0) {+            lo = 0;+            hi = x;+        }+        return kernel_exp(x, 0, lo, hi, k);+}+++/* @(#)e_pow.c 1.5 04/04/22 SMI */+/*+ * ====================================================+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.+ *+ * Permission to use, copy, modify, and distribute this+ * software is freely granted, provided that this notice + * is preserved.+ * ====================================================+ */++/* __ieee754_pow(x,y) return x**y+ *+ *		      n+ * Method:  Let x =  2   * (1+f)+ *	1. Compute and return log2(x) in two pieces:+ *		log2(x) = w1 + w2,+ *	   where w1 has 53-24 = 29 bit trailing zeros.+ *	2. Perform y*log2(x) = n+y' by simulating multi-precision + *	   arithmetic, where |y'|<=0.5.+ *	3. Return x**y = 2**n*exp(y'*log2)+ *+ * Special cases:+ *	1.  (anything) ** 0  is 1+ *	2.  (anything) ** 1  is itself+ *	3.  (anything) ** NAN is NAN+ *	4.  NAN ** (anything except 0) is NAN+ *	5.  +-(|x| > 1) **  +INF is +INF+ *	6.  +-(|x| > 1) **  -INF is +0+ *	7.  +-(|x| < 1) **  +INF is +0+ *	8.  +-(|x| < 1) **  -INF is +INF+ *	9.  +-1         ** +-INF is NAN+ *	10. +0 ** (+anything except 0, NAN)               is +0+ *	11. -0 ** (+anything except 0, NAN, odd integer)  is +0+ *	12. +0 ** (-anything except 0, NAN)               is +INF+ *	13. -0 ** (-anything except 0, NAN, odd integer)  is +INF+ *	14. -0 ** (odd integer) = -( +0 ** (odd integer) )+ *	15. +INF ** (+anything except 0,NAN) is +INF+ *	16. +INF ** (-anything except 0,NAN) is +0+ *	17. -INF ** (anything)  = -0 ** (-anything)+ *	18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)+ *	19. (-anything except 0 and inf) ** (non-integer) is NAN+ *+ * Accuracy:+ *	pow(x,y) returns x**y nearly rounded. In particular+ *			pow(integer,integer)+ *	always returns the correct integer provided it is + *	representable.+ *+ * Constants :+ * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown.+ */++static const double +bp[] = {1.0, 1.5,},+dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */+dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */+two53	=  9007199254740992.0,	/* 0x43400000, 0x00000000 */+	/* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */+lg2  =  6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */+lg2_h  =  6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */+lg2_l  = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */+ovt =  8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */+cp    =  9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */+cp_h  =  9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */+cp_l  = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/+ivln2    =  1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */+ivln2_h  =  1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/+ivln2_l  =  1.92596299112661746887e-08, /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/+ivlg10b2 = 0.3010299956639812, /*    0x3fd34413509f79ff 1/log2(10) */+ivlg10b2_h = 0.30102992057800293, /* 0x3fd3441300000000 1/log2(10) high */+ivlg10b2_l = 7.508597826552624e-8; /* 0x3e7427de7fbcc47c 1/log2(10) low */++static const double L_tab[] = {+    /* L1 */ 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */+    /* L2 */ 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */+    /* L3 */ 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */+    /* L4 */ 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */+    /* L5 */ 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */+    /* L6 */ 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */+};++/* compute (t1, t2) = log2(ax). is_small_ax is true if abs(ax)<= 2**-20 */+static void kernel_log2(double *pt1, double *pt2, double ax)+{+    double t, u, v, t1, t2, r;+    int n, j, ix, k;+    double ss, s2, s_h, s_l, t_h, t_l, p_l, p_h, z_h, z_l;++    n = 0;+    ix = get_high_word(ax);+    /* take care subnormal number */+    if(ix<0x00100000)+        {ax *= two53; n -= 53; ix = get_high_word(ax); }+    n  += ((ix)>>20)-0x3ff;+    j  = ix&0x000fffff;+    /* determine interval */+    ix = j|0x3ff00000;		/* normalize ix */+    if(j<=0x3988E) k=0;		/* |x|<sqrt(3/2) */+    else if(j<0xBB67A) k=1;	/* |x|<sqrt(3)   */+    else {k=0;n+=1;ix -= 0x00100000;}+    ax = set_high_word(ax, ix);+        +    /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */+    u = ax-bp[k];		/* bp[0]=1.0, bp[1]=1.5 */+    v = one/(ax+bp[k]);+    ss = u*v;+    s_h = zero_low(ss);+    /* t_h=ax+bp[k] High */+    t_h = zero;+    t_h = set_high_word(t_h, ((ix>>1)|0x20000000)+0x00080000+(k<<18));+    t_l = ax - (t_h-bp[k]);+    s_l = v*((u-s_h*t_h)-s_h*t_l);+    /* compute log(ax) */+    s2 = ss*ss;+    r = s2*s2*eval_poly(s2, L_tab, 6);+    r += s_l*(s_h+ss);+    s2  = s_h*s_h;+    t_h = zero_low(3.0+s2+r);+    t_l = r-((t_h-3.0)-s2);+    /* u+v = ss*(1+...) */+    u = s_h*t_h;+    v = s_l*t_h+t_l*ss;+    /* 2/(3log2)*(ss+...) */+    p_h = zero_low(u+v);+    p_l = v-(p_h-u);+    z_h = cp_h*p_h;		/* cp_h+cp_l = 2/(3*log2) */+    z_l = cp_l*p_h+p_l*cp+dp_l[k];+    /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */+    t = (double)n;+    t1 = zero_low(((z_h+z_l)+dp_h[k])+t);+    t2 = z_l-(((t1-t)-dp_h[k])-z_h);++    *pt1 = t1;+    *pt2 = t2;+}++/* flag = 0: log2()+   flag = 1: log()+   flag = 2: log10()+*/+static double js_log_internal(double x, int flag)+{+    double p_h, p_l, t, u, v;+    int hx, lx;++    EXTRACT_WORDS(hx, lx, x);+    if (hx <= 0) {+        if (((hx&0x7fffffff)|lx)==0) +            return -INFINITY;		/* log(+-0)=-inf */+        if (hx<0)+            return NAN;	/* log(-#) = NaN */+    } else if (hx >= 0x7ff00000) {+        /* log(inf) = inf, log(nan) = nan */+        return x+x;+    }+    kernel_log2(&p_h, &p_l, x);++    t = p_h + p_l;+    if (flag == 0) {+        return t;+    } else {+        t = zero_low(t);+        if (flag == 1) {+            /* multiply (p_l+p_h) by lg2 */+            u = t*lg2_h;+            v = (p_l-(t-p_h))*lg2+t*lg2_l;+        } else {+            /* mutiply (p_l+p_h) by 1/log2(10) */+            u = t*ivlg10b2_h;+            v = (p_l-(t-p_h))*ivlg10b2+t*ivlg10b2_l;+        }+        return u+v;+    }+}++double js_log2(double x)+{+    return js_log_internal(x, 0);+}++double js_log(double x)+{+    return js_log_internal(x, 1);+}++double js_log10(double x)+{+    return js_log_internal(x, 2);+}++double js_pow(double x, double y)+{+	double z,ax,p_h,p_l;+	double y1,t1,t2,s,t,u,v,w;+	int i,j,k,yisint,n;+	int hx,hy,ix,iy;+	unsigned lx,ly;++        EXTRACT_WORDS(hx, lx, x);+        EXTRACT_WORDS(hy, ly, y);+	ix = hx&0x7fffffff;  iy = hy&0x7fffffff;++    /* y==zero: x**0 = 1 */+	if((iy|ly)==0) return one; 	++    /* +-NaN return x+y */+	if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) ||+	   iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) +		return x+y;	++    /* determine if y is an odd int when x < 0+     * yisint = 0	... y is not an integer+     * yisint = 1	... y is an odd int+     * yisint = 2	... y is an even int+     */+	yisint  = 0;+	if(hx<0) {	+	    if(iy>=0x43400000) yisint = 2; /* even integer y */+	    else if(iy>=0x3ff00000) {+		k = (iy>>20)-0x3ff;	   /* exponent */+		if(k>20) {+		    j = ly>>(52-k);+		    if((j<<(52-k))==ly) yisint = 2-(j&1);+		} else if(ly==0) {+		    j = iy>>(20-k);+		    if((j<<(20-k))==iy) yisint = 2-(j&1);+		}+	    }		+	} ++    /* special value of y */+	if(ly==0) { 	+	    if (iy==0x7ff00000) {	/* y is +-inf */+	        if(((ix-0x3ff00000)|lx)==0)+		    return  y - y;	/* inf**+-1 is NaN */+	        else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */+		    return (hy>=0)? y: zero;+	        else			/* (|x|<1)**-,+inf = inf,0 */+		    return (hy<0)?-y: zero;+	    } +	    if(iy==0x3ff00000) {	/* y is  +-1 */+		if(hy<0) return one/x; else return x;+	    }+	    if(hy==0x40000000) return x*x; /* y is  2 */+	    if(hy==0x3fe00000) {	/* y is  0.5 */+		if(hx>=0)	/* x >= +0 */+		return js_sqrt(x);	+	    }+	}++	ax   = fabs(x);+    /* special value of x */+	if(lx==0) {+	    if(ix==0x7ff00000||ix==0||ix==0x3ff00000){+		z = ax;			/*x is +-0,+-inf,+-1*/+		if(hy<0) z = one/z;	/* z = (1/|x|) */+		if(hx<0) {+		    if(((ix-0x3ff00000)|yisint)==0) {+			z = (z-z)/(z-z); /* (-1)**non-int is NaN */+		    } else if(yisint==1) +			z = -z;		/* (x<0)**odd = -(|x|**odd) */+		}+		return z;+	    }+	}+    +	n = (hx>>31)+1;++    /* (x<0)**(non-int) is NaN */+	if((n|yisint)==0) return (x-x)/(x-x);++	s = one; /* s (sign of result -ve**odd) = -1 else = 1 */+	if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */++    /* |y| is huge */+	if(iy>0x41e00000) { /* if |y| > 2**31 */+	    if(iy>0x43f00000){	/* if |y| > 2**64, must o/uflow */+		if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny;+		if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny;+	    }+            /* over/underflow if x is not close to one */+	    if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny;+	    if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny;+            t = ax-one;		/* t has 20 trailing zeros */+            w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25));+            u = ivln2_h*t;	/* ivln2_h has 21 sig. bits */+            v = t*ivln2_l-w*ivln2;+            t1 = zero_low(u+v);+            t2 = v-(t1-u);+        } else {+            kernel_log2(&t1, &t2, ax);+        }+    /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */+	y1  = zero_low(y);+	p_l = (y-y1)*t1+y*t2;+	p_h = y1*t1;+	z = p_l+p_h;+        EXTRACT_WORDS(j, i, z);+	if (j>=0x40900000) {				/* z >= 1024 */+	    if(((j-0x40900000)|i)!=0)			/* if z > 1024 */+		return s*huge*huge;			/* overflow */+	    else {+		if(p_l+ovt>z-p_h) return s*huge*huge;	/* overflow */+	    }+	} else if((j&0x7fffffff)>=0x4090cc00 ) {	/* z <= -1075 */+	    if(((j-0xc090cc00)|i)!=0) 		/* z < -1075 */+		return s*tiny*tiny;		/* underflow */+	    else {+		if(p_l<=z-p_h) return s*tiny*tiny;	/* underflow */+	    }+	}+    /*+     * compute 2**(p_h+p_l)+     */+	i = j&0x7fffffff;+	k = (i>>20)-0x3ff;+	n = 0;+	if(i>0x3fe00000) {		/* if |z| > 0.5, set n = [z+0.5] */+	    n = j+(0x00100000>>(k+1));+	    k = ((n&0x7fffffff)>>20)-0x3ff;	/* new k for n */+	    t = zero;+	    t = set_high_word(t, n&~(0x000fffff>>k));+	    n = ((n&0x000fffff)|0x00100000)>>(20-k);+	    if(j<0) n = -n;+	    p_h -= t;+	}+        /* multiply (p_l+p_h) by lg2 */+	t = zero_low(p_l+p_h);+	u = t*lg2_h;+	v = (p_l-(t-p_h))*lg2+t*lg2_l;+	z = u+v;+	w = v-(z-u);+        return s * kernel_exp(z, w, 0, z, n);+}+
+ mquickjs/libm.h view
@@ -0,0 +1,46 @@+/*+ * Tiny Math 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.+ */+double js_scalbn(double x, int n);+double js_floor(double x);+double js_ceil(double x);+double js_trunc(double x);+double js_round_inf(double a);+double js_fabs(double x);+double js_sqrt(double x);+int32_t js_lrint(double a);+double js_fmod(double x, double y);+double js_sin(double x);+double js_cos(double x);+double js_tan(double x);+double js_acos(double x);+double js_asin(double x);+double js_atan(double x);+double js_atan2(double y, double x);+double js_exp(double x);+double js_log(double x);+double js_log2(double x);+double js_log10(double x);+double js_pow(double x, double y);+/* exported only for tests */+int js_rem_pio2(double x, double *y);
+ mquickjs/list.h view
@@ -0,0 +1,99 @@+/*+ * Linux klist like system+ * + * Copyright (c) 2016-2017 Fabrice Bellard+ *+ * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ *+ * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+ * THE SOFTWARE.+ */+#ifndef LIST_H+#define LIST_H++#ifndef NULL+#include <stddef.h>+#endif++struct list_head {+    struct list_head *prev;+    struct list_head *next;+};++#define LIST_HEAD_INIT(el) { &(el), &(el) }++/* return the pointer of type 'type *' containing 'el' as field 'member' */+#define list_entry(el, type, member) container_of(el, type, member)++static inline void init_list_head(struct list_head *head)+{+    head->prev = head;+    head->next = head;+}++/* insert 'el' between 'prev' and 'next' */+static inline void __list_add(struct list_head *el, +                              struct list_head *prev, struct list_head *next)+{+    prev->next = el;+    el->prev = prev;+    el->next = next;+    next->prev = el;+}++/* add 'el' at the head of the list 'head' (= after element head) */+static inline void list_add(struct list_head *el, struct list_head *head)+{+    __list_add(el, head, head->next);+}++/* add 'el' at the end of the list 'head' (= before element head) */+static inline void list_add_tail(struct list_head *el, struct list_head *head)+{+    __list_add(el, head->prev, head);+}++static inline void list_del(struct list_head *el)+{+    struct list_head *prev, *next;+    prev = el->prev;+    next = el->next;+    prev->next = next;+    next->prev = prev;+    el->prev = NULL; /* fail safe */+    el->next = NULL; /* fail safe */+}++static inline int list_empty(struct list_head *el)+{+    return el->next == el;+}++#define list_for_each(el, head) \+  for(el = (head)->next; el != (head); el = el->next)++#define list_for_each_safe(el, el1, head)                \+    for(el = (head)->next, el1 = el->next; el != (head); \+        el = el1, el1 = el->next)++#define list_for_each_prev(el, head) \+  for(el = (head)->prev; el != (head); el = el->prev)++#define list_for_each_prev_safe(el, el1, head)           \+    for(el = (head)->prev, el1 = el->prev; el != (head); \+        el = el1, el1 = el->prev)++#endif /* LIST_H */
+ mquickjs/mqjs_stdlib.h view
@@ -0,0 +1,2692 @@+/* this file is automatically generated - do not edit */++#include "mquickjs_priv.h"++static const uint64_t __attribute((aligned(64))) js_stdlib_table[] = {+  /* atom_table */+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "null" (offset=0) */+  0x000000006c6c756e,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "false" (offset=2) */+  0x00000065736c6166,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "true" (offset=4) */+  0x0000000065757274,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (2 << (JS_MTAG_BITS + 3)), /* "if" (offset=6) */+  0x0000000000006669,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "else" (offset=8) */+  0x0000000065736c65,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "return" (offset=10) */+  0x00006e7275746572,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "var" (offset=12) */+  0x0000000000726176,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "this" (offset=14) */+  0x0000000073696874,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "delete" (offset=16) */+  0x00006574656c6564,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "void" (offset=18) */+  0x0000000064696f76,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "typeof" (offset=20) */+  0x0000666f65707974,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "new" (offset=22) */+  0x000000000077656e,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (2 << (JS_MTAG_BITS + 3)), /* "in" (offset=24) */+  0x0000000000006e69,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (10 << (JS_MTAG_BITS + 3)), /* "instanceof" (offset=26) */+  0x65636e6174736e69,+  0x000000000000666f,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (2 << (JS_MTAG_BITS + 3)), /* "do" (offset=29) */+  0x0000000000006f64,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "while" (offset=31) */+  0x000000656c696877,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "for" (offset=33) */+  0x0000000000726f66,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "break" (offset=35) */+  0x0000006b61657262,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (8 << (JS_MTAG_BITS + 3)), /* "continue" (offset=37) */+  0x65756e69746e6f63,+  0x0000000000000000,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "switch" (offset=40) */+  0x0000686374697773,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "case" (offset=42) */+  0x0000000065736163,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "default" (offset=44) */+  0x00746c7561666564,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "throw" (offset=46) */+  0x000000776f726874,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "try" (offset=48) */+  0x0000000000797274,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "catch" (offset=50) */+  0x0000006863746163,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "finally" (offset=52) */+  0x00796c6c616e6966,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (8 << (JS_MTAG_BITS + 3)), /* "function" (offset=54) */+  0x6e6f6974636e7566,+  0x0000000000000000,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (8 << (JS_MTAG_BITS + 3)), /* "debugger" (offset=57) */+  0x7265676775626564,+  0x0000000000000000,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "with" (offset=60) */+  0x0000000068746977,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "class" (offset=62) */+  0x0000007373616c63,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "const" (offset=64) */+  0x00000074736e6f63,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "enum" (offset=66) */+  0x000000006d756e65,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "export" (offset=68) */+  0x000074726f707865,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "extends" (offset=70) */+  0x0073646e65747865,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "import" (offset=72) */+  0x000074726f706d69,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "super" (offset=74) */+  0x0000007265707573,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (10 << (JS_MTAG_BITS + 3)), /* "implements" (offset=76) */+  0x6e656d656c706d69,+  0x0000000000007374,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (9 << (JS_MTAG_BITS + 3)), /* "interface" (offset=79) */+  0x6361667265746e69,+  0x0000000000000065,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "let" (offset=82) */+  0x000000000074656c,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "package" (offset=84) */+  0x006567616b636170,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "private" (offset=86) */+  0x0065746176697270,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (9 << (JS_MTAG_BITS + 3)), /* "protected" (offset=88) */+  0x65746365746f7270,+  0x0000000000000064,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "public" (offset=91) */+  0x000063696c627570,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "static" (offset=93) */+  0x0000636974617473,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "yield" (offset=95) */+  0x000000646c656979,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (0 << (JS_MTAG_BITS + 3)), /* "" (offset=97) */+  0x0000000000000000,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (8 << (JS_MTAG_BITS + 3)), /* "toString" (offset=99) */+  0x676e697274536f74,+  0x0000000000000000,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "valueOf" (offset=102) */+  0x00664f65756c6176,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "number" (offset=104) */+  0x00007265626d756e,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "object" (offset=106) */+  0x00007463656a626f,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (9 << (JS_MTAG_BITS + 3)), /* "undefined" (offset=108) */+  0x656e696665646e75,+  0x0000000000000064,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "string" (offset=111) */+  0x0000676e69727473,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "boolean" (offset=113) */+  0x006e61656c6f6f62,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "<ret>" (offset=115) */+  0x0000003e7465723c,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "<eval>" (offset=117) */+  0x00003e6c6176653c,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "eval" (offset=119) */+  0x000000006c617665,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (9 << (JS_MTAG_BITS + 3)), /* "arguments" (offset=121) */+  0x746e656d75677261,+  0x0000000000000073,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "value" (offset=124) */+  0x00000065756c6176,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "get" (offset=126) */+  0x0000000000746567,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "set" (offset=128) */+  0x0000000000746573,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (9 << (JS_MTAG_BITS + 3)), /* "prototype" (offset=130) */+  0x7079746f746f7270,+  0x0000000000000065,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (11 << (JS_MTAG_BITS + 3)), /* "constructor" (offset=133) */+  0x63757274736e6f63,+  0x0000000000726f74,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "length" (offset=136) */+  0x00006874676e656c,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "target" (offset=138) */+  0x0000746567726174,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (2 << (JS_MTAG_BITS + 3)), /* "of" (offset=140) */+  0x000000000000666f,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (1 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "NaN" (offset=142) */+  0x00000000004e614e,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (1 << (JS_MTAG_BITS + 2)) | (8 << (JS_MTAG_BITS + 3)), /* "Infinity" (offset=144) */+  0x7974696e69666e49,+  0x0000000000000000,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (1 << (JS_MTAG_BITS + 2)) | (9 << (JS_MTAG_BITS + 3)), /* "-Infinity" (offset=147) */+  0x74696e69666e492d,+  0x0000000000000079,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "name" (offset=150) */+  0x00000000656d616e,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "Error" (offset=152) */+  0x000000726f727245,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (9 << (JS_MTAG_BITS + 3)), /* "__proto__" (offset=154) */+  0x5f6f746f72705f5f,+  0x000000000000005f,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "index" (offset=157) */+  0x0000007865646e69,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "input" (offset=159) */+  0x0000007475706e69,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "bound" (offset=161) */+  0x000000646e756f62,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "Object" (offset=163) */+  0x00007463656a624f,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (14 << (JS_MTAG_BITS + 3)), /* "defineProperty" (offset=165) */+  0x7250656e69666564,+  0x000079747265706f,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (14 << (JS_MTAG_BITS + 3)), /* "getPrototypeOf" (offset=168) */+  0x6f746f7250746567,+  0x0000664f65707974,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (14 << (JS_MTAG_BITS + 3)), /* "setPrototypeOf" (offset=171) */+  0x6f746f7250746573,+  0x0000664f65707974,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "create" (offset=174) */+  0x0000657461657263,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "keys" (offset=176) */+  0x000000007379656b,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (14 << (JS_MTAG_BITS + 3)), /* "hasOwnProperty" (offset=178) */+  0x72506e774f736168,+  0x000079747265706f,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (8 << (JS_MTAG_BITS + 3)), /* "Function" (offset=181) */+  0x6e6f6974636e7546,+  0x0000000000000000,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (13 << (JS_MTAG_BITS + 3)), /* "get prototype" (offset=184) */+  0x746f727020746567,+  0x000000657079746f,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (13 << (JS_MTAG_BITS + 3)), /* "set prototype" (offset=187) */+  0x746f727020746573,+  0x000000657079746f,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "call" (offset=190) */+  0x000000006c6c6163,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "apply" (offset=192) */+  0x000000796c707061,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "bind" (offset=194) */+  0x00000000646e6962,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (10 << (JS_MTAG_BITS + 3)), /* "get length" (offset=196) */+  0x676e656c20746567,+  0x0000000000006874,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (8 << (JS_MTAG_BITS + 3)), /* "get name" (offset=199) */+  0x656d616e20746567,+  0x0000000000000000,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "Number" (offset=202) */+  0x00007265626d754e,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (8 << (JS_MTAG_BITS + 3)), /* "parseInt" (offset=204) */+  0x746e496573726170,+  0x0000000000000000,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (10 << (JS_MTAG_BITS + 3)), /* "parseFloat" (offset=207) */+  0x6f6c466573726170,+  0x0000000000007461,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (9 << (JS_MTAG_BITS + 3)), /* "MAX_VALUE" (offset=210) */+  0x554c41565f58414d,+  0x0000000000000045,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (9 << (JS_MTAG_BITS + 3)), /* "MIN_VALUE" (offset=213) */+  0x554c41565f4e494d,+  0x0000000000000045,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (17 << (JS_MTAG_BITS + 3)), /* "NEGATIVE_INFINITY" (offset=216) */+  0x455649544147454e,+  0x54494e49464e495f,+  0x0000000000000059,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (17 << (JS_MTAG_BITS + 3)), /* "POSITIVE_INFINITY" (offset=220) */+  0x4556495449534f50,+  0x54494e49464e495f,+  0x0000000000000059,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "EPSILON" (offset=224) */+  0x004e4f4c49535045,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (16 << (JS_MTAG_BITS + 3)), /* "MAX_SAFE_INTEGER" (offset=226) */+  0x454641535f58414d,+  0x52454745544e495f,+  0x0000000000000000,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (16 << (JS_MTAG_BITS + 3)), /* "MIN_SAFE_INTEGER" (offset=230) */+  0x454641535f4e494d,+  0x52454745544e495f,+  0x0000000000000000,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (13 << (JS_MTAG_BITS + 3)), /* "toExponential" (offset=234) */+  0x656e6f7078456f74,+  0x0000006c6169746e,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "toFixed" (offset=237) */+  0x0064657869466f74,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (11 << (JS_MTAG_BITS + 3)), /* "toPrecision" (offset=239) */+  0x7369636572506f74,+  0x00000000006e6f69,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "Boolean" (offset=242) */+  0x006e61656c6f6f42,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "String" (offset=244) */+  0x0000676e69727453,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (12 << (JS_MTAG_BITS + 3)), /* "fromCharCode" (offset=246) */+  0x726168436d6f7266,+  0x0000000065646f43,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (13 << (JS_MTAG_BITS + 3)), /* "fromCodePoint" (offset=249) */+  0x65646f436d6f7266,+  0x000000746e696f50,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (10 << (JS_MTAG_BITS + 3)), /* "set length" (offset=252) */+  0x676e656c20746573,+  0x0000000000006874,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "charAt" (offset=255) */+  0x0000744172616863,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (10 << (JS_MTAG_BITS + 3)), /* "charCodeAt" (offset=257) */+  0x65646f4372616863,+  0x0000000000007441,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (11 << (JS_MTAG_BITS + 3)), /* "codePointAt" (offset=260) */+  0x6e696f5065646f63,+  0x0000000000744174,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "slice" (offset=263) */+  0x0000006563696c73,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (9 << (JS_MTAG_BITS + 3)), /* "substring" (offset=265) */+  0x6e69727473627573,+  0x0000000000000067,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "concat" (offset=268) */+  0x00007461636e6f63,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "indexOf" (offset=270) */+  0x00664f7865646e69,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (11 << (JS_MTAG_BITS + 3)), /* "lastIndexOf" (offset=272) */+  0x65646e497473616c,+  0x0000000000664f78,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "match" (offset=275) */+  0x000000686374616d,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "replace" (offset=277) */+  0x006563616c706572,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (10 << (JS_MTAG_BITS + 3)), /* "replaceAll" (offset=279) */+  0x416563616c706572,+  0x0000000000006c6c,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "search" (offset=282) */+  0x0000686372616573,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "split" (offset=284) */+  0x00000074696c7073,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (11 << (JS_MTAG_BITS + 3)), /* "toLowerCase" (offset=286) */+  0x437265776f4c6f74,+  0x0000000000657361,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (11 << (JS_MTAG_BITS + 3)), /* "toUpperCase" (offset=289) */+  0x4372657070556f74,+  0x0000000000657361,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "trim" (offset=292) */+  0x000000006d697274,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "trimEnd" (offset=294) */+  0x00646e456d697274,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (9 << (JS_MTAG_BITS + 3)), /* "trimStart" (offset=296) */+  0x726174536d697274,+  0x0000000000000074,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "repeat" (offset=299) */+  0x0000746165706572,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "Array" (offset=301) */+  0x0000007961727241,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "isArray" (offset=303) */+  0x0079617272417369,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "push" (offset=305) */+  0x0000000068737570,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "pop" (offset=307) */+  0x0000000000706f70,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "join" (offset=309) */+  0x000000006e696f6a,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "reverse" (offset=311) */+  0x0065737265766572,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "shift" (offset=313) */+  0x0000007466696873,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "splice" (offset=315) */+  0x00006563696c7073,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "unshift" (offset=317) */+  0x0074666968736e75,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "every" (offset=319) */+  0x0000007972657665,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "some" (offset=321) */+  0x00000000656d6f73,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "forEach" (offset=323) */+  0x0068636145726f66,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "map" (offset=325) */+  0x000000000070616d,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "filter" (offset=327) */+  0x00007265746c6966,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "reduce" (offset=329) */+  0x0000656375646572,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (11 << (JS_MTAG_BITS + 3)), /* "reduceRight" (offset=331) */+  0x6952656375646572,+  0x0000000000746867,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "sort" (offset=334) */+  0x0000000074726f73,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "Math" (offset=336) */+  0x000000006874614d,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "min" (offset=338) */+  0x00000000006e696d,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "max" (offset=340) */+  0x000000000078616d,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "sign" (offset=342) */+  0x000000006e676973,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "abs" (offset=344) */+  0x0000000000736261,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "floor" (offset=346) */+  0x000000726f6f6c66,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "ceil" (offset=348) */+  0x000000006c696563,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "round" (offset=350) */+  0x000000646e756f72,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "sqrt" (offset=352) */+  0x0000000074727173,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (1 << (JS_MTAG_BITS + 3)), /* "E" (offset=354) */+  0x0000000000000045,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "LN10" (offset=356) */+  0x0000000030314e4c,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "LN2" (offset=358) */+  0x0000000000324e4c,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "LOG2E" (offset=360) */+  0x0000004532474f4c,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "LOG10E" (offset=362) */+  0x0000453031474f4c,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (2 << (JS_MTAG_BITS + 3)), /* "PI" (offset=364) */+  0x0000000000004950,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "SQRT1_2" (offset=366) */+  0x00325f3154525153,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "SQRT2" (offset=368) */+  0x0000003254525153,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "sin" (offset=370) */+  0x00000000006e6973,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "cos" (offset=372) */+  0x0000000000736f63,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "tan" (offset=374) */+  0x00000000006e6174,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "asin" (offset=376) */+  0x000000006e697361,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "acos" (offset=378) */+  0x00000000736f6361,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "atan" (offset=380) */+  0x000000006e617461,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "atan2" (offset=382) */+  0x000000326e617461,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "exp" (offset=384) */+  0x0000000000707865,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "log" (offset=386) */+  0x0000000000676f6c,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "pow" (offset=388) */+  0x0000000000776f70,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "random" (offset=390) */+  0x00006d6f646e6172,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "imul" (offset=392) */+  0x000000006c756d69,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "clz32" (offset=394) */+  0x00000032337a6c63,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "fround" (offset=396) */+  0x0000646e756f7266,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "trunc" (offset=398) */+  0x000000636e757274,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "log2" (offset=400) */+  0x0000000032676f6c,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "log10" (offset=402) */+  0x0000003031676f6c,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "Date" (offset=404) */+  0x0000000065746144,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (3 << (JS_MTAG_BITS + 3)), /* "now" (offset=406) */+  0x0000000000776f6e,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "JSON" (offset=408) */+  0x000000004e4f534a,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "parse" (offset=410) */+  0x0000006573726170,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (9 << (JS_MTAG_BITS + 3)), /* "stringify" (offset=412) */+  0x6669676e69727473,+  0x0000000000000079,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "RegExp" (offset=415) */+  0x0000707845676552,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (9 << (JS_MTAG_BITS + 3)), /* "lastIndex" (offset=417) */+  0x65646e497473616c,+  0x0000000000000078,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (13 << (JS_MTAG_BITS + 3)), /* "get lastIndex" (offset=420) */+  0x7473616c20746567,+  0x0000007865646e49,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (13 << (JS_MTAG_BITS + 3)), /* "set lastIndex" (offset=423) */+  0x7473616c20746573,+  0x0000007865646e49,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "source" (offset=426) */+  0x0000656372756f73,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (10 << (JS_MTAG_BITS + 3)), /* "get source" (offset=428) */+  0x72756f7320746567,+  0x0000000000006563,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "flags" (offset=431) */+  0x0000007367616c66,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (9 << (JS_MTAG_BITS + 3)), /* "get flags" (offset=433) */+  0x67616c6620746567,+  0x0000000000000073,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "exec" (offset=436) */+  0x0000000063657865,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "test" (offset=438) */+  0x0000000074736574,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "message" (offset=440) */+  0x006567617373656d,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (11 << (JS_MTAG_BITS + 3)), /* "get message" (offset=442) */+  0x7373656d20746567,+  0x0000000000656761,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "stack" (offset=445) */+  0x0000006b63617473,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (9 << (JS_MTAG_BITS + 3)), /* "get stack" (offset=447) */+  0x6361747320746567,+  0x000000000000006b,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (9 << (JS_MTAG_BITS + 3)), /* "EvalError" (offset=450) */+  0x6f7272456c617645,+  0x0000000000000072,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (10 << (JS_MTAG_BITS + 3)), /* "RangeError" (offset=453) */+  0x72724565676e6152,+  0x000000000000726f,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (14 << (JS_MTAG_BITS + 3)), /* "ReferenceError" (offset=456) */+  0x636e657265666552,+  0x0000726f72724565,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (11 << (JS_MTAG_BITS + 3)), /* "SyntaxError" (offset=459) */+  0x72457861746e7953,+  0x0000000000726f72,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (9 << (JS_MTAG_BITS + 3)), /* "TypeError" (offset=462) */+  0x6f72724565707954,+  0x0000000000000072,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (8 << (JS_MTAG_BITS + 3)), /* "URIError" (offset=465) */+  0x726f727245495255,+  0x0000000000000000,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (13 << (JS_MTAG_BITS + 3)), /* "InternalError" (offset=468) */+  0x6c616e7265746e49,+  0x000000726f727245,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (11 << (JS_MTAG_BITS + 3)), /* "ArrayBuffer" (offset=471) */+  0x6675427961727241,+  0x0000000000726566,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (10 << (JS_MTAG_BITS + 3)), /* "byteLength" (offset=474) */+  0x676e654c65747962,+  0x0000000000006874,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (14 << (JS_MTAG_BITS + 3)), /* "get byteLength" (offset=477) */+  0x6574796220746567,+  0x00006874676e654c,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (17 << (JS_MTAG_BITS + 3)), /* "Uint8ClampedArray" (offset=480) */+  0x616c4338746e6955,+  0x617272416465706d,+  0x0000000000000079,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (10 << (JS_MTAG_BITS + 3)), /* "TypedArray" (offset=484) */+  0x7272416465707954,+  0x0000000000007961,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (10 << (JS_MTAG_BITS + 3)), /* "byteOffset" (offset=487) */+  0x7366664f65747962,+  0x0000000000007465,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (14 << (JS_MTAG_BITS + 3)), /* "get byteOffset" (offset=490) */+  0x6574796220746567,+  0x000074657366664f,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (6 << (JS_MTAG_BITS + 3)), /* "buffer" (offset=493) */+  0x0000726566667562,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (10 << (JS_MTAG_BITS + 3)), /* "get buffer" (offset=495) */+  0x6666756220746567,+  0x0000000000007265,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (8 << (JS_MTAG_BITS + 3)), /* "subarray" (offset=498) */+  0x7961727261627573,+  0x0000000000000000,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (17 << (JS_MTAG_BITS + 3)), /* "BYTES_PER_ELEMENT" (offset=501) */+  0x45505f5345545942,+  0x4e454d454c455f52,+  0x0000000000000054,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (9 << (JS_MTAG_BITS + 3)), /* "Int8Array" (offset=505) */+  0x6172724138746e49,+  0x0000000000000079,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (10 << (JS_MTAG_BITS + 3)), /* "Uint8Array" (offset=508) */+  0x72724138746e6955,+  0x0000000000007961,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (10 << (JS_MTAG_BITS + 3)), /* "Int16Array" (offset=511) */+  0x7272413631746e49,+  0x0000000000007961,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (11 << (JS_MTAG_BITS + 3)), /* "Uint16Array" (offset=514) */+  0x72413631746e6955,+  0x0000000000796172,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (10 << (JS_MTAG_BITS + 3)), /* "Int32Array" (offset=517) */+  0x7272413233746e49,+  0x0000000000007961,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (11 << (JS_MTAG_BITS + 3)), /* "Uint32Array" (offset=520) */+  0x72413233746e6955,+  0x0000000000796172,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (12 << (JS_MTAG_BITS + 3)), /* "Float32Array" (offset=523) */+  0x41323374616f6c46,+  0x0000000079617272,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (12 << (JS_MTAG_BITS + 3)), /* "Float64Array" (offset=526) */+  0x41343674616f6c46,+  0x0000000079617272,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "isNaN" (offset=529) */+  0x0000004e614e7369,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (8 << (JS_MTAG_BITS + 3)), /* "isFinite" (offset=531) */+  0x6574696e69467369,+  0x0000000000000000,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (10 << (JS_MTAG_BITS + 3)), /* "globalThis" (offset=534) */+  0x68546c61626f6c67,+  0x0000000000007369,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (7 << (JS_MTAG_BITS + 3)), /* "console" (offset=537) */+  0x00656c6f736e6f63,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (11 << (JS_MTAG_BITS + 3)), /* "performance" (offset=539) */+  0x616d726f66726570,+  0x000000000065636e,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (5 << (JS_MTAG_BITS + 3)), /* "print" (offset=542) */+  0x000000746e697270,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (2 << (JS_MTAG_BITS + 3)), /* "gc" (offset=544) */+  0x0000000000006367,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (4 << (JS_MTAG_BITS + 3)), /* "load" (offset=546) */+  0x0000000064616f6c,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (10 << (JS_MTAG_BITS + 3)), /* "setTimeout" (offset=548) */+  0x6f656d6954746573,+  0x0000000000007475,+  (JS_MTAG_STRING << 1) | (1 << JS_MTAG_BITS) | (1 << (JS_MTAG_BITS + 1)) | (0 << (JS_MTAG_BITS + 2)) | (12 << (JS_MTAG_BITS + 3)), /* "clearTimeout" (offset=551) */+  0x6d69547261656c63,+  0x0000000074756f65,++  /* sorted atom table (offset=554) */+  JS_VALUE_ARRAY_HEADER(232),+  JS_ROM_VALUE(97), /* empty */+  JS_ROM_VALUE(147), /* _Infinity */+  JS_ROM_VALUE(117), /* _eval_ */+  JS_ROM_VALUE(115), /* _ret_ */+  JS_ROM_VALUE(301), /* Array */+  JS_ROM_VALUE(471), /* ArrayBuffer */+  JS_ROM_VALUE(501), /* BYTES_PER_ELEMENT */+  JS_ROM_VALUE(242), /* Boolean */+  JS_ROM_VALUE(404), /* Date */+  JS_ROM_VALUE(354), /* E */+  JS_ROM_VALUE(224), /* EPSILON */+  JS_ROM_VALUE(152), /* Error */+  JS_ROM_VALUE(450), /* EvalError */+  JS_ROM_VALUE(523), /* Float32Array */+  JS_ROM_VALUE(526), /* Float64Array */+  JS_ROM_VALUE(181), /* Function */+  JS_ROM_VALUE(144), /* Infinity */+  JS_ROM_VALUE(511), /* Int16Array */+  JS_ROM_VALUE(517), /* Int32Array */+  JS_ROM_VALUE(505), /* Int8Array */+  JS_ROM_VALUE(468), /* InternalError */+  JS_ROM_VALUE(408), /* JSON */+  JS_ROM_VALUE(356), /* LN10 */+  JS_ROM_VALUE(358), /* LN2 */+  JS_ROM_VALUE(362), /* LOG10E */+  JS_ROM_VALUE(360), /* LOG2E */+  JS_ROM_VALUE(226), /* MAX_SAFE_INTEGER */+  JS_ROM_VALUE(210), /* MAX_VALUE */+  JS_ROM_VALUE(230), /* MIN_SAFE_INTEGER */+  JS_ROM_VALUE(213), /* MIN_VALUE */+  JS_ROM_VALUE(336), /* Math */+  JS_ROM_VALUE(216), /* NEGATIVE_INFINITY */+  JS_ROM_VALUE(142), /* NaN */+  JS_ROM_VALUE(202), /* Number */+  JS_ROM_VALUE(163), /* Object */+  JS_ROM_VALUE(364), /* PI */+  JS_ROM_VALUE(220), /* POSITIVE_INFINITY */+  JS_ROM_VALUE(453), /* RangeError */+  JS_ROM_VALUE(456), /* ReferenceError */+  JS_ROM_VALUE(415), /* RegExp */+  JS_ROM_VALUE(366), /* SQRT1_2 */+  JS_ROM_VALUE(368), /* SQRT2 */+  JS_ROM_VALUE(244), /* String */+  JS_ROM_VALUE(459), /* SyntaxError */+  JS_ROM_VALUE(462), /* TypeError */+  JS_ROM_VALUE(484), /* TypedArray */+  JS_ROM_VALUE(465), /* URIError */+  JS_ROM_VALUE(514), /* Uint16Array */+  JS_ROM_VALUE(520), /* Uint32Array */+  JS_ROM_VALUE(508), /* Uint8Array */+  JS_ROM_VALUE(480), /* Uint8ClampedArray */+  JS_ROM_VALUE(154), /* __proto__ */+  JS_ROM_VALUE(344), /* abs */+  JS_ROM_VALUE(378), /* acos */+  JS_ROM_VALUE(192), /* apply */+  JS_ROM_VALUE(121), /* arguments */+  JS_ROM_VALUE(376), /* asin */+  JS_ROM_VALUE(380), /* atan */+  JS_ROM_VALUE(382), /* atan2 */+  JS_ROM_VALUE(194), /* bind */+  JS_ROM_VALUE(113), /* boolean */+  JS_ROM_VALUE(161), /* bound */+  JS_ROM_VALUE(35), /* break */+  JS_ROM_VALUE(493), /* buffer */+  JS_ROM_VALUE(474), /* byteLength */+  JS_ROM_VALUE(487), /* byteOffset */+  JS_ROM_VALUE(190), /* call */+  JS_ROM_VALUE(42), /* case */+  JS_ROM_VALUE(50), /* catch */+  JS_ROM_VALUE(348), /* ceil */+  JS_ROM_VALUE(255), /* charAt */+  JS_ROM_VALUE(257), /* charCodeAt */+  JS_ROM_VALUE(62), /* class */+  JS_ROM_VALUE(551), /* clearTimeout */+  JS_ROM_VALUE(394), /* clz32 */+  JS_ROM_VALUE(260), /* codePointAt */+  JS_ROM_VALUE(268), /* concat */+  JS_ROM_VALUE(537), /* console */+  JS_ROM_VALUE(64), /* const */+  JS_ROM_VALUE(133), /* constructor */+  JS_ROM_VALUE(37), /* continue */+  JS_ROM_VALUE(372), /* cos */+  JS_ROM_VALUE(174), /* create */+  JS_ROM_VALUE(57), /* debugger */+  JS_ROM_VALUE(44), /* default */+  JS_ROM_VALUE(165), /* defineProperty */+  JS_ROM_VALUE(16), /* delete */+  JS_ROM_VALUE(29), /* do */+  JS_ROM_VALUE(8), /* else */+  JS_ROM_VALUE(66), /* enum */+  JS_ROM_VALUE(119), /* eval */+  JS_ROM_VALUE(319), /* every */+  JS_ROM_VALUE(436), /* exec */+  JS_ROM_VALUE(384), /* exp */+  JS_ROM_VALUE(68), /* export */+  JS_ROM_VALUE(70), /* extends */+  JS_ROM_VALUE(2), /* false */+  JS_ROM_VALUE(327), /* filter */+  JS_ROM_VALUE(52), /* finally */+  JS_ROM_VALUE(431), /* flags */+  JS_ROM_VALUE(346), /* floor */+  JS_ROM_VALUE(33), /* for */+  JS_ROM_VALUE(323), /* forEach */+  JS_ROM_VALUE(246), /* fromCharCode */+  JS_ROM_VALUE(249), /* fromCodePoint */+  JS_ROM_VALUE(396), /* fround */+  JS_ROM_VALUE(54), /* function */+  JS_ROM_VALUE(544), /* gc */+  JS_ROM_VALUE(126), /* get */+  JS_ROM_VALUE(495), /* get buffer */+  JS_ROM_VALUE(477), /* get byteLength */+  JS_ROM_VALUE(490), /* get byteOffset */+  JS_ROM_VALUE(433), /* get flags */+  JS_ROM_VALUE(420), /* get lastIndex */+  JS_ROM_VALUE(196), /* get length */+  JS_ROM_VALUE(442), /* get message */+  JS_ROM_VALUE(199), /* get name */+  JS_ROM_VALUE(184), /* get prototype */+  JS_ROM_VALUE(428), /* get source */+  JS_ROM_VALUE(447), /* get stack */+  JS_ROM_VALUE(168), /* getPrototypeOf */+  JS_ROM_VALUE(534), /* globalThis */+  JS_ROM_VALUE(178), /* hasOwnProperty */+  JS_ROM_VALUE(6), /* if */+  JS_ROM_VALUE(76), /* implements */+  JS_ROM_VALUE(72), /* import */+  JS_ROM_VALUE(392), /* imul */+  JS_ROM_VALUE(24), /* in */+  JS_ROM_VALUE(157), /* index */+  JS_ROM_VALUE(270), /* indexOf */+  JS_ROM_VALUE(159), /* input */+  JS_ROM_VALUE(26), /* instanceof */+  JS_ROM_VALUE(79), /* interface */+  JS_ROM_VALUE(303), /* isArray */+  JS_ROM_VALUE(531), /* isFinite */+  JS_ROM_VALUE(529), /* isNaN */+  JS_ROM_VALUE(309), /* join */+  JS_ROM_VALUE(176), /* keys */+  JS_ROM_VALUE(417), /* lastIndex */+  JS_ROM_VALUE(272), /* lastIndexOf */+  JS_ROM_VALUE(136), /* length */+  JS_ROM_VALUE(82), /* let */+  JS_ROM_VALUE(546), /* load */+  JS_ROM_VALUE(386), /* log */+  JS_ROM_VALUE(402), /* log10 */+  JS_ROM_VALUE(400), /* log2 */+  JS_ROM_VALUE(325), /* map */+  JS_ROM_VALUE(275), /* match */+  JS_ROM_VALUE(340), /* max */+  JS_ROM_VALUE(440), /* message */+  JS_ROM_VALUE(338), /* min */+  JS_ROM_VALUE(150), /* name */+  JS_ROM_VALUE(22), /* new */+  JS_ROM_VALUE(406), /* now */+  JS_ROM_VALUE(0), /* null */+  JS_ROM_VALUE(104), /* number */+  JS_ROM_VALUE(106), /* object */+  JS_ROM_VALUE(140), /* of */+  JS_ROM_VALUE(84), /* package */+  JS_ROM_VALUE(410), /* parse */+  JS_ROM_VALUE(207), /* parseFloat */+  JS_ROM_VALUE(204), /* parseInt */+  JS_ROM_VALUE(539), /* performance */+  JS_ROM_VALUE(307), /* pop */+  JS_ROM_VALUE(388), /* pow */+  JS_ROM_VALUE(542), /* print */+  JS_ROM_VALUE(86), /* private */+  JS_ROM_VALUE(88), /* protected */+  JS_ROM_VALUE(130), /* prototype */+  JS_ROM_VALUE(91), /* public */+  JS_ROM_VALUE(305), /* push */+  JS_ROM_VALUE(390), /* random */+  JS_ROM_VALUE(329), /* reduce */+  JS_ROM_VALUE(331), /* reduceRight */+  JS_ROM_VALUE(299), /* repeat */+  JS_ROM_VALUE(277), /* replace */+  JS_ROM_VALUE(279), /* replaceAll */+  JS_ROM_VALUE(10), /* return */+  JS_ROM_VALUE(311), /* reverse */+  JS_ROM_VALUE(350), /* round */+  JS_ROM_VALUE(282), /* search */+  JS_ROM_VALUE(128), /* set */+  JS_ROM_VALUE(423), /* set lastIndex */+  JS_ROM_VALUE(252), /* set length */+  JS_ROM_VALUE(187), /* set prototype */+  JS_ROM_VALUE(171), /* setPrototypeOf */+  JS_ROM_VALUE(548), /* setTimeout */+  JS_ROM_VALUE(313), /* shift */+  JS_ROM_VALUE(342), /* sign */+  JS_ROM_VALUE(370), /* sin */+  JS_ROM_VALUE(263), /* slice */+  JS_ROM_VALUE(321), /* some */+  JS_ROM_VALUE(334), /* sort */+  JS_ROM_VALUE(426), /* source */+  JS_ROM_VALUE(315), /* splice */+  JS_ROM_VALUE(284), /* split */+  JS_ROM_VALUE(352), /* sqrt */+  JS_ROM_VALUE(445), /* stack */+  JS_ROM_VALUE(93), /* static */+  JS_ROM_VALUE(111), /* string */+  JS_ROM_VALUE(412), /* stringify */+  JS_ROM_VALUE(498), /* subarray */+  JS_ROM_VALUE(265), /* substring */+  JS_ROM_VALUE(74), /* super */+  JS_ROM_VALUE(40), /* switch */+  JS_ROM_VALUE(374), /* tan */+  JS_ROM_VALUE(138), /* target */+  JS_ROM_VALUE(438), /* test */+  JS_ROM_VALUE(14), /* this */+  JS_ROM_VALUE(46), /* throw */+  JS_ROM_VALUE(234), /* toExponential */+  JS_ROM_VALUE(237), /* toFixed */+  JS_ROM_VALUE(286), /* toLowerCase */+  JS_ROM_VALUE(239), /* toPrecision */+  JS_ROM_VALUE(99), /* toString */+  JS_ROM_VALUE(289), /* toUpperCase */+  JS_ROM_VALUE(292), /* trim */+  JS_ROM_VALUE(294), /* trimEnd */+  JS_ROM_VALUE(296), /* trimStart */+  JS_ROM_VALUE(4), /* true */+  JS_ROM_VALUE(398), /* trunc */+  JS_ROM_VALUE(48), /* try */+  JS_ROM_VALUE(20), /* typeof */+  JS_ROM_VALUE(108), /* undefined */+  JS_ROM_VALUE(317), /* unshift */+  JS_ROM_VALUE(124), /* value */+  JS_ROM_VALUE(102), /* valueOf */+  JS_ROM_VALUE(12), /* var */+  JS_ROM_VALUE(18), /* void */+  JS_ROM_VALUE(31), /* while */+  JS_ROM_VALUE(60), /* with */+  JS_ROM_VALUE(95), /* yield */++  /* properties (offset=787) */+  JS_VALUE_ARRAY_HEADER(24),+  6 << 1, /* n_props */+  3 << 1, /* hash_mask */+  6 << 1,+  18 << 1,+  12 << 1,+  21 << 1,+  JS_ROM_VALUE(165) /* defineProperty */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 2),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(168) /* getPrototypeOf */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 3),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(171) /* setPrototypeOf */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 4),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(174) /* create */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 5),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(176) /* keys */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 6),+  (9 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_OBJECT << 1,+  (15 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=812) */+  JS_VALUE_ARRAY_HEADER(13),+  3 << 1, /* n_props */+  1 << 1, /* hash_mask */+  10 << 1,+  4 << 1,+  JS_ROM_VALUE(178) /* hasOwnProperty */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 7),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(99) /* toString */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 8),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_OBJECT - 1) << 1,+  (7 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=826) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(787),+  1,+  JS_ROM_VALUE(812),+  JS_NULL,++  /* properties (offset=831) */+  JS_VALUE_ARRAY_HEADER(6),+  1 << 1, /* n_props */+  0 << 1, /* hash_mask */+  3 << 1,+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_CLOSURE << 1,+  (0 << 1) | (JS_PROP_SPECIAL << 30),+  /* getset (offset=838) */+  JS_VALUE_ARRAY_HEADER(2),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 10),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 11),++  /* getset (offset=841) */+  JS_VALUE_ARRAY_HEADER(2),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 12),+  JS_UNDEFINED,++  /* getset (offset=844) */+  JS_VALUE_ARRAY_HEADER(2),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 13),+  JS_UNDEFINED,++  /* properties (offset=847) */+  JS_VALUE_ARRAY_HEADER(30),+  8 << 1, /* n_props */+  3 << 1, /* hash_mask */+  27 << 1,+  21 << 1,+  18 << 1,+  24 << 1,+  JS_ROM_VALUE(130) /* prototype */,+  JS_ROM_VALUE(838),+  (0 << 1) | (JS_PROP_GETSET << 30),+  JS_ROM_VALUE(190) /* call */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 14),+  (6 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(192) /* apply */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 15),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(194) /* bind */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 16),+  (9 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(99) /* toString */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 17),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(136) /* length */,+  JS_ROM_VALUE(841),+  (12 << 1) | (JS_PROP_GETSET << 30),+  JS_ROM_VALUE(150) /* name */,+  JS_ROM_VALUE(844),+  (15 << 1) | (JS_PROP_GETSET << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_CLOSURE - 1) << 1,+  (0 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=878) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(831),+  9,+  JS_ROM_VALUE(847),+  JS_NULL,++  /* float64 (offset=883) */+  JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),+  0x7fefffffffffffff,++  /* float64 (offset=885) */+  JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),+  0x0000000000000001,++  /* float64 (offset=887) */+  JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),+  0x7ff8000000000000,++  /* float64 (offset=889) */+  JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),+  0xfff0000000000000,++  /* float64 (offset=891) */+  JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),+  0x7ff0000000000000,++  /* float64 (offset=893) */+  JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),+  0x3cb0000000000000,++  /* float64 (offset=895) */+  JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),+  0x433fffffffffffff,++  /* float64 (offset=897) */+  JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),+  0xc33fffffffffffff,++  /* properties (offset=899) */+  JS_VALUE_ARRAY_HEADER(43),+  11 << 1, /* n_props */+  7 << 1, /* hash_mask */+  0 << 1,+  31 << 1,+  0 << 1,+  40 << 1,+  19 << 1,+  28 << 1,+  13 << 1,+  37 << 1,+  JS_ROM_VALUE(204) /* parseInt */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 19),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(207) /* parseFloat */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 20),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(210) /* MAX_VALUE */,+  JS_ROM_VALUE(883),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(213) /* MIN_VALUE */,+  JS_ROM_VALUE(885),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(142) /* NaN */,+  JS_ROM_VALUE(887),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(216) /* NEGATIVE_INFINITY */,+  JS_ROM_VALUE(889),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(220) /* POSITIVE_INFINITY */,+  JS_ROM_VALUE(891),+  (10 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(224) /* EPSILON */,+  JS_ROM_VALUE(893),+  (25 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(226) /* MAX_SAFE_INTEGER */,+  JS_ROM_VALUE(895),+  (16 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(230) /* MIN_SAFE_INTEGER */,+  JS_ROM_VALUE(897),+  (22 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_NUMBER << 1,+  (34 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=943) */+  JS_VALUE_ARRAY_HEADER(21),+  5 << 1, /* n_props */+  3 << 1, /* hash_mask */+  18 << 1,+  0 << 1,+  15 << 1,+  6 << 1,+  JS_ROM_VALUE(234) /* toExponential */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 21),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(237) /* toFixed */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 22),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(239) /* toPrecision */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 23),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(99) /* toString */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 24),+  (12 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_NUMBER - 1) << 1,+  (9 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=965) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(899),+  18,+  JS_ROM_VALUE(943),+  JS_NULL,++  /* properties (offset=970) */+  JS_VALUE_ARRAY_HEADER(6),+  1 << 1, /* n_props */+  0 << 1, /* hash_mask */+  3 << 1,+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_BOOLEAN << 1,+  (0 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=977) */+  JS_VALUE_ARRAY_HEADER(6),+  1 << 1, /* n_props */+  0 << 1, /* hash_mask */+  3 << 1,+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_BOOLEAN - 1) << 1,+  (0 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=984) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(970),+  25,+  JS_ROM_VALUE(977),+  JS_NULL,++  /* properties (offset=989) */+  JS_VALUE_ARRAY_HEADER(13),+  3 << 1, /* n_props */+  1 << 1, /* hash_mask */+  7 << 1,+  10 << 1,+  JS_ROM_VALUE(246) /* fromCharCode */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 27),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(249) /* fromCodePoint */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 28),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_STRING << 1,+  (4 << 1) | (JS_PROP_SPECIAL << 30),+  /* getset (offset=1003) */+  JS_VALUE_ARRAY_HEADER(2),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 29),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 30),++  /* properties (offset=1006) */+  JS_VALUE_ARRAY_HEADER(76),+  22 << 1, /* n_props */+  7 << 1, /* hash_mask */+  55 << 1,+  64 << 1,+  70 << 1,+  46 << 1,+  73 << 1,+  58 << 1,+  43 << 1,+  61 << 1,+  JS_ROM_VALUE(136) /* length */,+  JS_ROM_VALUE(1003),+  (0 << 1) | (JS_PROP_GETSET << 30),+  JS_ROM_VALUE(255) /* charAt */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 31),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(257) /* charCodeAt */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 32),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(260) /* codePointAt */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 33),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(263) /* slice */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 34),+  (13 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(265) /* substring */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 35),+  (16 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(268) /* concat */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 36),+  (19 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(270) /* indexOf */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 37),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(272) /* lastIndexOf */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 38),+  (10 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(275) /* match */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 39),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(277) /* replace */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 40),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(279) /* replaceAll */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 41),+  (22 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(282) /* search */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 42),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(284) /* split */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 43),+  (28 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(286) /* toLowerCase */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 44),+  (31 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(289) /* toUpperCase */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 45),+  (25 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(292) /* trim */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 46),+  (49 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(294) /* trimEnd */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 47),+  (52 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(296) /* trimStart */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 48),+  (34 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(99) /* toString */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 49),+  (37 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(299) /* repeat */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 50),+  (67 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_STRING - 1) << 1,+  (40 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1083) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(989),+  26,+  JS_ROM_VALUE(1006),+  JS_NULL,++  /* properties (offset=1088) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(303) /* isArray */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 52),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_ARRAY << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* getset (offset=1098) */+  JS_VALUE_ARRAY_HEADER(2),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 53),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 54),++  /* properties (offset=1101) */+  JS_VALUE_ARRAY_HEADER(79),+  23 << 1, /* n_props */+  7 << 1, /* hash_mask */+  70 << 1,+  46 << 1,+  67 << 1,+  0 << 1,+  76 << 1,+  10 << 1,+  61 << 1,+  73 << 1,+  JS_ROM_VALUE(268) /* concat */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 55),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(136) /* length */,+  JS_ROM_VALUE(1098),+  (0 << 1) | (JS_PROP_GETSET << 30),+  JS_ROM_VALUE(305) /* push */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 56),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(307) /* pop */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 57),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(309) /* join */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 58),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(99) /* toString */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 59),+  (19 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(311) /* reverse */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 60),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(313) /* shift */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 61),+  (16 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(263) /* slice */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 62),+  (28 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(315) /* splice */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 63),+  (25 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(317) /* unshift */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 64),+  (22 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(270) /* indexOf */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 65),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(272) /* lastIndexOf */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 66),+  (13 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(319) /* every */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 67),+  (34 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(321) /* some */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 68),+  (31 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(323) /* forEach */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 69),+  (37 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(325) /* map */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 70),+  (40 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(327) /* filter */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 71),+  (49 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(329) /* reduce */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 72),+  (52 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(331) /* reduceRight */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 73),+  (55 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(329) /* reduce */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 72),+  (64 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(334) /* sort */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 74),+  (43 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_ARRAY - 1) << 1,+  (58 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1181) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1088),+  51,+  JS_ROM_VALUE(1101),+  JS_NULL,++  /* float64 (offset=1186) */+  JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),+  0x4005bf0a8b145769,++  /* float64 (offset=1188) */+  JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),+  0x40026bb1bbb55516,++  /* float64 (offset=1190) */+  JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),+  0x3fe62e42fefa39ef,++  /* float64 (offset=1192) */+  JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),+  0x3ff71547652b82fe,++  /* float64 (offset=1194) */+  JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),+  0x3fdbcb7b1526e50e,++  /* float64 (offset=1196) */+  JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),+  0x400921fb54442d18,++  /* float64 (offset=1198) */+  JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),+  0x3fe6a09e667f3bcd,++  /* float64 (offset=1200) */+  JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),+  0x3ff6a09e667f3bcd,++  /* properties (offset=1202) */+  JS_VALUE_ARRAY_HEADER(109),+  33 << 1, /* n_props */+  7 << 1, /* hash_mask */+  0 << 1,+  103 << 1,+  0 << 1,+  106 << 1,+  34 << 1,+  97 << 1,+  0 << 1,+  100 << 1,+  JS_ROM_VALUE(338) /* min */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 75),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(340) /* max */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 76),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(342) /* sign */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 77),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(344) /* abs */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 78),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(346) /* floor */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 79),+  (10 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(348) /* ceil */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 80),+  (13 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(350) /* round */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 81),+  (16 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(352) /* sqrt */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 82),+  (19 << 1) | (JS_PROP_NORMAL << 30),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_STRING_CHAR, 69) /* E */,+  JS_ROM_VALUE(1186),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(356) /* LN10 */,+  JS_ROM_VALUE(1188),+  (25 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(358) /* LN2 */,+  JS_ROM_VALUE(1190),+  (28 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(360) /* LOG2E */,+  JS_ROM_VALUE(1192),+  (31 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(362) /* LOG10E */,+  JS_ROM_VALUE(1194),+  (22 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(364) /* PI */,+  JS_ROM_VALUE(1196),+  (37 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(366) /* SQRT1_2 */,+  JS_ROM_VALUE(1198),+  (40 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(368) /* SQRT2 */,+  JS_ROM_VALUE(1200),+  (43 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(370) /* sin */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 83),+  (46 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(372) /* cos */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 84),+  (49 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(374) /* tan */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 85),+  (52 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(376) /* asin */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 86),+  (55 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(378) /* acos */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 87),+  (58 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(380) /* atan */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 88),+  (61 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(382) /* atan2 */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 89),+  (64 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(384) /* exp */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 90),+  (67 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(386) /* log */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 91),+  (70 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(388) /* pow */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 92),+  (73 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(390) /* random */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 93),+  (76 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(392) /* imul */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 94),+  (79 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(394) /* clz32 */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 95),+  (82 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(396) /* fround */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 96),+  (85 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(398) /* trunc */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 97),+  (88 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(400) /* log2 */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 98),+  (91 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(402) /* log10 */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 99),+  (94 << 1) | (JS_PROP_NORMAL << 30),+  /* class (offset=1312) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1202),+  -1,+  JS_NULL,+  JS_NULL,++  /* properties (offset=1317) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(406) /* now */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 101),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_DATE << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=1327) */+  JS_VALUE_ARRAY_HEADER(6),+  1 << 1, /* n_props */+  0 << 1, /* hash_mask */+  3 << 1,+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_DATE - 1) << 1,+  (0 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1334) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1317),+  100,+  JS_ROM_VALUE(1327),+  JS_NULL,++  /* properties (offset=1339) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(410) /* parse */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 102),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(412) /* stringify */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 103),+  (3 << 1) | (JS_PROP_NORMAL << 30),+  /* class (offset=1349) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1339),+  -1,+  JS_NULL,+  JS_NULL,++  /* properties (offset=1354) */+  JS_VALUE_ARRAY_HEADER(6),+  1 << 1, /* n_props */+  0 << 1, /* hash_mask */+  3 << 1,+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_REGEXP << 1,+  (0 << 1) | (JS_PROP_SPECIAL << 30),+  /* getset (offset=1361) */+  JS_VALUE_ARRAY_HEADER(2),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 105),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 106),++  /* getset (offset=1364) */+  JS_VALUE_ARRAY_HEADER(2),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 107),+  JS_UNDEFINED,++  /* getset (offset=1367) */+  JS_VALUE_ARRAY_HEADER(2),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 108),+  JS_UNDEFINED,++  /* properties (offset=1370) */+  JS_VALUE_ARRAY_HEADER(24),+  6 << 1, /* n_props */+  3 << 1, /* hash_mask */+  21 << 1,+  15 << 1,+  12 << 1,+  18 << 1,+  JS_ROM_VALUE(417) /* lastIndex */,+  JS_ROM_VALUE(1361),+  (0 << 1) | (JS_PROP_GETSET << 30),+  JS_ROM_VALUE(426) /* source */,+  JS_ROM_VALUE(1364),+  (0 << 1) | (JS_PROP_GETSET << 30),+  JS_ROM_VALUE(431) /* flags */,+  JS_ROM_VALUE(1367),+  (0 << 1) | (JS_PROP_GETSET << 30),+  JS_ROM_VALUE(436) /* exec */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 109),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(438) /* test */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 110),+  (9 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_REGEXP - 1) << 1,+  (6 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1395) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1354),+  104,+  JS_ROM_VALUE(1370),+  JS_NULL,++  /* properties (offset=1400) */+  JS_VALUE_ARRAY_HEADER(6),+  1 << 1, /* n_props */+  0 << 1, /* hash_mask */+  3 << 1,+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_ERROR << 1,+  (0 << 1) | (JS_PROP_SPECIAL << 30),+  /* getset (offset=1407) */+  JS_VALUE_ARRAY_HEADER(2),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 112),+  JS_UNDEFINED,++  /* getset (offset=1410) */+  JS_VALUE_ARRAY_HEADER(2),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 113),+  JS_UNDEFINED,++  /* properties (offset=1413) */+  JS_VALUE_ARRAY_HEADER(21),+  5 << 1, /* n_props */+  3 << 1, /* hash_mask */+  18 << 1,+  12 << 1,+  6 << 1,+  9 << 1,+  JS_ROM_VALUE(99) /* toString */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 114),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(150) /* name */,+  JS_ROM_VALUE(152) /* Error */,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(440) /* message */,+  JS_ROM_VALUE(1407),+  (0 << 1) | (JS_PROP_GETSET << 30),+  JS_ROM_VALUE(445) /* stack */,+  JS_ROM_VALUE(1410),+  (0 << 1) | (JS_PROP_GETSET << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_ERROR - 1) << 1,+  (15 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1435) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1400),+  111,+  JS_ROM_VALUE(1413),+  JS_NULL,++  /* properties (offset=1440) */+  JS_VALUE_ARRAY_HEADER(6),+  1 << 1, /* n_props */+  0 << 1, /* hash_mask */+  3 << 1,+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_EVAL_ERROR << 1,+  (0 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=1447) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(150) /* name */,+  JS_ROM_VALUE(450) /* EvalError */,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_EVAL_ERROR - 1) << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1457) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1440),+  115,+  JS_ROM_VALUE(1447),+  JS_ROM_VALUE(1435),++  /* properties (offset=1462) */+  JS_VALUE_ARRAY_HEADER(6),+  1 << 1, /* n_props */+  0 << 1, /* hash_mask */+  3 << 1,+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_RANGE_ERROR << 1,+  (0 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=1469) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(150) /* name */,+  JS_ROM_VALUE(453) /* RangeError */,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_RANGE_ERROR - 1) << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1479) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1462),+  116,+  JS_ROM_VALUE(1469),+  JS_ROM_VALUE(1435),++  /* properties (offset=1484) */+  JS_VALUE_ARRAY_HEADER(6),+  1 << 1, /* n_props */+  0 << 1, /* hash_mask */+  3 << 1,+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_REFERENCE_ERROR << 1,+  (0 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=1491) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(150) /* name */,+  JS_ROM_VALUE(456) /* ReferenceError */,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_REFERENCE_ERROR - 1) << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1501) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1484),+  117,+  JS_ROM_VALUE(1491),+  JS_ROM_VALUE(1435),++  /* properties (offset=1506) */+  JS_VALUE_ARRAY_HEADER(6),+  1 << 1, /* n_props */+  0 << 1, /* hash_mask */+  3 << 1,+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_SYNTAX_ERROR << 1,+  (0 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=1513) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(150) /* name */,+  JS_ROM_VALUE(459) /* SyntaxError */,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_SYNTAX_ERROR - 1) << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1523) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1506),+  118,+  JS_ROM_VALUE(1513),+  JS_ROM_VALUE(1435),++  /* properties (offset=1528) */+  JS_VALUE_ARRAY_HEADER(6),+  1 << 1, /* n_props */+  0 << 1, /* hash_mask */+  3 << 1,+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_TYPE_ERROR << 1,+  (0 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=1535) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(150) /* name */,+  JS_ROM_VALUE(462) /* TypeError */,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_TYPE_ERROR - 1) << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1545) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1528),+  119,+  JS_ROM_VALUE(1535),+  JS_ROM_VALUE(1435),++  /* properties (offset=1550) */+  JS_VALUE_ARRAY_HEADER(6),+  1 << 1, /* n_props */+  0 << 1, /* hash_mask */+  3 << 1,+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_URI_ERROR << 1,+  (0 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=1557) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(150) /* name */,+  JS_ROM_VALUE(465) /* URIError */,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_URI_ERROR - 1) << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1567) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1550),+  120,+  JS_ROM_VALUE(1557),+  JS_ROM_VALUE(1435),++  /* properties (offset=1572) */+  JS_VALUE_ARRAY_HEADER(6),+  1 << 1, /* n_props */+  0 << 1, /* hash_mask */+  3 << 1,+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_INTERNAL_ERROR << 1,+  (0 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=1579) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(150) /* name */,+  JS_ROM_VALUE(468) /* InternalError */,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_INTERNAL_ERROR - 1) << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1589) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1572),+  121,+  JS_ROM_VALUE(1579),+  JS_ROM_VALUE(1435),++  /* properties (offset=1594) */+  JS_VALUE_ARRAY_HEADER(6),+  1 << 1, /* n_props */+  0 << 1, /* hash_mask */+  3 << 1,+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_ARRAY_BUFFER << 1,+  (0 << 1) | (JS_PROP_SPECIAL << 30),+  /* getset (offset=1601) */+  JS_VALUE_ARRAY_HEADER(2),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 123),+  JS_UNDEFINED,++  /* properties (offset=1604) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(474) /* byteLength */,+  JS_ROM_VALUE(1601),+  (0 << 1) | (JS_PROP_GETSET << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_ARRAY_BUFFER - 1) << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1614) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1594),+  122,+  JS_ROM_VALUE(1604),+  JS_NULL,++  /* properties (offset=1619) */+  JS_VALUE_ARRAY_HEADER(6),+  1 << 1, /* n_props */+  0 << 1, /* hash_mask */+  3 << 1,+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_TYPED_ARRAY << 1,+  (0 << 1) | (JS_PROP_SPECIAL << 30),+  /* getset (offset=1626) */+  JS_VALUE_ARRAY_HEADER(2),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 125),+  JS_UNDEFINED,++  /* getset (offset=1629) */+  JS_VALUE_ARRAY_HEADER(2),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 126),+  JS_UNDEFINED,++  /* getset (offset=1632) */+  JS_VALUE_ARRAY_HEADER(2),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 127),+  JS_UNDEFINED,++  /* getset (offset=1635) */+  JS_VALUE_ARRAY_HEADER(2),+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 128),+  JS_UNDEFINED,++  /* properties (offset=1638) */+  JS_VALUE_ARRAY_HEADER(37),+  9 << 1, /* n_props */+  7 << 1, /* hash_mask */+  0 << 1,+  31 << 1,+  25 << 1,+  28 << 1,+  34 << 1,+  0 << 1,+  16 << 1,+  0 << 1,+  JS_ROM_VALUE(136) /* length */,+  JS_ROM_VALUE(1626),+  (0 << 1) | (JS_PROP_GETSET << 30),+  JS_ROM_VALUE(474) /* byteLength */,+  JS_ROM_VALUE(1629),+  (0 << 1) | (JS_PROP_GETSET << 30),+  JS_ROM_VALUE(487) /* byteOffset */,+  JS_ROM_VALUE(1632),+  (0 << 1) | (JS_PROP_GETSET << 30),+  JS_ROM_VALUE(493) /* buffer */,+  JS_ROM_VALUE(1635),+  (0 << 1) | (JS_PROP_GETSET << 30),+  JS_ROM_VALUE(309) /* join */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 58),+  (19 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(99) /* toString */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 59),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(498) /* subarray */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 129),+  (13 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(128) /* set */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 130),+  (10 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_TYPED_ARRAY - 1) << 1,+  (22 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1676) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1619),+  124,+  JS_ROM_VALUE(1638),+  JS_NULL,++  /* properties (offset=1681) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(501) /* BYTES_PER_ELEMENT */,+  1 << 1,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_UINT8C_ARRAY << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=1691) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(501) /* BYTES_PER_ELEMENT */,+  1 << 1,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_UINT8C_ARRAY - 1) << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1701) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1681),+  131,+  JS_ROM_VALUE(1691),+  JS_ROM_VALUE(1676),++  /* properties (offset=1706) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(501) /* BYTES_PER_ELEMENT */,+  1 << 1,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_INT8_ARRAY << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=1716) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(501) /* BYTES_PER_ELEMENT */,+  1 << 1,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_INT8_ARRAY - 1) << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1726) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1706),+  132,+  JS_ROM_VALUE(1716),+  JS_ROM_VALUE(1676),++  /* properties (offset=1731) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(501) /* BYTES_PER_ELEMENT */,+  1 << 1,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_UINT8_ARRAY << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=1741) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(501) /* BYTES_PER_ELEMENT */,+  1 << 1,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_UINT8_ARRAY - 1) << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1751) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1731),+  133,+  JS_ROM_VALUE(1741),+  JS_ROM_VALUE(1676),++  /* properties (offset=1756) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(501) /* BYTES_PER_ELEMENT */,+  2 << 1,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_INT16_ARRAY << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=1766) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(501) /* BYTES_PER_ELEMENT */,+  2 << 1,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_INT16_ARRAY - 1) << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1776) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1756),+  134,+  JS_ROM_VALUE(1766),+  JS_ROM_VALUE(1676),++  /* properties (offset=1781) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(501) /* BYTES_PER_ELEMENT */,+  2 << 1,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_UINT16_ARRAY << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=1791) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(501) /* BYTES_PER_ELEMENT */,+  2 << 1,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_UINT16_ARRAY - 1) << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1801) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1781),+  135,+  JS_ROM_VALUE(1791),+  JS_ROM_VALUE(1676),++  /* properties (offset=1806) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(501) /* BYTES_PER_ELEMENT */,+  4 << 1,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_INT32_ARRAY << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=1816) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(501) /* BYTES_PER_ELEMENT */,+  4 << 1,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_INT32_ARRAY - 1) << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1826) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1806),+  136,+  JS_ROM_VALUE(1816),+  JS_ROM_VALUE(1676),++  /* properties (offset=1831) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(501) /* BYTES_PER_ELEMENT */,+  4 << 1,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_UINT32_ARRAY << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=1841) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(501) /* BYTES_PER_ELEMENT */,+  4 << 1,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_UINT32_ARRAY - 1) << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1851) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1831),+  137,+  JS_ROM_VALUE(1841),+  JS_ROM_VALUE(1676),++  /* properties (offset=1856) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(501) /* BYTES_PER_ELEMENT */,+  4 << 1,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_FLOAT32_ARRAY << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=1866) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(501) /* BYTES_PER_ELEMENT */,+  4 << 1,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_FLOAT32_ARRAY - 1) << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1876) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1856),+  138,+  JS_ROM_VALUE(1866),+  JS_ROM_VALUE(1676),++  /* properties (offset=1881) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(501) /* BYTES_PER_ELEMENT */,+  8 << 1,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(130) /* prototype */,+  JS_CLASS_FLOAT64_ARRAY << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* properties (offset=1891) */+  JS_VALUE_ARRAY_HEADER(9),+  2 << 1, /* n_props */+  0 << 1, /* hash_mask */+  6 << 1,+  JS_ROM_VALUE(501) /* BYTES_PER_ELEMENT */,+  8 << 1,+  (0 << 1) | (JS_PROP_NORMAL << 30),+  JS_ROM_VALUE(133) /* constructor */,+  (uint32_t)(-JS_CLASS_FLOAT64_ARRAY - 1) << 1,+  (3 << 1) | (JS_PROP_SPECIAL << 30),+  /* class (offset=1901) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1881),+  139,+  JS_ROM_VALUE(1891),+  JS_ROM_VALUE(1676),++  /* float64 (offset=1906) */+  JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),+  0x7ff0000000000000,++  /* float64 (offset=1908) */+  JS_MB_HEADER_DEF(JS_MTAG_FLOAT64),+  0x7ff8000000000000,++  /* properties (offset=1910) */+  JS_VALUE_ARRAY_HEADER(6),+  1 << 1, /* n_props */+  0 << 1, /* hash_mask */+  3 << 1,+  JS_ROM_VALUE(386) /* log */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 140),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  /* class (offset=1917) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1910),+  -1,+  JS_NULL,+  JS_NULL,++  /* properties (offset=1922) */+  JS_VALUE_ARRAY_HEADER(6),+  1 << 1, /* n_props */+  0 << 1, /* hash_mask */+  3 << 1,+  JS_ROM_VALUE(406) /* now */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 141),+  (0 << 1) | (JS_PROP_NORMAL << 30),+  /* class (offset=1929) */+  JS_MB_HEADER_DEF(JS_MTAG_OBJECT),+  JS_ROM_VALUE(1922),+  -1,+  JS_NULL,+  JS_NULL,++  /* global object properties (offset=1934) */+  JS_VALUE_ARRAY_HEADER(88),+  JS_ROM_VALUE(163) /* Object */,+  JS_ROM_VALUE(826),+  JS_ROM_VALUE(181) /* Function */,+  JS_ROM_VALUE(878),+  JS_ROM_VALUE(202) /* Number */,+  JS_ROM_VALUE(965),+  JS_ROM_VALUE(242) /* Boolean */,+  JS_ROM_VALUE(984),+  JS_ROM_VALUE(244) /* String */,+  JS_ROM_VALUE(1083),+  JS_ROM_VALUE(301) /* Array */,+  JS_ROM_VALUE(1181),+  JS_ROM_VALUE(336) /* Math */,+  JS_ROM_VALUE(1312),+  JS_ROM_VALUE(404) /* Date */,+  JS_ROM_VALUE(1334),+  JS_ROM_VALUE(408) /* JSON */,+  JS_ROM_VALUE(1349),+  JS_ROM_VALUE(415) /* RegExp */,+  JS_ROM_VALUE(1395),+  JS_ROM_VALUE(152) /* Error */,+  JS_ROM_VALUE(1435),+  JS_ROM_VALUE(450) /* EvalError */,+  JS_ROM_VALUE(1457),+  JS_ROM_VALUE(453) /* RangeError */,+  JS_ROM_VALUE(1479),+  JS_ROM_VALUE(456) /* ReferenceError */,+  JS_ROM_VALUE(1501),+  JS_ROM_VALUE(459) /* SyntaxError */,+  JS_ROM_VALUE(1523),+  JS_ROM_VALUE(462) /* TypeError */,+  JS_ROM_VALUE(1545),+  JS_ROM_VALUE(465) /* URIError */,+  JS_ROM_VALUE(1567),+  JS_ROM_VALUE(468) /* InternalError */,+  JS_ROM_VALUE(1589),+  JS_ROM_VALUE(471) /* ArrayBuffer */,+  JS_ROM_VALUE(1614),+  JS_ROM_VALUE(480) /* Uint8ClampedArray */,+  JS_ROM_VALUE(1701),+  JS_ROM_VALUE(505) /* Int8Array */,+  JS_ROM_VALUE(1726),+  JS_ROM_VALUE(508) /* Uint8Array */,+  JS_ROM_VALUE(1751),+  JS_ROM_VALUE(511) /* Int16Array */,+  JS_ROM_VALUE(1776),+  JS_ROM_VALUE(514) /* Uint16Array */,+  JS_ROM_VALUE(1801),+  JS_ROM_VALUE(517) /* Int32Array */,+  JS_ROM_VALUE(1826),+  JS_ROM_VALUE(520) /* Uint32Array */,+  JS_ROM_VALUE(1851),+  JS_ROM_VALUE(523) /* Float32Array */,+  JS_ROM_VALUE(1876),+  JS_ROM_VALUE(526) /* Float64Array */,+  JS_ROM_VALUE(1901),+  JS_ROM_VALUE(204) /* parseInt */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 19),+  JS_ROM_VALUE(207) /* parseFloat */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 20),+  JS_ROM_VALUE(119) /* eval */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 142),+  JS_ROM_VALUE(529) /* isNaN */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 143),+  JS_ROM_VALUE(531) /* isFinite */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 144),+  JS_ROM_VALUE(144) /* Infinity */,+  JS_ROM_VALUE(1906),+  JS_ROM_VALUE(142) /* NaN */,+  JS_ROM_VALUE(1908),+  JS_ROM_VALUE(108) /* undefined */,+  JS_UNDEFINED,+  JS_ROM_VALUE(534) /* globalThis */,+  JS_NULL,+  JS_ROM_VALUE(537) /* console */,+  JS_ROM_VALUE(1917),+  JS_ROM_VALUE(539) /* performance */,+  JS_ROM_VALUE(1929),+  JS_ROM_VALUE(542) /* print */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 145),+  JS_ROM_VALUE(544) /* gc */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 146),+  JS_ROM_VALUE(546) /* load */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 147),+  JS_ROM_VALUE(548) /* setTimeout */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 148),+  JS_ROM_VALUE(551) /* clearTimeout */,+  JS_VALUE_MAKE_SPECIAL(JS_TAG_SHORT_FUNC, 149),+};++static const JSCFunctionDef js_c_function_table[] = {+  { { .generic_params = js_function_bound },+    JS_ROM_VALUE(161) /* bound */,+    JS_CFUNC_generic_params, 0, 0 },+  { { .constructor = js_object_constructor },+    JS_ROM_VALUE(163) /* Object */,+    JS_CFUNC_constructor, 1, JS_CLASS_OBJECT },+  { { .generic = js_object_defineProperty },+    JS_ROM_VALUE(165) /* defineProperty */,+    JS_CFUNC_generic, 3, 0 },+  { { .generic = js_object_getPrototypeOf },+    JS_ROM_VALUE(168) /* getPrototypeOf */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_object_setPrototypeOf },+    JS_ROM_VALUE(171) /* setPrototypeOf */,+    JS_CFUNC_generic, 2, 0 },+  { { .generic = js_object_create },+    JS_ROM_VALUE(174) /* create */,+    JS_CFUNC_generic, 2, 0 },+  { { .generic = js_object_keys },+    JS_ROM_VALUE(176) /* keys */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_object_hasOwnProperty },+    JS_ROM_VALUE(178) /* hasOwnProperty */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_object_toString },+    JS_ROM_VALUE(99) /* toString */,+    JS_CFUNC_generic, 0, 0 },+  { { .constructor = js_function_constructor },+    JS_ROM_VALUE(181) /* Function */,+    JS_CFUNC_constructor, 1, JS_CLASS_CLOSURE },+  { { .generic = js_function_get_prototype },+    JS_ROM_VALUE(184) /* get prototype */,+    JS_CFUNC_generic, 0, 0 },+  { { .generic = js_function_set_prototype },+    JS_ROM_VALUE(187) /* set prototype */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic_magic = js_function_get_length_name },+    JS_ROM_VALUE(196) /* get length */,+    JS_CFUNC_generic_magic, 0, 0 },+  { { .generic_magic = js_function_get_length_name },+    JS_ROM_VALUE(199) /* get name */,+    JS_CFUNC_generic_magic, 0, 1 },+  { { .generic = js_function_call },+    JS_ROM_VALUE(190) /* call */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_function_apply },+    JS_ROM_VALUE(192) /* apply */,+    JS_CFUNC_generic, 2, 0 },+  { { .generic = js_function_bind },+    JS_ROM_VALUE(194) /* bind */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_function_toString },+    JS_ROM_VALUE(99) /* toString */,+    JS_CFUNC_generic, 0, 0 },+  { { .constructor = js_number_constructor },+    JS_ROM_VALUE(202) /* Number */,+    JS_CFUNC_constructor, 1, JS_CLASS_NUMBER },+  { { .generic = js_number_parseInt },+    JS_ROM_VALUE(204) /* parseInt */,+    JS_CFUNC_generic, 2, 0 },+  { { .generic = js_number_parseFloat },+    JS_ROM_VALUE(207) /* parseFloat */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_number_toExponential },+    JS_ROM_VALUE(234) /* toExponential */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_number_toFixed },+    JS_ROM_VALUE(237) /* toFixed */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_number_toPrecision },+    JS_ROM_VALUE(239) /* toPrecision */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_number_toString },+    JS_ROM_VALUE(99) /* toString */,+    JS_CFUNC_generic, 1, 0 },+  { { .constructor = js_boolean_constructor },+    JS_ROM_VALUE(242) /* Boolean */,+    JS_CFUNC_constructor, 1, JS_CLASS_BOOLEAN },+  { { .constructor = js_string_constructor },+    JS_ROM_VALUE(244) /* String */,+    JS_CFUNC_constructor, 1, JS_CLASS_STRING },+  { { .generic_magic = js_string_fromCharCode },+    JS_ROM_VALUE(246) /* fromCharCode */,+    JS_CFUNC_generic_magic, 1, 0 },+  { { .generic_magic = js_string_fromCharCode },+    JS_ROM_VALUE(249) /* fromCodePoint */,+    JS_CFUNC_generic_magic, 1, 1 },+  { { .generic = js_string_get_length },+    JS_ROM_VALUE(196) /* get length */,+    JS_CFUNC_generic, 0, 0 },+  { { .generic = js_string_set_length },+    JS_ROM_VALUE(252) /* set length */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic_magic = js_string_charAt },+    JS_ROM_VALUE(255) /* charAt */,+    JS_CFUNC_generic_magic, 1, magic_charAt },+  { { .generic_magic = js_string_charAt },+    JS_ROM_VALUE(257) /* charCodeAt */,+    JS_CFUNC_generic_magic, 1, magic_charCodeAt },+  { { .generic_magic = js_string_charAt },+    JS_ROM_VALUE(260) /* codePointAt */,+    JS_CFUNC_generic_magic, 1, magic_codePointAt },+  { { .generic = js_string_slice },+    JS_ROM_VALUE(263) /* slice */,+    JS_CFUNC_generic, 2, 0 },+  { { .generic = js_string_substring },+    JS_ROM_VALUE(265) /* substring */,+    JS_CFUNC_generic, 2, 0 },+  { { .generic = js_string_concat },+    JS_ROM_VALUE(268) /* concat */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic_magic = js_string_indexOf },+    JS_ROM_VALUE(270) /* indexOf */,+    JS_CFUNC_generic_magic, 1, 0 },+  { { .generic_magic = js_string_indexOf },+    JS_ROM_VALUE(272) /* lastIndexOf */,+    JS_CFUNC_generic_magic, 1, 1 },+  { { .generic = js_string_match },+    JS_ROM_VALUE(275) /* match */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic_magic = js_string_replace },+    JS_ROM_VALUE(277) /* replace */,+    JS_CFUNC_generic_magic, 2, 0 },+  { { .generic_magic = js_string_replace },+    JS_ROM_VALUE(279) /* replaceAll */,+    JS_CFUNC_generic_magic, 2, 1 },+  { { .generic = js_string_search },+    JS_ROM_VALUE(282) /* search */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_string_split },+    JS_ROM_VALUE(284) /* split */,+    JS_CFUNC_generic, 2, 0 },+  { { .generic_magic = js_string_toLowerCase },+    JS_ROM_VALUE(286) /* toLowerCase */,+    JS_CFUNC_generic_magic, 0, 1 },+  { { .generic_magic = js_string_toLowerCase },+    JS_ROM_VALUE(289) /* toUpperCase */,+    JS_CFUNC_generic_magic, 0, 0 },+  { { .generic_magic = js_string_trim },+    JS_ROM_VALUE(292) /* trim */,+    JS_CFUNC_generic_magic, 0, 3 },+  { { .generic_magic = js_string_trim },+    JS_ROM_VALUE(294) /* trimEnd */,+    JS_CFUNC_generic_magic, 0, 2 },+  { { .generic_magic = js_string_trim },+    JS_ROM_VALUE(296) /* trimStart */,+    JS_CFUNC_generic_magic, 0, 1 },+  { { .generic = js_string_toString },+    JS_ROM_VALUE(99) /* toString */,+    JS_CFUNC_generic, 0, 0 },+  { { .generic = js_string_repeat },+    JS_ROM_VALUE(299) /* repeat */,+    JS_CFUNC_generic, 1, 0 },+  { { .constructor = js_array_constructor },+    JS_ROM_VALUE(301) /* Array */,+    JS_CFUNC_constructor, 1, JS_CLASS_ARRAY },+  { { .generic = js_array_isArray },+    JS_ROM_VALUE(303) /* isArray */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_array_get_length },+    JS_ROM_VALUE(196) /* get length */,+    JS_CFUNC_generic, 0, 0 },+  { { .generic = js_array_set_length },+    JS_ROM_VALUE(252) /* set length */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_array_concat },+    JS_ROM_VALUE(268) /* concat */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic_magic = js_array_push },+    JS_ROM_VALUE(305) /* push */,+    JS_CFUNC_generic_magic, 1, 0 },+  { { .generic = js_array_pop },+    JS_ROM_VALUE(307) /* pop */,+    JS_CFUNC_generic, 0, 0 },+  { { .generic = js_array_join },+    JS_ROM_VALUE(309) /* join */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_array_toString },+    JS_ROM_VALUE(99) /* toString */,+    JS_CFUNC_generic, 0, 0 },+  { { .generic = js_array_reverse },+    JS_ROM_VALUE(311) /* reverse */,+    JS_CFUNC_generic, 0, 0 },+  { { .generic = js_array_shift },+    JS_ROM_VALUE(313) /* shift */,+    JS_CFUNC_generic, 0, 0 },+  { { .generic = js_array_slice },+    JS_ROM_VALUE(263) /* slice */,+    JS_CFUNC_generic, 2, 0 },+  { { .generic = js_array_splice },+    JS_ROM_VALUE(315) /* splice */,+    JS_CFUNC_generic, 2, 0 },+  { { .generic_magic = js_array_push },+    JS_ROM_VALUE(317) /* unshift */,+    JS_CFUNC_generic_magic, 1, 1 },+  { { .generic_magic = js_array_indexOf },+    JS_ROM_VALUE(270) /* indexOf */,+    JS_CFUNC_generic_magic, 1, 0 },+  { { .generic_magic = js_array_indexOf },+    JS_ROM_VALUE(272) /* lastIndexOf */,+    JS_CFUNC_generic_magic, 1, 1 },+  { { .generic_magic = js_array_every },+    JS_ROM_VALUE(319) /* every */,+    JS_CFUNC_generic_magic, 1, js_special_every },+  { { .generic_magic = js_array_every },+    JS_ROM_VALUE(321) /* some */,+    JS_CFUNC_generic_magic, 1, js_special_some },+  { { .generic_magic = js_array_every },+    JS_ROM_VALUE(323) /* forEach */,+    JS_CFUNC_generic_magic, 1, js_special_forEach },+  { { .generic_magic = js_array_every },+    JS_ROM_VALUE(325) /* map */,+    JS_CFUNC_generic_magic, 1, js_special_map },+  { { .generic_magic = js_array_every },+    JS_ROM_VALUE(327) /* filter */,+    JS_CFUNC_generic_magic, 1, js_special_filter },+  { { .generic_magic = js_array_reduce },+    JS_ROM_VALUE(329) /* reduce */,+    JS_CFUNC_generic_magic, 1, js_special_reduce },+  { { .generic_magic = js_array_reduce },+    JS_ROM_VALUE(331) /* reduceRight */,+    JS_CFUNC_generic_magic, 1, js_special_reduceRight },+  { { .generic = js_array_sort },+    JS_ROM_VALUE(334) /* sort */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic_magic = js_math_min_max },+    JS_ROM_VALUE(338) /* min */,+    JS_CFUNC_generic_magic, 2, 0 },+  { { .generic_magic = js_math_min_max },+    JS_ROM_VALUE(340) /* max */,+    JS_CFUNC_generic_magic, 2, 1 },+  { { .f_f = js_math_sign },+    JS_ROM_VALUE(342) /* sign */,+    JS_CFUNC_f_f, 1, 0 },+  { { .f_f = js_fabs },+    JS_ROM_VALUE(344) /* abs */,+    JS_CFUNC_f_f, 1, 0 },+  { { .f_f = js_floor },+    JS_ROM_VALUE(346) /* floor */,+    JS_CFUNC_f_f, 1, 0 },+  { { .f_f = js_ceil },+    JS_ROM_VALUE(348) /* ceil */,+    JS_CFUNC_f_f, 1, 0 },+  { { .f_f = js_round_inf },+    JS_ROM_VALUE(350) /* round */,+    JS_CFUNC_f_f, 1, 0 },+  { { .f_f = js_sqrt },+    JS_ROM_VALUE(352) /* sqrt */,+    JS_CFUNC_f_f, 1, 0 },+  { { .f_f = js_sin },+    JS_ROM_VALUE(370) /* sin */,+    JS_CFUNC_f_f, 1, 0 },+  { { .f_f = js_cos },+    JS_ROM_VALUE(372) /* cos */,+    JS_CFUNC_f_f, 1, 0 },+  { { .f_f = js_tan },+    JS_ROM_VALUE(374) /* tan */,+    JS_CFUNC_f_f, 1, 0 },+  { { .f_f = js_asin },+    JS_ROM_VALUE(376) /* asin */,+    JS_CFUNC_f_f, 1, 0 },+  { { .f_f = js_acos },+    JS_ROM_VALUE(378) /* acos */,+    JS_CFUNC_f_f, 1, 0 },+  { { .f_f = js_atan },+    JS_ROM_VALUE(380) /* atan */,+    JS_CFUNC_f_f, 1, 0 },+  { { .generic = js_math_atan2 },+    JS_ROM_VALUE(382) /* atan2 */,+    JS_CFUNC_generic, 2, 0 },+  { { .f_f = js_exp },+    JS_ROM_VALUE(384) /* exp */,+    JS_CFUNC_f_f, 1, 0 },+  { { .f_f = js_log },+    JS_ROM_VALUE(386) /* log */,+    JS_CFUNC_f_f, 1, 0 },+  { { .generic = js_math_pow },+    JS_ROM_VALUE(388) /* pow */,+    JS_CFUNC_generic, 2, 0 },+  { { .generic = js_math_random },+    JS_ROM_VALUE(390) /* random */,+    JS_CFUNC_generic, 0, 0 },+  { { .generic = js_math_imul },+    JS_ROM_VALUE(392) /* imul */,+    JS_CFUNC_generic, 2, 0 },+  { { .generic = js_math_clz32 },+    JS_ROM_VALUE(394) /* clz32 */,+    JS_CFUNC_generic, 1, 0 },+  { { .f_f = js_math_fround },+    JS_ROM_VALUE(396) /* fround */,+    JS_CFUNC_f_f, 1, 0 },+  { { .f_f = js_trunc },+    JS_ROM_VALUE(398) /* trunc */,+    JS_CFUNC_f_f, 1, 0 },+  { { .f_f = js_log2 },+    JS_ROM_VALUE(400) /* log2 */,+    JS_CFUNC_f_f, 1, 0 },+  { { .f_f = js_log10 },+    JS_ROM_VALUE(402) /* log10 */,+    JS_CFUNC_f_f, 1, 0 },+  { { .constructor = js_date_constructor },+    JS_ROM_VALUE(404) /* Date */,+    JS_CFUNC_constructor, 7, JS_CLASS_DATE },+  { { .generic = js_date_now },+    JS_ROM_VALUE(406) /* now */,+    JS_CFUNC_generic, 0, 0 },+  { { .generic = js_json_parse },+    JS_ROM_VALUE(410) /* parse */,+    JS_CFUNC_generic, 2, 0 },+  { { .generic = js_json_stringify },+    JS_ROM_VALUE(412) /* stringify */,+    JS_CFUNC_generic, 3, 0 },+  { { .constructor = js_regexp_constructor },+    JS_ROM_VALUE(415) /* RegExp */,+    JS_CFUNC_constructor, 2, JS_CLASS_REGEXP },+  { { .generic = js_regexp_get_lastIndex },+    JS_ROM_VALUE(420) /* get lastIndex */,+    JS_CFUNC_generic, 0, 0 },+  { { .generic = js_regexp_set_lastIndex },+    JS_ROM_VALUE(423) /* set lastIndex */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_regexp_get_source },+    JS_ROM_VALUE(428) /* get source */,+    JS_CFUNC_generic, 0, 0 },+  { { .generic = js_regexp_get_flags },+    JS_ROM_VALUE(433) /* get flags */,+    JS_CFUNC_generic, 0, 0 },+  { { .generic_magic = js_regexp_exec },+    JS_ROM_VALUE(436) /* exec */,+    JS_CFUNC_generic_magic, 1, 0 },+  { { .generic_magic = js_regexp_exec },+    JS_ROM_VALUE(438) /* test */,+    JS_CFUNC_generic_magic, 1, 1 },+  { { .constructor_magic = js_error_constructor },+    JS_ROM_VALUE(152) /* Error */,+    JS_CFUNC_constructor_magic, 1, JS_CLASS_ERROR },+  { { .generic_magic = js_error_get_message },+    JS_ROM_VALUE(442) /* get message */,+    JS_CFUNC_generic_magic, 0, 0 },+  { { .generic_magic = js_error_get_message },+    JS_ROM_VALUE(447) /* get stack */,+    JS_CFUNC_generic_magic, 0, 1 },+  { { .generic = js_error_toString },+    JS_ROM_VALUE(99) /* toString */,+    JS_CFUNC_generic, 0, 0 },+  { { .constructor_magic = js_error_constructor },+    JS_ROM_VALUE(450) /* EvalError */,+    JS_CFUNC_constructor_magic, 1, JS_CLASS_EVAL_ERROR },+  { { .constructor_magic = js_error_constructor },+    JS_ROM_VALUE(453) /* RangeError */,+    JS_CFUNC_constructor_magic, 1, JS_CLASS_RANGE_ERROR },+  { { .constructor_magic = js_error_constructor },+    JS_ROM_VALUE(456) /* ReferenceError */,+    JS_CFUNC_constructor_magic, 1, JS_CLASS_REFERENCE_ERROR },+  { { .constructor_magic = js_error_constructor },+    JS_ROM_VALUE(459) /* SyntaxError */,+    JS_CFUNC_constructor_magic, 1, JS_CLASS_SYNTAX_ERROR },+  { { .constructor_magic = js_error_constructor },+    JS_ROM_VALUE(462) /* TypeError */,+    JS_CFUNC_constructor_magic, 1, JS_CLASS_TYPE_ERROR },+  { { .constructor_magic = js_error_constructor },+    JS_ROM_VALUE(465) /* URIError */,+    JS_CFUNC_constructor_magic, 1, JS_CLASS_URI_ERROR },+  { { .constructor_magic = js_error_constructor },+    JS_ROM_VALUE(468) /* InternalError */,+    JS_CFUNC_constructor_magic, 1, JS_CLASS_INTERNAL_ERROR },+  { { .constructor = js_array_buffer_constructor },+    JS_ROM_VALUE(471) /* ArrayBuffer */,+    JS_CFUNC_constructor, 1, JS_CLASS_ARRAY_BUFFER },+  { { .generic = js_array_buffer_get_byteLength },+    JS_ROM_VALUE(477) /* get byteLength */,+    JS_CFUNC_generic, 0, 0 },+  { { .constructor = js_typed_array_base_constructor },+    JS_ROM_VALUE(484) /* TypedArray */,+    JS_CFUNC_constructor, 0, JS_CLASS_TYPED_ARRAY },+  { { .generic_magic = js_typed_array_get_length },+    JS_ROM_VALUE(196) /* get length */,+    JS_CFUNC_generic_magic, 0, 0 },+  { { .generic_magic = js_typed_array_get_length },+    JS_ROM_VALUE(477) /* get byteLength */,+    JS_CFUNC_generic_magic, 0, 1 },+  { { .generic_magic = js_typed_array_get_length },+    JS_ROM_VALUE(490) /* get byteOffset */,+    JS_CFUNC_generic_magic, 0, 2 },+  { { .generic_magic = js_typed_array_get_length },+    JS_ROM_VALUE(495) /* get buffer */,+    JS_CFUNC_generic_magic, 0, 3 },+  { { .generic = js_typed_array_subarray },+    JS_ROM_VALUE(498) /* subarray */,+    JS_CFUNC_generic, 2, 0 },+  { { .generic = js_typed_array_set },+    JS_ROM_VALUE(128) /* set */,+    JS_CFUNC_generic, 1, 0 },+  { { .constructor_magic = js_typed_array_constructor },+    JS_ROM_VALUE(480) /* Uint8ClampedArray */,+    JS_CFUNC_constructor_magic, 3, JS_CLASS_UINT8C_ARRAY },+  { { .constructor_magic = js_typed_array_constructor },+    JS_ROM_VALUE(505) /* Int8Array */,+    JS_CFUNC_constructor_magic, 3, JS_CLASS_INT8_ARRAY },+  { { .constructor_magic = js_typed_array_constructor },+    JS_ROM_VALUE(508) /* Uint8Array */,+    JS_CFUNC_constructor_magic, 3, JS_CLASS_UINT8_ARRAY },+  { { .constructor_magic = js_typed_array_constructor },+    JS_ROM_VALUE(511) /* Int16Array */,+    JS_CFUNC_constructor_magic, 3, JS_CLASS_INT16_ARRAY },+  { { .constructor_magic = js_typed_array_constructor },+    JS_ROM_VALUE(514) /* Uint16Array */,+    JS_CFUNC_constructor_magic, 3, JS_CLASS_UINT16_ARRAY },+  { { .constructor_magic = js_typed_array_constructor },+    JS_ROM_VALUE(517) /* Int32Array */,+    JS_CFUNC_constructor_magic, 3, JS_CLASS_INT32_ARRAY },+  { { .constructor_magic = js_typed_array_constructor },+    JS_ROM_VALUE(520) /* Uint32Array */,+    JS_CFUNC_constructor_magic, 3, JS_CLASS_UINT32_ARRAY },+  { { .constructor_magic = js_typed_array_constructor },+    JS_ROM_VALUE(523) /* Float32Array */,+    JS_CFUNC_constructor_magic, 3, JS_CLASS_FLOAT32_ARRAY },+  { { .constructor_magic = js_typed_array_constructor },+    JS_ROM_VALUE(526) /* Float64Array */,+    JS_CFUNC_constructor_magic, 3, JS_CLASS_FLOAT64_ARRAY },+  { { .generic = js_print },+    JS_ROM_VALUE(386) /* log */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_performance_now },+    JS_ROM_VALUE(406) /* now */,+    JS_CFUNC_generic, 0, 0 },+  { { .generic = js_global_eval },+    JS_ROM_VALUE(119) /* eval */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_global_isNaN },+    JS_ROM_VALUE(529) /* isNaN */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_global_isFinite },+    JS_ROM_VALUE(531) /* isFinite */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_print },+    JS_ROM_VALUE(542) /* print */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_gc },+    JS_ROM_VALUE(544) /* gc */,+    JS_CFUNC_generic, 0, 0 },+  { { .generic = js_load },+    JS_ROM_VALUE(546) /* load */,+    JS_CFUNC_generic, 1, 0 },+  { { .generic = js_setTimeout },+    JS_ROM_VALUE(548) /* setTimeout */,+    JS_CFUNC_generic, 2, 0 },+  { { .generic = js_clearTimeout },+    JS_ROM_VALUE(551) /* clearTimeout */,+    JS_CFUNC_generic, 1, 0 },+};++#ifndef JS_CLASS_COUNT+#define JS_CLASS_COUNT JS_CLASS_USER /* total number of classes */+#endif++static const JSCFinalizer js_c_finalizer_table[JS_CLASS_COUNT - JS_CLASS_USER] = {+};++const JSSTDLibraryDef js_stdlib = {+  js_stdlib_table,+  js_c_function_table,+  js_c_finalizer_table,+  2023,+  64,+  554,+  1934,+  JS_CLASS_COUNT,+};+
+ mquickjs/mquickjs.c view
@@ -0,0 +1,18320 @@+/*+ * Micro QuickJS Javascript Engine+ *+ * Copyright (c) 2017-2025 Fabrice Bellard+ * Copyright (c) 2017-2025 Charlie Gordon+ *+ * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ *+ * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+ * THE SOFTWARE.+ */+#include <stdlib.h>+#include <stdio.h>+#include <stdarg.h>+#include <inttypes.h>+#include <string.h>+#include <assert.h>+#include <math.h>+#include <setjmp.h>++#include "cutils.h"+#include "dtoa.h"+#include "mquickjs_priv.h"++/*+  TODO:+  - regexp: better error position info+  - use a specific MTAG for short functions instead of an immediate value+  - use hash table for atoms+  - set the length accessors as non configurable so that the+    'get_length' instruction optimizations are always safe.+  - memory:+    - fix stack_bottom logic+    - launch gc at regular intervals+    - only launch compaction when needed (handle free blocks in malloc())+    - avoid pass to rehash the properties+    - ensure no undefined bytes (e.g. at end of JSString) in+      saved bytecode ?+  - reduced memory usage:+    - reduce JSFunctionBytecode size (remove source_pos)+    - do not explicitly store function names for get/set/bound+    - use JSSTDLibraryDef fields instead of copying them to JSContext ?+*/++#define __exception __attribute__((warn_unused_result))++#define JS_STACK_SLACK  16   /* additional free space on the stack */+/* min free size in bytes between heap_free and the bottom of the stack */+#define JS_MIN_FREE_SIZE 512+/* minimum free size in bytes to create the out of memory object */+#define JS_MIN_CRITICAL_FREE_SIZE (JS_MIN_FREE_SIZE - 256)+#define JS_MAX_LOCAL_VARS 65535+#define JS_MAX_FUNC_STACK_SIZE 65535+#define JS_MAX_ARGC 65535+/* maximum number of recursing JS_Call() */+#define JS_MAX_CALL_RECURSE 8+++#define JS_VALUE_IS_BOTH_INT(a, b) ((((a) | (b)) & 1) == 0)+#define JS_VALUE_IS_BOTH_SHORT_FLOAT(a, b) (((((a) - JS_TAG_SHORT_FLOAT) | ((b) - JS_TAG_SHORT_FLOAT)) & 7) == 0)++static __maybe_unused const char *js_mtag_name[JS_MTAG_COUNT] = {+    "free",+    "object",+    "float64",+    "string",+    "func_bytecode",+    "value_array",+    "byte_array",+    "varref",+};++/* function call flags (max 31 bits) */+#define FRAME_CF_ARGC_MASK      0xffff+/* FRAME_CF_CTOR */+#define FRAME_CF_POP_RET        (1 << 17) /* pop the return value */+#define FRAME_CF_PC_ADD1        (1 << 18) /* increment the PC by 1 instead of 3 */++#define JS_MB_PAD(n)  (JSW * 8 - (n))++typedef struct {+    JS_MB_HEADER;+    JSWord dummy: JS_MB_PAD(JS_MTAG_BITS);+} JSMemBlockHeader;++typedef struct {+    JS_MB_HEADER;+    /* in JSWords excluding the header. Free blocks of JSW bytes+       are only generated by js_shrink() and may not be always+       compacted */+    JSWord size: JS_MB_PAD(JS_MTAG_BITS);+} JSFreeBlock;++#if JSW == 8+#define JS_STRING_LEN_MAX 0x7ffffffe+#else+#define JS_STRING_LEN_MAX ((1 << (32 - JS_MTAG_BITS - 3)) - 1)+#endif++typedef struct {+    JS_MB_HEADER;+    JSWord is_unique: 1;+    JSWord is_ascii: 1;+    /* true if the string content represents a number, only meaningful+       is is_unique = true */+    JSWord is_numeric: 1;+    JSWord len: JS_MB_PAD(JS_MTAG_BITS + 3);+    uint8_t buf[];+} JSString;++typedef struct {+    JSWord string_buf[sizeof(JSString) / sizeof(JSWord)]; /* for JSString */+    uint8_t buf[5];+} JSStringCharBuf;++#define JS_BYTE_ARRAY_SIZE_MAX ((1 << (32 - JS_MTAG_BITS)) - 1)++typedef struct {+    JS_MB_HEADER;+    JSWord size: JS_MB_PAD(JS_MTAG_BITS);+    uint8_t buf[];+} JSByteArray;++#define JS_VALUE_ARRAY_SIZE_MAX ((1 << (32 - JS_MTAG_BITS)) - 1)++typedef struct {+    JS_MB_HEADER;+    JSWord size: JS_MB_PAD(JS_MTAG_BITS);+    JSValue arr[];+} JSValueArray;++typedef struct JSVarRef {+    JS_MB_HEADER;+    JSWord is_detached : 1;+    JSWord dummy: JS_MB_PAD(JS_MTAG_BITS + 1);+    union {+        JSValue value; /* is_detached = true */+        struct {+            JSValue next; /* is_detached = false: JS_NULL or JSVarRef,+                             must be at the same address as 'value' */+            JSValue *pvalue;+        };+    } u;+} JSVarRef;++typedef struct {+    JS_MB_HEADER;+    JSWord dummy: JS_MB_PAD(JS_MTAG_BITS);+#ifdef JS_PTR64+    struct {+        double dval;+    } u;+#else+    /* unaligned 64 bit access in 32-bit mode */+    struct __attribute__((packed)) {+        double dval;+    } u;+#endif+} JSFloat64;++typedef struct JSROMClass {+    JS_MB_HEADER;+    JSWord dummy: JS_MB_PAD(JS_MTAG_BITS);+    JSValue props;+    int32_t ctor_idx; /* -1 if defining a normal object */+    JSValue proto_props;+    JSValue parent_class; /* JSROMClass or JS_NULL */+} JSROMClass;++#define N_ROM_ATOM_TABLES_MAX 2++/* must be large enough to have a negligible runtime cost and small+   enough to call the interrupt callback often. */+#define JS_INTERRUPT_COUNTER_INIT 10000++#define JS_STRING_POS_CACHE_SIZE 2+#define JS_STRING_POS_CACHE_MIN_LEN 16 ++typedef enum {+    POS_TYPE_UTF8,+    POS_TYPE_UTF16,+} StringPosTypeEnum;++typedef struct {+    JSValue str; /* JS_NULL or weak reference to a JSString. It+                    contains at least JS_STRING_POS_CACHE_MIN_LEN+                    bytes and is a non ascii string */+    uint32_t str_pos[2]; /* 0 = UTF-8 pos (in bytes), 1 = UTF-16 pos */+} JSStringPosCacheEntry;++struct JSContext {+    /* memory map:+       Stack+       Free area+       Heap+       JSContext+    */+    uint8_t *heap_base;+    uint8_t *heap_free; /* first free area */+    uint8_t *stack_top;+    JSValue *stack_bottom; /* sp must always be higher than stack_bottom */+    JSValue *sp; /* current stack pointer */+    JSValue *fp; /* current frame pointer, stack_top if none */+    uint32_t min_free_size; /* min free size between heap_free and the+                               bottom of the stack */+    BOOL in_out_of_memory : 8; /* != 0 if generating the out of memory object */+    uint8_t n_rom_atom_tables;+    uint8_t string_pos_cache_counter; /* used for string_pos_cache[] update */+    uint16_t class_count; /* number of classes including user classes */+    int16_t interrupt_counter;+    BOOL current_exception_is_uncatchable : 8;+    struct JSParseState *parse_state; /* != NULL during JS_Eval() */+    int unique_strings_len;+    int js_call_rec_count; /* number of recursing JS_Call() */+    JSGCRef *top_gc_ref; /* used to reference temporary GC roots (stack top) */+    JSGCRef *last_gc_ref; /* used to reference temporary GC roots (list) */+    const JSWord *atom_table; /* constant atom table */+    /* 'n_rom_atom_tables' atom tables from code loaded from rom */+    const JSValueArray *rom_atom_tables[N_ROM_ATOM_TABLES_MAX];+    const JSCFunctionDef *c_function_table;+    const JSCFinalizer *c_finalizer_table;+    uint64_t random_state;+    JSInterruptHandler *interrupt_handler;+    JSWriteFunc *write_func; /* for the various dump functions */+    void *opaque;+    JSValue *class_obj; /* same as class_proto + class_count */+    JSStringPosCacheEntry string_pos_cache[JS_STRING_POS_CACHE_SIZE];+                                           +    /* must only contain JSValue from this point (see JS_GC()) */+    JSValue unique_strings; /* JSValueArray of sorted strings or JS_NULL */+    +    JSValue current_exception; /* currently pending exception, must+                                  come after unique_strings */+#ifdef DEBUG_GC+    JSValue dummy_block; /* dummy memory block near the start of the memory */+#endif+    JSValue empty_props; /* empty prop list, for objects with no properties */+    JSValue global_obj;+    JSValue minus_zero; /* minus zero float64 value */+    JSValue class_proto[]; /* prototype for each class (class_count+                              element, then class_count elements for+                              class_obj */+};++typedef enum {+    JS_VARREF_KIND_ARG, /* var_idx is an argument of the parent function */+    JS_VARREF_KIND_VAR, /* var_idx is a local variable of the parent function */+    JS_VARREF_KIND_VAR_REF, /* var_idx is a var ref of the parent function */+    JS_VARREF_KIND_GLOBAL, /* to debug */+} JSVarRefKindEnum;++typedef struct JSObject JSObject;++typedef struct {+    /* string, short integer or JS_UNINITIALIZED if no property. If+       the last property is uninitialized, hash_next = 2 *+       first_free. */+    JSValue key;+    /* JS_PROP_GETSET: JSValueArray of two elements+       JS_PROP_VARREF: JSVarRef */+    JSValue value;+    /* XXX: when JSW = 8, could use 32 bits for hash_next (faster) */+    uint32_t hash_next : 30;  /* low bit at zero */+    uint32_t prop_type : 2;+} JSProperty;++typedef struct {+    JSValue func_bytecode; /* JSFunctionBytecode */+    JSValue var_refs[]; /* JSValueArray */+} JSClosureData;++typedef struct {+    uint32_t idx;+    JSValue params; /* optional associated parameters */+} JSCFunctionData;+    +typedef struct {+    JSValue tab; /* JS_NULL or JSValueArray */+    uint32_t len; /* maximum value: 2^30-1 */+} JSArrayData;++typedef struct {+    JSValue message; /* string or JS_NULL */+    JSValue stack; /* string or JS_NULL */+} JSErrorData;+    +typedef struct {+    JSValue byte_buffer; /* JSByteBuffer */+} JSArrayBuffer;++typedef struct {+    JSValue buffer; /* corresponding array buffer */+    uint32_t len; /* in elements */+    uint32_t offset; /* in elements */+} JSTypedArray;++typedef struct {+    JSValue source;+    JSValue byte_code;+    int last_index;+} JSRegExp;++typedef struct {+    void *opaque;+} JSObjectUserData;++struct JSObject {+    JS_MB_HEADER;+    JSWord class_id: 8;+    JSWord extra_size: JS_MB_PAD(JS_MTAG_BITS + 8);  /* object additional size, in JSValue */++    JSValue proto; /* JSObject or JS_NULL */+    /* JSValueArray. structure:+       prop_count (number of properties excluding deleted ones)+       hash_mask (= hash_size - 1)+       hash_table[hash_size] (0 = end of list or offset in array)+       JSProperty props[]+    */+    JSValue props;+    /* number of additional fields depends on the object */+    union {+        JSClosureData closure;+        JSCFunctionData cfunc;+        JSArrayData array;+        JSErrorData error;+        JSArrayBuffer array_buffer;+        JSTypedArray typed_array;+        JSRegExp regexp;+        JSObjectUserData user;+    } u;+};++typedef struct JSFunctionBytecode {+    JS_MB_HEADER;+    JSWord has_arguments : 1; /* only used during parsing */+    JSWord has_local_func_name : 1; /* only used during parsing */+    JSWord has_column : 1; /* column debug info is present */+    /* during parse: variable index + 1 of hoisted function, 0 otherwise */+    JSWord arg_count : 16; +    JSWord dummy: JS_MB_PAD(JS_MTAG_BITS + 3 + 16);++    JSValue func_name; /* JS_NULL if anonymous function */+    JSValue byte_code; /* JS_NULL if the function is not parsed yet */+    JSValue cpool; /* constant pool */+    JSValue vars; /* only for debug */+    JSValue ext_vars; /* records of (var_name, var_kind (2 bits) var_idx (16 bits)) */+    uint16_t stack_size; /* maximum stack size */+    uint16_t ext_vars_len; /* XXX: only used during parsing */+    JSValue filename; /* filename in which the function is defined */+    JSValue pc2line; /* JSByteArray or JS_NULL if not initialized */+    uint32_t source_pos; /* only used during parsing (XXX: shrink) */+} JSFunctionBytecode;++static JSValue js_resize_value_array(JSContext *ctx, JSValue val, int new_size);+static int get_mblock_size(const void *ptr);+static JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValue proto, int class_id, int extra_size);+static void js_shrink_byte_array(JSContext *ctx, JSValue *pval, int new_size);+static void build_backtrace(JSContext *ctx, JSValue error_obj,+                            const char *filename, int line_num, int col_num, int skip_level);+static JSValue JS_ToPropertyKey(JSContext *ctx, JSValue val);+static JSByteArray *js_alloc_byte_array(JSContext *ctx, int size);+static JSValue js_new_c_function_proto(JSContext *ctx, int func_idx, JSValue proto, BOOL has_params,+                                       JSValue params);+static int JS_ToUint8Clamp(JSContext *ctx, int *pres, JSValue val);+static JSValue js_set_prototype_internal(JSContext *ctx, JSValue obj, JSValue proto);+static JSValue js_resize_byte_array(JSContext *ctx, JSValue val, int new_size);+static JSValueArray *js_alloc_props(JSContext *ctx, int n);++typedef enum OPCodeFormat {+#define FMT(f) OP_FMT_ ## f,+#define DEF(id, size, n_pop, n_push, f)+#include "mquickjs_opcode.h"+#undef DEF+#undef FMT+} OPCodeFormat;++typedef enum OPCodeEnum {+#define FMT(f)+#define DEF(id, size, n_pop, n_push, f) OP_ ## id,+#define def(id, size, n_pop, n_push, f)+#include "mquickjs_opcode.h"+#undef def+#undef DEF+#undef FMT+    OP_COUNT,+} OPCodeEnum;++typedef struct {+#ifdef DUMP_BYTECODE+    const char *name;+#endif+    uint8_t size; /* in bytes */+    /* the opcodes remove n_pop items from the top of the stack, then+       pushes n_pusch items */+    uint8_t n_pop;+    uint8_t n_push;+    uint8_t fmt;+} JSOpCode;++static __maybe_unused const JSOpCode opcode_info[OP_COUNT] = {+#define FMT(f)+#ifdef DUMP_BYTECODE+#define DEF(id, size, n_pop, n_push, f) { #id, size, n_pop, n_push, OP_FMT_ ## f },+#else+#define DEF(id, size, n_pop, n_push, f) { size, n_pop, n_push, OP_FMT_ ## f },+#endif+#include "mquickjs_opcode.h"+#undef DEF+#undef FMT+};++#include "mquickjs_atom.h"++JSValue *JS_PushGCRef(JSContext *ctx, JSGCRef *ref)+{+    ref->prev = ctx->top_gc_ref;+    ctx->top_gc_ref = ref;+    ref->val = JS_UNDEFINED;+    return &ref->val;+}++JSValue JS_PopGCRef(JSContext *ctx, JSGCRef *ref)+{+    ctx->top_gc_ref = ref->prev;+    return ref->val;+}++JSValue *JS_AddGCRef(JSContext *ctx, JSGCRef *ref)+{+    ref->prev = ctx->last_gc_ref;+    ctx->last_gc_ref = ref;+    ref->val = JS_UNDEFINED;+    return &ref->val;+}++void JS_DeleteGCRef(JSContext *ctx, JSGCRef *ref)+{+    JSGCRef **pref, *ref1;+    pref = &ctx->last_gc_ref;+    for(;;) {+        ref1 = *pref;+        if (ref1 == NULL)+            abort();+        if (ref1 == ref) {+            *pref = ref1->prev;+            break;+        }+        pref = &ref1->prev;+    }+}++#undef JS_PUSH_VALUE+#undef JS_POP_VALUE++#define JS_PUSH_VALUE(ctx, v) do {               \+        v ## _ref.prev = ctx->top_gc_ref;       \+        ctx->top_gc_ref = &v ## _ref;            \+        v ## _ref.val = v;                     \+    } while (0)+          +#define JS_POP_VALUE(ctx, v) do {                     \+          v = v ## _ref.val;                        \+          ctx->top_gc_ref = v ## _ref.prev;         \+      } while (0)++static JSValue js_get_atom(JSContext *ctx, int a)+{+    return JS_VALUE_FROM_PTR(&ctx->atom_table[a]);+}++static force_inline JSValue JS_NewTailCall(int val)+{+    return JS_VALUE_MAKE_SPECIAL(JS_TAG_EXCEPTION, JS_EX_CALL + val);+}++static inline JS_BOOL JS_IsExceptionOrTailCall(JSValue v)+{+    return JS_VALUE_GET_SPECIAL_TAG(v) == JS_TAG_EXCEPTION;+}++static int js_get_mtag(void *ptr)+{+    return ((JSMemBlockHeader *)ptr)->mtag;+}++static int check_free_mem(JSContext *ctx, JSValue *stack_bottom, uint32_t size)+{+#ifdef DEBUG_GC+    assert(ctx->sp >= stack_bottom);+    /* don't start the GC before dummy_block is allocated */+    if (JS_IsPtr(ctx->dummy_block)) {+        JS_GC(ctx);+    }+#endif+    if (((uint8_t *)stack_bottom - ctx->heap_free) < size + ctx->min_free_size) {+        JS_GC(ctx);+        if (((uint8_t *)stack_bottom - ctx->heap_free) < size + ctx->min_free_size) {+            JS_ThrowOutOfMemory(ctx);+            return -1;+        }+    }+    return 0;+}++/* check that 'len' values can be pushed on the stack. Return 0 if OK,+   -1 if not enough space. May trigger a GC(). */+int JS_StackCheck(JSContext *ctx, uint32_t len)+{+    JSValue *new_stack_bottom;++    len += JS_STACK_SLACK;+    new_stack_bottom = ctx->sp - len;+    if (check_free_mem(ctx, new_stack_bottom, len * sizeof(JSValue)))+        return -1;+    ctx->stack_bottom = new_stack_bottom;+    return 0;+}++static void *js_malloc(JSContext *ctx, uint32_t size, int mtag)+{+    JSMemBlockHeader *p;++    if (size == 0)+        return NULL;+    size = (size + JSW - 1) & ~(JSW - 1);++    if (check_free_mem(ctx, ctx->stack_bottom, size))+        return NULL;+    +    p = (JSMemBlockHeader *)ctx->heap_free;+    ctx->heap_free += size;++    p->mtag = mtag;+    p->gc_mark = 0;+    p->dummy = 0;+    return p;+}++static void *js_mallocz(JSContext *ctx, uint32_t size, int mtag)+{+    uint8_t *ptr;+    ptr = js_malloc(ctx, size, mtag);+    if (!ptr)+        return NULL;+    if (size > sizeof(uint32_t)) {+        memset(ptr + sizeof(uint32_t), 0, size - sizeof(uint32_t));+    }+    return ptr;+}++/* currently only free the last element */+static void js_free(JSContext *ctx, void *ptr)+{+    uint8_t *ptr1;+    if (!ptr)+        return;+    ptr1 = ptr;+    ptr1 += get_mblock_size(ptr1);+    if (ptr1 == ctx->heap_free)+        ctx->heap_free = ptr;+}++/* 'size' is in bytes and must be multiple of JSW and > 0 */+static void set_free_block(void *ptr, uint32_t size)+{+    JSFreeBlock *p;+    p = (JSFreeBlock *)ptr;+    p->mtag = JS_MTAG_FREE;+    p->gc_mark = 0;+    p->size = (size - sizeof(JSFreeBlock)) / sizeof(JSWord);+}++/* 'ptr' must be != NULL. new_size must be less or equal to the+   current block size. */+static void *js_shrink(JSContext *ctx, void *ptr, uint32_t new_size)+{+    uint32_t old_size;+    uint32_t diff;+    +    new_size = (new_size + (JSW - 1)) & ~(JSW - 1);++    if (new_size == 0) {+        js_free(ctx, ptr);+        return NULL;+    }+    old_size = get_mblock_size(ptr);+    assert(new_size <= old_size);+    diff = old_size - new_size;+    if (diff == 0)+        return ptr;+    set_free_block((uint8_t *)ptr + new_size, diff);+    /* add a new free block after 'ptr' */+    return ptr;+}++JSValue JS_Throw(JSContext *ctx, JSValue obj)+{+    ctx->current_exception = obj;+    ctx->current_exception_is_uncatchable = FALSE;+    return JS_EXCEPTION;+}++/* return the byte length. 'buf' must contain UTF8_CHAR_LEN_MAX + 1 bytes */+static int get_short_string(uint8_t *buf, JSValue val)+{+    int len;+    len = unicode_to_utf8(buf, JS_VALUE_GET_SPECIAL_VALUE(val));+    buf[len] = '\0';+    return len;+}++/* printf utility */++#define PF_ZERO_PAD (1 << 0) /* 0 */+#define PF_ALT_FORM (1 << 1) /* # */+#define PF_MARK_POS (1 << 2) /* + */+#define PF_LEFT_ADJ (1 << 3) /* - */+#define PF_PAD_POS  (1 << 4) /* ' ' */+#define PF_INT64    (1 << 5) /* l/ll */++static BOOL is_digit(int c)+{+    return (c >= '0' && c <= '9');+}++/* pad with chars 'c' */+static void pad(JSWriteFunc *write_func, void *opaque, char c,+                int width, int len)+{+    char buf[16];+    int l;+    if (len >= width)+        return;+    width -= len;+    memset(buf, c, min_int(sizeof(buf), width));+    while (width != 0) {+        l = min_int(width, sizeof(buf));+        write_func(opaque, buf, l);+        width -= l;+    }+}++/* The 'o' format can be used to print a JSValue. Only short int,+   bool, null, undefined and string types are supported. */+static void js_vprintf(JSWriteFunc *write_func, void *opaque, const char *fmt, va_list ap)+{+    const char *p;+    int width, prec, flags, c;+    char tmp_buf[32], *buf;+    size_t len;+    +    while (*fmt != '\0') {+        p = fmt;+        while (*fmt != '%' && *fmt != '\0')+            fmt++;+        if (fmt > p)+            write_func(opaque, p, fmt - p);+        if (*fmt == '\0')+            break;+        fmt++;+        /* get the flags */+        flags = 0;+        for(;;) {+            c = *fmt;+            if (c == '0') {+                flags |= PF_ZERO_PAD;+            } else if (c == '#') {+                flags |= PF_ALT_FORM;+            } else if (c == '+') {+                flags |= PF_MARK_POS;+            } else if (c == '-') {+                flags |= PF_LEFT_ADJ;+            } else if (c == ' ') {+                flags |= PF_MARK_POS;+            } else {+                break;+            }+            fmt++;+        }+        width = 0;+        if (*fmt == '*') {+            width = va_arg(ap, int);+        } else {+            while (is_digit(*fmt)) {+                width = width * 10 + *fmt - '0';+                fmt++;+            }+        }+        prec = 0;+        if (*fmt == '.') {+            fmt++;+            if (*fmt == '*') {+                prec = va_arg(ap, int);+            } else {+                while (is_digit(*fmt)) {+                    prec = prec * 10 + *fmt - '0';+                    fmt++;+                }+            }+        }+        /* modifiers */+        for(;;) {+            c = *fmt;+            if (c == 'l') {+                if (sizeof(long) == sizeof(int64_t) || fmt[-1] == 'l')+                    flags |= PF_INT64;+            } else+            if (c == 'z' || c == 't') {+                if (sizeof(size_t) == sizeof(uint64_t))+                    flags |= PF_INT64;+            } else {+                break;+            }+            fmt++;+        }++        c = *fmt++;+        /* XXX: not complete, just enough for our needs */+        buf = tmp_buf;+        len = 0;+        switch(c) {+        case '%':+            write_func(opaque, fmt - 1, 1);+            break;+        case 'c':+            buf[0] = va_arg(ap, int);+            len = 1;+            flags &= ~PF_ZERO_PAD;+            break;+        case 's':+            buf = va_arg(ap, char *);+            if (!buf)+                buf = "null";+            len = strlen(buf);+            flags &= ~PF_ZERO_PAD;+            break;+        case 'd':+            if (flags & PF_INT64)+                len = i64toa(buf, va_arg(ap, int64_t));+            else+                len = i32toa(buf, va_arg(ap, int32_t));+            break;+        case 'u':+            if (flags & PF_INT64)+                len = u64toa(buf, va_arg(ap, uint64_t));+            else+                len = u32toa(buf, va_arg(ap, uint32_t));+            break;+        case 'x':+            if (flags & PF_INT64)+                len = u64toa_radix(buf, va_arg(ap, uint64_t), 16);+            else+                len = u64toa_radix(buf, va_arg(ap, uint32_t), 16);+            break;+        case 'p':+            buf[0] = '0';+            buf[1] = 'x';+            len = u64toa_radix(buf + 2, (uintptr_t)va_arg(ap, void *), 16);+            len += 2;+            break;+        case 'o':+            {+                JSValue val = (flags & PF_INT64) ? va_arg(ap, uint64_t) : va_arg(ap, uint32_t);+                if (JS_IsInt(val)) {+                    len = i32toa(buf, JS_VALUE_GET_INT(val));+                } else+#ifdef JS_USE_SHORT_FLOAT+                if (JS_IsShortFloat(val)) {+                    /* XXX: print it */+                    buf = "[short_float]";+                    goto do_strlen;+                } else+#endif+                if (!JS_IsPtr(val)) {+                    switch(JS_VALUE_GET_SPECIAL_TAG(val)) {+                    case JS_TAG_NULL:+                        buf = "null";+                        goto do_strlen;+                    case JS_TAG_UNDEFINED:+                        buf = "undefined";+                        goto do_strlen;+                    case JS_TAG_UNINITIALIZED:+                        buf = "uninitialized";+                        goto do_strlen;+                    case JS_TAG_BOOL:+                        buf = JS_VALUE_GET_SPECIAL_VALUE(val) ? "true" : "false";+                        goto do_strlen;+                    case JS_TAG_STRING_CHAR:+                        len = get_short_string((uint8_t *)buf, val);+                        break;+                    default:+                        buf = "[tag]";+                        goto do_strlen;+                    }+                } else {+                    void *ptr = JS_VALUE_TO_PTR(val);+                    int mtag = ((JSMemBlockHeader *)ptr)->mtag;+                    switch(mtag) {+                    case JS_MTAG_STRING:+                        {+                            JSString *p = ptr;+                            buf = (char *)p->buf;+                            len = p->len;+                        }+                        break;+                    default:+                        buf = "[mtag]";+                    do_strlen:+                        len = strlen(buf);+                        break;+                    }+                }+                /* remove the trailing '\n' if any (used in error output) */+                if ((flags & PF_ALT_FORM) && len > 0 && buf[len - 1] == '\n')+                    len--;+                flags &= ~PF_ZERO_PAD;+            }+            break;+        default:+            goto error;+        }+        if (flags & PF_ZERO_PAD) {+            /* XXX: incorrect with prefix */+            pad(write_func, opaque, '0', width, len);+        } else {+            if (!(flags & PF_LEFT_ADJ))+                pad(write_func, opaque, ' ', width, len);+        }+        write_func(opaque, buf, len);+        if (flags & PF_LEFT_ADJ)+            pad(write_func, opaque, ' ', width, len);+    }+    return;+ error:+    return;+}++/* used for the debug output */+static void __js_printf_like(2, 3) js_printf(JSContext *ctx,+                                             const char *fmt, ...)+{+    va_list ap;+    va_start(ap, fmt);+    js_vprintf(ctx->write_func, ctx->opaque, fmt, ap);+    va_end(ap);+}++static __maybe_unused void js_putchar(JSContext *ctx, uint8_t c)+{+    ctx->write_func(ctx->opaque, &c, 1);+}++typedef struct {+    char *ptr;+    char *buf_end;+    int len;+} SNPrintfState;++static void snprintf_write_func(void *opaque, const void *buf, size_t buf_len)+{+    SNPrintfState *s = opaque;+    size_t l;+    s->len += buf_len;+    l = min_size_t(buf_len, s->buf_end - s->ptr);+    if (l != 0) {+        memcpy(s->ptr, buf, l);+        s->ptr += l;+    }+}++static int js_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap)+{+    SNPrintfState ss, *s = &ss;+    s->ptr = buf;+    s->buf_end = buf + max_size_t(buf_size, 1) - 1;+    s->len = 0;+    js_vprintf(snprintf_write_func, s, fmt, ap);+    if (buf_size > 0)+        *s->ptr = '\0';+    return s->len;+}++static int __maybe_unused __js_printf_like(3, 4) js_snprintf(char *buf, size_t buf_size, const char *fmt, ...)+{+    va_list ap;+    int ret;+    va_start(ap, fmt);+    ret = js_vsnprintf(buf, buf_size, fmt, ap);+    va_end(ap);+    return ret;+}++JSValue __js_printf_like(3, 4) JS_ThrowError(JSContext *ctx, JSObjectClassEnum error_num,+                                           const char *fmt, ...)+{+    JSObject *p;+    va_list ap;+    char buf[128];+    JSValue msg, error_obj;+    JSGCRef msg_ref, error_obj_ref;+    +    va_start(ap, fmt);+    js_vsnprintf(buf, sizeof(buf), fmt, ap);+    va_end(ap);+    msg = JS_NewString(ctx, buf);++    JS_PUSH_VALUE(ctx, msg);+    error_obj = JS_NewObjectProtoClass(ctx, ctx->class_proto[error_num], JS_CLASS_ERROR,+                                       sizeof(JSErrorData));+    JS_POP_VALUE(ctx, msg);+    if (JS_IsException(error_obj))+        return error_obj;++    p = JS_VALUE_TO_PTR(error_obj);+    p->u.error.message = msg;+    p->u.error.stack = JS_NULL;++    /* in case of syntax error, the backtrace is added later */+    if (error_num != JS_CLASS_SYNTAX_ERROR) {+        JS_PUSH_VALUE(ctx, error_obj);+        build_backtrace(ctx, error_obj, NULL, 0, 0, 0);+        JS_POP_VALUE(ctx, error_obj);+    }++    return JS_Throw(ctx, error_obj);+}++JSValue JS_ThrowOutOfMemory(JSContext *ctx)+{+    JSValue val;+    if (ctx->in_out_of_memory)+        return JS_Throw(ctx, JS_NULL);+    ctx->in_out_of_memory = TRUE;+    ctx->min_free_size = JS_MIN_CRITICAL_FREE_SIZE;+    val = JS_ThrowInternalError(ctx, "out of memory");+    ctx->in_out_of_memory = FALSE;+    ctx->min_free_size = JS_MIN_FREE_SIZE;+    return val;+}++#define JS_SHORTINT_MIN (-(1 << 30))+#define JS_SHORTINT_MAX ((1 << 30) - 1)++#ifdef JS_USE_SHORT_FLOAT++#define JS_FLOAT64_VALUE_EXP_MIN (1023 - 127)+#define JS_FLOAT64_VALUE_ADDEND ((uint64_t)(JS_FLOAT64_VALUE_EXP_MIN - (JS_TAG_SHORT_FLOAT << 8)) << 52)++/* 1 <= n <= 63 */+static inline uint64_t rotl64(uint64_t a, int n)+{+    return (a << n) | (a >> (64 - n));+}++static double js_get_short_float(JSValue v)+{+    return uint64_as_float64(rotl64(v, 60) + JS_FLOAT64_VALUE_ADDEND);+}++static JSValue js_to_short_float(double d)+{+    return rotl64(float64_as_uint64(d) - JS_FLOAT64_VALUE_ADDEND, 4);+}++#endif /* JS_USE_SHORT_FLOAT */++static JSValue js_alloc_float64(JSContext *ctx, double d)+{+    JSFloat64 *f;+    f = js_malloc(ctx, sizeof(JSFloat64), JS_MTAG_FLOAT64);+    if (!f)+        return JS_EXCEPTION;+    f->u.dval = d;+    return JS_VALUE_FROM_PTR(f);+}++/* create a new float64 value which is known not to be a short integer */+static JSValue __JS_NewFloat64(JSContext *ctx, double d)+{+    if (float64_as_uint64(d) == 0x8000000000000000) {+        /* minus zero often happens, so it is worth having a constant+           value */+        return ctx->minus_zero;+    } else+#ifdef JS_USE_SHORT_FLOAT+    /* Note: this test is false for NaN */+    if (fabs(d) >= 0x1p-127 && fabs(d) <= 0x1p+128) {+        return js_to_short_float(d);+    } else+#endif+    {+        return js_alloc_float64(ctx, d);+    }+}++static inline JSValue JS_NewShortInt(int32_t val)+{+    return JS_TAG_INT + (val << 1);+}++#if defined(USE_SOFTFLOAT)+JSValue JS_NewFloat64(JSContext *ctx, double d)+{+    uint64_t a, m;+    int e, b, shift;+    JSValue v;++    a = float64_as_uint64(d);+    if (a == 0) {+        v = JS_NewShortInt(0);+    } else {+        e = (a >> 52) & 0x7ff;+        if (e >= 1023 && e <= 1023 + 30 - 1) {+            m = (a & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);+            shift = 52 - (e - 1023);+            /* test if exact integer */+            if ((m & (((uint64_t)1 << shift) - 1)) != 0)+                goto not_int;+            b = m >> shift;+            if (a >> 63)+                b = -b;+            v = JS_NewShortInt(b);+        } else if (a == 0xc1d0000000000000) {+            v = JS_NewShortInt(-(1 << 30));+        } else {+        not_int:+            v = __JS_NewFloat64(ctx, d);+        }+    }+    return v;+}+#else+JSValue JS_NewFloat64(JSContext *ctx, double d)+{+    int32_t val;+    if (d >= JS_SHORTINT_MIN && d <= JS_SHORTINT_MAX) {+        val = (int32_t)d;+        /* -0 cannot be represented as integer, so we compare the bit+           representation */+        if (float64_as_uint64(d) == float64_as_uint64((double)val))+            return JS_NewShortInt(val);+    }+    return __JS_NewFloat64(ctx, d);+}+#endif++static inline BOOL int64_is_short_int(int64_t val)+{+    return val >= JS_SHORTINT_MIN && val <= JS_SHORTINT_MAX;+}++JSValue JS_NewInt64(JSContext *ctx, int64_t val)+{+    JSValue v;+    if (likely(int64_is_short_int(val))) {+        v = JS_NewShortInt(val);+    } else {+        v = __JS_NewFloat64(ctx, val);+    }+    return v;+}++JSValue JS_NewInt32(JSContext *ctx, int32_t val)+{+    return JS_NewInt64(ctx, val);+}++JSValue JS_NewUint32(JSContext *ctx, uint32_t val)+{+    return JS_NewInt64(ctx, val);+}++static BOOL JS_IsPrimitive(JSContext *ctx, JSValue val)+{+    if (!JS_IsPtr(val)) {+        return JS_VALUE_GET_SPECIAL_TAG(val) != JS_TAG_SHORT_FUNC;+    } else {+        return (js_get_mtag(JS_VALUE_TO_PTR(val)) != JS_MTAG_OBJECT);+    }+}++/* Note: short functions are not considered as objects by this function */+static BOOL JS_IsObject(JSContext *ctx, JSValue val)+{+    if (!JS_IsPtr(val)) {+        return FALSE;+    } else {+        JSObject *p = JS_VALUE_TO_PTR(val);+        return (p->mtag == JS_MTAG_OBJECT);+    }+}++/* return -1 if not an object */+int JS_GetClassID(JSContext *ctx, JSValue val)+{+    if (!JS_IsPtr(val)) {+        return -1;+    } else {+        JSObject *p = JS_VALUE_TO_PTR(val);+        if (p->mtag != JS_MTAG_OBJECT)+            return -1;+        else+            return p->class_id;+    }+}++void JS_SetOpaque(JSContext *ctx, JSValue val, void *opaque)+{+    JSObject *p;+    assert(JS_IsPtr(val));+    p = JS_VALUE_TO_PTR(val);+    assert(p->mtag == JS_MTAG_OBJECT);+    assert(p->class_id >= JS_CLASS_USER);+    p->u.user.opaque = opaque;+}++void *JS_GetOpaque(JSContext *ctx, JSValue val)+{+    JSObject *p;+    assert(JS_IsPtr(val));+    p = JS_VALUE_TO_PTR(val);+    assert(p->mtag == JS_MTAG_OBJECT);+    assert(p->class_id >= JS_CLASS_USER);+    return p->u.user.opaque;+}++static JSObject *js_get_object_class(JSContext *ctx, JSValue val, int class_id)+{+    if (!JS_IsPtr(val)) {+        return NULL;+    } else {+        JSObject *p = JS_VALUE_TO_PTR(val);+        if (p->mtag != JS_MTAG_OBJECT || p->class_id != class_id)+            return NULL;+        else+            return p;+    }+}++BOOL JS_IsFunction(JSContext *ctx, JSValue val)+{+    if (!JS_IsPtr(val)) {+        return JS_VALUE_GET_SPECIAL_TAG(val) == JS_TAG_SHORT_FUNC;+    } else {+        JSObject *p = JS_VALUE_TO_PTR(val);+        return (p->mtag == JS_MTAG_OBJECT &&+                (p->class_id == JS_CLASS_CLOSURE ||+                 p->class_id == JS_CLASS_C_FUNCTION));+    }+}++static BOOL JS_IsFunctionObject(JSContext *ctx, JSValue val)+{+    if (!JS_IsPtr(val)) {+        return FALSE;+    } else {+        JSObject *p = JS_VALUE_TO_PTR(val);+        return (p->mtag == JS_MTAG_OBJECT &&+                (p->class_id == JS_CLASS_CLOSURE ||+                 p->class_id == JS_CLASS_C_FUNCTION));+    }+}++BOOL JS_IsError(JSContext *ctx, JSValue val)+{+    if (!JS_IsPtr(val)) {+        return FALSE;+    } else {+        JSObject *p = JS_VALUE_TO_PTR(val);+        return (p->mtag == JS_MTAG_OBJECT && p->class_id == JS_CLASS_ERROR);+    }+}++static force_inline BOOL JS_IsIntOrShortFloat(JSValue val)+{+#ifdef JS_USE_SHORT_FLOAT+    return JS_IsInt(val) || JS_IsShortFloat(val);+#else+    return JS_IsInt(val);+#endif+}++BOOL JS_IsNumber(JSContext *ctx, JSValue val)+{+    if (JS_IsIntOrShortFloat(val)) {+        return TRUE;+    } else if (JS_IsPtr(val)) {+        void *ptr = JS_VALUE_TO_PTR(val);+        return (js_get_mtag(ptr) == JS_MTAG_FLOAT64);+    } else {+        return FALSE;+    }+}++BOOL JS_IsString(JSContext *ctx, JSValue val)+{+    if (!JS_IsPtr(val)) {+        return JS_VALUE_GET_SPECIAL_TAG(val) == JS_TAG_STRING_CHAR;+    } else {+        void *ptr = JS_VALUE_TO_PTR(val);+        return (js_get_mtag(ptr) == JS_MTAG_STRING);+    }+}++static JSString *js_alloc_string(JSContext *ctx, uint32_t buf_len)+{+    JSString *p;++    if (buf_len > JS_STRING_LEN_MAX) {+        JS_ThrowInternalError(ctx, "string too long");+        return NULL;+    }+    p = js_malloc(ctx, sizeof(JSString) + buf_len + 1, JS_MTAG_STRING);+    if (!p)+        return NULL;+    p->is_unique = FALSE;+    p->is_ascii = FALSE;+    p->is_numeric = FALSE;+    p->len = buf_len;+    p->buf[buf_len] = '\0';+    return p;+}++/* 0 <= c <= 0x10ffff */+static inline JSValue JS_NewStringChar(uint32_t c)+{+    return JS_VALUE_MAKE_SPECIAL(JS_TAG_STRING_CHAR, c);+}++static force_inline int utf8_char_len(int c)+{+    int l;+    if (c < 0x80) {+        l = 1;+    } else if (c < 0xc0) {+        l = 1;+    } else if (c < 0xe0) {+        l = 2;+    } else if (c < 0xf0) {+        l = 3;+    } else if (c < 0xf8) {+        l = 4;+    } else {+        l = 1;+    }+    return l;+}++static BOOL is_ascii_string(const char *buf, size_t len)+{+    size_t i;+    for(i = 0; i < len; i++) {+        if ((uint8_t)buf[i] > 0x7f)+            return FALSE;+    }+    return TRUE;+}++static JSString *get_string_ptr(JSContext *ctx, JSStringCharBuf *buf,+                               JSValue val)+{+    if (JS_VALUE_GET_SPECIAL_TAG(val) == JS_TAG_STRING_CHAR) {+        JSString *p = (JSString *)buf;+        p->is_unique = FALSE;+        p->is_ascii = JS_VALUE_GET_SPECIAL_VALUE(val) <= 0x7f;+        p->len = get_short_string(p->buf, val);+        return p;+    } else {+        return JS_VALUE_TO_PTR(val);+    }+}++static JSValue js_sub_string_utf8(JSContext *ctx, JSValue val,+                                  uint32_t start0, uint32_t end0)+{+    JSString *p, *p1;+    int len, start, end, c;+    BOOL start_surrogate, end_surrogate;+    JSStringCharBuf buf;+    JSGCRef val_ref;+    const uint8_t *ptr;+    size_t clen;+    +    if (end0 - start0 == 0) {+        return js_get_atom(ctx, JS_ATOM_empty);+    }+    start_surrogate = start0 & 1;+    end_surrogate = end0 & 1;+    start = start0 >> 1;+    end = end0 >> 1;+    len = end - start;+    p1 = get_string_ptr(ctx, &buf, val);+    ptr = p1->buf;+    if (!start_surrogate && !end_surrogate && utf8_char_len(ptr[start]) == len) {+        c = utf8_get(ptr + start, &clen);+        return JS_NewStringChar(c);+    }++    JS_PUSH_VALUE(ctx, val);+    p = js_alloc_string(ctx, len - start_surrogate + (end_surrogate ? 3 : 0));+    JS_POP_VALUE(ctx, val);+    if (!p)+        return JS_EXCEPTION;+    p1 = get_string_ptr(ctx, &buf, val);+    ptr = p1->buf;+    if (unlikely(start_surrogate || end_surrogate)) {+        uint8_t *q = p->buf;+        p->is_ascii = FALSE;+        if (start_surrogate) {+            c = utf8_get(ptr + start, &clen);+            c = 0xdc00 + ((c - 0x10000) & 0x3ff); /* right surrogate */+            q += unicode_to_utf8(q, c);+            start += 4;+        }+        memcpy(q, ptr + start, end - start);+        q += end - start;+        if (end_surrogate) {+            c = utf8_get(ptr + end, &clen);+            c = 0xd800 + ((c - 0x10000) >> 10); /* left surrogate */+            q += unicode_to_utf8(q, c);+        }+        assert((q - p->buf) == p->len);+    } else {+        p->is_ascii = p1->is_ascii ? TRUE : is_ascii_string((const char *)(ptr + start), len);+        memcpy(p->buf, ptr + start, len);+    }+    return JS_VALUE_FROM_PTR(p);+}++/* Warning: the string must be a valid WTF-8 string (= UTF-8 ++   unpaired surrogates). */+JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t len)+{+    JSString *p;+    +    if (len == 0) {+        return js_get_atom(ctx, JS_ATOM_empty);+    } else {+        if (utf8_char_len(buf[0]) == len) {+            size_t clen;+            int c;+            c = utf8_get((const uint8_t *)buf, &clen);+            return JS_NewStringChar(c);+        }+    }+    p = js_alloc_string(ctx, len);+    if (!p)+        return JS_EXCEPTION;+    p->is_ascii = is_ascii_string((const char *)buf, len);+    memcpy(p->buf, buf, len);+    return JS_VALUE_FROM_PTR(p);+}++/* Warning: the string must be a valid UTF-8 string. */+JSValue JS_NewString(JSContext *ctx, const char *buf)+{+    return JS_NewStringLen(ctx, buf, strlen(buf));+}++/* the byte array must be zero terminated. */+static JSValue js_byte_array_to_string(JSContext *ctx, JSValue val, int len, BOOL is_ascii)+{+    JSByteArray *arr = JS_VALUE_TO_PTR(val);+    JSString *p;++    assert(len + 1 <= arr->size);+    if (len == 0) {+        return js_get_atom(ctx, JS_ATOM_empty);+    } else if (utf8_char_len(arr->buf[0]) == len) {+        size_t clen;+        return JS_NewStringChar(utf8_get(arr->buf, &clen));+    } else {+        js_shrink_byte_array(ctx, &val, len + 1);+        p = (JSString *)arr;+        p->mtag = JS_MTAG_STRING;+        p->is_ascii = is_ascii;+        p->is_unique = FALSE;+        p->is_numeric = FALSE;+        p->len = len;+        return val;+    }+}++/* in bytes */+static __maybe_unused int js_string_byte_len(JSContext *ctx, JSValue val)+{+    if (JS_VALUE_GET_SPECIAL_TAG(val) == JS_TAG_STRING_CHAR) {+        int c = JS_VALUE_GET_SPECIAL_VALUE(val);+        if (c < 0x80)+            return 1;+        else if (c < 0x800)+            return 2;+        else if (c < 0x10000)+            return 3;+        else+            return 4;+    } else {+        JSString *p = JS_VALUE_TO_PTR(val);+        return p->len;+    }+}+    +/* assuming that utf8_next() returns 4, validate the corresponding UTF-8 sequence */+static BOOL is_valid_len4_utf8(const uint8_t *buf)+{+    return (((buf[0] & 0xf) << 6) | (buf[1] & 0x3f)) >= 0x10;+}++static __maybe_unused void dump_string_pos_cache(JSContext *ctx)+{+    int i;+    JSStringPosCacheEntry *ce;+    for(i = 0; i < JS_STRING_POS_CACHE_SIZE; i++) {+        ce = &ctx->string_pos_cache[i];+        printf("%d: ", i);+        if (ce->str == JS_NULL) {+            printf("<empty>\n");+        } else {+            JSString *p = JS_VALUE_TO_PTR(ce->str);+            printf(" utf8_pos=%u/%u utf16_pos=%u\n",+                   ce->str_pos[POS_TYPE_UTF8], (int)p->len, ce->str_pos[POS_TYPE_UTF16]);+        }+    }+}++/* an UTF-8 position is the byte position multiplied by 2. One is+   added when the corresponding UTF-16 character represents the right+   surrogate if the code is >= 0x10000.+*/+static uint32_t js_string_convert_pos(JSContext *ctx, JSValue val, uint32_t pos,+                                      StringPosTypeEnum pos_type)+{+    JSStringCharBuf buf;+    JSString *p;+    size_t i, clen, len, start;+    uint32_t d_min, d, j;+    JSStringPosCacheEntry *ce, *ce1;+    uint32_t surrogate_flag, has_surrogate, limit;+    int ce_idx;++    p = get_string_ptr(ctx, &buf, val);+    len = p->len;+    if (p->is_ascii) {+        if (pos_type == POS_TYPE_UTF8)+            return min_int(len, pos / 2);+        else+            return min_int(len, pos) * 2;+    }++    if (pos_type == POS_TYPE_UTF8) {+        has_surrogate = pos & 1;+        pos >>= 1;+    } else {+        has_surrogate = 0;+    }+    +    ce = NULL;+    if (len < JS_STRING_POS_CACHE_MIN_LEN) {+        j = 0;+        i = 0;+        goto uncached;+    }++    d_min = pos;+    for(ce_idx = 0; ce_idx < JS_STRING_POS_CACHE_SIZE; ce_idx++) {+        ce1 = &ctx->string_pos_cache[ce_idx];+        if (ce1->str == val) {+            d = ce1->str_pos[pos_type];+            d = d >= pos ? d - pos : pos - d;+            if (d < d_min) {+                d_min = d;+                ce = ce1;+            }+        }+    }+    if (!ce) {+        /* "random" replacement */+        ce = &ctx->string_pos_cache[ctx->string_pos_cache_counter];+        if (++ctx->string_pos_cache_counter == JS_STRING_POS_CACHE_SIZE)+            ctx->string_pos_cache_counter = 0;+        ce->str = val;+        ce->str_pos[POS_TYPE_UTF8] = 0;+        ce->str_pos[POS_TYPE_UTF16] = 0;+    }+    +    i = ce->str_pos[POS_TYPE_UTF8];+    j = ce->str_pos[POS_TYPE_UTF16];+    if (ce->str_pos[pos_type] <= pos) {+    uncached:+        surrogate_flag = 0;+        if (pos_type == POS_TYPE_UTF8) {+            limit = INT32_MAX;+            len = pos;+        } else {+            limit = pos;+        }+        for(; i < len; i += clen) {+            if (j == limit)+                break;+            clen = utf8_char_len(p->buf[i]);+            if (clen == 4 && is_valid_len4_utf8(p->buf + i)) {+                if ((j + 1) == limit) {+                    surrogate_flag = 1;+                    break;+                }+                j += 2;+            } else {+                j++;+            }+        }+    } else {+        surrogate_flag = 0;+        if (pos_type == POS_TYPE_UTF8) {+            start = pos;+            limit = INT32_MAX;+        } else {+            limit = pos;+            start = 0;+        }+        while (i > start) {+            size_t i0 = i;+            i--;+            while ((p->buf[i] & 0xc0) == 0x80)+                i--;+            clen = i0 - i;+            if (clen == 4 && is_valid_len4_utf8(p->buf + i)) {+                j -= 2;+                if ((j + 1) == limit) {+                    surrogate_flag = 1;+                    break;+                }+            } else {+                j--;+            }+            if (j == limit)+                break;+        }+    }+    if (ce) {+        ce->str_pos[POS_TYPE_UTF8] = i;+        ce->str_pos[POS_TYPE_UTF16] = j;+    }+    if (pos_type == POS_TYPE_UTF8)+        return j + has_surrogate;+    else+        return i * 2 + surrogate_flag;+}++static uint32_t js_string_utf16_to_utf8_pos(JSContext *ctx, JSValue val, uint32_t utf16_pos)+{+    return js_string_convert_pos(ctx, val, utf16_pos, POS_TYPE_UTF16);+}++static uint32_t js_string_utf8_to_utf16_pos(JSContext *ctx, JSValue val, uint32_t utf8_pos)+{+    return js_string_convert_pos(ctx, val, utf8_pos, POS_TYPE_UTF8);+}++/* Testing the third byte is not needed as the UTF-8 encoding must be+   correct */+static BOOL is_utf8_left_surrogate(const uint8_t *p)+{+    return p[0] == 0xed && (p[1] >= 0xa0 && p[1] <= 0xaf);+}++static BOOL is_utf8_right_surrogate(const uint8_t *p)+{+    return p[0] == 0xed && (p[1] >= 0xb0 && p[1] <= 0xbf);+}++typedef struct {+    JSGCRef buffer_ref; /* string, JSByteBuffer or JS_EXCEPTION */+    int len; /* current string length (in bytes) */+    BOOL is_ascii;+} StringBuffer;++/* return 0 if OK, -1 in case of exception (exception possible if len > 0) */+static int string_buffer_push(JSContext *ctx, StringBuffer *s, int len)+{+    s->len = 0;+    s->is_ascii = TRUE;+    if (len > 0) {+        JSByteArray *arr;+        arr = js_alloc_byte_array(ctx, len);+        if (!arr)+            return -1;+        s->buffer_ref.val = JS_VALUE_FROM_PTR(arr);+    } else {+        s->buffer_ref.val = js_get_atom(ctx, JS_ATOM_empty);+    }+    s->buffer_ref.prev = ctx->top_gc_ref;+    ctx->top_gc_ref = &s->buffer_ref;+    return 0;+}++/* val2 must be a string. Return 0 if OK, -1 in case of exception */+static int string_buffer_concat_str(JSContext *ctx, StringBuffer *s, JSValue val2)+{+    JSStringCharBuf buf1, buf2;+    JSByteArray *arr;+    JSString *p1, *p2;+    int len, len1, len2;+    JSValue val1;+    uint8_t *q;+    +    if (JS_IsException(s->buffer_ref.val))+        return -1;+    p2 = get_string_ptr(ctx, &buf2, val2);+    len2 = p2->len;+    if (len2 == 0)+        return 0;+    if (JS_IsString(ctx, s->buffer_ref.val)) {+        p1 = get_string_ptr(ctx, &buf1, s->buffer_ref.val);+        len1 = p1->len;+        if (len1 == 0) {+            /* empty string in buffer: just keep 'val2' */+            s->buffer_ref.val = val2;+            return 0;+        }+        arr = NULL;+        val1 = s->buffer_ref.val;+        s->buffer_ref.val = JS_NULL;+    } else {+        arr = JS_VALUE_TO_PTR(s->buffer_ref.val);+        len1 = s->len;+        val1 = JS_NULL;+    }++    len = len1 + len2;+    if (len > JS_STRING_LEN_MAX) {+        s->buffer_ref.val = JS_ThrowInternalError(ctx, "string too long");+        return -1;+    }++    if (!arr || (len + 1) > arr->size) {+        JSGCRef val1_ref, val2_ref;++        JS_PUSH_VALUE(ctx, val1);+        JS_PUSH_VALUE(ctx, val2);+        s->buffer_ref.val = js_resize_byte_array(ctx, s->buffer_ref.val, len + 1);+        JS_POP_VALUE(ctx, val2);+        JS_POP_VALUE(ctx, val1);+        if (JS_IsException(s->buffer_ref.val))+            return -1;+        arr = JS_VALUE_TO_PTR(s->buffer_ref.val);+        if (val1 != JS_NULL) {+            p1 = get_string_ptr(ctx, &buf1, val1);+            s->is_ascii = p1->is_ascii;+            memcpy(arr->buf, p1->buf, len1);+        }+        p2 = get_string_ptr(ctx, &buf2, val2);+    }+    +    q = arr->buf + len1;+    if (len2 >= 3 && unlikely(is_utf8_right_surrogate(p2->buf)) &&+        len1 >= 3 && is_utf8_left_surrogate(q - 3)) {+        size_t clen;+        int c;+        /* contract the two surrogates to 4 bytes */+        c = (utf8_get(q - 3, &clen) & 0x3ff) << 10;+        c |= (utf8_get(p2->buf, &clen) & 0x3ff);+        c += 0x10000;+        len -= 2;+        len2 -= 3;+        q -= 3;+        q += unicode_to_utf8(q, c);+        s->is_ascii = FALSE;+    }+    memcpy(q, p2->buf + p2->len - len2, len2);+    s->len = len;+    s->is_ascii &= p2->is_ascii;+    return 0;+}++/* 'str' must be a string */+static int string_buffer_concat_utf8(JSContext *ctx, StringBuffer *s, JSValue str,+                                     uint32_t start, uint32_t end)+{+    JSValue val2;+    +    if (end <= start)+        return 0;+    /* XXX: avoid explicitly constructing the substring */+    val2 = js_sub_string_utf8(ctx, str, start, end);+    if (JS_IsException(val2)) {+        s->buffer_ref.val = JS_EXCEPTION;+        return -1;+    }+    return string_buffer_concat_str(ctx, s, val2);+}++static int string_buffer_concat_utf16(JSContext *ctx, StringBuffer *s, JSValue str,+                                      uint32_t start, uint32_t end)+{+    uint32_t start_utf8, end_utf8;+    if (end <= start)+        return 0;+    start_utf8 = js_string_utf16_to_utf8_pos(ctx, str, start);+    end_utf8 = js_string_utf16_to_utf8_pos(ctx, str, end);+    return string_buffer_concat_utf8(ctx, s, str, start_utf8, end_utf8);+}++static int string_buffer_concat(JSContext *ctx, StringBuffer *s, JSValue val2)+{+    val2 = JS_ToString(ctx, val2);+    if (JS_IsException(val2)) {+        s->buffer_ref.val = JS_EXCEPTION;+        return -1;+    }+    return string_buffer_concat_str(ctx, s, val2);+}++/* XXX: could optimize */+static int string_buffer_putc(JSContext *ctx, StringBuffer *s, int c)+{+    return string_buffer_concat_str(ctx, s, JS_NewStringChar(c));+}++static int string_buffer_puts(JSContext *ctx, StringBuffer *s, const char *str)+{+    JSValue val;++    /* XXX: avoid this allocation */+    val = JS_NewString(ctx, str);+    if (JS_IsException(val))+        return -1;+    return string_buffer_concat_str(ctx, s, val);+}++static JSValue string_buffer_pop(JSContext *ctx, StringBuffer *s)+{+    JSValue res;+    if (JS_IsException(s->buffer_ref.val) ||+        JS_IsString(ctx, s->buffer_ref.val)) {+        res = s->buffer_ref.val;+    } else {+        if (s->len != 0) {+            /* add the trailing '\0' */+            JSByteArray *arr = JS_VALUE_TO_PTR(s->buffer_ref.val);+            arr->buf[s->len] = '\0';+        }+        res = js_byte_array_to_string(ctx, s->buffer_ref.val, s->len, s->is_ascii);+    }+    ctx->top_gc_ref = s->buffer_ref.prev;+    return res;+}++/* val1 and val2 must be strings or exception */+static JSValue JS_ConcatString(JSContext *ctx, JSValue val1, JSValue val2)+{+    StringBuffer b_s, *b = &b_s;++    if (JS_IsException(val1) ||+        JS_IsException(val2))+        return JS_EXCEPTION;++    string_buffer_push(ctx, b, 0);+    string_buffer_concat_str(ctx, b, val1); /* no memory allocation */+    string_buffer_concat_str(ctx, b, val2);+    return string_buffer_pop(ctx, b);+}++static BOOL js_string_eq(JSContext *ctx, JSValue val1, JSValue val2)+{+    JSStringCharBuf buf1, buf2;+    JSString *p1, *p2;++    p1 = get_string_ptr(ctx, &buf1, val1);+    p2 = get_string_ptr(ctx, &buf2, val2);+    if (p1->len != p2->len)+        return FALSE;+    return !memcmp(p1->buf, p2->buf, p1->len);+}++/* Return the unicode character containing the byte at position+   'i'. Return -1 in case of error. */+static int string_get_cp(const uint8_t *p)+{+    size_t clen;+    while ((*p & 0xc0) == 0x80)+        p--;+    return utf8_get(p, &clen);+}++static int js_string_compare(JSContext *ctx, JSValue val1, JSValue val2)+{+    JSStringCharBuf buf1, buf2;+    int len, i, res;+    JSString *p1, *p2;+    +    p1 = get_string_ptr(ctx, &buf1, val1);+    p2 = get_string_ptr(ctx, &buf2, val2);+    len = min_int(p1->len, p2->len);+    for(i = 0; i < len; i++) {+        if (p1->buf[i] != p2->buf[i])+            break;+    }+    if (i != len) {+        int c1, c2;+        /* if valid UTF-8, the strings cannot be equal at this point */+        /* Note: UTF-16 does not preserve unicode order like UTF-8 */+        c1 = string_get_cp(p1->buf + i);+        c2 = string_get_cp(p2->buf + i);+        if ((c1 < 0x10000 && c2 < 0x10000) ||+            (c1 >= 0x10000 && c2 >= 0x10000)) {+            if (c1 < c2)+                res = -1;+            else+                res = 1;+        } else if (c1 < 0x10000) {+            /* p1 < p2 if same first UTF-16 char */+            c2 = 0xd800 + ((c2 - 0x10000) >> 10);+            if (c1 <= c2)+                res = -1;+            else+                res = 1;+        } else {+            /* p1 > p2 if same first UTF-16 char */+            c1 = 0xd800 + ((c1 - 0x10000) >> 10);+            if (c1 < c2)+                res = -1;+            else+                res = 1;+        }+    } else {+        if (p1->len == p2->len)+            res = 0;+        else if (p1->len < p2->len)+            res = -1;+        else+            res = 1;+    }+    return res;+}++/* return the string length in UTF16 characters. 'val' must be a+   string char or a string */+static int js_string_len(JSContext *ctx, JSValue val)+{+    if (JS_VALUE_GET_SPECIAL_TAG(val) == JS_TAG_STRING_CHAR) {+        return JS_VALUE_GET_SPECIAL_VALUE(val) >= 0x10000 ? 2 : 1;+    } else {+        JSString *p;+        p = JS_VALUE_TO_PTR(val);+        if (p->is_ascii)+            return p->len;+        else+            return js_string_utf8_to_utf16_pos(ctx, val, p->len * 2);+    }+}++/* return the UTF-16 code or the unicode character at a given UTF-8+   position or -1 if outside the string */+static int string_getcp(JSContext *ctx, JSValue str, uint32_t utf16_pos, BOOL is_codepoint)+{+    JSString *p;+    JSStringCharBuf buf;+    uint32_t surrogate_flag, c, utf8_pos;+    size_t clen;++    utf8_pos = js_string_utf16_to_utf8_pos(ctx, str, utf16_pos);+    surrogate_flag = utf8_pos & 1;+    utf8_pos >>= 1;+    p = get_string_ptr(ctx, &buf, str);+    if (utf8_pos >= p->len)+        return -1;+    c = utf8_get(p->buf + utf8_pos, &clen);+    if (c < 0x10000 || (!surrogate_flag && is_codepoint)) {+        return c;+    } else {+        c -= 0x10000;+        if (!surrogate_flag)+            return 0xd800 + (c >> 10); /* left surrogate */+        else+            return 0xdc00 + (c & 0x3ff); /* right surrogate */+    }+}++static int string_getc(JSContext *ctx, JSValue str, uint32_t utf16_pos)+{+    return string_getcp(ctx, str, utf16_pos, FALSE);+}++/* precondition: 0 <= start <= end <= string length */+static JSValue js_sub_string(JSContext *ctx, JSValue val, int start, int end)+{+    uint32_t start_utf8, end_utf8;+    +    if (end <= start)+        return js_get_atom(ctx, JS_ATOM_empty);+    start_utf8 = js_string_utf16_to_utf8_pos(ctx, val, start);+    end_utf8 = js_string_utf16_to_utf8_pos(ctx, val, end);+    return js_sub_string_utf8(ctx, val, start_utf8, end_utf8);+}++static inline int is_num(int c)+{+    return c >= '0' && c <= '9';+}++/* return TRUE if the property 'val' represents a numeric property. -1+   is returned in case of exception. 'val' must be a string.  It is+   assumed that NaN and infinities have already been handled. */+static int js_is_numeric_string(JSContext *ctx, JSValue val)+{+    int c, len;+    double d;+    const char *r, *q;+    JSString *p;+    JSByteArray *tmp_arr;+    JSGCRef val_ref;+    char buf[32]; /* enough for js_dtoa() */+    +    p = JS_VALUE_TO_PTR(val);+    /* the fast case is when the string is not a number */+    if (p->len == 0 || !p->is_ascii)+        return FALSE;+    q = (const char *)p->buf;+    c = *q;+    if (c == '-') {+        if (p->len == 1)+            return FALSE;+        q++;+        c = *q;+    }+    if (!is_num(c))+        return FALSE;++    JS_PUSH_VALUE(ctx, val);+    tmp_arr = js_alloc_byte_array(ctx, max_int(sizeof(JSATODTempMem),+                                               sizeof(JSDTOATempMem)));+    JS_POP_VALUE(ctx, val);+    if (!tmp_arr)+        return -1;+    p = JS_VALUE_TO_PTR(val);+    d = js_atod((char *)p->buf, &r, 10, 0, (JSATODTempMem *)tmp_arr->buf);+    if ((r - (char *)p->buf) != p->len) {+        js_free(ctx, tmp_arr);+        return FALSE;+    }+    len = js_dtoa(buf, d, 10, 0, JS_DTOA_FORMAT_FREE, (JSDTOATempMem *)tmp_arr->buf);+    js_free(ctx, tmp_arr);+    return (p->len == len && !memcmp(buf, p->buf, len));+}++/* return JS_NULL if not found */+static JSValue find_atom(JSContext *ctx, int *pidx, const JSValueArray *arr, int len, JSValue val)+{+    int a, b, m, r;+    JSValue val1;++    a = 0;+    b = len - 1;+    while (a <= b) {+        m = (a + b) >> 1;+        val1 = arr->arr[m];+        r = js_string_compare(ctx, val, val1);+        if (r == 0) {+            /* found */+            *pidx = m;+            return val1;+        } else if (r < 0) {+            b = m - 1;+        } else {+            a = m + 1;+        }+    }+    *pidx = a;+    return JS_NULL;+}++/* if 'val' is not a string, it is returned */+/* XXX: use hash table */+static JSValue JS_MakeUniqueString(JSContext *ctx, JSValue val)+{+    JSString *p;+    int a, is_numeric, i;+    JSValueArray *arr;+    const JSValueArray *arr1;+    JSValue val1, new_tab;+    JSGCRef val_ref;+    +    if (!JS_IsPtr(val))+        return val;+    p = JS_VALUE_TO_PTR(val);+    if (p->mtag != JS_MTAG_STRING || p->is_unique)+        return val;++    /* not unique: find it in the ROM or RAM sorted unique string table */+    for(i = 0; i < ctx->n_rom_atom_tables; i++) {+        arr1 = ctx->rom_atom_tables[i];+        if (arr1) {+            val1 = find_atom(ctx, &a, arr1, arr1->size, val); +            if (!JS_IsNull(val1))+                return val1;+        }+    }+    +    arr = JS_VALUE_TO_PTR( ctx->unique_strings);+    val1 = find_atom(ctx, &a, arr, ctx->unique_strings_len, val); +    if (!JS_IsNull(val1))+        return val1;+    +    JS_PUSH_VALUE(ctx, val);+    is_numeric = js_is_numeric_string(ctx, val);+    JS_POP_VALUE(ctx, val);+    if (is_numeric < 0)+        return JS_EXCEPTION;+    +    /* not found: add it in the table */+    JS_PUSH_VALUE(ctx, val);+    new_tab = js_resize_value_array(ctx, ctx->unique_strings,+                                 ctx->unique_strings_len + 1);+    JS_POP_VALUE(ctx, val);+    if (JS_IsException(new_tab))+        return JS_EXCEPTION;+    ctx->unique_strings = new_tab;+    arr = JS_VALUE_TO_PTR( ctx->unique_strings);+    memmove(&arr->arr[a + 1], &arr->arr[a],+            sizeof(arr->arr[0]) * (ctx->unique_strings_len - a));+    arr->arr[a] = val;+    p = JS_VALUE_TO_PTR(val);+    p->is_unique = TRUE;+    p->is_numeric = is_numeric;+    ctx->unique_strings_len++;+    return val;+}++static int JS_ToBool(JSContext *ctx, JSValue val)+{+    if (JS_IsInt(val)) {+        return JS_VALUE_GET_INT(val) != 0;+    } else+#ifdef JS_USE_SHORT_FLOAT+    if (JS_IsShortFloat(val)) {+        double d;+        d = js_get_short_float(val);+        return !isnan(d) && d != 0;+    } else+#endif+    if (!JS_IsPtr(val)) {+        switch(JS_VALUE_GET_SPECIAL_TAG(val)) {+        case JS_TAG_BOOL:+        case JS_TAG_NULL:+        case JS_TAG_UNDEFINED:+            return JS_VALUE_GET_SPECIAL_VALUE(val);+        case JS_TAG_SHORT_FUNC:+        case JS_TAG_STRING_CHAR:+            return TRUE;+        default:+            return FALSE;+        }+    } else {+        JSMemBlockHeader *h = JS_VALUE_TO_PTR(val);+        switch(h->mtag) {+        case JS_MTAG_STRING:+            {+                JSString *p = (JSString *)h;+                return p->len != 0;+            }+        case JS_MTAG_FLOAT64:+            {+                JSFloat64 *p = (JSFloat64 *)h;+                return !isnan(p->u.dval) && p->u.dval != 0;+            }+        default:+        case JS_MTAG_OBJECT:+            return TRUE;+        }+    }+}++/* plen can be NULL. No memory allocation is done if 'val' already is+   a string. */+const char *JS_ToCStringLen(JSContext *ctx, size_t *plen, JSValue val,+                            JSCStringBuf *buf)+{+    const char *p;+    int len;++    val = JS_ToString(ctx, val);+    if (JS_IsException(val))+        return NULL;+    if (JS_VALUE_GET_SPECIAL_TAG(val) == JS_TAG_STRING_CHAR) {+        len = get_short_string(buf->buf, val);+        p = (const char *)buf->buf;+    } else {+        JSString *r;+        r = JS_VALUE_TO_PTR(val);+        p = (const char *)r->buf;+        len = r->len;+    }+    if (plen)+        *plen = len;+    return p;+}++const char *JS_ToCString(JSContext *ctx, JSValue val, JSCStringBuf *buf)+{+    return JS_ToCStringLen(ctx, NULL, val, buf);+}++JSValue JS_GetException(JSContext *ctx)+{+    JSValue obj;+    obj = ctx->current_exception;+    ctx->current_exception = JS_UNDEFINED;+    return obj;+}++static JSValue JS_ToStringCheckObject(JSContext *ctx, JSValue val)+{+    if (val == JS_NULL || val == JS_UNDEFINED)+        return JS_ThrowTypeError(ctx, "null or undefined are forbidden");+    return JS_ToString(ctx, val);+}++static JSValue JS_ThrowTypeErrorNotAnObject(JSContext *ctx)+{+    return JS_ThrowTypeError(ctx, "not an object");+}++/* 'val' must be a string. return TRUE if the string represents a+   short integer */+static inline BOOL is_num_string(JSContext *ctx, int32_t *pval, JSValue val)+{+    JSStringCharBuf buf;+    uint32_t n;+    uint64_t n64;+    JSString *p1;+    int c, is_neg;+    const uint8_t *p, *p_end;+    +    p1 = get_string_ptr(ctx, &buf, val);+    if (p1->len == 0 || p1->len > 11 || !p1->is_ascii)+        return FALSE;+    p = p1->buf;+    p_end = p + p1->len;+    c = *p++;+    is_neg = 0;+    if (c == '-') {+        if (p >= p_end)+            return FALSE;+        is_neg = 1;+        c = *p++;+    }+    if (!is_num(c))+        return FALSE;+    if (c == '0') {+        if (p != p_end || is_neg)+            return FALSE;+        n = 0;+    } else {+        n = c - '0';+        while (p < p_end) {+            c = *p++;+            if (!is_num(c))+                return FALSE;+            /* XXX: simplify ? */+            n64 = (uint64_t)n * 10 + (c - '0');+            if (n64 > (JS_SHORTINT_MAX + is_neg))+                return FALSE;+            n = n64;+        }+        if (is_neg)+            n = -n;+    }+    *pval = n;+    return TRUE;+}++/* return TRUE if the property 'val' represent a numeric property. It+   is assumed that the shortint case has been tested before */+static BOOL JS_IsNumericProperty(JSContext *ctx, JSValue val)+{+    JSString *p;+    if (!JS_IsPtr(val))+        return FALSE; /* JS_TAG_STRING_CHAR */+    p = JS_VALUE_TO_PTR(val);+    return p->is_numeric;+}++static JSValueArray *js_alloc_value_array(JSContext *ctx, int init_base, int new_size)+{+    JSValueArray *arr;+    int i;+    +    if (new_size > JS_VALUE_ARRAY_SIZE_MAX) {+        JS_ThrowOutOfMemory(ctx);+        return NULL;+    }+    arr = js_malloc(ctx, sizeof(JSValueArray) + new_size * sizeof(JSValue), JS_MTAG_VALUE_ARRAY);+    if (!arr)+        return NULL;+    arr->size = new_size;+    for(i = init_base; i < new_size; i++)+        arr->arr[i] = JS_UNDEFINED;+    return arr;+}++/* val can be JS_NULL (zero size). 'prop_base' is non zero only when+ * resizing the property arrays so that the property array has a size+ * which is a multiple of 3 */+static JSValue js_resize_value_array2(JSContext *ctx, JSValue val, int new_size, int prop_base)+{+    JSValueArray *slots, *new_slots;+    int old_size, new_size1;+    JSGCRef val_ref;+    +    if (val == JS_NULL) {+        slots = NULL;+        old_size = 0;+    } else {+        slots = JS_VALUE_TO_PTR(val);+        old_size = slots->size;+    }+    if (unlikely(new_size > old_size)) {+        new_size1 = old_size + old_size / 2;+        if (new_size1 > new_size) {+            new_size = new_size1;+            /* ensure that the property array has a size which is a+             * multiple of 3 */+            if (prop_base != 0) {+                int align = (new_size - prop_base) % 3;+                if (align != 0)+                    new_size += 3 - align;+            }+        }+        new_size = max_int(new_size, old_size + old_size / 2);+        JS_PUSH_VALUE(ctx, val);+        new_slots = js_alloc_value_array(ctx, old_size, new_size);+        JS_POP_VALUE(ctx, val);+        if (!new_slots)+            return JS_EXCEPTION;+        if (old_size > 0) {+            slots = JS_VALUE_TO_PTR(val);+            memcpy(new_slots->arr, slots->arr, old_size * sizeof(JSValue));+        }+        val = JS_VALUE_FROM_PTR(new_slots);+    }+    return val;+}++static JSValue js_resize_value_array(JSContext *ctx, JSValue val, int new_size)+{+    return js_resize_value_array2(ctx, val, new_size, 0);+}++/* no allocation is done */+static void js_shrink_value_array(JSContext *ctx, JSValue *pval, int new_size)+{+    JSValueArray *arr;+    if (*pval == JS_NULL)+        return;+    arr = JS_VALUE_TO_PTR(*pval);+    assert(new_size <= arr->size);+    if (new_size == 0) {+        js_free(ctx, arr);+        *pval = JS_NULL;+    } else {+        arr = js_shrink(ctx, arr, sizeof(JSValueArray) + new_size * sizeof(JSValue));+        arr->size = new_size;+    }+}++static JSByteArray *js_alloc_byte_array(JSContext *ctx, int size)+{+    JSByteArray *arr;+    +    if (size > JS_BYTE_ARRAY_SIZE_MAX) {+        JS_ThrowOutOfMemory(ctx);+        return NULL;+    }+    arr = js_malloc(ctx, sizeof(JSByteArray) + size, JS_MTAG_BYTE_ARRAY);+    if (!arr)+        return NULL;+    arr->size = size;+    return arr;+}++static JSValue js_resize_byte_array(JSContext *ctx, JSValue val, int new_size)+{+    JSByteArray *arr, *new_arr;+    int old_size;+    JSGCRef val_ref;+    +    if (val == JS_NULL) {+        arr = NULL;+        old_size = 0;+    } else {+        arr = JS_VALUE_TO_PTR(val);+        old_size = arr->size;+    }+    if (unlikely(new_size > old_size)) {+        new_size = max_int(new_size, old_size + old_size / 2);+        JS_PUSH_VALUE(ctx, val);+        new_arr = js_alloc_byte_array(ctx, new_size);+        JS_POP_VALUE(ctx, val);+        if (!new_arr)+            return JS_EXCEPTION;+        if (old_size > 0) {+            arr = JS_VALUE_TO_PTR(val);+            memcpy(new_arr->buf, arr->buf, old_size);+        }+        val = JS_VALUE_FROM_PTR(new_arr);+    }+    return val;+}++static void js_shrink_byte_array(JSContext *ctx, JSValue *pval, int new_size)+{+    JSByteArray *arr;+    if (*pval == JS_NULL)+        return;+    arr = JS_VALUE_TO_PTR(*pval);+    assert(new_size <= arr->size);+    if (new_size == 0) {+        js_free(ctx, arr);+        *pval = JS_NULL;+    } else {+        arr = js_shrink(ctx, arr, sizeof(JSByteArray) + new_size);+        arr->size = new_size;+    }+}++/* extra_size is in bytes */+static JSObject *JS_NewObjectProtoClass1(JSContext *ctx, JSValue proto, +                                         int class_id, int extra_size)+{+    JSObject *p;+    JSGCRef proto_ref;+    extra_size = (unsigned)(extra_size + JSW - 1) / JSW;+    JS_PUSH_VALUE(ctx, proto);+    p = js_malloc(ctx, offsetof(JSObject, u) + extra_size * JSW,  JS_MTAG_OBJECT);+    JS_POP_VALUE(ctx, proto);+    if (!p)+        return NULL;+    p->class_id = class_id;+    p->extra_size = extra_size;+    p->proto = proto;+    p->props = ctx->empty_props;+    return p;+}++static JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValue proto, int class_id, int extra_size)+{+    JSObject *p;+    p = JS_NewObjectProtoClass1(ctx, proto, class_id, extra_size);+    if (!p)+        return JS_EXCEPTION;+    else+        return JS_VALUE_FROM_PTR(p);+}++static JSValue JS_NewObjectClass(JSContext *ctx, int class_id, int extra_size)+{+    return JS_NewObjectProtoClass(ctx, ctx->class_proto[class_id], class_id, extra_size);+}++JSValue JS_NewObjectClassUser(JSContext *ctx, int class_id)+{+    JSObject *p;+    assert(class_id >= JS_CLASS_USER);+    p = JS_NewObjectProtoClass1(ctx, ctx->class_proto[class_id], class_id,+                                sizeof(JSObjectUserData));+    if (!p)+        return JS_EXCEPTION;+    p->u.user.opaque = NULL;+    return JS_VALUE_FROM_PTR(p);+}++JSValue JS_NewObject(JSContext *ctx)+{+    return JS_NewObjectClass(ctx, JS_CLASS_OBJECT, 0);+}++/* same as JS_NewObject() but preallocate for 'n' properties */+JSValue JS_NewObjectPrealloc(JSContext *ctx, int n)+{+    JSValue obj;+    JSValueArray *arr;+    JSObject *p;+    JSGCRef obj_ref;+    +    obj = JS_NewObjectClass(ctx, JS_CLASS_OBJECT, 0);+    if (JS_IsException(obj) || n <= 0)+        return obj;+    JS_PUSH_VALUE(ctx, obj);+    arr = js_alloc_props(ctx, n);+    JS_POP_VALUE(ctx, obj);+    if (!arr)+        return JS_EXCEPTION;+    p = JS_VALUE_TO_PTR(obj);+    p->props = JS_VALUE_FROM_PTR(arr);+    return obj;+}++JSValue JS_NewArray(JSContext *ctx, int initial_len)+{+    JSObject *p;+    JSValue val;+    JSGCRef val_ref;+    +    val = JS_NewObjectClass(ctx, JS_CLASS_ARRAY, sizeof(JSArrayData));+    if (JS_IsException(val))+        return val;+    p = JS_VALUE_TO_PTR(val);+    p->u.array.tab = JS_NULL;+    p->u.array.len = 0;+    if (initial_len > 0) {+        JSValueArray *arr;+        JS_PUSH_VALUE(ctx, val);+        arr = js_alloc_value_array(ctx, 0, initial_len);+        JS_POP_VALUE(ctx, val);+        if (!arr)+            return JS_EXCEPTION;+        p = JS_VALUE_TO_PTR(val);+        p->u.array.tab = JS_VALUE_FROM_PTR(arr);+        p->u.array.len = initial_len;+    }+    return val;+}++static inline uint32_t hash_prop(JSValue prop)+{+    return (prop / JSW) ^ (prop % JSW); /* XXX: improve */+}++/* return NULL if not found */+static force_inline JSProperty *find_own_property_inlined(JSContext *ctx,+                                                          JSObject *p, JSValue prop)+{+    JSValueArray *arr;+    JSProperty *pr;+    uint32_t hash_mask, h, idx;+    +    arr = JS_VALUE_TO_PTR(p->props);+    hash_mask = JS_VALUE_GET_INT(arr->arr[1]);+    h = hash_prop(prop) & hash_mask;+    idx = arr->arr[2 + h]; /* JSValue, hence idx * 2 */+    while (idx != 0) {+        pr = (JSProperty *)((uint8_t *)arr->arr + idx * (sizeof(JSValue) / 2));+        if (pr->key == prop)+            return pr;+        idx = pr->hash_next; /* JSValue, hence idx * 2 */+    }+    return NULL;+}++static inline JSProperty *find_own_property(JSContext *ctx,+                                            JSObject *p, JSValue prop)+{+    return find_own_property_inlined(ctx, p, prop);+}++static JSValue get_special_prop(JSContext *ctx, JSValue val)+{+    int idx;+    /* 'prototype' or 'constructor' property in ROM */+    idx = JS_VALUE_GET_INT(val);+    if (idx >= 0)+        return ctx->class_proto[idx];+    else+        return ctx->class_obj[-idx - 1];+}++/* return the value or:+   - exception +   - tail call : returned in case of getter and handle_getset =+   true. The function is put on the stack+*/+static JSValue JS_GetPropertyInternal(JSContext *ctx, JSValue obj, JSValue prop,+                                      BOOL allow_tail_call)+{+    JSObject *p;+    JSValue proto;+    JSProperty *pr;++    if (unlikely(!JS_IsPtr(obj))) {+        if (JS_IsIntOrShortFloat(obj)) {+            p = JS_VALUE_TO_PTR(ctx->class_proto[JS_CLASS_NUMBER]);+        } else {+            switch(JS_VALUE_GET_SPECIAL_TAG(obj)) {+            case JS_TAG_BOOL:+                p = JS_VALUE_TO_PTR(ctx->class_proto[JS_CLASS_BOOLEAN]);+                break;+            case JS_TAG_SHORT_FUNC:+                p = JS_VALUE_TO_PTR(ctx->class_proto[JS_CLASS_CLOSURE]);+                break;+            case JS_TAG_STRING_CHAR:+                goto string_proto;+            case JS_TAG_NULL:+                return JS_ThrowTypeError(ctx, "cannot read property '%"JSValue_PRI"' of null", prop);+            case JS_TAG_UNDEFINED:+                return JS_ThrowTypeError(ctx, "cannot read property '%"JSValue_PRI"' of undefined", prop);+            default:+                goto no_prop;+            }+        }+    } else {+        p = JS_VALUE_TO_PTR(obj);+    }+    if (unlikely(p->mtag != JS_MTAG_OBJECT)) {+        switch(p->mtag) {+        case JS_MTAG_FLOAT64:+            p = JS_VALUE_TO_PTR(ctx->class_proto[JS_CLASS_NUMBER]);+            break;+        case JS_MTAG_STRING:+        string_proto:+            {+                if (JS_IsInt(prop)) {+                    JSValue ret;+                    ret = js_string_charAt(ctx, &obj, 1, &prop, magic_internalAt);+                    if (!JS_IsUndefined(ret))+                        return ret;+                }+                p = JS_VALUE_TO_PTR(ctx->class_proto[JS_CLASS_STRING]);+            }+            break;+        default:+        no_prop:+            return JS_ThrowTypeError(ctx, "cannot read property '%"JSValue_PRI"' of value", prop);+        }+    }++    for(;;) {+        if (p->class_id == JS_CLASS_ARRAY) {+            if (JS_IsInt(prop)) {+                uint32_t idx = JS_VALUE_GET_INT(prop);+                if (idx < p->u.array.len) {+                    JSValueArray *arr = JS_VALUE_TO_PTR(p->u.array.tab);+                    return arr->arr[idx];+                }+            } else if (JS_IsNumericProperty(ctx, prop)) {+                return JS_UNDEFINED;+            }+        } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&+                   p->class_id <= JS_CLASS_FLOAT64_ARRAY) {+            if (JS_IsInt(prop)) {+                uint32_t idx = JS_VALUE_GET_INT(prop);+                JSObject *pbuffer;+                JSByteArray *arr;+                if (idx < p->u.typed_array.len) {+                    idx += p->u.typed_array.offset;+                    pbuffer = JS_VALUE_TO_PTR(p->u.typed_array.buffer);+                    arr = JS_VALUE_TO_PTR(pbuffer->u.array_buffer.byte_buffer);+                    switch(p->class_id) {+                    default:+                    case JS_CLASS_UINT8C_ARRAY:+                    case JS_CLASS_UINT8_ARRAY:+                        return JS_NewShortInt(*((uint8_t *)arr->buf + idx));+                    case JS_CLASS_INT8_ARRAY:+                        return JS_NewShortInt(*((int8_t *)arr->buf + idx));+                    case JS_CLASS_INT16_ARRAY:+                        return JS_NewShortInt(*((int16_t *)arr->buf + idx));+                    case JS_CLASS_UINT16_ARRAY:+                        return JS_NewShortInt(*((uint16_t *)arr->buf + idx));+                    case JS_CLASS_INT32_ARRAY:+                        return JS_NewInt32(ctx, *((int32_t *)arr->buf + idx));+                    case JS_CLASS_UINT32_ARRAY:+                        return JS_NewUint32(ctx, *((uint32_t *)arr->buf + idx));+                    case JS_CLASS_FLOAT32_ARRAY:+                        return JS_NewFloat64(ctx, *((float *)arr->buf + idx));+                    case JS_CLASS_FLOAT64_ARRAY:+                        return JS_NewFloat64(ctx, *((double *)arr->buf + idx));+                    }+                }+            } else if (JS_IsNumericProperty(ctx, prop)) {+                return JS_UNDEFINED;+            }+        }++        pr = find_own_property(ctx, p, prop);+        if (pr) {+            if (likely(pr->prop_type == JS_PROP_NORMAL)) {+                return pr->value;+            } else if (pr->prop_type == JS_PROP_VARREF) {+                JSVarRef *pv = JS_VALUE_TO_PTR(pr->value);+                /* always detached */+                return pv->u.value;+            } else if (pr->prop_type == JS_PROP_SPECIAL) {+                return get_special_prop(ctx, pr->value);+            } else {+                JSValueArray *arr = JS_VALUE_TO_PTR(pr->value);+                JSValue getter = arr->arr[0];+                if (getter == JS_UNDEFINED)+                    return JS_UNDEFINED;+                if (allow_tail_call) {+                    /* It is assumed 'this_obj' is on the stack and+                       that the stack has some slack to add one element. */+                    ctx->sp[-1] = ctx->sp[0];+                    ctx->sp[0] = getter;+                    ctx->sp--;+                    return JS_NewTailCall(0);+                } else {+                    JSGCRef getter_ref, obj_ref;+                    int err;+                    JS_PUSH_VALUE(ctx, getter);+                    JS_PUSH_VALUE(ctx, obj);+                    err = JS_StackCheck(ctx, 2);+                    JS_POP_VALUE(ctx, obj);+                    JS_POP_VALUE(ctx, getter);+                    if (err)+                        return JS_EXCEPTION;+                    JS_PushArg(ctx, getter);+                    JS_PushArg(ctx, obj);+                    return JS_Call(ctx, 0);+                }+            }+        }+        /* look in the prototype */+        proto = p->proto;+        if (proto == JS_NULL)+            break;+        p = JS_VALUE_TO_PTR(proto);+    }+    return JS_UNDEFINED;+}++static JSValue JS_GetProperty(JSContext *ctx, JSValue obj, JSValue prop)+{+    return JS_GetPropertyInternal(ctx, obj, prop, FALSE);+}++JSValue JS_GetPropertyStr(JSContext *ctx, JSValue this_obj, const char *str)+{+    JSValue prop;+    JSGCRef this_obj_ref;+    +    JS_PUSH_VALUE(ctx, this_obj);+    prop = JS_NewString(ctx, str);+    if (!JS_IsException(prop)) {+        prop = JS_ToPropertyKey(ctx, prop);+    }+    JS_POP_VALUE(ctx, this_obj);+    if (JS_IsException(prop))+        return prop;+    return JS_GetProperty(ctx, this_obj, prop);+}++JSValue JS_GetPropertyUint32(JSContext *ctx, JSValue obj, uint32_t idx)+{+    if (idx > JS_SHORTINT_MAX)+        return JS_ThrowRangeError(ctx, "invalid array index");+    return JS_GetProperty(ctx, obj, JS_NewInt32(ctx, idx));+}++static BOOL JS_HasProperty(JSContext *ctx, JSValue obj, JSValue prop)+{+    JSObject *p;+    JSProperty *pr;+    +    if (!JS_IsPtr(obj))+        return FALSE;+    p = JS_VALUE_TO_PTR(obj);+    if (p->mtag != JS_MTAG_OBJECT)+        return FALSE;+    for(;;) {+        pr = find_own_property(ctx, p, prop);+        if (pr)+            return TRUE;+        obj = p->proto;+        if (obj == JS_NULL)+            break;+        p = JS_VALUE_TO_PTR(obj);+    }+    return FALSE;+}++static int get_prop_hash_size_log2(int prop_count)+{+    /* XXX: adjust ? */+    if (prop_count <= 1)+        return 0;+    else+        return (32 - clz32(prop_count - 1)) - 1;+}++/* allocate 'n' properties, assuming n >= 1 */+static JSValueArray *js_alloc_props(JSContext *ctx, int n)+{+    int hash_size_log2, hash_mask, size, i, first_free;+    JSValueArray *arr;+    JSProperty *pr;+    +    hash_size_log2 = get_prop_hash_size_log2(n);+    hash_mask = (1 << hash_size_log2) - 1;+    first_free = 2 + hash_mask + 1;+    size = first_free + 3 * n;+    arr = js_alloc_value_array(ctx, 0, size);+    if (!arr)+        return NULL;+    arr->arr[0] = JS_NewShortInt(0); /* no property is allocated yet */+    arr->arr[1] = JS_NewShortInt(hash_mask);+    for(i = 0; i <= hash_mask; i++)+        arr->arr[2 + i] = 0;+    pr = NULL; /* avoid warning */+    for(i = 0; i < n; i++) {+        pr = (JSProperty *)&arr->arr[2 + hash_mask + 1 + 3 * i];+        pr->key = JS_UNINITIALIZED;+    }+    /* last property */+    pr->hash_next = first_free << 1;+    return arr;+}+                          +static void js_rehash_props(JSContext *ctx, JSObject *p, BOOL gc_rehash)+{+    JSValueArray *arr;+    int prop_count, hash_mask, h, idx, i, j;+    JSProperty *pr;++    arr = JS_VALUE_TO_PTR(p->props);+    if (JS_IS_ROM_PTR(ctx, arr))+        return;+    hash_mask = JS_VALUE_GET_INT(arr->arr[1]);+    if (hash_mask == 0 && gc_rehash)+        return; /* no need to rehash if single hash entry */+    prop_count = JS_VALUE_GET_INT(arr->arr[0]);+    for(i = 0; i <= hash_mask; i++) {+        arr->arr[2 + i] = JS_NewShortInt(0);+    }+    for(i = 0, j = 0; j < prop_count; i++) {+        idx = 2 + (hash_mask + 1) + 3 * i;+        pr = (JSProperty *)&arr->arr[idx];+        if (pr->key != JS_UNINITIALIZED) {+            h = hash_prop(pr->key) & hash_mask;+            pr->hash_next = arr->arr[2 + h];+            arr->arr[2 + h] = JS_NewShortInt(idx);+            j++;+        }+    }+}++/* Compact the properties. No memory allocation is done */+static void js_compact_props(JSContext *ctx, JSObject *p)+{+   JSValueArray *arr;+   int prop_count, hash_mask, i, j, hash_size_log2;+   int new_size, new_hash_mask;+   JSProperty *pr, *pr1;+   +   arr = JS_VALUE_TO_PTR(p->props);+   prop_count = JS_VALUE_GET_INT(arr->arr[0]);++   /* no property */+   if (prop_count == 0) {+       if (p->props != ctx->empty_props) {+           //js_free(ctx, p->props);+           p->props = ctx->empty_props;+       }+       return;+   }++   hash_mask = JS_VALUE_GET_INT(arr->arr[1]);+   hash_size_log2 = get_prop_hash_size_log2(prop_count);+   new_hash_mask = min_int(hash_mask, (1 << hash_size_log2) - 1);+   new_size = 2 + new_hash_mask + 1 + 3 * prop_count;+   if (new_size >= arr->size)+       return; /* nothing to do */+   //   printf("compact_props: new_size=%d size=%d hash=%d\n", new_size, arr->size, new_hash_mask);+   +   arr->arr[1] = JS_NewShortInt(new_hash_mask);++   /* move the properties, skipping the deleted ones */+   for(i = 0, j = 0; j < prop_count; i++) {+        pr = (JSProperty *)&arr->arr[2 + (hash_mask + 1) + 3 * i];+        if (pr->key != JS_UNINITIALIZED) {+            pr1 = (JSProperty *)&arr->arr[2 + (new_hash_mask + 1) + 3 * j];+            *pr1 = *pr;+            j++;+        }+   }+   +   js_shrink_value_array(ctx, &p->props, new_size);++   js_rehash_props(ctx, p, FALSE);+}++/* if the existing properties are in ROM, copy them to RAM. Return non zero if error */+static int js_update_props(JSContext *ctx, JSValue obj)+{+    JSObject *p;+    JSValueArray *arr, *arr1;+    JSGCRef obj_ref;+    int i, idx, prop_count, hash_mask;+    JSProperty *pr;+    +    p = JS_VALUE_TO_PTR(obj);+    arr = JS_VALUE_TO_PTR(p->props);+    if (!JS_IS_ROM_PTR(ctx, arr))+        return 0;+    JS_PUSH_VALUE(ctx, obj);+    arr1 = js_alloc_value_array(ctx, 0, arr->size);+    JS_POP_VALUE(ctx, obj);+    if (!arr1)+        return -1;+    /* no rehashing is needed because all the atoms are in ROM */+    memcpy(arr1->arr, arr->arr, arr->size * sizeof(JSValue));+    prop_count = JS_VALUE_GET_INT(arr1->arr[0]);+    hash_mask = JS_VALUE_GET_INT(arr1->arr[1]);+    /* no deleted properties in ROM */+    assert(arr1->size == 2 + (hash_mask + 1) + 3 * prop_count);+    /* convert JS_PROP_SPECIAL properties ("prototype" and "constructor") */+    for(i = 0; i < prop_count; i++) {+        idx = 2 + (hash_mask + 1) + 3 * i;+        pr = (JSProperty *)&arr1->arr[idx];+        if (pr->prop_type == JS_PROP_SPECIAL) {+            pr->value = get_special_prop(ctx, pr->value);+            pr->prop_type = JS_PROP_NORMAL;+        }+    }+    +    p = JS_VALUE_TO_PTR(obj);+    p->props = JS_VALUE_FROM_PTR(arr1);+    return 0;+}++/* compute 'first_free' in a property list */+static int get_first_free(JSValueArray *arr)+{+    JSProperty *pr1;+    int first_free;+    +    pr1 = (JSProperty *)&arr->arr[arr->size - 3];+    if (pr1->key == JS_UNINITIALIZED)+        first_free = pr1->hash_next >> 1;+    else+        first_free = arr->size;+    return first_free;+}++/* It is assumed that the property does not already exists. */+static JSProperty *js_create_property(JSContext *ctx, JSValue obj,+                                      JSValue prop)+{+    JSObject *p;+    JSValueArray *arr;+    int prop_count, hash_mask, new_size, h, first_free, new_hash_mask;+    JSProperty *pr, *pr1;+    JSValue new_props;+    JSGCRef obj_ref, prop_ref;++    p = JS_VALUE_TO_PTR(obj);+    arr = JS_VALUE_TO_PTR(p->props);++    //    JS_DumpValue(ctx, "create", prop);+    prop_count = JS_VALUE_GET_INT(arr->arr[0]);+    hash_mask = JS_VALUE_GET_INT(arr->arr[1]);+    /* extend the array if no space left (this single test is valid+       even if the property list is empty) */+    pr1 = (JSProperty *)&arr->arr[arr->size - 3];+    if (pr1->key != JS_UNINITIALIZED) {+        if (p->props == ctx->empty_props) {+            /* XXX: remove and move empty_props to ROM */+            JS_PUSH_VALUE(ctx, obj);+            JS_PUSH_VALUE(ctx, prop);+            arr = js_alloc_props(ctx, 1);+            JS_POP_VALUE(ctx, prop);+            JS_POP_VALUE(ctx, obj);+            if (!arr)+                return NULL;+            p = JS_VALUE_TO_PTR(obj);+            p->props = JS_VALUE_FROM_PTR(arr);+            first_free = 3;+        } else {+            first_free = arr->size;+            new_size = first_free + 3;+            new_hash_mask = hash_mask;+            if ((prop_count + 1) > 2 * (hash_mask + 1)) {+                /* resize the hash table if too many properties */+                new_hash_mask = 2 * (hash_mask + 1) - 1;+                new_size += new_hash_mask - hash_mask;+            }+            JS_PUSH_VALUE(ctx, obj);+            JS_PUSH_VALUE(ctx, prop);+            //            printf("resize_props: new_size=%d hash=%d %d\n", new_size, new_hash_mask, hash_mask);+            new_props = js_resize_value_array2(ctx, p->props, new_size, 2 + new_hash_mask + 1);+            JS_POP_VALUE(ctx, prop);+            JS_POP_VALUE(ctx, obj);+            if (JS_IsException(new_props))+                return NULL;+            p = JS_VALUE_TO_PTR(obj);+            p->props = new_props;+            arr = JS_VALUE_TO_PTR(p->props);+            if (new_hash_mask != hash_mask) {+                /* rebuild the hash table */+                memmove(&arr->arr[2 + (new_hash_mask + 1)],+                        &arr->arr[2 + (hash_mask + 1)],+                        (first_free - (2 + hash_mask + 1)) * sizeof(JSValue));+                first_free += new_hash_mask - hash_mask;+                hash_mask = new_hash_mask;+                arr->arr[1] = JS_NewShortInt(hash_mask);+                js_rehash_props(ctx, p, FALSE);+            }+        }+        /* ensure the last element is marked as uninitialized to store 'first_free' */+        pr1 = (JSProperty *)&arr->arr[arr->size - 3];+        pr1->key = JS_UNINITIALIZED;+    } else {+        first_free = pr1->hash_next >> 1;+    }++    pr = (JSProperty *)&arr->arr[first_free];+    pr->key = prop;+    pr->value = JS_UNDEFINED;+    pr->prop_type = JS_PROP_NORMAL;+    h = hash_prop(prop) & hash_mask;+    pr->hash_next = arr->arr[2 + h];+    arr->arr[2 + h] = JS_NewShortInt(first_free);+    arr->arr[0] = JS_NewShortInt(prop_count + 1);+    /* update first_free */+    first_free += 3;+    if (first_free < arr->size) {+        pr1 = (JSProperty *)&arr->arr[arr->size - 3];+        pr1->hash_next = first_free << 1;+    }++    return pr;+}++/* don't do property lookup if not present */+#define JS_DEF_PROP_LOOKUP  (1 << 0)+/* return the raw property value */+#define JS_DEF_PROP_RET_VAL (1 << 1)+#define JS_DEF_PROP_HAS_VALUE (1 << 2)+#define JS_DEF_PROP_HAS_GET   (1 << 3)+#define JS_DEF_PROP_HAS_SET   (1 << 4)++/* XXX: handle arrays and typed arrays */+static JSValue JS_DefinePropertyInternal(JSContext *ctx, JSValue obj,+                                         JSValue prop, JSValue val,+                                         JSValue setter, int flags)+{+    JSProperty *pr;+    JSValueArray *arr;+    JSGCRef obj_ref, prop_ref, val_ref, setter_ref;+    int ret, prop_type;+    +    /* move to RAM if needed */+    JS_PUSH_VALUE(ctx, obj);+    JS_PUSH_VALUE(ctx, prop);+    JS_PUSH_VALUE(ctx, val);+    JS_PUSH_VALUE(ctx, setter);+    ret = js_update_props(ctx, obj);+    JS_POP_VALUE(ctx, setter);+    JS_POP_VALUE(ctx, val);+    JS_POP_VALUE(ctx, prop);+    JS_POP_VALUE(ctx, obj);+    if (ret)+        return JS_EXCEPTION;+    +    if (flags & JS_DEF_PROP_LOOKUP) {+        pr = find_own_property(ctx, JS_VALUE_TO_PTR(obj), prop);+        if (pr) {+            if (flags & JS_DEF_PROP_HAS_VALUE) {+                if (pr->prop_type == JS_PROP_NORMAL) {+                    pr->value = val;+                } else if (pr->prop_type == JS_PROP_VARREF) {+                    JSVarRef *pv = JS_VALUE_TO_PTR(pr->value);+                    pv->u.value = val;+                } else {+                    goto error_modify;+                }+            } else if (flags & (JS_DEF_PROP_HAS_GET | JS_DEF_PROP_HAS_SET)) {+                if (pr->prop_type != JS_PROP_GETSET) {+                error_modify:+                    return JS_ThrowTypeError(ctx, "cannot modify getter/setter/value kind");+                }+                arr = JS_VALUE_TO_PTR(pr->value);+                if (unlikely(JS_IS_ROM_PTR(ctx, arr))) {+                    /* move to RAM */+                    JSValueArray *arr2;+                    JS_PUSH_VALUE(ctx, obj);+                    JS_PUSH_VALUE(ctx, prop);+                    JS_PUSH_VALUE(ctx, val);+                    JS_PUSH_VALUE(ctx, setter);+                    arr2 = js_alloc_value_array(ctx, 0, 2);+                    JS_POP_VALUE(ctx, setter);+                    JS_POP_VALUE(ctx, val);+                    JS_POP_VALUE(ctx, prop);+                    JS_POP_VALUE(ctx, obj);+                    if (!arr2)+                        return JS_EXCEPTION;+                    pr = find_own_property(ctx, JS_VALUE_TO_PTR(obj), prop);+                    arr = JS_VALUE_TO_PTR(pr->value);+                    arr2->arr[0] = arr->arr[0];+                    arr2->arr[1] = arr->arr[1];+                    pr->value = JS_VALUE_FROM_PTR(arr2);+                    arr = arr2;+                }+                if (flags & JS_DEF_PROP_HAS_GET)+                    arr->arr[0] = val;+                if (flags & JS_DEF_PROP_HAS_SET)+                    arr->arr[1] = setter;+            }+            goto done;+        }+    }++    if (flags & (JS_DEF_PROP_HAS_GET | JS_DEF_PROP_HAS_SET)) {+        prop_type = JS_PROP_GETSET;+        JS_PUSH_VALUE(ctx, obj);+        JS_PUSH_VALUE(ctx, prop);+        JS_PUSH_VALUE(ctx, val);+        JS_PUSH_VALUE(ctx, setter);+        arr = js_alloc_value_array(ctx, 0, 2);+        JS_POP_VALUE(ctx, setter);+        JS_POP_VALUE(ctx, val);+        JS_POP_VALUE(ctx, prop);+        JS_POP_VALUE(ctx, obj);+        if (!arr)+            return JS_EXCEPTION;+        arr->arr[0] = val;+        arr->arr[1] = setter;+        val = JS_VALUE_FROM_PTR(arr);+    } else if (obj == ctx->global_obj) {+        JSVarRef *pv;+        +        prop_type = JS_PROP_VARREF;+        JS_PUSH_VALUE(ctx, obj);+        JS_PUSH_VALUE(ctx, prop);+        JS_PUSH_VALUE(ctx, val);+        pv = js_malloc(ctx, sizeof(JSVarRef) - sizeof(JSValue), JS_MTAG_VARREF);+        JS_POP_VALUE(ctx, val);+        JS_POP_VALUE(ctx, prop);+        JS_POP_VALUE(ctx, obj);+        if (!pv)+            return JS_EXCEPTION;+        pv->is_detached = TRUE;+        pv->u.value = val;+        val = JS_VALUE_FROM_PTR(pv);+    } else {+        prop_type = JS_PROP_NORMAL;+    }+    JS_PUSH_VALUE(ctx, val);+    pr = js_create_property(ctx, obj, prop);+    JS_POP_VALUE(ctx, val);+    if (!pr)+        return JS_EXCEPTION;+    pr->prop_type = prop_type;+    pr->value = val;+ done:+    if (flags & JS_DEF_PROP_RET_VAL) {+        return pr->value;+    } else {+        return JS_UNDEFINED;+    }+}++static JSValue JS_DefinePropertyValue(JSContext *ctx, JSValue obj,+                                      JSValue prop, JSValue val)+{+    return JS_DefinePropertyInternal(ctx, obj, prop, val, JS_NULL,+                                     JS_DEF_PROP_LOOKUP | JS_DEF_PROP_HAS_VALUE);+}++static JSValue JS_DefinePropertyGetSet(JSContext *ctx, JSValue obj,+                                       JSValue prop, JSValue getter,+                                       JSValue setter, int flags)+{+    return JS_DefinePropertyInternal(ctx, obj, prop, getter, setter,+                                     JS_DEF_PROP_LOOKUP | flags);+}++/* return a JSVarRef or an exception. */+static JSValue add_global_var(JSContext *ctx, JSValue prop, BOOL define_flag)+{+    JSObject *p;+    JSProperty *pr;+    +    p = JS_VALUE_TO_PTR(ctx->global_obj);+    pr = find_own_property(ctx, p, prop);+    if (pr) {+        if (pr->prop_type != JS_PROP_VARREF)+            return JS_ThrowReferenceError(ctx, "global variable '%"JSValue_PRI"' must be a reference", prop);+        if (define_flag) {+            JSVarRef *pv = JS_VALUE_TO_PTR(pr->value);+            /* define the variable if needed */+            if (pv->u.value == JS_UNINITIALIZED)+                pv->u.value = JS_UNDEFINED;+        }+        return pr->value;+    }+    return JS_DefinePropertyInternal(ctx, ctx->global_obj, prop,+                                     define_flag ? JS_UNDEFINED : JS_UNINITIALIZED, JS_NULL,+                                     JS_DEF_PROP_RET_VAL | JS_DEF_PROP_HAS_VALUE);+}++/* return JS_UNDEFINED in the normal case. Otherwise:+   - exception +   - tail call : returned in case of getter and handle_getset =+   true. The function is put on the stack+*/+static JSValue JS_SetPropertyInternal(JSContext *ctx, JSValue this_obj,+                                      JSValue prop, JSValue val,+                                      BOOL allow_tail_call)+{+    JSValue proto;+    JSObject *p;+    JSProperty *pr;+    BOOL is_obj;+    +    if (unlikely(!JS_IsPtr(this_obj))) {+        is_obj = FALSE;+        if (JS_IsIntOrShortFloat(this_obj)) {+            p = JS_VALUE_TO_PTR(ctx->class_proto[JS_CLASS_NUMBER]);+            goto prototype_lookup;+        } else {+            switch(JS_VALUE_GET_SPECIAL_TAG(this_obj)) {+            case JS_TAG_BOOL:+                p = JS_VALUE_TO_PTR(ctx->class_proto[JS_CLASS_BOOLEAN]);+                goto prototype_lookup;+            case JS_TAG_SHORT_FUNC:+                p = JS_VALUE_TO_PTR(ctx->class_proto[JS_CLASS_CLOSURE]);+                goto prototype_lookup;+            case JS_TAG_STRING_CHAR:+                p = JS_VALUE_TO_PTR(ctx->class_proto[JS_CLASS_STRING]);+                goto prototype_lookup;+            case JS_TAG_NULL:+                return JS_ThrowTypeError(ctx, "cannot set property '%"JSValue_PRI"' of null", prop);+            case JS_TAG_UNDEFINED:+                return JS_ThrowTypeError(ctx, "cannot set property '%"JSValue_PRI"' of undefined", prop);+            default:+                goto no_prop;+            }+        }+    } else {+        is_obj = TRUE;+        p = JS_VALUE_TO_PTR(this_obj);+    }+    if (unlikely(p->mtag != JS_MTAG_OBJECT)) {+        is_obj = FALSE;+        switch(p->mtag) {+        case JS_MTAG_FLOAT64:+            p = JS_VALUE_TO_PTR(ctx->class_proto[JS_CLASS_NUMBER]);+            goto prototype_lookup;+        case JS_MTAG_STRING:+            p = JS_VALUE_TO_PTR(ctx->class_proto[JS_CLASS_STRING]);+            goto prototype_lookup;+        default:+        no_prop:+            return JS_ThrowTypeError(ctx, "cannot set property '%"JSValue_PRI"' of value", prop);+        }+    }++    /* search if the property is already present */+    if (p->class_id == JS_CLASS_ARRAY) {+        if (JS_IsInt(prop)) {+            JSValueArray *arr;+            uint32_t idx = JS_VALUE_GET_INT(prop);+            /* not standard: we refuse to add properties to object+               except at the last position */+            if (idx < p->u.array.len) {+                arr = JS_VALUE_TO_PTR(p->u.array.tab);+                arr->arr[idx] = val;+                return JS_UNDEFINED;+            } else if (idx == p->u.array.len) {+                JSValue new_tab;+                JSGCRef this_obj_ref, val_ref;++                JS_PUSH_VALUE(ctx, this_obj);+                JS_PUSH_VALUE(ctx, val);+                new_tab = js_resize_value_array(ctx, p->u.array.tab, idx + 1);+                JS_POP_VALUE(ctx, val);+                JS_POP_VALUE(ctx, this_obj);+                if (JS_IsException(new_tab))+                    return JS_EXCEPTION;+                p = JS_VALUE_TO_PTR(this_obj);+                p->u.array.tab = new_tab;+                arr = JS_VALUE_TO_PTR(p->u.array.tab);+                arr->arr[idx] = val;+                p->u.array.len++;+                return JS_UNDEFINED;+            } else {+                goto invalid_array_subscript;+            }+        } else if (JS_IsNumericProperty(ctx, prop)) {+            goto invalid_array_subscript;+        }+    } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&+               p->class_id <= JS_CLASS_FLOAT64_ARRAY) {+        if (JS_IsInt(prop)) {+            uint32_t idx = JS_VALUE_GET_INT(prop);+            int v, conv_ret;+            double d;+            JSObject *pbuffer;+            JSByteArray *arr;+            JSGCRef val_ref, this_obj_ref;++            JS_PUSH_VALUE(ctx, this_obj);+            JS_PUSH_VALUE(ctx, val);+            switch(p->class_id) {+            case JS_CLASS_UINT8C_ARRAY:+                conv_ret = JS_ToUint8Clamp(ctx, &v, val);+                break;+            case JS_CLASS_FLOAT32_ARRAY:+            case JS_CLASS_FLOAT64_ARRAY:+                conv_ret = JS_ToNumber(ctx, &d, val);+                break;+            default:+                conv_ret = JS_ToInt32(ctx, &v, val);+                break;+            }+            JS_POP_VALUE(ctx, val);+            JS_POP_VALUE(ctx, this_obj);+            if (conv_ret)+                return JS_EXCEPTION;+            +            p = JS_VALUE_TO_PTR(this_obj);+            if (idx >= p->u.typed_array.len)+                goto invalid_array_subscript;+            idx += p->u.typed_array.offset;+            pbuffer = JS_VALUE_TO_PTR(p->u.typed_array.buffer);+            arr = JS_VALUE_TO_PTR(pbuffer->u.array_buffer.byte_buffer);+            switch(p->class_id) {+            default:+            case JS_CLASS_UINT8C_ARRAY:+            case JS_CLASS_INT8_ARRAY:+            case JS_CLASS_UINT8_ARRAY:+                *((uint8_t *)arr->buf + idx) = v;+                break;+            case JS_CLASS_INT16_ARRAY:+            case JS_CLASS_UINT16_ARRAY:+                *((uint16_t *)arr->buf + idx) = v;+                break;+            case JS_CLASS_INT32_ARRAY:+            case JS_CLASS_UINT32_ARRAY:+                *((uint32_t *)arr->buf + idx) = v;+                break;+            case JS_CLASS_FLOAT32_ARRAY:+                *((float *)arr->buf + idx) = d;+                break;+            case JS_CLASS_FLOAT64_ARRAY:+                *((double *)arr->buf + idx) = d;+                break;+            }+            return JS_UNDEFINED;+        } else if (JS_IsNumericProperty(ctx, prop)) {+        invalid_array_subscript:+            return JS_ThrowTypeError(ctx, "invalid array subscript");+        }+    }++ redo:+    pr = find_own_property(ctx, p, prop);+    if (pr) {+        if (likely(pr->prop_type == JS_PROP_NORMAL)) {+            if (unlikely(JS_IS_ROM_PTR(ctx, pr)))+                goto convert_to_ram;+            pr->value = val;+            return JS_UNDEFINED;+        } else if (pr->prop_type == JS_PROP_VARREF) {+            JSVarRef *pv = JS_VALUE_TO_PTR(pr->value);+            /* always detached */+            pv->u.value = val;+            return JS_UNDEFINED;+        } else if (pr->prop_type == JS_PROP_SPECIAL) {+            JSGCRef val_ref, prop_ref, this_obj_ref;+            int err;+        convert_to_ram:+            JS_PUSH_VALUE(ctx, this_obj);+            JS_PUSH_VALUE(ctx, prop);+            JS_PUSH_VALUE(ctx, val);+            err = js_update_props(ctx, this_obj);+            JS_POP_VALUE(ctx, val);+            JS_POP_VALUE(ctx, prop);+            JS_POP_VALUE(ctx, this_obj);+            if (err)+                return JS_EXCEPTION;+            p = JS_VALUE_TO_PTR(this_obj);+            goto redo;+        } else {+            goto getset;+        }+    }++    /* search in the prototype chain (getter/setters) */+    for(;;) {+        proto = p->proto;+        if (proto == JS_NULL)+            break;+        p = JS_VALUE_TO_PTR(proto);+    prototype_lookup:+        pr = find_own_property(ctx, p, prop);+        if (pr) {+            if (unlikely(pr->prop_type == JS_PROP_GETSET)) {+                JSValueArray *arr;+                JSValue setter;+            getset:+                arr = JS_VALUE_TO_PTR(pr->value);+                setter = arr->arr[1];+                if (allow_tail_call) {+                    /* It is assumed "this_obj" already is on the stack+                       and that the stack has some slack to add one+                       element. */+                    ctx->sp[-2] = ctx->sp[0];+                    ctx->sp[-1] = setter;+                    ctx->sp[0] = val;+                    ctx->sp -= 2;+                    return JS_NewTailCall(1 | FRAME_CF_POP_RET);+                } else {+                    JSGCRef val_ref, setter_ref, this_obj_ref;+                    int err;+                    JS_PUSH_VALUE(ctx, val);+                    JS_PUSH_VALUE(ctx, setter);+                    JS_PUSH_VALUE(ctx, this_obj);+                    err = JS_StackCheck(ctx, 3);+                    JS_POP_VALUE(ctx, this_obj);+                    JS_POP_VALUE(ctx, setter);+                    JS_POP_VALUE(ctx, val);+                    if (err)+                        return JS_EXCEPTION;+                    JS_PushArg(ctx, val);+                    JS_PushArg(ctx, setter);+                    JS_PushArg(ctx, this_obj);+                    return JS_Call(ctx, 1);+                }+            } else {+                /* stop prototype chain lookup */+                break;+            }+        }+    }+    +    /* add the property in the object */+    if (!is_obj)+        return JS_ThrowTypeErrorNotAnObject(ctx);+    return JS_DefinePropertyInternal(ctx, this_obj, prop, val, JS_UNDEFINED,+                                     JS_DEF_PROP_HAS_VALUE);+}++JSValue JS_SetPropertyStr(JSContext *ctx, JSValue this_obj,+                          const char *str, JSValue val)+{+    JSValue prop;+    JSGCRef this_obj_ref, val_ref;+    +    JS_PUSH_VALUE(ctx, this_obj);+    JS_PUSH_VALUE(ctx, val);+    prop = JS_NewString(ctx, str);+    if (!JS_IsException(prop)) {+        prop = JS_ToPropertyKey(ctx, prop);+    }+    JS_POP_VALUE(ctx, val);+    JS_POP_VALUE(ctx, this_obj);+    if (JS_IsException(prop))+        return prop;+    return JS_SetPropertyInternal(ctx, this_obj, prop, val, FALSE);+}++JSValue JS_SetPropertyUint32(JSContext *ctx, JSValue this_obj,+                             uint32_t idx, JSValue val)+{+    if (idx > JS_SHORTINT_MAX)+        return JS_ThrowRangeError(ctx, "invalid array index");+    return JS_SetPropertyInternal(ctx, this_obj, JS_NewShortInt(idx), val, FALSE);+}++/* return JS_FALSE, JS_TRUE or JS_EXCEPTION. Return false only if the+   property is not configurable which is never the case here. */+static JSValue JS_DeleteProperty(JSContext *ctx, JSValue this_obj,+                                 JSValue prop)+{+    JSObject *p;+    JSProperty *pr, *pr1;+    JSValueArray *arr;+    int h, idx, hash_mask, last_idx, prop_count, first_free;+    JSGCRef this_obj_ref;+    +    JS_PUSH_VALUE(ctx, this_obj);+    prop = JS_ToPropertyKey(ctx, prop);+    JS_POP_VALUE(ctx, this_obj);+    if (JS_IsException(prop))+        return prop;+    +    /* XXX: check return value */+    if (!JS_IsPtr(this_obj))+        return JS_TRUE;+    p = JS_VALUE_TO_PTR(this_obj);+    if (p->mtag != JS_MTAG_OBJECT)+        return JS_TRUE;++    arr = JS_VALUE_TO_PTR(p->props);+    hash_mask = JS_VALUE_GET_INT(arr->arr[1]);+    h = hash_prop(prop) & hash_mask;+    idx = JS_VALUE_GET_INT(arr->arr[2 + h]);+    last_idx = -1;+    while (idx != 0) {+        pr = (JSProperty *)(arr->arr + idx);+        if (pr->key == prop) {+            if (JS_IS_ROM_PTR(ctx, arr)) {+                JSGCRef this_obj_ref;+                int ret;+                JS_PUSH_VALUE(ctx, this_obj);+                ret = js_update_props(ctx, this_obj);+                JS_POP_VALUE(ctx, this_obj);+                if (ret)+                    return JS_EXCEPTION;+                p = JS_VALUE_TO_PTR(this_obj);+                arr = JS_VALUE_TO_PTR(p->props);+                pr = (JSProperty *)(arr->arr + idx);+            }+            /* found: remove it */+            if (last_idx >= 0) {+                JSProperty *lpr = (JSProperty *)(arr->arr + last_idx);+                lpr->hash_next = pr->hash_next;+            } else {+                arr->arr[2 + h] = pr->hash_next;+            }+            first_free = get_first_free(arr);++            prop_count = JS_VALUE_GET_INT(arr->arr[0]);+            arr->arr[0] = JS_NewShortInt(prop_count - 1);+            pr->prop_type = JS_PROP_NORMAL;+            pr->key = JS_UNINITIALIZED;+            pr->value = JS_UNDEFINED;++            /* update first_free if needed */+            while (first_free > 2 + hash_mask + 1) {+                pr1 = (JSProperty *)&arr->arr[first_free - 3];+                if (pr1->key != JS_UNINITIALIZED)+                    break;+                first_free -= 3;+            }++            /* update first_free */+            if (first_free < arr->size) {+                pr1 = (JSProperty *)&arr->arr[arr->size - 3];+                pr1->hash_next = first_free << 1;+            }++            /* compact the properties if needed */+            if ((2 + hash_mask + 1 + 3 * prop_count) < arr->size / 2)+                js_compact_props(ctx, p);+            return JS_TRUE;+        }+        last_idx = idx;+        idx = pr->hash_next >> 1;+    }+    /* not found */+    return JS_TRUE;+}++static JSValue stdlib_init_class(JSContext *ctx, const JSROMClass *class_def)+{+    JSValue obj, proto, parent_class, parent_proto;+    JSGCRef parent_class_ref;+    JSObject *p;+    int ctor_idx = class_def->ctor_idx;++    if (ctor_idx >= 0) {+        int class_id = ctx->c_function_table[ctor_idx].magic;+        obj = ctx->class_obj[class_id];+        if (!JS_IsNull(obj))+            return obj; /* already defined */++       /* initialize the parent class if necessary */+        if (!JS_IsNull(class_def->parent_class)) {+            JSROMClass *parent_class_def = JS_VALUE_TO_PTR(class_def->parent_class);+            int parent_class_id;+            parent_class = stdlib_init_class(ctx, parent_class_def);+            parent_class_id = ctx->c_function_table[parent_class_def->ctor_idx].magic;+            parent_proto = ctx->class_proto[parent_class_id];+        } else {+            parent_class = JS_NULL;+            parent_proto = ctx->class_proto[JS_CLASS_OBJECT];+        }+        /* initialize the prototype before. It is already defined only+           for Object and Function */+        proto = ctx->class_proto[class_id];+        if (JS_IsNull(proto)) {+            JS_PUSH_VALUE(ctx, parent_class);+            proto = JS_NewObjectProtoClass(ctx, parent_proto, JS_CLASS_OBJECT, 0);+            JS_POP_VALUE(ctx, parent_class);+            ctx->class_proto[class_id] = proto;+        }+        p = JS_VALUE_TO_PTR(proto);+        if (!JS_IsNull(class_def->proto_props))+            p->props = class_def->proto_props;++        if (JS_IsNull(parent_class))+            parent_class = ctx->class_proto[JS_CLASS_CLOSURE];+        obj = js_new_c_function_proto(ctx, ctor_idx, parent_class, FALSE, JS_NULL);+        ctx->class_obj[class_id] = obj;+    } else {+        /* normal object */+        obj = JS_NewObject(ctx);+    }+    p = JS_VALUE_TO_PTR(obj);+    if (!JS_IsNull(class_def->props)) {+        /* set the properties from the ROM. They are copied to RAM+           when modified */+        p->props = class_def->props;+    } +    return obj;+}++static void stdlib_init(JSContext *ctx, const JSValueArray *arr)+{+    JSValue name, val;+    int i;++    for(i = 0; i < arr->size; i += 2) {+        name = arr->arr[i];+        val = arr->arr[i + 1];+        if (JS_IsObject(ctx, val)) {+            val = stdlib_init_class(ctx, JS_VALUE_TO_PTR(val));+        } else if (val == JS_NULL) {+            val = ctx->global_obj;+        }+        JS_DefinePropertyInternal(ctx, ctx->global_obj, name,+                                  val, JS_NULL,+                                  JS_DEF_PROP_HAS_VALUE);+    }+}++static void dummy_write_func(void *opaque, const void *buf, size_t buf_len)+{+    //    fwrite(buf, 1, buf_len, stdout);+}++/* if prepare_compilation is true, the context will be used to compile+   to a binary file. It is not expected to be used in the embedded+   version */+JSContext *JS_NewContext2(void *mem_start, size_t mem_size, const JSSTDLibraryDef *stdlib_def, BOOL prepare_compilation)+{+    JSContext *ctx;+    JSValueArray *arr;+    int i, mem_align;++#ifdef JS_PTR64+    mem_align = 8;+#else+    mem_align = 4;+#endif+    mem_size = mem_size & ~(mem_align - 1);+    assert(mem_size >= 1024);+    assert(((uintptr_t)mem_start & (mem_align - 1)) == 0);++    ctx = mem_start;+    memset(ctx, 0, sizeof(*ctx));+    ctx->class_count = stdlib_def->class_count;+    ctx->class_obj = ctx->class_proto + ctx->class_count;+    ctx->heap_base = (void *)(ctx->class_proto + 2 * ctx->class_count);+    ctx->heap_free = ctx->heap_base;+    ctx->stack_top = mem_start + mem_size;+    ctx->sp = (JSValue *)ctx->stack_top;+    ctx->stack_bottom = ctx->sp;+    ctx->fp = ctx->sp;+    ctx->min_free_size = JS_MIN_FREE_SIZE;+#ifdef DEBUG_GC+    ctx->dummy_block = JS_NULL;+    ctx->unique_strings = JS_NULL;+#endif    +    ctx->random_state = 1;+    ctx->write_func = dummy_write_func;+    for(i = 0; i < JS_STRING_POS_CACHE_SIZE; i++)+        ctx->string_pos_cache[i].str = JS_NULL;++    if (prepare_compilation) {+        int atom_table_len;+        JSValueArray *arr, *arr1;+        uint8_t *ptr;+        +        /* for compilation, no stdlib is needed. Only the atoms+           corresponding to JS_ATOM_x are needed and they are stored+           in RAM. */+        /* copy the atoms to a fixed location at the beginning of the+           heap */+        ctx->atom_table = (JSWord *)ctx->heap_free;+        atom_table_len = stdlib_def->sorted_atoms_offset;+        memcpy(ctx->heap_free, stdlib_def->stdlib_table,+               atom_table_len * sizeof(JSWord));+        ctx->heap_free += atom_table_len * sizeof(JSWord);++        /* allocate the sorted atom table and populate it */+        arr1 = (JSValueArray *)(stdlib_def->stdlib_table + atom_table_len);+        arr = js_alloc_value_array(ctx, 0, arr1->size);+        ctx->unique_strings = JS_VALUE_FROM_PTR(arr);+        for(i = 0; i < arr1->size; i++) {+            ptr = JS_VALUE_TO_PTR(arr1->arr[i]);+            ptr = ptr - (uint8_t *)stdlib_def->stdlib_table ++                (uint8_t *)ctx->atom_table;+            arr->arr[i] = JS_VALUE_FROM_PTR(ptr);+        }+        ctx->unique_strings_len = arr1->size;+    } else {+        ctx->atom_table = stdlib_def->stdlib_table;+        ctx->rom_atom_tables[0] = (JSValueArray *)(stdlib_def->stdlib_table ++                                                   stdlib_def->sorted_atoms_offset);+        ctx->n_rom_atom_tables = 1;+        ctx->c_function_table = stdlib_def->c_function_table;+        ctx->c_finalizer_table = stdlib_def->c_finalizer_table;+        ctx->unique_strings = JS_NULL;+        ctx->unique_strings_len = 0;+    }+    +    +    ctx->current_exception = JS_UNDEFINED;+#ifdef DEBUG_GC+    /* set the dummy block at the start of the memory */+    {+        JSByteArray *barr;+        barr = js_alloc_byte_array(ctx, (min_int(mem_size / 2, 1 << 17)) & ~(JSW - 1));+        ctx->dummy_block = JS_VALUE_FROM_PTR(barr);+    }+#endif++    arr = js_alloc_value_array(ctx, 0, 3);+    arr->arr[0] = JS_NewShortInt(0); /* prop_count */+    arr->arr[1] = JS_NewShortInt(0); /* hash_mark */+    arr->arr[2] = JS_NewShortInt(0); /* hash_table[1] */+    ctx->empty_props = JS_VALUE_FROM_PTR(arr);+    for(i = 0; i < ctx->class_count; i++)+        ctx->class_proto[i] = JS_NULL;+    for(i = 0; i < ctx->class_count; i++)+        ctx->class_obj[i] = JS_NULL;+    /* must be done first so that the prototype of Object.prototype is+       JS_NULL */+    ctx->class_proto[JS_CLASS_OBJECT] = JS_NewObject(ctx); +    /* must be done for proper function init */+    ctx->class_proto[JS_CLASS_CLOSURE] = JS_NewObject(ctx); ++    ctx->global_obj = JS_NewObject(ctx);+    ctx->minus_zero = js_alloc_float64(ctx, -0.0); /* XXX: use a ROM value instead */+        +    if (!prepare_compilation) {+        stdlib_init(ctx, (JSValueArray *)(stdlib_def->stdlib_table + stdlib_def->global_object_offset));+    }+    +    return ctx;+}++JSContext *JS_NewContext(void *mem_start, size_t mem_size, const JSSTDLibraryDef *stdlib_def)+{+    return JS_NewContext2(mem_start, mem_size, stdlib_def, FALSE);+}++void JS_FreeContext(JSContext *ctx)+{+    /* call the user C finalizers */+    uint8_t *ptr;+    int size;+    JSObject *p;+    +    ptr = ctx->heap_base;+    while (ptr < ctx->heap_free) {+        size = get_mblock_size(ptr);+        p = (JSObject *)ptr;+        if (p->mtag == JS_MTAG_OBJECT && p->class_id >= JS_CLASS_USER &&+            ctx->c_finalizer_table[p->class_id - JS_CLASS_USER] != NULL) {+            ctx->c_finalizer_table[p->class_id - JS_CLASS_USER](ctx, p->u.user.opaque);+        }+        ptr += size;+    }+}++void JS_SetContextOpaque(JSContext *ctx, void *opaque)+{+    ctx->opaque = opaque;+}++void JS_SetInterruptHandler(JSContext *ctx, JSInterruptHandler *interrupt_handler)+{+    ctx->interrupt_handler = interrupt_handler;+}++void JS_SetLogFunc(JSContext *ctx, JSWriteFunc *write_func)+{+    ctx->write_func = write_func;+}++void JS_SetRandomSeed(JSContext *ctx, uint64_t seed)+{+    ctx->random_state = seed;+}++JSValue JS_GetGlobalObject(JSContext *ctx)+{+    return ctx->global_obj;+}++static JSValue get_var_ref(JSContext *ctx, JSValue *pfirst_var_ref, JSValue *pval)+{+    JSValue val;+    JSVarRef *p;+    +    val = *pfirst_var_ref;+    for(;;) {+        if (val == JS_NULL)+            break;+        p = JS_VALUE_TO_PTR(val);+        assert(!p->is_detached);+        if (p->u.pvalue == pval)+            return val;+        val = p->u.next;+    }++    p = js_malloc(ctx, sizeof(JSVarRef), JS_MTAG_VARREF);+    if (!p)+        return JS_EXCEPTION;+    p->is_detached = FALSE;+    p->u.pvalue = pval;+    p->u.next = *pfirst_var_ref;+    val = JS_VALUE_FROM_PTR(p);+    *pfirst_var_ref = val;+    return val;+}++#define FRAME_OFFSET_ARG0       4+#define FRAME_OFFSET_FUNC_OBJ   3+#define FRAME_OFFSET_THIS_OBJ   2+#define FRAME_OFFSET_CALL_FLAGS 1+#define FRAME_OFFSET_SAVED_FP   0+#define FRAME_OFFSET_CUR_PC     (-1) /* current pc_offset */+#define FRAME_OFFSET_FIRST_VARREF (-2)+#define FRAME_OFFSET_VAR0      (-3)++/* stack layout:+   +   padded_args (padded_argc - argc)+   args (argc)+   func_obj                   fp[3]+   this_obj                   fp[2]+   call_flags     (int)       fp[1]+   saved_fp (int)             fp[0]+   cur_pc   (int)             fp[-1]+   first_var_ref (val)        fp[-2]+   vars (var_count)+   temp stack          (pointed by sp)+*/++#define SP_TO_VALUE(ctx, fp) JS_NewShortInt((uint8_t *)(fp) - (uint8_t *)ctx)+#define VALUE_TO_SP(ctx, val) (void *)((uint8_t *)ctx + JS_VALUE_GET_INT(val))++/* buf_end points to the end of the buffer (after the final '\0') */+static __js_printf_like(3, 4) void cprintf(char **pp, char *buf_end, const char *fmt, ...)+{+    char *p;+    va_list ap;+    +    p = *pp;+    if ((p + 1) >= buf_end)+        return;+    va_start(ap, fmt);+    js_vsnprintf(p, buf_end - p, fmt, ap);+    va_end(ap);+    p += strlen(p);+    *pp = p;+}++static JSValue reloc_c_func_name(JSContext *ctx, JSValue val)+{+    return val;+}++/* no memory allocation is done */+/* XXX: handle bound functions */+static JSValue js_function_get_length_name1(JSContext *ctx, JSValue *this_val,+                                           int is_name, JSFunctionBytecode **pb)+{+    int short_func_idx;+    const JSCFunctionDef *fd;+    JSValue ret;++    if (!JS_IsPtr(*this_val)) {+        if (JS_VALUE_GET_SPECIAL_TAG(*this_val) != JS_TAG_SHORT_FUNC)+            goto fail;+        short_func_idx = JS_VALUE_GET_SPECIAL_VALUE(*this_val);+        goto short_func;+    } else {+        JSObject *p = JS_VALUE_TO_PTR(*this_val);+        JSFunctionBytecode *b;+        if (p->mtag != JS_MTAG_OBJECT)+            goto fail;+        if (p->class_id == JS_CLASS_CLOSURE) {+            b = JS_VALUE_TO_PTR(p->u.closure.func_bytecode);+            if (is_name) {+                /* XXX: directly set func_name to the empty string ? */+                if (b->func_name == JS_NULL)+                    ret = js_get_atom(ctx, JS_ATOM_empty);+                else+                    ret = b->func_name;+            } else {+                ret = JS_NewShortInt(b->arg_count);+            }+            *pb = b;+            return ret;+        } else if (p->class_id == JS_CLASS_C_FUNCTION) {+            short_func_idx = p->u.cfunc.idx;+        short_func:+            fd = &ctx->c_function_table[short_func_idx];+            if (is_name) {+                ret = reloc_c_func_name(ctx, fd->name);+            } else {+                ret = JS_NewShortInt(fd->arg_count);+            }+            *pb = NULL;+            return ret;+        } else {+        fail:+            *pb = NULL;+            return JS_NULL;+        }+    }+}++static uint32_t get_bit(const uint8_t *buf, uint32_t index)+{+    return (buf[index >> 3] >> (7 - (index & 7))) & 1;+}++static uint32_t get_bits_slow(const uint8_t *buf, uint32_t index, int n)+{+    int i;+    uint32_t val;+    val = 0;+    for(i = 0; i < n; i++)+        val |= get_bit(buf, index + i) << (n - 1 - i);+    return val;+}++static uint32_t get_bits(const uint8_t *buf, uint32_t buf_len,+                         uint32_t index, int n)+{+    uint32_t val, pos;++    pos = index >> 3;+    if (unlikely(n > 25 || (pos + 3) >= buf_len)) {+        /* slow case */+        return get_bits_slow(buf, index, n);+    } else {+        /* fast case */+        val = get_be32(buf + pos);+        return (val >> (32 - (index & 7) - n)) & ((1 << n) - 1);+    }+}++static uint32_t get_ugolomb(const uint8_t *buf, uint32_t buf_len,+                            uint32_t *pindex)+{+    uint32_t index = *pindex;+    int i;+    uint32_t v;+    +    i = 0;+    for(;;) {+        if (get_bit(buf, index++))+            break;+        i++;+        if (i == 32) {+            /* error */+            *pindex = index;+            return 0xffffffff;+        }+    }+    if (i == 0) {+        v = 0;+    } else {+        v = ((1 << i) | get_bits(buf, buf_len, index, i)) - 1;+        index += i;+    }+    *pindex = index;+    //    printf("get_ugolomb: v=%d\n", v);+    return v;+}++static int32_t get_sgolomb(const uint8_t *buf, uint32_t buf_len,+                           uint32_t *pindex)+{+    uint32_t val;+    val = get_ugolomb(buf, buf_len, pindex);+    return (val >> 1) ^ -(val & 1);+}++static int get_pc2line_hoisted_code_len(const uint8_t *buf, size_t buf_len)+{+    size_t i = buf_len;+    int v = 0;+    while (i > 0) {+        i--;+        v = (v << 7) | (buf[i] & 0x7f);+        if ((buf[i] & 0x80) == 0)+            break;+    }+    return v;+}++/* line_num, col_num and index are updated */+static void get_pc2line(int *pline_num, int *pcol_num, const uint8_t *buf,+                        uint32_t buf_len, uint32_t *pindex, BOOL has_column)+{+    int line_delta, line_num, col_num, col_delta;++    line_num = *pline_num;+    col_num = *pcol_num;+    +    line_delta = get_sgolomb(buf, buf_len, pindex);+    line_num += line_delta;+    if (has_column) {+        if (line_delta == 0) {+            col_delta = get_sgolomb(buf, buf_len, pindex);+            col_num += col_delta;+        } else {+            col_num = get_ugolomb(buf, buf_len, pindex) + 1;+        }+    } else {+        col_num = 0;+    }+    *pline_num = line_num;+    *pcol_num = col_num;+}++/* return 0 if line/col number info */+static int find_line_col(int *pcol_num, JSFunctionBytecode *b, uint32_t pc)+{+    JSByteArray *arr, *pc2line;+    int pos, op, line_num, col_num;+    uint32_t pc2line_pos;+    +    if (b->pc2line == JS_NULL)+        goto fail;+    arr = JS_VALUE_TO_PTR(b->byte_code);+    pc2line = JS_VALUE_TO_PTR(b->pc2line);++    /* skip the hoisted code */+    pos = get_pc2line_hoisted_code_len(pc2line->buf, pc2line->size);+    if (pc < pos)+        pc = pos;+    pc2line_pos = 0;+    line_num = 1;+    col_num = 1;+    while (pos < arr->size) {+        get_pc2line(&line_num, &col_num, pc2line->buf, pc2line->size,+                    &pc2line_pos, b->has_column);+        if (pos == pc) {+            *pcol_num = col_num;+            return line_num;+        }+        op = arr->buf[pos];+        pos += opcode_info[op].size;+    }+ fail:+    *pcol_num = 0;+    return 0;+}++static const char *get_func_name(JSContext *ctx, JSValue func_obj,+                                 JSCStringBuf *str_buf, JSFunctionBytecode **pb)+{+    JSValue val;+    val = js_function_get_length_name1(ctx, &func_obj, 1, pb);+    if (JS_IsNull(val))+        return NULL;+    return JS_ToCString(ctx, val, str_buf);+}++static void build_backtrace(JSContext *ctx, JSValue error_obj,+                            const char *filename, int line_num, int col_num, int skip_level)+{+    JSObject *p1;+    char buf[128], *p, *buf_end, *line_start;+    const char *str;+    JSValue *fp, stack_str;+    JSCStringBuf str_buf;+    JSFunctionBytecode *b;+    int level;+    JSGCRef error_obj_ref;+    +    if (!JS_IsError(ctx, error_obj))+        return;+    p = buf;+    buf_end = buf + sizeof(buf);+    p[0] = '\0';+    if (filename) {+        cprintf(&p, buf_end, "    at %s:%d:%d\n", filename, line_num, col_num);+    }+    fp = ctx->fp;+    level = 0;+    while (fp != (JSValue *)ctx->stack_top && level < 10) {+        if (skip_level != 0) {+            skip_level--;+        } else {+            line_start = p;+            str = get_func_name(ctx, fp[FRAME_OFFSET_FUNC_OBJ], &str_buf, &b);+            if (!str)+                str = "<anonymous>";+            cprintf(&p, buf_end, "    at %s", str);+            if (b) {+                int pc, line_num, col_num;+                const char *filename;+                filename = JS_ToCString(ctx, b->filename, &str_buf);+                pc = JS_VALUE_GET_INT(fp[FRAME_OFFSET_CUR_PC]) - 1;+                line_num = find_line_col(&col_num, b, pc);+                cprintf(&p, buf_end, " (%s", filename);+                if (line_num != 0) {+                    cprintf(&p, buf_end, ":%d", line_num);+                    if (col_num != 0)+                        cprintf(&p, buf_end, ":%d", col_num);+                }+                cprintf(&p, buf_end, ")");+            } else {+                cprintf(&p, buf_end, " (native)");+            }+            cprintf(&p, buf_end, "\n");+            /* if truncated line, remove it and stop */+            if ((p + 1) >= buf_end) {+                *line_start = '\0';+                break;+            }+            level++;+        }+        fp = VALUE_TO_SP(ctx, fp[FRAME_OFFSET_SAVED_FP]);+    }++    JS_PUSH_VALUE(ctx, error_obj);+    stack_str = JS_NewString(ctx, buf);+    JS_POP_VALUE(ctx, error_obj);+    p1 = JS_VALUE_TO_PTR(error_obj);+    p1->u.error.stack = stack_str;+}++#define HINT_STRING  0+#define HINT_NUMBER  1+#define HINT_NONE    HINT_NUMBER++static JSValue JS_ToPrimitive(JSContext *ctx, JSValue val, int hint)+{+    int i, atom;+    JSValue method, ret;+    JSGCRef val_ref, method_ref;+    +    if (JS_IsPrimitive(ctx, val))+        return val;+    for(i = 0; i < 2; i++) {+        if ((i ^ hint) == 0) {+            atom = JS_ATOM_toString;+        } else {+            atom = JS_ATOM_valueOf;+        }+        JS_PUSH_VALUE(ctx, val);+        method = JS_GetProperty(ctx, val, js_get_atom(ctx, atom));+        JS_POP_VALUE(ctx, val);+        if (JS_IsException(method))+            return method;+        if (JS_IsFunction(ctx, method)) {+            int err;+            JS_PUSH_VALUE(ctx, method);+            JS_PUSH_VALUE(ctx, val);+            err = JS_StackCheck(ctx, 2);+            JS_POP_VALUE(ctx, val);+            JS_POP_VALUE(ctx, method);+            if (err)+                return JS_EXCEPTION;++            JS_PushArg(ctx, method);+            JS_PushArg(ctx, val);+            JS_PUSH_VALUE(ctx, val);+            ret = JS_Call(ctx, 0);+            JS_POP_VALUE(ctx, val);+            if (JS_IsException(ret))+                return ret;+            if (!JS_IsObject(ctx, ret))+                return ret;+        }+    }+    return JS_ThrowTypeError(ctx, "toPrimitive");+}++/* return a string or an exception */+static JSValue js_dtoa2(JSContext *ctx, double d, int radix, int n_digits, int flags)+{+    int len_max, len;+    JSValue str;+    JSGCRef str_ref;+    JSByteArray *tmp_arr, *p;++    len_max = js_dtoa_max_len(d, radix, n_digits, flags);+    p = js_alloc_byte_array(ctx, len_max + 1);+    if (!p)+        return JS_EXCEPTION;+    /* allocate the temporary buffer */+    str = JS_VALUE_FROM_PTR(p);+    JS_PUSH_VALUE(ctx, str);+    tmp_arr = js_alloc_byte_array(ctx, sizeof(JSDTOATempMem));+    JS_POP_VALUE(ctx, str);+    if (!tmp_arr)+        return JS_EXCEPTION;+    p = JS_VALUE_TO_PTR(str);+    /* Note: tmp_arr->buf is always 32 bit aligned */+    len = js_dtoa((char *)p->buf, d, radix, n_digits, flags, (JSDTOATempMem *)tmp_arr->buf);+    js_free(ctx, tmp_arr);+    return js_byte_array_to_string(ctx, str, len, TRUE);+}+    +JSValue JS_ToString(JSContext *ctx, JSValue val)+{+    char buf[128];+    int atom;+    const char *str;+    + redo:+    if (JS_IsInt(val)) {+        int len;+        len = i32toa(buf, JS_VALUE_GET_INT(val));+        buf[len] = '\0';+        goto ret_buf;+    } else+#ifdef JS_USE_SHORT_FLOAT+    if (JS_IsShortFloat(val)) {+        return js_dtoa2(ctx, js_get_short_float(val), 10, 0, JS_DTOA_FORMAT_FREE);+    } else+#endif+    if (JS_IsPtr(val)) {+        void *ptr = JS_VALUE_TO_PTR(val);+        int mtag = js_get_mtag(ptr);+        switch(mtag) {+        case JS_MTAG_OBJECT:+        to_primitive:+            val = JS_ToPrimitive(ctx, val, HINT_STRING);+            if (JS_IsException(val))+                return val;+            goto redo;+        case JS_MTAG_STRING:+            return val;+        case JS_MTAG_FLOAT64:+            {+                JSFloat64 *p = ptr;+                return js_dtoa2(ctx, p->u.dval, 10, 0, JS_DTOA_FORMAT_FREE);+            }+        default:+            js_snprintf(buf, sizeof(buf), "[mtag %d]", mtag);+            goto ret_buf;+        }+    } else {+        switch(JS_VALUE_GET_SPECIAL_TAG(val)) {+        case JS_TAG_NULL:+            atom = JS_ATOM_null;+            goto ret_atom;+        case JS_TAG_UNDEFINED:+            atom = JS_ATOM_undefined;+            goto ret_atom;+        case JS_TAG_BOOL:+            if (JS_VALUE_GET_SPECIAL_VALUE(val))+                atom = JS_ATOM_true;+            else+                atom = JS_ATOM_false;+        ret_atom:+            return js_get_atom(ctx, atom);+        case JS_TAG_STRING_CHAR:+            return val;+        case JS_TAG_SHORT_FUNC:+            goto to_primitive;+        default:+            str = "?";+            goto ret_str;+        ret_buf:+            str = buf;+        ret_str:+            return JS_NewString(ctx, str);+        }+    }+}++/* return either a unique string or an integer. Strings representing+   a short integer are converted to short integer */+static JSValue JS_ToPropertyKey(JSContext *ctx, JSValue val)+{+    int32_t n;+    if (JS_IsInt(val))+        return val;+    val = JS_ToString(ctx, val);+    if (JS_IsException(val))+        return val;+    if (is_num_string(ctx, &n, val))+        return JS_NewShortInt(n);+    else+        return JS_MakeUniqueString(ctx, val);+}++static int skip_spaces(const char *p1)+{+    const char *p = p1;+    int c;+    for(;;) {+        c = *p;+        if (!((c >= 0x09 && c <= 0x0d) || (c == 0x20)))+            break;+        p++;+    }+    return p - p1;+}++/* JS_ToString() specific behaviors */+#define JS_ATOD_TOSTRING (1 << 8)++/* 'val' must be a string */+static int js_atod1(JSContext *ctx, double *pres, JSValue val,+                    int radix, int flags)+{+    JSString *p;+    JSByteArray *tmp_arr;+    double d;+    JSGCRef val_ref;+    const char *p1;++    if (JS_VALUE_GET_SPECIAL_TAG(val) == JS_TAG_STRING_CHAR) {+        int c = JS_VALUE_GET_SPECIAL_VALUE(val);+        if (c >= '0' && c <= '9') {+            *pres = c - '0';+        } else {+            *pres = NAN;+        }+        return 0;+    }+    +    JS_PUSH_VALUE(ctx, val);+    tmp_arr = js_alloc_byte_array(ctx, sizeof(JSATODTempMem));+    JS_POP_VALUE(ctx, val);+    if (!tmp_arr) {+        *pres = NAN;+        return -1;+    }+    p = JS_VALUE_TO_PTR(val);+    p1 = (char *)p->buf;+    p1 += skip_spaces(p1);+    if ((p1 - (char *)p->buf) == p->len) {+        if (flags & JS_ATOD_TOSTRING)+            d = 0;+        else+            d = NAN;+        goto done;+    }+    d = js_atod(p1, &p1, radix, flags, (JSATODTempMem *)tmp_arr->buf);+    js_free(ctx, tmp_arr);+    if (flags & JS_ATOD_TOSTRING) {+        p1 += skip_spaces(p1);+        if ((p1 - (char *)p->buf) < p->len)+            d = NAN;+    }+ done:+    *pres = d;+    return 0;+}++/* Note: can fail due to memory allocation even if primitive type */+int JS_ToNumber(JSContext *ctx, double *pres, JSValue val)+{+ redo:+    if (JS_IsInt(val)) {+        *pres = (double)JS_VALUE_GET_INT(val);+        return 0;+    } else+#ifdef JS_USE_SHORT_FLOAT+    if (JS_IsShortFloat(val)) {+        *pres = js_get_short_float(val);+        return 0;+    } else+#endif+    if (JS_IsPtr(val)) {+        void *ptr = JS_VALUE_TO_PTR(val);+        switch(js_get_mtag(ptr)) {+        case JS_MTAG_STRING:+            goto atod;+        case JS_MTAG_FLOAT64:+            {+                JSFloat64 *p = ptr;+                *pres = p->u.dval;+                return 0;+            }+        case JS_MTAG_OBJECT:+            val = JS_ToPrimitive(ctx, val, HINT_NUMBER);+            if (JS_IsException(val)) {+                *pres = NAN;+                return -1;+            }+            goto redo;+        default:+            *pres = NAN;+            return 0;+        }+    } else {+        switch(JS_VALUE_GET_SPECIAL_TAG(val)) {+        case JS_TAG_NULL:+        case JS_TAG_BOOL:+            *pres = (double)JS_VALUE_GET_SPECIAL_VALUE(val);+            return 0;+        case JS_TAG_UNDEFINED:+            *pres = NAN;+            return 0;+        case JS_TAG_STRING_CHAR:+        atod:+            return js_atod1(ctx, pres, val, 0,+                            JS_ATOD_ACCEPT_BIN_OCT | JS_ATOD_TOSTRING);+        default:+            *pres = NAN;+            return 0;+        }+    }+}++static int JS_ToInt32Internal(JSContext *ctx, int *pres, JSValue val, BOOL sat_flag)+{+    int32_t ret;+    double d;++    if (JS_IsInt(val)) {+        ret = JS_VALUE_GET_INT(val);+    } else+#ifdef JS_USE_SHORT_FLOAT+    if (JS_IsShortFloat(val)) {+        d = js_get_short_float(val);+        goto handle_float64;+    } else+#endif+    if (JS_IsPtr(val)) {+        uint64_t u;+        int e;++    handle_number:+        if (JS_ToNumber(ctx, &d, val)) {+            *pres = 0;+            return -1;+        }+#ifdef JS_USE_SHORT_FLOAT+    handle_float64:+#endif        +        u = float64_as_uint64(d);+        e = (u >> 52) & 0x7ff;+        if (likely(e <= (1023 + 30))) {+            /* fast case */+            ret = (int32_t)d;+        } else if (!sat_flag) {+            if (e <= (1023 + 30 + 53)) {+                uint64_t v;+                /* remainder modulo 2^32 */+                v = (u & (((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 >> 63)+                    ret = -ret;+            } else {+                ret = 0; /* also handles NaN and +inf */+            }+        } else {+            if (e == 2047 && (u & (((uint64_t)1 << 52) - 1)) != 0) {+                /* nan */+                ret = 0;+            } else {+                /* take the sign into account */+                if (u >> 63)+                    ret = 0x80000000;+                else+                    ret = 0x7fffffff;+            }+        }+    } else {+        switch(JS_VALUE_GET_SPECIAL_TAG(val)) {+        case JS_TAG_BOOL:+        case JS_TAG_NULL:+        case JS_TAG_UNDEFINED:+            ret = JS_VALUE_GET_SPECIAL_VALUE(val);+            break;+        default:+            goto handle_number;+        }+    }+    *pres = ret;+    return 0;+}++int JS_ToInt32(JSContext *ctx, int *pres, JSValue val)+{+    return JS_ToInt32Internal(ctx, pres, val, FALSE);+}++int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValue val)+{+    return JS_ToInt32Internal(ctx, (int *)pres, val, FALSE);+}++int JS_ToInt32Sat(JSContext *ctx, int *pres, JSValue val)+{+    return JS_ToInt32Internal(ctx, pres, val, TRUE);+}++static int JS_ToInt32Clamp(JSContext *ctx, int *pres, JSValue val,+                           int min, int max, int min_offset)+{+    int res = JS_ToInt32Sat(ctx, pres, 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_ToUint8Clamp(JSContext *ctx, int *pres, JSValue val)+{+    int32_t ret;+    double d;++    if (JS_IsInt(val)) {+        ret = JS_VALUE_GET_INT(val);+        if (ret < 0)+            ret = 0;+        else if (ret > 255)+            ret = 255;+    } else+#ifdef JS_USE_SHORT_FLOAT+    if (JS_IsShortFloat(val)) {+        d = js_get_short_float(val);+        goto handle_float64;+    } else+#endif+    if (JS_IsPtr(val)) {+    handle_number:+        if (JS_ToNumber(ctx, &d, val)) {+            *pres = 0;+            return -1;+        }+#ifdef JS_USE_SHORT_FLOAT+    handle_float64:+#endif        +        if (d < 0 || isnan(d))+            ret = 0;+        else if (d > 255)+            ret = 255;+        else+            ret = js_lrint(d);+    } else {+        switch(JS_VALUE_GET_SPECIAL_TAG(val)) {+        case JS_TAG_BOOL:+        case JS_TAG_NULL:+        case JS_TAG_UNDEFINED:+            ret = JS_VALUE_GET_SPECIAL_VALUE(val);+            break;+        default:+            goto handle_number;+        }+    }+    *pres = ret;+    return 0;+}++static int js_get_length32(JSContext *ctx, uint32_t *pres, JSValue obj)+{+    JSValue len_val;+    len_val = JS_GetProperty(ctx, obj, js_get_atom(ctx, JS_ATOM_length));+    if (JS_IsException(len_val)) {+        *pres = 0;+        return -1;+    }+    return JS_ToUint32(ctx, pres, len_val);+}++static no_inline JSValue js_add_slow(JSContext *ctx)+{+    JSValue *op1, *op2;+    +    op1 = &ctx->sp[1];+    op2 = &ctx->sp[0];+    *op1 = JS_ToPrimitive(ctx, *op1, HINT_NONE);+    if (JS_IsException(*op1))+        return JS_EXCEPTION;+    *op2 = JS_ToPrimitive(ctx, *op2, HINT_NONE);+    if (JS_IsException(*op2))+        return JS_EXCEPTION;+    if (JS_IsString(ctx, *op1) || JS_IsString(ctx, *op2)) {+        *op1 = JS_ToString(ctx, *op1);+        if (JS_IsException(*op1))+            return JS_EXCEPTION;+        *op2 = JS_ToString(ctx, *op2);+        if (JS_IsException(*op2))+            return JS_EXCEPTION;+        return JS_ConcatString(ctx, *op1, *op2);+    } else {+        double d1, d2, r;+        /* cannot fail */+        if (JS_ToNumber(ctx, &d1, *op1))+            return JS_EXCEPTION;+        if (JS_ToNumber(ctx, &d2, *op2))+            return JS_EXCEPTION;+        r = d1 + d2;+        return JS_NewFloat64(ctx, r);+    }+}++static no_inline JSValue js_binary_arith_slow(JSContext *ctx, OPCodeEnum op)+{+    double d1, d2, r;++    if (JS_ToNumber(ctx, &d1, ctx->sp[1]))+        return JS_EXCEPTION;++    if (JS_ToNumber(ctx, &d2, ctx->sp[0]))+        return JS_EXCEPTION;+        +    switch(op) {+    case OP_sub:+        r = d1 - d2;+        break;+    case OP_mul:+        r = d1 * d2;+        break;+    case OP_div:+        r = d1 / d2;+        break;+    case OP_mod:+        r = js_fmod(d1, d2);+        break;+    case OP_pow:+        r = js_pow(d1, d2);+        break;+    default:+        abort();+    }+    return JS_NewFloat64(ctx, r);+}++static no_inline JSValue js_unary_arith_slow(JSContext *ctx, OPCodeEnum op)+{+    double d;+    +    if (JS_ToNumber(ctx, &d, ctx->sp[0]))+        return JS_EXCEPTION;++    switch(op) {+    case OP_inc:+        d++;+        break;+    case OP_dec:+        d--;+        break;+    case OP_plus:+        break;+    case OP_neg:+        d = -d;+        break;+    default:+        abort();+    }+    return JS_NewFloat64(ctx, d);+}++/* specific case necessary for correct return value semantics */+static no_inline JSValue js_post_inc_slow(JSContext *ctx, OPCodeEnum op)+{+    JSValue val;+    double d, r;+    +    if (JS_ToNumber(ctx, &d, ctx->sp[0]))+        return JS_EXCEPTION;+    r = d + 2 * (op - OP_post_dec) - 1;+    val = JS_NewFloat64(ctx, d);+    if (JS_IsException(val))+        return val;+    ctx->sp[0] = val;+    return JS_NewFloat64(ctx, r);+}++static no_inline JSValue js_binary_logic_slow(JSContext *ctx, OPCodeEnum op)+{+    uint32_t v1, v2, r;++    if (JS_ToUint32(ctx, &v1, ctx->sp[1]))+        return JS_EXCEPTION;+    if (JS_ToUint32(ctx, &v2, ctx->sp[0]))+        return JS_EXCEPTION;+    switch(op) {+    case OP_shl:+        r = v1 << (v2 & 0x1f);+        break;+    case OP_sar:+        r = (int)v1 >> (v2 & 0x1f);+        break;+    case OP_shr:+        r = v1 >> (v2 & 0x1f);+        return JS_NewUint32(ctx, r);+    case OP_and:+        r = v1 & v2;+        break;+    case OP_or:+        r = v1 | v2;+        break;+    case OP_xor:+        r = v1 ^ v2;+        break;+    default:+        abort();+    }+    return JS_NewInt32(ctx, r);+}++static no_inline JSValue js_not_slow(JSContext *ctx)+{+    uint32_t r;+    +    if (JS_ToUint32(ctx, &r, ctx->sp[0]))+        return JS_EXCEPTION;+    return JS_NewInt32(ctx, ~r);+}++static no_inline JSValue js_relational_slow(JSContext *ctx, OPCodeEnum op)+{+    JSValue *op1, *op2;+    int res;+    double d1, d2;+    +    op1 = &ctx->sp[1];+    op2 = &ctx->sp[0];+    *op1 = JS_ToPrimitive(ctx, *op1, HINT_NUMBER);+    if (JS_IsException(*op1))+        return JS_EXCEPTION;+    *op2 = JS_ToPrimitive(ctx, *op2, HINT_NUMBER);+    if (JS_IsException(*op2))+        return JS_EXCEPTION;+    if (JS_IsString(ctx, *op1) && JS_IsString(ctx, *op2)) {+        res = js_string_compare(ctx, *op1, *op2);+        switch(op) {+        case OP_lt:+            res = (res < 0);+            break;+        case OP_lte:+            res = (res <= 0);+            break;+        case OP_gt:+            res = (res > 0);+            break;+        default:+        case OP_gte:+            res = (res >= 0);+            break;+        }+    } else {+        if (JS_ToNumber(ctx, &d1, *op1))+            return JS_EXCEPTION;+        if (JS_ToNumber(ctx, &d2, *op2))+            return JS_EXCEPTION;+        switch(op) {+        case OP_lt:+            res = (d1 < d2); /* if NaN return false */+            break;+        case OP_lte:+            res = (d1 <= d2); /* if NaN return false */+            break;+        case OP_gt:+            res = (d1 > d2); /* if NaN return false */+            break;+        default:+        case OP_gte:+            res = (d1 >= d2); /* if NaN return false */+            break;+        }+    }+    return JS_NewBool(res);+}++static BOOL js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2)+{+    BOOL res;+    +    if (JS_IsNumber(ctx, op1)) {+        if (!JS_IsNumber(ctx, op2)) {+            res = FALSE;+        } else {+            double d1, d2;+            /* cannot fail */+            JS_ToNumber(ctx, &d1, op1);+            JS_ToNumber(ctx, &d2, op2);+            res = (d1 == d2); /* if NaN return false */+        }+    } else if (JS_IsString(ctx, op1)) {+        if (!JS_IsString(ctx, op2)) {+            res = FALSE;+        } else {+            res = js_string_eq(ctx, op1, op2);+        }+    } else {+        /* special value or object */+        res = (op1 == op2);+    }+    return res;+}++static JSValue js_strict_eq_slow(JSContext *ctx, BOOL is_neq)+{+    BOOL res;+    res = js_strict_eq(ctx, ctx->sp[1], ctx->sp[0]);+    return JS_NewBool(res ^ is_neq);+}++enum {+    /* special tags to simplify the comparison */+    JS_ETAG_NUMBER = JS_TAG_SPECIAL | (8 << 2),+    JS_ETAG_STRING = JS_TAG_SPECIAL | (9 << 2),+    JS_ETAG_OBJECT = JS_TAG_SPECIAL | (10 << 2),+};++static int js_eq_get_type(JSContext *ctx, JSValue val)+{+    if (JS_IsIntOrShortFloat(val)) {+        return JS_ETAG_NUMBER;+    } else if (JS_IsPtr(val)) {+        void *ptr = JS_VALUE_TO_PTR(val);+        switch(js_get_mtag(ptr)) {+        case JS_MTAG_FLOAT64:+            return JS_ETAG_NUMBER;+        case JS_MTAG_STRING:+            return JS_ETAG_STRING;+        default:+        case JS_MTAG_OBJECT:+            return JS_ETAG_OBJECT;+        }+    } else {+        int tag = JS_VALUE_GET_SPECIAL_TAG(val);+        switch(tag) {+        case JS_TAG_STRING_CHAR:+            return JS_ETAG_STRING;+        case JS_TAG_SHORT_FUNC:+            return JS_ETAG_OBJECT;+        default:+            return tag;+        }+    }+}++static no_inline JSValue js_eq_slow(JSContext *ctx, BOOL is_neq)+{+    JSValue op1, op2;+    int tag1, tag2;+    BOOL res;+    + redo:+    op1 = ctx->sp[1];+    op2 = ctx->sp[0];+    tag1 = js_eq_get_type(ctx, op1);+    tag2 = js_eq_get_type(ctx, op2);+    if (tag1 == tag2) {+        res = js_strict_eq(ctx, op1, op2);+    } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) ||+               (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) {+        res = TRUE;+    } else if ((tag1 == JS_ETAG_STRING && tag2 == JS_ETAG_NUMBER) ||+               (tag2 == JS_ETAG_STRING && tag1 == JS_ETAG_NUMBER)) {+        double d1;+        double d2;+        if (JS_ToNumber(ctx, &d1, ctx->sp[1]))+            return JS_EXCEPTION;+        if (JS_ToNumber(ctx, &d2, ctx->sp[0]))+            return JS_EXCEPTION;+        res = (d1 == d2);+    } else if (tag1 == JS_TAG_BOOL) {+        ctx->sp[1] = JS_NewShortInt(JS_VALUE_GET_SPECIAL_VALUE(op1));+        goto redo;+    } else if (tag2 == JS_TAG_BOOL) {+        ctx->sp[0] = JS_NewShortInt(JS_VALUE_GET_SPECIAL_VALUE(op2));+        goto redo;+    } else if (tag1 == JS_ETAG_OBJECT &&+               (tag2 == JS_ETAG_NUMBER || tag2 == JS_ETAG_STRING)) {+        ctx->sp[1] = JS_ToPrimitive(ctx, op1, HINT_NONE);+        if (JS_IsException(ctx->sp[1]))+            return JS_EXCEPTION;+        goto redo;+    } else if (tag2 == JS_ETAG_OBJECT &&+               (tag1 == JS_ETAG_NUMBER || tag1 == JS_ETAG_STRING)) {+        ctx->sp[0] = JS_ToPrimitive(ctx, op2, HINT_NONE);+        if (JS_IsException(ctx->sp[0]))+            return JS_EXCEPTION;+        goto redo;+    } else {+        res = FALSE;+    }+    return JS_NewBool(res ^ is_neq);+}++static JSValue js_operator_in(JSContext *ctx)+{+    JSValue prop;+    int res;++    if (js_eq_get_type(ctx, ctx->sp[0]) != JS_ETAG_OBJECT)+        return JS_ThrowTypeError(ctx, "invalid 'in' operand");+    prop = JS_ToPropertyKey(ctx, ctx->sp[1]);+    if (JS_IsException(prop))+        return prop;+    res = JS_HasProperty(ctx, ctx->sp[0], prop);+    return JS_NewBool(res);+}++static JSValue js_operator_instanceof(JSContext *ctx)+{+    JSValue op1, op2, proto;+    JSObject *p;++    op1 = ctx->sp[1];+    op2 = ctx->sp[0];+    if (!JS_IsFunctionObject(ctx, op2))+        return JS_ThrowTypeError(ctx, "invalid 'instanceof' right operand");+    proto = JS_GetProperty(ctx, op2, js_get_atom(ctx, JS_ATOM_prototype));+    if (JS_IsException(proto))+        return proto;+    if (!JS_IsObject(ctx, op1))+        return JS_NewBool(FALSE);+    p = JS_VALUE_TO_PTR(op1);+    for(;;) {+        if (p->proto == JS_NULL)+            return JS_NewBool(FALSE);+        if (p->proto == proto)+            return JS_NewBool(TRUE);+        p = JS_VALUE_TO_PTR(p->proto);+    }+    return JS_NewBool(FALSE);+}++static JSValue js_operator_typeof(JSContext *ctx, JSValue val)+{+    int tag, atom;+    tag = js_eq_get_type(ctx, val);+    switch(tag) {+    case JS_ETAG_NUMBER:+        atom = JS_ATOM_number;+        break;+    case JS_ETAG_STRING:+        atom = JS_ATOM_string;+        break;+    case JS_TAG_BOOL:+        atom = JS_ATOM_boolean;+        break;+    case JS_ETAG_OBJECT:+        if (JS_IsFunction(ctx, val))+            atom = JS_ATOM_function;+        else+            atom = JS_ATOM_object;+        break;+    case JS_TAG_NULL:+        atom = JS_ATOM_object;+        break;+    default:+    case JS_TAG_UNDEFINED:+        atom = JS_ATOM_undefined;+        break;+    }+    return js_get_atom(ctx, atom);+}++static void js_reverse_val(JSValue *tab, int n)+{+    int i;+    JSValue tmp;+    +    for(i = 0; i < n / 2; i++) {+        tmp = tab[i];+        tab[i] = tab[n - 1 - i];+        tab[n - 1 - i] = tmp;+    }+}+ +static JSValue js_closure(JSContext *ctx, JSValue bfunc, JSValue *fp)+{+    JSFunctionBytecode *b;+    JSObject *p;+    JSGCRef bfunc_ref, closure_ref;+    JSValueArray *ext_vars;+    JSValue closure;+    int ext_vars_len;+    +    b = JS_VALUE_TO_PTR(bfunc);+    if (b->ext_vars != JS_NULL) {+        ext_vars = JS_VALUE_TO_PTR(b->ext_vars);+        ext_vars_len = ext_vars->size / 2;+    } else {+        ext_vars_len = 0;+    }+    +    JS_PUSH_VALUE(ctx, bfunc);+    closure = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_CLOSURE], JS_CLASS_CLOSURE,+                                     sizeof(JSClosureData) + ext_vars_len * sizeof(JSValue));+    JS_POP_VALUE(ctx, bfunc);+    if (JS_IsException(closure))+        return JS_EXCEPTION;+    p = JS_VALUE_TO_PTR(closure);+    p->u.closure.func_bytecode = bfunc;+        +    if (ext_vars_len > 0) {+        JSValue *pfirst_var_ref, val;+        int i, var_idx, var_kind, decl;+        +        /* initialize the var_refs in case of exception */+        memset(p->u.closure.var_refs, 0, sizeof(JSValue) * ext_vars_len);+        if (fp) {+            pfirst_var_ref = &fp[FRAME_OFFSET_FIRST_VARREF];+        } else {+            pfirst_var_ref = NULL; /* not used */+        }+        for(i = 0; i < ext_vars_len; i++) {+            b = JS_VALUE_TO_PTR(bfunc);+            ext_vars = JS_VALUE_TO_PTR(b->ext_vars);+            decl = JS_VALUE_GET_INT(ext_vars->arr[2 * i + 1]);+            var_kind = decl >> 16;+            var_idx = decl & 0xffff;+            JS_PUSH_VALUE(ctx, bfunc);+            JS_PUSH_VALUE(ctx, closure);+            switch(var_kind) {+            case JS_VARREF_KIND_ARG:+                val = get_var_ref(ctx, pfirst_var_ref, +                                  &fp[FRAME_OFFSET_ARG0 + var_idx]);+                break;+            case JS_VARREF_KIND_VAR:+                val = get_var_ref(ctx, pfirst_var_ref,+                                  &fp[FRAME_OFFSET_VAR0 - var_idx]);+                break;+            case JS_VARREF_KIND_VAR_REF:+                {+                    JSObject *p;+                    p = JS_VALUE_TO_PTR(fp[FRAME_OFFSET_FUNC_OBJ]);+                    val = p->u.closure.var_refs[var_idx];+                }+                break;+            case JS_VARREF_KIND_GLOBAL:+                /* only for eval code */+                val = add_global_var(ctx, ext_vars->arr[2 * i], (var_idx != 0));+                break;+            default:+                abort();+            }+            JS_POP_VALUE(ctx, closure);+            JS_POP_VALUE(ctx, bfunc);+            if (JS_IsException(val))+                return val;+            p = JS_VALUE_TO_PTR(closure);+            p->u.closure.var_refs[i] = val;+        }+    }+    return closure;+}++static JSValue js_for_of_start(JSContext *ctx, BOOL is_for_in)+{+    JSValueArray *arr;++    if (is_for_in) {+        /* XXX: not spec compliant and slow. We return only the own+           object keys. */+        ctx->sp[0] = js_object_keys(ctx, NULL, 1, &ctx->sp[0]);+        if (JS_IsException(ctx->sp[0]))+            return JS_EXCEPTION;+    }+    +    if (!js_get_object_class(ctx, ctx->sp[0], JS_CLASS_ARRAY))+        return JS_ThrowTypeError(ctx, "unsupported type in for...of");+    +    arr = js_alloc_value_array(ctx, 0, 2);+    if (!arr)+        return JS_EXCEPTION;+    arr->arr[0] = ctx->sp[0];+    arr->arr[1] = JS_NewShortInt(0);+    return JS_VALUE_FROM_PTR(arr);+}++static JSValue js_for_of_next(JSContext *ctx)+{+    JSValueArray *arr, *arr1;+    JSObject *p;+    int pos;+    +    arr = JS_VALUE_TO_PTR(ctx->sp[0]);+    pos = JS_VALUE_GET_INT(arr->arr[1]);+    p = JS_VALUE_TO_PTR(arr->arr[0]);+    if (pos >= p->u.array.len) {+        ctx->sp[-2] = JS_TRUE;+        ctx->sp[-1] = JS_UNDEFINED;+    } else {+        ctx->sp[-2] = JS_FALSE;+        arr1 = JS_VALUE_TO_PTR(p->u.array.tab);+        ctx->sp[-1] = arr1->arr[pos];+        arr->arr[1] = JS_NewShortInt(pos + 1);+    }+    return JS_UNDEFINED;+}++static JSValue js_new_c_function_proto(JSContext *ctx, int func_idx, JSValue proto, BOOL has_params,+                                       JSValue params)+{+    JSObject *p;+    JSGCRef params_ref;+    +    JS_PUSH_VALUE(ctx, params);+    p = JS_NewObjectProtoClass1(ctx, proto, JS_CLASS_C_FUNCTION,+                                sizeof(JSCFunctionData) - (!has_params ? sizeof(JSValue) : 0));+    JS_POP_VALUE(ctx, params);+    if (!p)+        return JS_EXCEPTION;+    p->u.cfunc.idx = func_idx;+    if (has_params)+        p->u.cfunc.params = params;+    return JS_VALUE_FROM_PTR(p);+}++JSValue JS_NewCFunctionParams(JSContext *ctx, int func_idx, JSValue params)+{+    return js_new_c_function_proto(ctx, func_idx, ctx->class_proto[JS_CLASS_CLOSURE], TRUE, params);+}++static JSValue js_call_constructor_start(JSContext *ctx, JSValue func)+{+    JSValue proto;+    proto = JS_GetProperty(ctx, func, js_get_atom(ctx, JS_ATOM_prototype));+    if (JS_IsException(proto))+        return proto;+    if (!JS_IsObject(ctx, proto))+        proto = ctx->class_proto[JS_CLASS_OBJECT];+    return JS_NewObjectProtoClass(ctx, proto, JS_CLASS_OBJECT, 0);+}++#define SAVE() do { \+        fp[FRAME_OFFSET_CUR_PC] = JS_NewShortInt(pc - ((JSByteArray *)JS_VALUE_TO_PTR(b->byte_code))->buf); \+        ctx->sp = sp; \+        ctx->fp = fp; \+    } while (0)++/* only need to restore PC */+#define RESTORE() do { \+        b = JS_VALUE_TO_PTR(((JSObject *)JS_VALUE_TO_PTR(fp[FRAME_OFFSET_FUNC_OBJ]))->u.closure.func_bytecode); \+        pc = ((JSByteArray *)JS_VALUE_TO_PTR(b->byte_code))->buf + JS_VALUE_GET_INT(fp[FRAME_OFFSET_CUR_PC]); \+    } while (0)++static JSValue __js_poll_interrupt(JSContext *ctx)+{+    ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT;+    if (ctx->interrupt_handler && ctx->interrupt_handler(ctx, ctx->opaque)) {+        JS_ThrowInternalError(ctx, "interrupted");+        ctx->current_exception_is_uncatchable = TRUE;+        return JS_EXCEPTION;+    }+    return JS_UNDEFINED;+}++/* handle user interruption */+#define POLL_INTERRUPT() do {                           \+        if (unlikely(--ctx->interrupt_counter <= 0)) {  \+            SAVE();                                     \+            val = __js_poll_interrupt(ctx);             \+            RESTORE();                                  \+            if (JS_IsException(val))                    \+                goto exception;                         \+        }                                               \+    } while(0)++/* must use JS_StackCheck() before using it */+void JS_PushArg(JSContext *ctx, JSValue val)+{+#ifdef DEBUG_GC+    assert((ctx->sp - 1) >= ctx->stack_bottom);+#endif+    *--ctx->sp = val;+}++/* Usage:+   if (JS_StackCheck(ctx, n + 2)) ...+   JS_PushArg(ctx, arg[n - 1]);+   ...+   JS_PushArg(ctx, arg[0]);+   JS_PushArg(ctx, func);+   JS_PushArg(ctx, this_obj);+   res = JS_Call(ctx, n);+*/+JSValue JS_Call(JSContext *ctx, int call_flags)+{+    JSValue *fp, *sp, val = JS_UNDEFINED, *initial_fp;+    uint8_t *pc;+    /* temporary variables */+    int opcode = OP_invalid, i;+    JSFunctionBytecode *b;+#ifdef JS_USE_SHORT_FLOAT+    double dr;+#endif+    +    if (ctx->js_call_rec_count >= JS_MAX_CALL_RECURSE)+        return JS_ThrowInternalError(ctx, "C stack overflow");+    ctx->js_call_rec_count++;++    sp = ctx->sp;+    fp = ctx->fp;+    initial_fp = fp;+    b = NULL;+    pc = NULL;+    goto function_call;++#define CASE(op)        case op+#define DEFAULT         default+#define BREAK           break+    +    for(;;) {+        opcode = *pc++;+#ifdef DUMP_EXEC+        {+            JSByteArray *arr;+            arr = JS_VALUE_TO_PTR(b->byte_code);+            js_printf(ctx, "    sp=%d\n", (int)(sp - fp));+            js_printf(ctx, "%4d: %s\n", (int)(pc - arr->buf - 1),+                   opcode_info[opcode].name);+        }+#endif+        switch(opcode) {+        CASE(OP_push_minus1):+        CASE(OP_push_0):+        CASE(OP_push_1):+        CASE(OP_push_2):+        CASE(OP_push_3):+        CASE(OP_push_4):+        CASE(OP_push_5):+        CASE(OP_push_6):+        CASE(OP_push_7):+            *--sp = JS_NewShortInt(opcode - OP_push_0);+            BREAK;+        CASE(OP_push_i8):+            *--sp = JS_NewShortInt(get_i8(pc));+            pc += 1;+            BREAK;+        CASE(OP_push_i16):+            *--sp = JS_NewShortInt(get_i16(pc));+            pc += 2;+            BREAK;+        CASE(OP_push_value):+            *--sp = get_u32(pc);+            pc += 4;+            BREAK;+        CASE(OP_push_const):+            {+                JSValueArray *cpool = JS_VALUE_TO_PTR(b->cpool);+                *--sp = cpool->arr[get_u16(pc)];+                pc += 2;+            }+            BREAK;+        CASE(OP_undefined):+            *--sp = JS_UNDEFINED;+            BREAK;+        CASE(OP_null):+            *--sp = JS_NULL;+            BREAK;+        CASE(OP_push_this):+            *--sp = fp[FRAME_OFFSET_THIS_OBJ];+            BREAK;+        CASE(OP_push_false):+            *--sp = JS_FALSE;+            BREAK;+        CASE(OP_push_true):+            *--sp = JS_TRUE;+            BREAK;+        CASE(OP_object):+            {+                int n = get_u16(pc);+                SAVE();+                val = JS_NewObjectPrealloc(ctx, n);+                RESTORE();+                if (JS_IsException(val))+                    goto exception;+                *--sp = val;+                pc += 2;+            }+            BREAK;+        CASE(OP_regexp):+            {+                JSObject *p;+                SAVE();+                val = JS_NewObjectClass(ctx, JS_CLASS_REGEXP, sizeof(JSRegExp));+                RESTORE();+                if (JS_IsException(val))+                    goto exception;+                p = JS_VALUE_TO_PTR(val);+                p->u.regexp.source = sp[1];+                p->u.regexp.byte_code = sp[0];+                p->u.regexp.last_index = 0;+                sp[1] = val;+                sp++;+            }+            BREAK;+        CASE(OP_array_from):+            {+                JSObject *p;+                JSValueArray *arr;+                int i, argc;++                argc = get_u16(pc);+                SAVE();+                val = JS_NewArray(ctx, argc);+                RESTORE();+                if (JS_IsException(val))+                    goto exception;+                pc += 2;+                p = JS_VALUE_TO_PTR(val);+                arr = JS_VALUE_TO_PTR(p->u.array.tab);+                for(i = 0; i < argc; i++) {+                    arr->arr[i] = sp[argc - 1 - i];+                }+                sp += argc;+                *--sp = val;+            }+            BREAK;+        CASE(OP_this_func):+            *--sp = fp[FRAME_OFFSET_FUNC_OBJ];+            BREAK;+        CASE(OP_arguments):+            {+                JSObject *p;+                JSValueArray *arr;+                int i, argc;+                +                argc = JS_VALUE_GET_INT(fp[FRAME_OFFSET_CALL_FLAGS]) & FRAME_CF_ARGC_MASK;+                SAVE();+                val = JS_NewArray(ctx, argc);+                RESTORE();+                if (JS_IsException(val))+                    goto exception;+                p = JS_VALUE_TO_PTR(val);+                arr = JS_VALUE_TO_PTR(p->u.array.tab);+                for(i = 0; i < argc; i++) {+                    arr->arr[i] = fp[FRAME_OFFSET_ARG0 + i];+                }+                *--sp = val;+            }+            BREAK;+        CASE(OP_new_target):+            call_flags = JS_VALUE_GET_INT(fp[FRAME_OFFSET_CALL_FLAGS]);+            if (call_flags & FRAME_CF_CTOR) {+                *--sp = fp[FRAME_OFFSET_FUNC_OBJ];+            } else {+                *--sp = JS_UNDEFINED;+            }+            BREAK;+        CASE(OP_drop):+            sp++;+            BREAK;+        CASE(OP_nip):+            sp[1] = sp[0];+            sp++;+            BREAK;+        CASE(OP_dup):+            sp--;+            sp[0] = sp[1];+            BREAK;+        CASE(OP_dup2):+            sp -= 2;+            sp[0] = sp[2];+            sp[1] = sp[3];+            BREAK;+        CASE(OP_insert2):+            sp[-1] = sp[0];+            sp[0] = sp[1];+            sp[1] = sp[-1];+            sp--;+            BREAK;+        CASE(OP_insert3):+            sp[-1] = sp[0];+            sp[0] = sp[1];+            sp[1] = sp[2];+            sp[2] = sp[-1];+            sp--;+            BREAK;+        CASE(OP_perm3): /* obj a b -> a obj b (213) */+            {+                JSValue tmp;+                tmp = sp[1];+                sp[1] = sp[2];+                sp[2] = tmp;+            }+            BREAK;+        CASE(OP_rot3l): /* x a b -> a b x (231) */+            {+                JSValue tmp;+                tmp = sp[2];+                sp[2] = sp[1];+                sp[1] = sp[0];+                sp[0] = tmp;+            }+            BREAK;+        CASE(OP_perm4): /* obj prop a b -> a obj prop b */+            {+                JSValue tmp;+                tmp = sp[1];+                sp[1] = sp[2];+                sp[2] = sp[3];+                sp[3] = tmp;+            }+            BREAK;+        CASE(OP_swap): /* a b -> b a */+            {+                JSValue tmp;+                tmp = sp[1];+                sp[1] = sp[0];+                sp[0] = tmp;+            }+            BREAK;++        CASE(OP_fclosure):+            {+                int idx;+                JSValueArray *cpool = JS_VALUE_TO_PTR(b->cpool);+                idx = get_u16(pc);+                SAVE();+                val = js_closure(ctx, cpool->arr[idx], fp);+                RESTORE();+                if (unlikely(JS_IsException(val)))+                    goto exception;+                pc += 2;+                *--sp = val;+            }+            BREAK;++        CASE(OP_call_constructor):+            call_flags = get_u16(pc) | FRAME_CF_CTOR;+            goto global_function_call;+        CASE(OP_call):+            call_flags = get_u16(pc);+        global_function_call:+            js_reverse_val(sp, (call_flags & FRAME_CF_ARGC_MASK) + 1);+            *--sp = JS_UNDEFINED;+            goto generic_function_call;+        CASE(OP_call_method):+            {+                int n, argc, short_func_idx;+                JSValue func_obj;+                JSObject *p;+                JSByteArray *byte_code;+                +                call_flags = get_u16(pc);++                n = (call_flags & FRAME_CF_ARGC_MASK) + 2;+                js_reverse_val(sp, n);+                +            generic_function_call:+                POLL_INTERRUPT();+                byte_code = JS_VALUE_TO_PTR(b->byte_code);+                /* save pc + 1 of the current call */+                fp[FRAME_OFFSET_CUR_PC] = JS_NewShortInt(pc - byte_code->buf);+            function_call:+                *--sp = JS_NewShortInt(call_flags);+                *--sp = SP_TO_VALUE(ctx, fp);+                +                func_obj = sp[FRAME_OFFSET_FUNC_OBJ];+#if defined(DUMP_EXEC)+                JS_DumpValue(ctx, "calling", func_obj);+#endif+                if (!JS_IsPtr(func_obj)) {+                    if (JS_VALUE_GET_SPECIAL_TAG(func_obj) != JS_TAG_SHORT_FUNC)+                        goto not_a_function;+                    short_func_idx = JS_VALUE_GET_SPECIAL_VALUE(func_obj);+                    p = NULL;+                    goto c_function;+                } else {+                    p = JS_VALUE_TO_PTR(func_obj);+                    if (p->mtag != JS_MTAG_OBJECT)+                        goto not_a_function;+                    if (p->class_id == JS_CLASS_C_FUNCTION) {+                        const JSCFunctionDef *fd;+                        int pushed_argc;+                        short_func_idx = p->u.cfunc.idx;+                    c_function:+                        fd = &ctx->c_function_table[short_func_idx];+                        /* add undefined arguments if the caller did not+                           provide enough arguments */+                        call_flags = JS_VALUE_GET_INT(sp[FRAME_OFFSET_CALL_FLAGS]);+                        if ((call_flags & FRAME_CF_CTOR) &&+                            (fd->def_type != JS_CFUNC_constructor &&+                             fd->def_type != JS_CFUNC_constructor_magic)) {+                            sp += 2; /* go back to the caller frame */+                            ctx->sp = sp;+                            ctx->fp = fp;+                            val = JS_ThrowTypeError(ctx, "not a constructor");+                            goto call_exception;+                        }++                        argc = call_flags & FRAME_CF_ARGC_MASK;+                        /* JS_StackCheck may trigger a gc */+                        ctx->sp = sp;+                        ctx->fp = fp;+                        n = JS_StackCheck(ctx, max_int(fd->arg_count - argc, 0));+                        if (n) {+                            sp += 2; /* go back to the caller frame */+                            val = JS_EXCEPTION;+                            goto call_exception;+                        }+                        pushed_argc = argc;+                        if (fd->arg_count > argc) {+                            n = fd->arg_count - argc;+                            sp -= n;+                            for(i = 0; i < FRAME_OFFSET_ARG0 + argc; i++)+                                sp[i] = sp[i + n];+                            for(i = 0; i < n; i++)+                                sp[FRAME_OFFSET_ARG0 + argc + i] = JS_UNDEFINED;+                            pushed_argc = fd->arg_count;+                        }+                        fp = sp;+                        ctx->sp = sp;+                        ctx->fp = fp;+                        switch(fd->def_type) {+                        case JS_CFUNC_generic:+                        case JS_CFUNC_constructor:+                            val = fd->func.generic(ctx, &fp[FRAME_OFFSET_THIS_OBJ],+                                                   call_flags & (FRAME_CF_CTOR | FRAME_CF_ARGC_MASK),+                                                   fp + FRAME_OFFSET_ARG0);+                            break;+                        case JS_CFUNC_generic_magic:+                        case JS_CFUNC_constructor_magic:+                            val = fd->func.generic_magic(ctx, &fp[FRAME_OFFSET_THIS_OBJ],+                                                   call_flags & (FRAME_CF_CTOR | FRAME_CF_ARGC_MASK),+                                                   fp + FRAME_OFFSET_ARG0, fd->magic);+                            break;+                        case JS_CFUNC_generic_params:+                            p = JS_VALUE_TO_PTR(fp[FRAME_OFFSET_FUNC_OBJ]);+                            val = fd->func.generic_params(ctx, &fp[FRAME_OFFSET_THIS_OBJ],+                                                          call_flags & (FRAME_CF_CTOR | FRAME_CF_ARGC_MASK),+                                                          fp + FRAME_OFFSET_ARG0, p->u.cfunc.params);+                            break;+                        case JS_CFUNC_f_f:+                            {+                                double d;+                                if (JS_ToNumber(ctx, &d, fp[FRAME_OFFSET_ARG0])) {+                                    val = JS_EXCEPTION;+                                } else {+                                    d = fd->func.f_f(d);+                                }+                                val = JS_NewFloat64(ctx, d);+                            }+                            break;+                        default:+                            assert(0);+                        }+                        if (JS_IsExceptionOrTailCall(val) &&+                            JS_VALUE_GET_SPECIAL_VALUE(val) >= JS_EX_CALL) {+                            JSValue *fp1, *sp1;+                            /* tail call: equivalent to calling the+                               function after the C function */+                            /* XXX: handle the call flags of the caller ? */+                            call_flags = JS_VALUE_GET_SPECIAL_VALUE(val) - JS_EX_CALL;+                            sp = ctx->sp;+                            /* pop the frame */+                            fp1 = VALUE_TO_SP(ctx, fp[FRAME_OFFSET_SAVED_FP]);+                            /* move the new arguments at the correct stack position */+                            argc = (call_flags & FRAME_CF_ARGC_MASK) + 2;+                            sp1 = fp + FRAME_OFFSET_ARG0 + pushed_argc - argc;+                            memmove(sp1, sp, sizeof(*sp) * (argc));+                            sp = sp1;+                            fp = fp1;+                            goto function_call;+                        } else {+                            sp = fp + FRAME_OFFSET_ARG0 + pushed_argc;+                            goto return_call;+                        }+                    } else if (p->class_id == JS_CLASS_CLOSURE) {+                        int n_vars;+                        call_flags = JS_VALUE_GET_INT(sp[FRAME_OFFSET_CALL_FLAGS]);+                        if (call_flags & FRAME_CF_CTOR) {+                            ctx->sp = sp;+                            ctx->fp = fp;+                            /* Note: can recurse at this point */+                            val = js_call_constructor_start(ctx, func_obj);+                            if (JS_IsException(val))+                                goto call_exception;+                            sp[FRAME_OFFSET_THIS_OBJ] = val;+                            func_obj = sp[FRAME_OFFSET_FUNC_OBJ];+                            p = JS_VALUE_TO_PTR(func_obj);+                        }+                        b = JS_VALUE_TO_PTR(p->u.closure.func_bytecode);+                        if (b->vars != JS_NULL) {+                            JSValueArray *vars = JS_VALUE_TO_PTR(b->vars);+                            n_vars = vars->size - b->arg_count;+                        } else {+                            n_vars = 0;+                        }+                        argc = call_flags & FRAME_CF_ARGC_MASK;+                        /* JS_StackCheck may trigger a gc */+                        ctx->sp = sp;+                        ctx->fp = fp;+                        n = JS_StackCheck(ctx, max_int(b->arg_count - argc, 0) + 2 + n_vars ++                                           b->stack_size);+                        if (n) {+                            val = JS_EXCEPTION;+                            goto call_exception;+                        }+                        func_obj = sp[FRAME_OFFSET_FUNC_OBJ];+                        p = JS_VALUE_TO_PTR(func_obj);+                        b = JS_VALUE_TO_PTR(p->u.closure.func_bytecode);+                        /* add undefined arguments if the caller did not+                           provide enough arguments */+                        if (unlikely(b->arg_count > argc)) {+                            n = b->arg_count - argc;+                            sp -= n;+                            for(i = 0; i < FRAME_OFFSET_ARG0 + argc; i++)+                                sp[i] = sp[i + n];+                            for(i = 0; i < n; i++)+                                sp[FRAME_OFFSET_ARG0 + argc + i] = JS_UNDEFINED;+                        }+                        fp = sp;+                        *--sp = JS_NewShortInt(0); /* FRAME_OFFSET_CUR_PC */+                        *--sp = JS_NULL; /* FRAME_OFFSET_FIRST_VARREF */+                        sp -= n_vars;+                        for(i = 0; i < n_vars; i++)+                            sp[i] = JS_UNDEFINED;+                        byte_code = JS_VALUE_TO_PTR(b->byte_code);+                        pc = byte_code->buf;+                    } else {+                    not_a_function:+                        sp += 2; /* go back to the caller frame */+                        ctx->sp = sp;+                        ctx->fp = fp;+                        val = JS_ThrowTypeError(ctx, "not a function");+                    call_exception:+                        if (!pc) {+                            goto done;+                        } else {+                            RESTORE();+                            goto exception;+                        }+                    }+                }+            }+            BREAK;++        exception:+            /* 'val' must contain the exception */+            {+                JSValue *stack_top, val2;+                JSValueArray *vars;+                int v;+                /* exception before entering in the first function ?+                   (XXX: remove this test) */+                if (!pc) +                    goto done;+                v = JS_VALUE_GET_SPECIAL_VALUE(val);+                if (v >= JS_EX_CALL) {+                    /* tail call */+                    call_flags = JS_VALUE_GET_SPECIAL_VALUE(val) - JS_EX_CALL;+                    /* the opcode has only one byte, hence the PC must+                       be updated accordingly after the function+                       returns */+                    if (opcode == OP_get_length ||+                        opcode == OP_get_length2 ||+                        opcode == OP_get_array_el ||+                        opcode == OP_get_array_el2 ||+                        opcode == OP_put_array_el) {+                        call_flags |= FRAME_CF_PC_ADD1;+                    }+                    //                    js_printf(ctx, "tail call: 0x%x\n", call_flags);+                    goto generic_function_call;+                }+                /* XXX: start gc in case of JS_EXCEPTION_MEM */+                stack_top = fp + FRAME_OFFSET_VAR0 + 1;+                if (b->vars != JS_NULL) {+                    vars = JS_VALUE_TO_PTR(b->vars);+                    stack_top -= (vars->size - b->arg_count);+                }+                if (ctx->current_exception_is_uncatchable) {+                    sp = stack_top;+                } else {+                    while (sp < stack_top) {+                        val2 = *sp++;+                        if (JS_VALUE_GET_SPECIAL_TAG(val2) == JS_TAG_CATCH_OFFSET) {+                            JSByteArray *byte_code;+                            /* exception caught by a 'catch' in the+                               current function */+                            *--sp = ctx->current_exception;+                            ctx->current_exception = JS_NULL;+                            byte_code = JS_VALUE_TO_PTR(b->byte_code);+                            pc = byte_code->buf + JS_VALUE_GET_SPECIAL_VALUE(val2);+                            goto restart;+                        }+                    }+                }+            }+            goto generic_return;++        CASE(OP_return_undef):+            val = JS_UNDEFINED;+            goto generic_return;+            +        CASE(OP_return):+            val = sp[0];+        generic_return:+            {+                JSObject *p;+                int argc, pc_offset;+                JSValue val2;+                JSVarRef *pv;+                JSByteArray *byte_code;+                +                /* detach the variable references */+                val2 = fp[FRAME_OFFSET_FIRST_VARREF];+                while (val2 != JS_NULL) {+                    pv = JS_VALUE_TO_PTR(val2);+                    val2 = pv->u.next;+                    assert(!pv->is_detached);+                    pv->u.value = *pv->u.pvalue;+                    pv->is_detached = TRUE;+                    /* shrink 'pv' */+                    set_free_block((uint8_t *)pv + sizeof(JSVarRef) - sizeof(JSValue), sizeof(JSValue));+                }++                call_flags = JS_VALUE_GET_INT(fp[FRAME_OFFSET_CALL_FLAGS]);+                if (unlikely(call_flags & FRAME_CF_CTOR)) {+                    if (!JS_IsException(val) && !JS_IsObject(ctx, val)) {+                        val = fp[FRAME_OFFSET_THIS_OBJ];+                    }+                }+                argc = call_flags & FRAME_CF_ARGC_MASK;+                argc = max_int(argc, b->arg_count);+                sp = fp + FRAME_OFFSET_ARG0 + argc;+        return_call:+                call_flags = JS_VALUE_GET_INT(fp[FRAME_OFFSET_CALL_FLAGS]);+                /* XXX: restore stack_bottom to reduce memory usage */+                fp = VALUE_TO_SP(ctx, fp[FRAME_OFFSET_SAVED_FP]);+                if (fp == initial_fp)+                    goto done;+                pc_offset = JS_VALUE_GET_INT(fp[FRAME_OFFSET_CUR_PC]);+                p = JS_VALUE_TO_PTR(fp[FRAME_OFFSET_FUNC_OBJ]);+                b = JS_VALUE_TO_PTR(p->u.closure.func_bytecode);+                byte_code = JS_VALUE_TO_PTR(b->byte_code);+                pc = byte_code->buf + pc_offset;+                /* now we are in the calling function */+                if (JS_IsException(val))+                    goto exception;+                if (!(call_flags & FRAME_CF_POP_RET))+                    *--sp = val;+                /* Note: if variable size call, can add a flag in call_flags */+                if (!(call_flags & FRAME_CF_PC_ADD1))+                    pc += 2; /* skip the call arg or get_field/put_field arg */+            }+            BREAK;+                +       CASE(OP_catch):+            {+                int32_t diff;+                JSByteArray *byte_code = JS_VALUE_TO_PTR(b->byte_code);+                diff = get_u32(pc);+                *--sp = JS_VALUE_MAKE_SPECIAL(JS_TAG_CATCH_OFFSET, pc + diff - byte_code->buf);+                pc += 4;+            }+            BREAK;+        CASE(OP_throw):+            val = *sp++;+            SAVE();+            val = JS_Throw(ctx, val);+            RESTORE();+            goto exception;+        CASE(OP_gosub):+            {+                int32_t diff;+                JSByteArray *byte_code = JS_VALUE_TO_PTR(b->byte_code);+                diff = get_u32(pc);+                *--sp = JS_NewShortInt(pc + 4 - byte_code->buf);+                pc += diff;+            }+            BREAK;+        CASE(OP_ret):+            {+                JSByteArray *byte_code = JS_VALUE_TO_PTR(b->byte_code);+                uint32_t pos;+                if (unlikely(!JS_IsInt(sp[0])))+                    goto ret_fail;+                pos = JS_VALUE_GET_INT(sp[0]);+                if (unlikely(pos >= byte_code->size)) {+                ret_fail:+                    SAVE();+                    val = JS_ThrowInternalError(ctx, "invalid ret value");+                    RESTORE();+                    goto exception;+                }+                sp++;+                pc = byte_code->buf + pos;+            }+            BREAK;++        CASE(OP_get_loc):+            {+                int idx;+                idx = get_u16(pc);+                pc += 2;+                *--sp = fp[FRAME_OFFSET_VAR0 - idx];+            }+            BREAK;+        CASE(OP_put_loc):+            {+                int idx;+                idx = get_u16(pc);+                pc += 2;+                fp[FRAME_OFFSET_VAR0 - idx] = sp[0];+                sp++;+            }+            BREAK;+        CASE(OP_get_arg):+            {+                int idx;+                idx = get_u16(pc);+                pc += 2;+                *--sp = fp[FRAME_OFFSET_ARG0 + idx];+            }+            BREAK;+        CASE(OP_put_arg):+            {+                int idx;+                idx = get_u16(pc);+                pc += 2;+                fp[FRAME_OFFSET_ARG0 + idx] = sp[0];+                sp++;+            }+            BREAK;+            +        CASE(OP_get_loc0): *--sp = fp[FRAME_OFFSET_VAR0 - 0]; BREAK;+        CASE(OP_get_loc1): *--sp = fp[FRAME_OFFSET_VAR0 - 1]; BREAK;+        CASE(OP_get_loc2): *--sp = fp[FRAME_OFFSET_VAR0 - 2]; BREAK;+        CASE(OP_get_loc3): *--sp = fp[FRAME_OFFSET_VAR0 - 3]; BREAK;+        CASE(OP_get_loc8): *--sp = fp[FRAME_OFFSET_VAR0 - *pc++]; BREAK;+            +        CASE(OP_put_loc0): fp[FRAME_OFFSET_VAR0 - 0] = *sp++; BREAK;+        CASE(OP_put_loc1): fp[FRAME_OFFSET_VAR0 - 1] = *sp++; BREAK;+        CASE(OP_put_loc2): fp[FRAME_OFFSET_VAR0 - 2] = *sp++; BREAK;+        CASE(OP_put_loc3): fp[FRAME_OFFSET_VAR0 - 3] = *sp++; BREAK;+        CASE(OP_put_loc8): fp[FRAME_OFFSET_VAR0 - *pc++] = *sp++; BREAK;++        CASE(OP_get_arg0): *--sp = fp[FRAME_OFFSET_ARG0 + 0]; BREAK;+        CASE(OP_get_arg1): *--sp = fp[FRAME_OFFSET_ARG0 + 1]; BREAK;+        CASE(OP_get_arg2): *--sp = fp[FRAME_OFFSET_ARG0 + 2]; BREAK;+        CASE(OP_get_arg3): *--sp = fp[FRAME_OFFSET_ARG0 + 3]; BREAK;++        CASE(OP_put_arg0): fp[FRAME_OFFSET_ARG0 + 0] = *sp++; BREAK;+        CASE(OP_put_arg1): fp[FRAME_OFFSET_ARG0 + 1] = *sp++; BREAK;+        CASE(OP_put_arg2): fp[FRAME_OFFSET_ARG0 + 2] = *sp++; BREAK;+        CASE(OP_put_arg3): fp[FRAME_OFFSET_ARG0 + 3] = *sp++; BREAK;+            +        CASE(OP_get_var_ref):+        CASE(OP_get_var_ref_nocheck):+            {+                int idx;+                JSObject *p;+                JSVarRef *pv;+                idx = get_u16(pc);+                p = JS_VALUE_TO_PTR(fp[FRAME_OFFSET_FUNC_OBJ]);+                pv = JS_VALUE_TO_PTR(p->u.closure.var_refs[idx]);+                if (pv->is_detached)+                    val = pv->u.value;+                else+                    val = *pv->u.pvalue;+                if (unlikely(val == JS_TAG_UNINITIALIZED) &&+                    opcode == OP_get_var_ref) {+                    JSValueArray *ext_vars = JS_VALUE_TO_PTR(b->ext_vars);+                    SAVE();+                    val = JS_ThrowReferenceError(ctx, "variable '%"JSValue_PRI"' is not defined", ext_vars->arr[2 * idx]);+                    RESTORE();+                    goto exception;+                }+                pc += 2;+                *--sp = val;+            }+            BREAK;+        CASE(OP_put_var_ref):+        CASE(OP_put_var_ref_nocheck):+            {+                int idx;+                JSObject *p;+                JSVarRef *pv;+                JSValue *pval;+                idx = get_u16(pc);+                p = JS_VALUE_TO_PTR(fp[FRAME_OFFSET_FUNC_OBJ]);+                pv = JS_VALUE_TO_PTR(p->u.closure.var_refs[idx]);+                if (pv->is_detached)+                    pval = &pv->u.value;+                else+                    pval = pv->u.pvalue;+                if (unlikely(*pval == JS_TAG_UNINITIALIZED) &&+                    opcode == OP_put_var_ref) {+                    JSValueArray *ext_vars = JS_VALUE_TO_PTR(b->ext_vars);+                    SAVE();+                    val = JS_ThrowReferenceError(ctx, "variable '%"JSValue_PRI"' is not defined", ext_vars->arr[2 * idx]);+                    RESTORE();+                    goto exception;+                }+                *pval = *sp++;+                pc += 2;+            }+            BREAK;++        CASE(OP_goto):+            pc += (int32_t)get_u32(pc);+            POLL_INTERRUPT();+            BREAK;+        CASE(OP_if_false):+        CASE(OP_if_true):+            {+                int res;++                pc += 4;++                res = JS_ToBool(ctx, *sp++);+                if (res ^ (OP_if_true - opcode)) {+                    pc += (int32_t)get_u32(pc - 4) - 4;+                }+                POLL_INTERRUPT();+            }+            BREAK;++        CASE(OP_lnot):+            {+                int res;+                res = JS_ToBool(ctx, sp[0]);+                sp[0] = JS_NewBool(!res);+            }+            BREAK;+            +        CASE(OP_get_field2):+            sp--;+            sp[0] = sp[1];+            goto get_field_common;+        CASE(OP_get_field):+        get_field_common:+            {+                int idx;+                JSValue prop, obj;+                JSValueArray *cpool = JS_VALUE_TO_PTR(b->cpool);+                idx = get_u16(pc);+                prop = cpool->arr[idx];+                obj = sp[0];+                if (likely(JS_IsPtr(obj))) {+                    /* fast case */+                    JSObject *p = JS_VALUE_TO_PTR(obj);+                    JSProperty *pr;+                    if (unlikely(p->mtag != JS_MTAG_OBJECT))+                        goto get_field_slow;+                    for(;;) {+                        /* no array check is necessary because 'prop' is+                           guaranteed not to be a numeric property */+                        /* XXX: slow due to short ints */+                        pr = find_own_property_inlined(ctx, p, prop);+                        if (pr) {+                            if (unlikely(pr->prop_type != JS_PROP_NORMAL)) {+                                /* sp[0] is this_obj, obj is the current+                                   object */+                                goto get_field_slow;+                            } else {+                                val = pr->value;+                                break;+                            }+                        }+                        obj = p->proto;+                        if (obj == JS_NULL) {+                            val = JS_UNDEFINED;+                            break;+                        }+                        p = JS_VALUE_TO_PTR(obj);+                    }+                } else {+                get_field_slow:+                    SAVE();+                    val = JS_GetPropertyInternal(ctx, obj, prop, TRUE);+                    RESTORE();+                    if (unlikely(JS_IsExceptionOrTailCall(val))) {+                        sp = ctx->sp;+                        goto exception;+                    }+                }+                pc += 2;+                sp[0] = val;+            }+            BREAK;++        CASE(OP_get_length2):+            sp--;+            sp[0] = sp[1];+            goto get_length_common;+            +        CASE(OP_get_length):+        get_length_common:+            {+                JSValue obj;+                obj = sp[0];+                if (likely(JS_IsPtr(obj))) {+                    /* fast case */+                    JSObject *p = JS_VALUE_TO_PTR(obj);+                    if (p->mtag == JS_MTAG_OBJECT) {+                        if (p->class_id == JS_CLASS_ARRAY) {+                            if (unlikely(p->proto != ctx->class_proto[JS_CLASS_ARRAY] ||+                                         p->props != ctx->empty_props))+                                goto get_length_slow;+                            val = JS_NewShortInt(p->u.array.len);+                        } else {+                            goto get_length_slow;+                        }+                    } else if (p->mtag == JS_MTAG_STRING) {+                        JSString *ps = (JSString *)p;+                        if (likely(ps->is_ascii))+                            val = JS_NewShortInt(ps->len);+                        else+                            val = JS_NewShortInt(js_string_utf8_to_utf16_pos(ctx, obj, ps->len * 2));+                    } else {+                        goto get_length_slow;+                    }+                } else if (JS_VALUE_GET_SPECIAL_TAG(val) == JS_TAG_STRING_CHAR) {+                    val = JS_NewShortInt(JS_VALUE_GET_SPECIAL_VALUE(val) >= 0x10000 ? 2 : 1); +                } else {+                get_length_slow:+                    SAVE();+                    val = JS_GetPropertyInternal(ctx, obj, js_get_atom(ctx, JS_ATOM_length), TRUE);+                    RESTORE();+                    if (unlikely(JS_IsExceptionOrTailCall(val))) {+                        sp = ctx->sp;+                        goto exception;+                    }+                }+                sp[0] = val;+            }+            BREAK;++        CASE(OP_put_field):+            {+                int idx;+                JSValue prop, obj;+                JSValueArray *cpool = JS_VALUE_TO_PTR(b->cpool);++                idx = get_u16(pc);+                prop = cpool->arr[idx];+                obj = sp[1];+                if (likely(JS_IsPtr(obj))) {+                    /* fast case */+                    JSObject *p = JS_VALUE_TO_PTR(obj);+                    JSProperty *pr;+                    if (unlikely(p->mtag != JS_MTAG_OBJECT))+                        goto put_field_slow;+                    /* no array check is necessary because 'prop' is+                       guaranteed not to be a numeric property */+                    /* XXX: slow due to short ints */+                    pr = find_own_property_inlined(ctx, p, prop);+                    if (unlikely(!pr))+                        goto put_field_slow;+                    if (unlikely(pr->prop_type != JS_PROP_NORMAL))+                        goto put_field_slow;+                    /* XXX: slow */+                    if (unlikely(JS_IS_ROM_PTR(ctx, pr)))+                        goto put_field_slow;+                    pr->value = sp[0];+                    sp += 2;+                } else {+                put_field_slow:+                    val = *sp++;+                    SAVE();+                    val = JS_SetPropertyInternal(ctx, sp[0], prop, val, TRUE);+                    RESTORE();+                    if (unlikely(JS_IsExceptionOrTailCall(val))) {+                        sp = ctx->sp;+                        goto exception;+                    }+                    sp++;+                }+                pc += 2;+            }+            BREAK;++        CASE(OP_get_array_el2):+            val = sp[0];+            sp[0] = sp[1];+            goto get_array_el_common;+        CASE(OP_get_array_el):+            val = sp[0];+            sp++;+        get_array_el_common:+            {+                JSValue prop = val, obj;+                obj = sp[0];+                if (JS_IsPtr(obj) && JS_IsInt(prop)) {+                    /* fast case with array */+                    /* XXX: optimize typed arrays too ? */+                    JSObject *p = JS_VALUE_TO_PTR(obj);+                    uint32_t idx;+                    JSValueArray *arr;+                    if (unlikely(p->mtag != JS_MTAG_OBJECT))+                        goto get_array_el_slow;+                    if (unlikely(p->class_id != JS_CLASS_ARRAY))+                        goto get_array_el_slow;+                    idx = JS_VALUE_GET_INT(prop);+                    if (unlikely(idx >= p->u.array.len))+                        goto get_array_el_slow;+                        +                    arr = JS_VALUE_TO_PTR(p->u.array.tab);+                    val = arr->arr[idx];+                } else {+                get_array_el_slow:+                    SAVE();+                    prop = JS_ToPropertyKey(ctx, prop);+                    RESTORE();+                    if (JS_IsException(prop)) {+                        val = prop;+                        goto exception;+                    }+                    SAVE();+                    val = JS_GetPropertyInternal(ctx, sp[0], prop, TRUE);+                    RESTORE();+                    if (unlikely(JS_IsExceptionOrTailCall(val))) {+                        sp = ctx->sp;+                        goto exception;+                    }+                }+                sp[0] = val;+            }+            BREAK;+            +        CASE(OP_put_array_el):+            {+                JSValue prop, obj;+                obj = sp[2];+                prop = sp[1];+                if (JS_IsPtr(obj) && JS_IsInt(prop)) {+                    /* fast case with array */+                    /* XXX: optimize typed arrays too ? */+                    JSObject *p = JS_VALUE_TO_PTR(obj);+                    uint32_t idx;+                    JSValueArray *arr;+                    if (unlikely(p->mtag != JS_MTAG_OBJECT))+                        goto put_array_el_slow;+                    if (unlikely(p->class_id != JS_CLASS_ARRAY))+                        goto put_array_el_slow;+                    idx = JS_VALUE_GET_INT(prop);+                    arr = JS_VALUE_TO_PTR(p->u.array.tab);+                    if (unlikely(idx >= p->u.array.len)) {+                        if (idx == p->u.array.len &&+                            p->u.array.tab != JS_NULL &&+                            idx < arr->size) {+                            arr->arr[idx] = sp[0];+                            p->u.array.len = idx + 1;+                        } else {+                            goto put_array_el_slow;+                        }+                    } else {+                        arr->arr[idx] = sp[0];+                    }+                    sp += 3;+                } else {+                put_array_el_slow:+                    SAVE();+                    sp[1] = JS_ToPropertyKey(ctx, sp[1]);+                    RESTORE();+                    if (JS_IsException(sp[1])) {+                        val = sp[1];+                        goto exception;+                    }+                    val = *sp++;+                    prop = *sp++;+                    SAVE();+                    val = JS_SetPropertyInternal(ctx, sp[0], prop, val, TRUE);+                    RESTORE();+                    if (unlikely(JS_IsExceptionOrTailCall(val))) {+                        sp = ctx->sp;+                        goto exception;+                    }+                    sp++;+                }+            }+            BREAK;+            +        CASE(OP_define_field):+        CASE(OP_define_getter):+        CASE(OP_define_setter):+            {+                int idx;+                JSValue prop;+                JSValueArray *cpool = JS_VALUE_TO_PTR(b->cpool);+                +                idx = get_u16(pc);+                prop = cpool->arr[idx];+                +                SAVE();+                if (opcode == OP_define_field) {+                    val = JS_DefinePropertyValue(ctx, sp[1], prop, sp[0]);+                } else if (opcode == OP_define_getter)+                    val = JS_DefinePropertyGetSet(ctx, sp[1], prop, sp[0], JS_UNDEFINED, JS_DEF_PROP_HAS_GET);+                else+                    val = JS_DefinePropertyGetSet(ctx, sp[1], prop, JS_UNDEFINED, sp[0], JS_DEF_PROP_HAS_SET);+                RESTORE();+                if (unlikely(JS_IsException(val)))+                    goto exception;+                pc += 2;+                sp++;+            }+            BREAK;++        CASE(OP_set_proto):+            {+                if (JS_IsObject(ctx, sp[0]) || JS_IsNull(sp[0])) {+                    SAVE();+                    val = js_set_prototype_internal(ctx, sp[1], sp[0]);+                    RESTORE();+                    if (unlikely(JS_IsException(val)))+                        goto exception;+                }+                sp++;+            }+            BREAK;+            +        CASE(OP_add):+            {+                JSValue op1, op2;+                op1 = sp[1];+                op2 = sp[0];+                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {+                    int r;+                    if (unlikely(__builtin_add_overflow((int)op1, (int)op2, &r)))+                        goto add_slow;+                    sp[1] = (uint32_t)r;+                } else +#ifdef JS_USE_SHORT_FLOAT+                if (JS_VALUE_IS_BOTH_SHORT_FLOAT(op1, op2)) {+                    double d1, d2;+                    d1 = js_get_short_float(op1);+                    d2 = js_get_short_float(op2);+                    dr = d1 + d2;+                    sp++;+                    goto float_result;+                } else+#endif+                {+                add_slow:+                    SAVE();+                    val = js_add_slow(ctx);+                    RESTORE();+                    if (JS_IsException(val))+                        goto exception;+                    sp[1] = val;+                }+                sp++;+            }+            BREAK;+        CASE(OP_sub):+            {+                JSValue op1, op2;+                op1 = sp[1];+                op2 = sp[0];+                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {+                    int r;+                    if (unlikely(__builtin_sub_overflow((int)op1, (int)op2, &r)))+                        goto binary_arith_slow;+                    sp[1] = (uint32_t)r;+                } else+#ifdef JS_USE_SHORT_FLOAT+                if (JS_VALUE_IS_BOTH_SHORT_FLOAT(op1, op2)) {+                    double d1, d2;+                    d1 = js_get_short_float(op1);+                    d2 = js_get_short_float(op2);+                    dr = d1 - d2;+                    sp++;+                    goto float_result;+                } else+#endif+                {+                    goto binary_arith_slow;+                }+                sp++;+            }+            BREAK;+        CASE(OP_mul):+            {+                JSValue op1, op2;+                op1 = sp[1];+                op2 = sp[0];+                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {+                    int v1, v2;+                    int64_t r;+                    v1 = (int)op1;+                    v2 = (int)op2 >> 1;+                    r = (int64_t)v1 * (int64_t)v2;+                    if (unlikely(r != (int)r)) {+#if defined(JS_USE_SHORT_FLOAT)+                        dr = (double)(r >> 1);+                        sp++;+                        goto float_result;+#else+                        goto binary_arith_slow;+#endif+                    }+                    /* -0 case */+                    if (unlikely(r == 0 && (v1 | v2) < 0)) {+                        sp[1] = ctx->minus_zero;+                    } else {+                        sp[1] = (uint32_t)r;+                    }+                } else+#ifdef JS_USE_SHORT_FLOAT+                if (JS_VALUE_IS_BOTH_SHORT_FLOAT(op1, op2)) {+                    double d1, d2;+                    d1 = js_get_short_float(op1);+                    d2 = js_get_short_float(op2);+                    dr = d1 * d2;+                    sp++;+                    goto float_result;+                } else+#endif+                {+                    goto binary_arith_slow;+                }+                sp++;+            }+            BREAK;+        CASE(OP_div):+            {+                JSValue op1, op2;+                op1 = sp[1];+                op2 = sp[0];+                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {+                    int v1, v2;+                    v1 = JS_VALUE_GET_INT(op1);+                    v2 = JS_VALUE_GET_INT(op2);+                    SAVE();+                    val = JS_NewFloat64(ctx, (double)v1 / (double)v2);+                    RESTORE();+                    if (JS_IsException(val))+                        goto exception;+                    sp[1] = val;+                    sp++;+                } else {+                    goto binary_arith_slow;+                }+            }+            BREAK;+        CASE(OP_mod):+            {+                JSValue op1, op2;+                op1 = sp[1];+                op2 = sp[0];+                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {+                    int v1, v2, r;+                    v1 = JS_VALUE_GET_INT(op1);+                    v2 = JS_VALUE_GET_INT(op2);+                    if (unlikely(v1 < 0 || v2 <= 0))+                        goto binary_arith_slow;+                    r = v1 % v2;+                    sp[1] = JS_NewShortInt(r);+                    sp++;+                } else {+                    goto binary_arith_slow;+                }+            }+            BREAK;+        CASE(OP_pow):+        binary_arith_slow:+            SAVE();+            val = js_binary_arith_slow(ctx, opcode);+            RESTORE();+            if (JS_IsException(val))+                goto exception;+            sp[1] = val;+            sp++;+            BREAK;+        CASE(OP_plus):+            {+                JSValue op1;+                op1 = sp[0];+                if (JS_IsIntOrShortFloat(op1) ||+                    (JS_IsPtr(op1) && js_get_mtag(JS_VALUE_TO_PTR(op1)) == JS_MTAG_FLOAT64)) {+                } else {+                    goto unary_arith_slow;+                }+            }+            BREAK;+        CASE(OP_neg):+            {+                JSValue op1;+                int v1;+                op1 = sp[0];+                if (JS_IsInt(op1)) {+                    v1 = op1;+                    if (v1 == 0) {+                        sp[0] = ctx->minus_zero;+                    } else if (v1 == INT32_MIN) {+#if defined(JS_USE_SHORT_FLOAT)+                        dr = -(double)JS_SHORTINT_MIN;+                        goto float_result;+#else+                        goto unary_arith_slow;+#endif                        +                    } else {+                        sp[0] = -v1;+                    }+                } else+#if defined(JS_USE_SHORT_FLOAT)+                if (JS_IsShortFloat(op1)) {+                    dr = -js_get_short_float(op1);+                float_result:+                    /* for efficiency, we don't try to store it as a short integer */+                    if (likely(fabs(dr) >= 0x1p-127 && fabs(dr) <= 0x1p+128)) {+                        val = js_to_short_float(dr);+                    } else if (dr == 0.0) {+                        if (float64_as_uint64(dr) != 0) {+                            /* minus zero often happens, so it is worth having a constant+                               value */+                            val = ctx->minus_zero;+                        } else {+                            /* XXX: could have a short float+                               representation for zero and minus zero+                               so that the float fast case is still+                               used when they happen */+                            val = JS_NewShortInt(0);+                        }+                    } else {+                        /* slow case: need to allocate it */+                        SAVE();+                        val = js_alloc_float64(ctx, dr);+                        RESTORE();+                        if (JS_IsException(val))+                            goto exception;+                    }+                    sp[0] = val;+                } else+#endif+                {+                    goto unary_arith_slow;+                }+            }+            BREAK;+        CASE(OP_inc):+            {+                JSValue op1;+                int v1;+                op1 = sp[0];+                if (JS_IsInt(op1)) {+                    v1 = JS_VALUE_GET_INT(op1);+                    if (unlikely(v1 == JS_SHORTINT_MAX))+                        goto unary_arith_slow;+                    sp[0] = JS_NewShortInt(v1 + 1);+                } else {+                    goto unary_arith_slow;+                }+            }+            BREAK;+        CASE(OP_dec):+            {+                JSValue op1;+                int v1;+                op1 = sp[0];+                if (JS_IsInt(op1)) {+                    v1 = JS_VALUE_GET_INT(op1);+                    if (unlikely(v1 == JS_SHORTINT_MIN))+                        goto unary_arith_slow;+                    sp[0] = JS_NewShortInt(v1 - 1);+                } else {+                unary_arith_slow:+                    SAVE();+                    val = js_unary_arith_slow(ctx, opcode);+                    RESTORE();+                    if (JS_IsException(val))+                        goto exception;+                    sp[0] = val;+                }+            }+            BREAK;+        CASE(OP_post_inc):+        CASE(OP_post_dec):+            {+                JSValue op1;+                int v1;+                op1 = sp[0];+                if (JS_IsInt(op1)) {+                    v1 = JS_VALUE_GET_INT(op1) + 2 * (opcode - OP_post_dec) - 1;+                    if (v1 < JS_SHORTINT_MIN || v1 > JS_SHORTINT_MAX)+                        goto slow_post_inc_dec;+                    val = JS_NewShortInt(v1);+                } else {+                slow_post_inc_dec:+                    SAVE();+                    val = js_post_inc_slow(ctx, opcode);+                    RESTORE();+                    if (JS_IsException(val))+                        goto exception;+                }+                *--sp = val;+            }+            BREAK;++        CASE(OP_not):+            {+                JSValue op1;+                op1 = sp[0];+                if (JS_IsInt(op1)) {+                    sp[0] = (~op1) & (~1);+                } else {+                    SAVE();+                    val = js_not_slow(ctx);+                    RESTORE();+                    if (JS_IsException(val))+                        goto exception;+                    sp[0] = val;+                }+            }+            BREAK;++        CASE(OP_shl):+            {+                JSValue op1, op2;+                op1 = sp[1];+                op2 = sp[0];+                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {+                    int32_t r;+                    r = JS_VALUE_GET_INT(op1) << (JS_VALUE_GET_INT(op2) & 0x1f);+                    if (unlikely(r < JS_SHORTINT_MIN || r > JS_SHORTINT_MAX)) {+#if defined(JS_USE_SHORT_FLOAT)+                        dr = (double)r;+                        sp++;+                        goto float_result;+#else+                        goto binary_logic_slow;+#endif+                    }+                    sp[1] = JS_NewShortInt(r);+                    sp++;+                } else {+                    goto binary_logic_slow;+                }+            }+            BREAK;+        CASE(OP_shr):+            {+                JSValue op1, op2;+                op1 = sp[1];+                op2 = sp[0];+                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {+                    uint32_t r;+                    r = (uint32_t)JS_VALUE_GET_INT(op1) >>+                        ((uint32_t)JS_VALUE_GET_INT(op2) & 0x1f);+                    if (unlikely(r > JS_SHORTINT_MAX)) {+#if defined(JS_USE_SHORT_FLOAT)+                        dr = (double)r;+                        sp++;+                        goto float_result;+#else+                        goto binary_logic_slow;+#endif+                    }+                    sp[1] = JS_NewShortInt(r);+                    sp++;+                } else {+                    goto binary_logic_slow;+                }+            }+            BREAK;+        CASE(OP_sar):+            {+                JSValue op1, op2;+                op1 = sp[1];+                op2 = sp[0];+                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {+                    sp[1] = ((int)op1 >> ((uint32_t)JS_VALUE_GET_INT(op2) & 0x1f)) & ~1;+                    sp++;+                } else {+                    goto binary_logic_slow;+                }+            }+            BREAK;+        CASE(OP_and):+            {+                JSValue op1, op2;+                op1 = sp[1];+                op2 = sp[0];+                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {+                    sp[1] = op1 & op2;+                    sp++;+                } else {+                    goto binary_logic_slow;+                }+            }+            BREAK;+        CASE(OP_or):+            {+                JSValue op1, op2;+                op1 = sp[1];+                op2 = sp[0];+                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {+                    sp[1] = op1 | op2;+                    sp++;+                } else {+                    goto binary_logic_slow;+                }+            }+            BREAK;+        CASE(OP_xor):+            {+                JSValue op1, op2;+                op1 = sp[1];+                op2 = sp[0];+                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {+                    sp[1] = op1 ^ op2;+                    sp++;+                } else {+                binary_logic_slow:+                    SAVE();+                    val = js_binary_logic_slow(ctx, opcode);+                    RESTORE();+                    if (JS_IsException(val))+                        goto exception;+                    sp[1] = val;+                    sp++;+                }+            }+            BREAK;+            ++#define OP_CMP(opcode, binary_op, slow_call)              \+            CASE(opcode):                                  \+                {                                         \+                JSValue op1, op2;                         \+                op1 = sp[1];                                   \+                op2 = sp[0];                                   \+                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {           \+                    sp[1] = JS_NewBool(JS_VALUE_GET_INT(op1) binary_op JS_VALUE_GET_INT(op2)); \+                    sp++;                                               \+                } else {                                                \+                    SAVE();                                             \+                    val = slow_call;                                    \+                    RESTORE();                                          \+                    if (JS_IsException(val))                            \+                        goto exception;                                 \+                    sp[1] = val;                                        \+                    sp++;                                               \+                }                                                       \+                }                                                       \+                BREAK;+            +            OP_CMP(OP_lt, <, js_relational_slow(ctx, opcode));+            OP_CMP(OP_lte, <=, js_relational_slow(ctx, opcode));+            OP_CMP(OP_gt, >, js_relational_slow(ctx, opcode));+            OP_CMP(OP_gte, >=, js_relational_slow(ctx, opcode));+            OP_CMP(OP_eq, ==, js_eq_slow(ctx, 0));+            OP_CMP(OP_neq, !=, js_eq_slow(ctx, 1));+            OP_CMP(OP_strict_eq, ==, js_strict_eq_slow(ctx, 0));+            OP_CMP(OP_strict_neq, !=, js_strict_eq_slow(ctx, 1));+        CASE(OP_in):+            SAVE();+            val = js_operator_in(ctx);+            RESTORE();+            if (unlikely(JS_IsException(val)))+                goto exception;+            sp[1] = val;+            sp++;+            BREAK;+        CASE(OP_instanceof):+            SAVE();+            val = js_operator_instanceof(ctx);+            RESTORE();+            if (unlikely(JS_IsException(val)))+                goto exception;+            sp[1] = val;+            sp++;+            BREAK;+        CASE(OP_typeof):+            SAVE();+            val = js_operator_typeof(ctx, sp[0]);+            RESTORE();+            if (unlikely(JS_IsException(val)))+                goto exception;+            sp[0] = val;+            BREAK;+        CASE(OP_delete):+            SAVE();+            val = JS_DeleteProperty(ctx, sp[1], sp[0]);+            RESTORE();+            if (unlikely(JS_IsException(val)))+                goto exception;+            sp[1] = val;+            sp++;+            BREAK;+        CASE(OP_for_in_start):+        CASE(OP_for_of_start):+            SAVE();+            val = js_for_of_start(ctx, (opcode == OP_for_in_start));+            RESTORE();+            if (unlikely(JS_IsException(val)))+                goto exception;+            sp[0] = val;+            BREAK;+        CASE(OP_for_of_next):+            SAVE();+            val = js_for_of_next(ctx);+            RESTORE();+            if (unlikely(JS_IsException(val)))+                goto exception;+            sp -= 2;+            BREAK;+        default:+            {+                JSByteArray *byte_code = JS_VALUE_TO_PTR(b->byte_code);+                SAVE();+                val = JS_ThrowInternalError(ctx, "invalid opcode: pc=%u opcode=0x%02x",+                                            (int)(pc - byte_code->buf - 1), opcode);+                RESTORE();+            }+            goto exception;+        }+      restart: ;+    } /* switch */+ done:+    ctx->sp = sp;+    ctx->fp = fp;+    ctx->js_call_rec_count--;+    return val;+}++#undef SAVE+#undef RESTORE++static inline int is_ident_first(int c)+{+    return (c >= 'a' && c <= 'z') ||+        (c >= 'A' && c <= 'Z') ||+        c == '_' || c == '$';+}++static inline int is_ident_next(int c)+{+    return is_ident_first(c) || is_num(c);+}++/**********************************************************************/+/* dump utilities */++#ifdef JS_DUMP++static void js_dump_array(JSContext *ctx, JSValueArray *arr, int len)+{+    int i;+    +    js_printf(ctx, "[ ");+    for(i = 0; i < len; i++) {+        if (i != 0)+            js_printf(ctx, ", ");+        JS_PrintValue(ctx, arr->arr[i]);+    }+    js_printf(ctx, " ]");+}++/* put constructors into a separate table */+/* XXX: improve by using a table */+static JSValue js_find_class_name(JSContext *ctx, int class_id)+{+    const JSCFunctionDef *fd;+    fd = ctx->c_function_table;+    while ((fd->def_type != JS_CFUNC_constructor_magic &&+            fd->def_type != JS_CFUNC_constructor) ||+           fd->magic != class_id) {+        fd++;+    }+    return reloc_c_func_name(ctx, fd->name);+}++static void js_dump_float64(JSContext *ctx, double d)+{+    char buf[32];+    JSDTOATempMem tmp_mem; /* XXX: potentially large stack size */+    js_dtoa(buf, d, 10, 0, JS_DTOA_FORMAT_FREE | JS_DTOA_MINUS_ZERO, &tmp_mem);+    js_printf(ctx, "%s", buf);+}++static void dump_regexp(JSContext *ctx, JSObject *p);++static void js_dump_error(JSContext *ctx, JSObject *p)+{+    JSObject *p1;+    JSProperty *pr;+    JSValue name;+    +    /* find the error name without side effect */+    p1 = p;+    if (p->proto != JS_NULL) +        p1 = JS_VALUE_TO_PTR(p->proto);+    pr = find_own_property(ctx, p1, js_get_atom(ctx, JS_ATOM_name));+    if (!pr || !JS_IsString(ctx, pr->value))+        name = js_get_atom(ctx, JS_ATOM_Error);+    else+        name = pr->value;+    js_printf(ctx, "%" JSValue_PRI, name);+    if (p->u.error.message != JS_NULL) {+        js_printf(ctx, ": %" JSValue_PRI, p->u.error.message);+    }+    if (p->u.error.stack != JS_NULL) {+        /* remove the trailing '\n' if any */+        js_printf(ctx, "\n%#" JSValue_PRI, p->u.error.stack);+    }+}++static void js_dump_object(JSContext *ctx, JSObject *p, int flags)+{+    if (flags & JS_DUMP_LONG) {+        switch(p->class_id) {+        case JS_CLASS_CLOSURE:+            {+                JSFunctionBytecode *b = JS_VALUE_TO_PTR(p->u.closure.func_bytecode);+                js_printf(ctx, "function ");+                JS_PrintValueF(ctx, b->func_name, JS_DUMP_NOQUOTE);+                js_printf(ctx, "()");+            }+            break;+        case JS_CLASS_C_FUNCTION:+            js_printf(ctx, "function ");+            JS_PrintValueF(ctx, reloc_c_func_name(ctx, ctx->c_function_table[p->u.cfunc.idx].name), JS_DUMP_NOQUOTE);+            js_printf(ctx, "()");+            break;+        case JS_CLASS_ERROR:+            js_dump_error(ctx, p);+            break;+        case JS_CLASS_REGEXP:+            dump_regexp(ctx, p);+            break;+        default:+        case JS_CLASS_ARRAY:+        case JS_CLASS_OBJECT:+            if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&+                p->class_id <= JS_CLASS_FLOAT64_ARRAY) {            +                int i, idx;+                uint32_t v;+                double d;+                JSObject *pbuffer;+                JSByteArray *arr;+                JS_PrintValueF(ctx, js_find_class_name(ctx, p->class_id),+                               JS_DUMP_NOQUOTE);+                js_printf(ctx, "([ ");+                pbuffer = JS_VALUE_TO_PTR(p->u.typed_array.buffer);+                arr = JS_VALUE_TO_PTR(pbuffer->u.array_buffer.byte_buffer);+                for(i = 0; i < p->u.typed_array.len; i++) {+                    if (i != 0)+                        js_printf(ctx, ", ");+                    idx = i + p->u.typed_array.offset;+                    switch(p->class_id) {+                    default:+                    case JS_CLASS_UINT8C_ARRAY:+                    case JS_CLASS_UINT8_ARRAY:+                        v = *((uint8_t *)arr->buf + idx);+                        goto ta_i32;+                    case JS_CLASS_INT8_ARRAY:+                        v = *((int8_t *)arr->buf + idx);+                        goto ta_i32;+                    case JS_CLASS_INT16_ARRAY:+                        v = *((int16_t *)arr->buf + idx);+                        goto ta_i32;+                    case JS_CLASS_UINT16_ARRAY:+                        v = *((uint16_t *)arr->buf + idx);+                        goto ta_i32;+                    case JS_CLASS_INT32_ARRAY:+                        v = *((int32_t *)arr->buf + idx);+                    ta_i32:+                        js_printf(ctx, "%d", v);+                        break;+                    case JS_CLASS_UINT32_ARRAY:+                        v = *((uint32_t *)arr->buf + idx);+                        js_printf(ctx, "%u", v);+                        break;+                    case JS_CLASS_FLOAT32_ARRAY:+                        d = *((float *)arr->buf + idx);+                        goto ta_d;+                    case JS_CLASS_FLOAT64_ARRAY:+                        d = *((double *)arr->buf + idx);+                    ta_d:+                        js_dump_float64(ctx, d);+                        break;+                    }+                }+                js_printf(ctx, " ])");+            } else {+                int i, j, prop_count, hash_mask;+                JSProperty *pr;+                JSValueArray *arr;+                BOOL is_first = TRUE;++                arr = JS_VALUE_TO_PTR(p->props);+                prop_count = JS_VALUE_GET_INT(arr->arr[0]);+                hash_mask = JS_VALUE_GET_INT(arr->arr[1]);+                if (p->class_id == JS_CLASS_ARRAY) {+                    JSValueArray *tab = JS_VALUE_TO_PTR(p->u.array.tab);+                    js_printf(ctx, "[ ");+                    for(i = 0; i < p->u.array.len; i++) {+                        if (!is_first)+                            js_printf(ctx, ", ");+                        JS_PrintValue(ctx, tab->arr[i]);+                        is_first = FALSE;+                    }+                } else {+                    if (p->class_id != JS_CLASS_OBJECT) {+                        JSValue class_name = js_find_class_name(ctx, p->class_id);+                        if (!JS_IsNull(class_name))+                            JS_PrintValueF(ctx, class_name, JS_DUMP_NOQUOTE);+                        js_putchar(ctx, ' ');+                    }+                    js_printf(ctx, "{ ");+                }+                for(i = 0, j = 0; j < prop_count; i++) {+                    pr = (JSProperty *)&arr->arr[2 + (hash_mask + 1) + 3 * i];+                    if (pr->key != JS_UNINITIALIZED) {+                        if (!is_first)+                            js_printf(ctx, ", ");+                        JS_PrintValueF(ctx, pr->key, JS_DUMP_NOQUOTE);+                        js_printf(ctx, ": ");+                        if (!(flags & JS_DUMP_RAW) && pr->prop_type == JS_PROP_SPECIAL) {+                            JS_PrintValue(ctx, get_special_prop(ctx, pr->value));+                        } else {+                            JS_PrintValue(ctx, pr->value);+                        }+                        is_first = FALSE;+                        j++;+                    }+                }+                js_printf(ctx, " %c",+                          p->class_id == JS_CLASS_ARRAY ? ']' : '}');+            }+            break;+        }+    } else {+        const char *str;+        if (p->class_id == JS_CLASS_ARRAY)+            str = "Array";+        else if (p->class_id == JS_CLASS_ERROR)+            str = "Error";+        else if (p->class_id == JS_CLASS_CLOSURE ||+                 p->class_id == JS_CLASS_C_FUNCTION) {+            str = "Function";+        } else {+            str = "Object";+        }+        js_printf(ctx, "[object %s]", str);+    }+}++static void dump_string(JSContext *ctx, int sep, const uint8_t *buf, size_t len,+                        int flags)+{+    BOOL use_quote;+    const uint8_t *p, *p_end;+    size_t i, clen;+    int c;++    use_quote = TRUE;+    if (flags & JS_DUMP_NOQUOTE) {+        if (len >= 1 && is_ident_first(buf[0])) {+            for(i = 1; i < len; i++) {+                if (!is_ident_next(buf[i]))+                    goto need_quote;+            }+            use_quote = FALSE;+        }+    need_quote: ;+    }+    +    if (!(flags & JS_DUMP_RAW))+        sep = '"';+    if (use_quote)+        js_putchar(ctx, sep);+    p = buf;+    p_end = buf + len;+    while (p < p_end) {+        c = utf8_get(p, &clen);+        switch(c) {+        case '\t':+            c = 't';+            goto quote;+        case '\r':+            c = 'r';+            goto quote;+        case '\n':+            c = 'n';+            goto quote;+        case '\b':+            c = 'b';+            goto quote;+        case '\f':+            c = 'f';+            goto quote;+        case '\"':+        case '\\':+        quote:+            js_putchar(ctx, '\\');+            js_putchar(ctx, c);+            break;+        default:+            if (c < 32 || (c >= 0xd800 && c < 0xe000)) {+                js_printf(ctx, "\\u%04x", c);+            } else {+                ctx->write_func(ctx->opaque, p, clen);+            }+            break;+        }+        p += clen;+    }+    if (use_quote)+        js_putchar(ctx, sep);+}++void JS_PrintValueF(JSContext *ctx, JSValue val, int flags)+{+    if (JS_IsInt(val)) {+        js_printf(ctx, "%d", JS_VALUE_GET_INT(val));+    } else+#ifdef JS_USE_SHORT_FLOAT+    if (JS_IsShortFloat(val)) {+        js_dump_float64(ctx, js_get_short_float(val));+    } else+#endif+    if (!JS_IsPtr(val)) {+        switch(JS_VALUE_GET_SPECIAL_TAG(val)) {+        case JS_TAG_NULL:+        case JS_TAG_UNDEFINED:+        case JS_TAG_UNINITIALIZED:+        case JS_TAG_BOOL:+            js_printf(ctx, "%"JSValue_PRI"", val);+            break;+        case JS_TAG_EXCEPTION:+            js_printf(ctx, "[exception %d]", JS_VALUE_GET_SPECIAL_VALUE(val));+            break;+        case JS_TAG_CATCH_OFFSET:+            js_printf(ctx, "[catch_offset %d]", JS_VALUE_GET_SPECIAL_VALUE(val));+            break;+        case JS_TAG_SHORT_FUNC:+            {+                int idx = JS_VALUE_GET_SPECIAL_VALUE(val);+                js_printf(ctx, "function ");+                JS_PrintValueF(ctx, reloc_c_func_name(ctx, ctx->c_function_table[idx].name), JS_DUMP_NOQUOTE);+                js_printf(ctx, "()");+            }+            break;+        case JS_TAG_STRING_CHAR:+            {+                uint8_t buf[UTF8_CHAR_LEN_MAX + 1];+                int len;+                len = get_short_string(buf, val);+                dump_string(ctx, '`', buf, len, flags);+            }+            break;+        default:+            js_printf(ctx, "[tag %d]", (int)JS_VALUE_GET_SPECIAL_TAG(val));+            break;+        }+    } else {+        void *ptr = JS_VALUE_TO_PTR(val);+        int mtag = ((JSMemBlockHeader *)ptr)->mtag;+        switch(mtag) {+        case JS_MTAG_FLOAT64:+            {+                JSFloat64 *p = ptr;+                js_dump_float64(ctx, p->u.dval);+            }+            break;+        case JS_MTAG_OBJECT:+            js_dump_object(ctx, ptr, flags);+            break;+        case JS_MTAG_STRING:+            {+                JSString *p = ptr;+                int sep;+                sep = p->is_unique ? '\'' : '\"';+                dump_string(ctx, sep, p->buf, p->len, flags);+            }+            break;+        case JS_MTAG_VALUE_ARRAY:+            {+                JSValueArray *arr = ptr;+                js_dump_array(ctx, arr, arr->size);+            }+            break;+        case JS_MTAG_BYTE_ARRAY:+            {+                JSByteArray *arr = ptr;+                js_printf(ctx, "byte_array(%" PRIu64 ")", (uint64_t)arr->size);+            }+            break;+        case JS_MTAG_FUNCTION_BYTECODE:+            {+                JSFunctionBytecode *b = ptr;+                js_printf(ctx, "bytecode_function ");+                JS_PrintValueF(ctx, b->func_name, JS_DUMP_NOQUOTE);+                js_printf(ctx, "()");+            }+            break;+        case JS_MTAG_VARREF:+            {+                JSVarRef *pv = ptr;+                js_printf(ctx, "var_ref(");+                if (pv->is_detached)+                    JS_PrintValue(ctx, pv->u.value);+                else+                    JS_PrintValue(ctx, *pv->u.pvalue);+                js_printf(ctx, ")");+            }+            break;+        default:+            js_printf(ctx, "[mtag %d]", mtag);+            break;+        }+    }+}++void JS_PrintValue(JSContext *ctx, JSValue val)+{+    return JS_PrintValueF(ctx, val, 0);+}++static const char *get_mtag_name(unsigned int mtag)+{+    if (mtag >= countof(js_mtag_name))+        return "?";+    else+        return js_mtag_name[mtag];+}++static uint32_t val_to_offset(JSContext *ctx, JSValue val)+{+    if (!JS_IsPtr(val))+        return 0;+    else+        return (uint8_t *)JS_VALUE_TO_PTR(val) - ctx->heap_base;+}++void JS_DumpMemory(JSContext *ctx, BOOL is_long)+{+    uint8_t *ptr;+    uint32_t mtag_mem_size[JS_MTAG_COUNT];+    uint32_t mtag_count[JS_MTAG_COUNT];+    uint32_t tot_size, i;+    if (is_long) {+        js_printf(ctx, "%10s %s %8s %15s %10s %10s %s\n", "OFFSET", "M", "SIZE", "TAG", "PROTO", "PROPS", "EXTRA");+    }+    for(i = 0; i < JS_MTAG_COUNT; i++) {+        mtag_mem_size[i] = 0;+        mtag_count[i] = 0;+    }+    tot_size = 0;+    ptr = ctx->heap_base;+    while (ptr < ctx->heap_free) {+        int mtag, size, gc_mark;+        mtag = ((JSMemBlockHeader *)ptr)->mtag;+        gc_mark = ((JSMemBlockHeader *)ptr)->gc_mark;+        size = get_mblock_size(ptr);+        mtag_mem_size[mtag] += size;+        mtag_count[mtag]++;+        tot_size += size;+        if (is_long) {+            js_printf(ctx, "0x%08x %c %8u %15s",+                      (unsigned int)((uint8_t *)ptr - ctx->heap_base),+                      gc_mark ? '*' : ' ',+                      size,+                      get_mtag_name(mtag));+            if (mtag != JS_MTAG_FREE) {+                if (mtag == JS_MTAG_OBJECT) {+                    JSObject *p = (JSObject *)ptr;+                    js_printf(ctx, " 0x%08x 0x%08x",+                              val_to_offset(ctx, p->proto), val_to_offset(ctx, p->props));+                } else {+                    js_printf(ctx, " %10s %10s", "", "");+                }+                js_printf(ctx, " ");+                JS_PrintValueF(ctx, JS_VALUE_FROM_PTR(ptr), JS_DUMP_RAW);+            }+            js_printf(ctx, "\n");+        }+        ptr += size;+    }+    +    js_printf(ctx, "%15s %8s %8s %8s %8s\n", "TAG", "COUNT", "AVG_SIZE", "SIZE", "RATIO");+    for(i = 0; i < JS_MTAG_COUNT; i++) {+        if (mtag_count[i] != 0) {+            js_printf(ctx, "%15s %8u %8d %8u %7d%%\n",+                      get_mtag_name(i),+                      (unsigned int)mtag_count[i],+                      (int)js_lrint((double)mtag_mem_size[i] / (double)mtag_count[i]),+                      (unsigned int)mtag_mem_size[i],+                      (int)js_lrint((double)mtag_mem_size[i] / (double)tot_size * 100.0));+        }+    }+    js_printf(ctx, "heap size=%u/%u stack_size=%u\n",+           (unsigned int)(ctx->heap_free - ctx->heap_base),+           (unsigned int)(ctx->stack_top - ctx->heap_base),+           (unsigned int)(ctx->stack_top - (uint8_t *)ctx->sp));+}++static __maybe_unused void JS_DumpUniqueStrings(JSContext *ctx)+{+    int i;+    JSValueArray *arr;+    +    arr = JS_VALUE_TO_PTR( ctx->unique_strings);+    js_printf(ctx, "%5s %s\n", "N", "UNIQUE_STRING");+    for(i = 0; i < ctx->unique_strings_len; i++) {+        js_printf(ctx, "%5d ", i);+        JS_PrintValue(ctx, arr->arr[i]);+        js_printf(ctx, "\n");+    }+}+#else+void JS_PrintValueF(JSContext *ctx, JSValue val, int flags)+{+}+void JS_PrintValue(JSContext *ctx, JSValue val)+{+    return JS_PrintValueF(ctx, val, 0);+}+void JS_DumpMemory(JSContext *ctx, BOOL is_long)+{+}+static __maybe_unused void JS_DumpUniqueStrings(JSContext *ctx)+{+}+#endif++void JS_DumpValueF(JSContext *ctx, const char *str,+                   JSValue val, int flags)+{+    js_printf(ctx, "%s=", str);+    JS_PrintValueF(ctx, val, flags);+    js_printf(ctx, "\n");+}++void JS_DumpValue(JSContext *ctx, const char *str,+                   JSValue val)+{+    JS_DumpValueF(ctx, str, val, 0);+}+++/**************************************************/+/* JS parser */++enum {+    TOK_NUMBER = 128,+    TOK_STRING,+    TOK_IDENT,+    TOK_REGEXP,+    /* warning: order matters (see js_parse_assign_expr) */+    TOK_MUL_ASSIGN, +    TOK_DIV_ASSIGN, +    TOK_MOD_ASSIGN, +    TOK_PLUS_ASSIGN, +    TOK_MINUS_ASSIGN,+    TOK_SHL_ASSIGN,+    TOK_SAR_ASSIGN,+    TOK_SHR_ASSIGN,+    TOK_AND_ASSIGN,+    TOK_XOR_ASSIGN,+    TOK_OR_ASSIGN,+    TOK_POW_ASSIGN,+    TOK_DEC,+    TOK_INC,+    TOK_SHL,+    TOK_SAR,+    TOK_SHR,+    TOK_LT,+    TOK_LTE,+    TOK_GT,+    TOK_GTE,+    TOK_EQ,+    TOK_STRICT_EQ,+    TOK_NEQ,+    TOK_STRICT_NEQ,+    TOK_LAND,+    TOK_LOR,+    TOK_POW,+    TOK_EOF,+    /* keywords */+    TOK_FIRST_KEYWORD,+    TOK_NULL = TOK_FIRST_KEYWORD + JS_ATOM_null,+    TOK_FALSE = TOK_FIRST_KEYWORD + JS_ATOM_false,+    TOK_TRUE = TOK_FIRST_KEYWORD + JS_ATOM_true,+    TOK_IF = TOK_FIRST_KEYWORD + JS_ATOM_if,+    TOK_ELSE = TOK_FIRST_KEYWORD + JS_ATOM_else,+    TOK_RETURN = TOK_FIRST_KEYWORD + JS_ATOM_return,+    TOK_VAR = TOK_FIRST_KEYWORD + JS_ATOM_var,+    TOK_THIS = TOK_FIRST_KEYWORD + JS_ATOM_this,+    TOK_DELETE = TOK_FIRST_KEYWORD + JS_ATOM_delete,+    TOK_VOID = TOK_FIRST_KEYWORD + JS_ATOM_void,+    TOK_TYPEOF = TOK_FIRST_KEYWORD + JS_ATOM_typeof,+    TOK_NEW = TOK_FIRST_KEYWORD + JS_ATOM_new,+    TOK_IN = TOK_FIRST_KEYWORD + JS_ATOM_in,+    TOK_INSTANCEOF = TOK_FIRST_KEYWORD + JS_ATOM_instanceof,+    TOK_DO = TOK_FIRST_KEYWORD + JS_ATOM_do,+    TOK_WHILE = TOK_FIRST_KEYWORD + JS_ATOM_while,+    TOK_FOR = TOK_FIRST_KEYWORD + JS_ATOM_for,+    TOK_BREAK = TOK_FIRST_KEYWORD + JS_ATOM_break,+    TOK_CONTINUE = TOK_FIRST_KEYWORD + JS_ATOM_continue,+    TOK_SWITCH = TOK_FIRST_KEYWORD + JS_ATOM_switch,+    TOK_CASE = TOK_FIRST_KEYWORD + JS_ATOM_case,+    TOK_DEFAULT = TOK_FIRST_KEYWORD + JS_ATOM_default,+    TOK_THROW = TOK_FIRST_KEYWORD + JS_ATOM_throw,+    TOK_TRY = TOK_FIRST_KEYWORD + JS_ATOM_try,+    TOK_CATCH = TOK_FIRST_KEYWORD + JS_ATOM_catch,+    TOK_FINALLY = TOK_FIRST_KEYWORD + JS_ATOM_finally,+    TOK_FUNCTION = TOK_FIRST_KEYWORD + JS_ATOM_function,+    TOK_DEBUGGER = TOK_FIRST_KEYWORD + JS_ATOM_debugger,+    TOK_WITH = TOK_FIRST_KEYWORD + JS_ATOM_with,+    TOK_CLASS = TOK_FIRST_KEYWORD + JS_ATOM_class,+    TOK_CONST = TOK_FIRST_KEYWORD + JS_ATOM_const,+    TOK_ENUM = TOK_FIRST_KEYWORD + JS_ATOM_enum,+    TOK_EXPORT = TOK_FIRST_KEYWORD + JS_ATOM_export,+    TOK_EXTENDS = TOK_FIRST_KEYWORD + JS_ATOM_extends,+    TOK_IMPORT = TOK_FIRST_KEYWORD + JS_ATOM_import,+    TOK_SUPER = TOK_FIRST_KEYWORD + JS_ATOM_super,+    TOK_IMPLEMENTS = TOK_FIRST_KEYWORD + JS_ATOM_implements,+    TOK_INTERFACE = TOK_FIRST_KEYWORD + JS_ATOM_interface,+    TOK_LET = TOK_FIRST_KEYWORD + JS_ATOM_let,+    TOK_PACKAGE = TOK_FIRST_KEYWORD + JS_ATOM_package,+    TOK_PRIVATE = TOK_FIRST_KEYWORD + JS_ATOM_private,+    TOK_PROTECTED = TOK_FIRST_KEYWORD + JS_ATOM_protected,+    TOK_PUBLIC = TOK_FIRST_KEYWORD + JS_ATOM_public,+    TOK_STATIC = TOK_FIRST_KEYWORD + JS_ATOM_static,+    TOK_YIELD = TOK_FIRST_KEYWORD + JS_ATOM_yield,+};++/* this structure is pushed on the JS stack, so all members must be JSValue */+typedef struct BlockEnv {+    JSValue prev; /* JS_NULL or stack index */+    JSValue label_name; /* JS_NULL if none */+    JSValue label_break;+    JSValue label_cont;+    JSValue label_finally;+    JSValue drop_count; /* (int) number of stack elements to drop */+} BlockEnv;++typedef uint32_t JSSourcePos;++typedef struct JSToken {+    int val;+    JSSourcePos source_pos; /* position in source */+    union {+        double d; /* TOK_NUMBER */+        struct {+            uint32_t re_flags; /* regular expression flags */+            uint32_t re_end_pos; /* at the final '/' */+        } regexp;+    } u;+    JSValue value; /* associated value: string for TOK_STRING, TOK_REGEXP;+                      identifier for TOK_IDENT or keyword */+} JSToken;++typedef struct JSParseState {+    JSContext *ctx;+    JSToken token;++    BOOL got_lf : 8; /* true if got line feed before the current token */+    /* global eval: variables are defined as global */+    BOOL is_eval : 8;+    /* if true, return the last value. */+    BOOL has_retval : 8;+    /* if true, implicitly define global variables in an+       assignment. */+    BOOL is_repl : 8;+    BOOL has_column : 8; /* column debug info is present */+    /* TRUE if the expression result has been dropped (see PF_DROP) */+    BOOL dropped_result : 8;+    JSValue source_str; /* source string or JS_NULL */+    JSValue filename_str; /* 'filename' converted to string */+    /* zero terminated source buffer. Automatically updated by the GC+       if source_str is a string */+    const uint8_t *source_buf; +    uint32_t buf_pos;+    uint32_t buf_len;++    /* current function */+    JSValue cur_func;+    JSValue byte_code;+    uint32_t byte_code_len;+    int last_opcode_pos; /* -1 if no last opcode */+    int last_pc2line_pos; /* pc2line pos for the last opcode */+    JSSourcePos last_pc2line_source_pos;+    +    uint32_t pc2line_bit_len;+    JSSourcePos pc2line_source_pos; /* last generated source pos */+    +    uint16_t cpool_len;+    /* size of the byte code necessary to define the hoisted functions  */+    uint32_t hoisted_code_len;+    +    /* argument + defined local variable count */+    uint16_t local_vars_len;+    +    int eval_ret_idx; /* variable index for the eval return value, -1+                         if no return value */+    JSValue top_break; /* JS_NULL or SP_TO_VALUE(BlockEnv *) */++    /* regexp parsing only */+    uint8_t capture_count;+    uint8_t re_in_js: 1;+    uint8_t multi_line : 1;+    uint8_t dotall : 1;+    uint8_t ignore_case : 1;+    uint8_t is_unicode : 1;++    /* error handling */+    jmp_buf jmp_env;+    char error_msg[64];+} JSParseState;++static int js_parse_json_value(JSParseState *s, int state, int dummy_param);+static JSValue js_parse_regexp(JSParseState *s, int eval_flags);+static size_t js_parse_regexp_flags(int *pre_flags, const uint8_t *buf);+static int re_parse_alternative(JSParseState *s, int state, int dummy_param);+static int re_parse_disjunction(JSParseState *s, int state, int dummy_param);++#ifdef DUMP_BYTECODE+static __maybe_unused void dump_byte_code(JSContext *ctx, JSFunctionBytecode *b)+{+    JSByteArray *arr, *pc2line;+    JSValueArray *cpool, *vars, *ext_vars;+    const JSOpCode *oi;+    int pos, op, size, addr, idx, arg_count, len, i, line_num, col_num;+    int line_num1, col_num1, hoisted_code_len;+    uint8_t *tab;+    uint32_t pc2line_pos;+    +    arr = JS_VALUE_TO_PTR(b->byte_code);+    if (b->cpool != JS_NULL)+        cpool = JS_VALUE_TO_PTR(b->cpool);+    else+        cpool = NULL;+    if (b->vars != JS_NULL)+        vars = JS_VALUE_TO_PTR(b->vars);+    else+        vars = NULL;+    if (b->ext_vars != JS_NULL)+        ext_vars = JS_VALUE_TO_PTR(b->ext_vars);+    else+        ext_vars = NULL;+    if (b->pc2line != JS_NULL)+        pc2line = JS_VALUE_TO_PTR(b->pc2line);+    else+        pc2line = NULL;++    arg_count = b->arg_count;++    JS_PrintValueF(ctx, b->filename, JS_DUMP_NOQUOTE);+    js_printf(ctx, ": function ");+    JS_PrintValueF(ctx, b->func_name, JS_DUMP_NOQUOTE);+    js_printf(ctx, ":\n");++    if (b->arg_count && vars) {+        js_printf(ctx, "  args:");+        for(i = 0; i < b->arg_count; i++) {+            js_printf(ctx, " ");+            JS_PrintValue(ctx, vars->arr[i]);+        }+        js_printf(ctx, "\n");+    }+    if (vars) {+        js_printf(ctx, "  locals:");+        for(i = 0; i < vars->size - b->arg_count; i++) {+            js_printf(ctx, " ");+            JS_PrintValue(ctx, vars->arr[i + b->arg_count]);+        }+        js_printf(ctx, "\n");+    }+    if (ext_vars) {+        js_printf(ctx, "  refs:");+        for(i = 0; i < b->ext_vars_len; i++) {+            int var_kind, var_idx, decl;+            static const char *var_kind_str[] = { "arg", "var", "ref", "global" };+            js_printf(ctx, " ");+            JS_PrintValue(ctx, ext_vars->arr[2 * i]);+            decl = JS_VALUE_GET_INT(ext_vars->arr[2 * i + 1]);+            var_kind = decl >> 16;+            var_idx = decl & 0xffff;+            js_printf(ctx, " (%s:%d)", var_kind_str[var_kind], var_idx);+        }+        js_printf(ctx, "\n");+    }+    +    js_printf(ctx, "  cpool_size: %d\n", cpool ? (int)cpool->size : 0);+    js_printf(ctx, "  stack_size: %d\n", b->stack_size);+    js_printf(ctx, "  opcodes:\n");+    tab = arr->buf;+    len = arr->size;+    pos = 0;+    pc2line_pos = 0;+    hoisted_code_len = 0;+    if (pc2line)+        hoisted_code_len = get_pc2line_hoisted_code_len(pc2line->buf, pc2line->size);+    line_num = 1;+    col_num = 1;+    line_num1 = 0;+    col_num1 = 0;+    while (pos < len) {+        /* extract the debug info */+        if (pc2line && pos >= hoisted_code_len) {+            get_pc2line(&line_num, &col_num, pc2line->buf, pc2line->size,+                        &pc2line_pos, b->has_column);+            if (line_num != line_num1 || col_num != col_num1) {+                js_printf(ctx, "    # %d", line_num);+                if (b->has_column)+                    js_printf(ctx, ", %d", col_num);+                js_printf(ctx, "\n");+                line_num1 = line_num;+                col_num1 = col_num;+            }+        }+        op = tab[pos];+        js_printf(ctx, "%5d: ", pos);+        if (op >= OP_COUNT) {+            js_printf(ctx, "invalid opcode (0x%02x)\n", op); +            pos++;+            continue;+        }+        oi = &opcode_info[op];+        size = oi->size;+        if ((pos + size) > len) {+            js_printf(ctx, "truncated opcode (0x%02x)\n", op);+            break;+        }+        js_printf(ctx, "%s", oi->name);+        pos++;+        switch(oi->fmt) {+        case OP_FMT_u8:+            js_printf(ctx, " %u", (int)get_u8(tab + pos));+            break;+        case OP_FMT_i8:+            js_printf(ctx, " %d", (int)get_i8(tab + pos));+            break;+        case OP_FMT_u16:+        case OP_FMT_npop:+            js_printf(ctx, " %u", (int)get_u16(tab + pos));+            break;+        case OP_FMT_i16:+            js_printf(ctx, " %d", (int)get_i16(tab + pos));+            break;+        case OP_FMT_i32:+            js_printf(ctx, " %d", (int)get_i32(tab + pos));+            break;+        case OP_FMT_u32:+            js_printf(ctx, " %u", (int)get_u32(tab + pos));+            break;+        case OP_FMT_none_int:+            js_printf(ctx, " %d", op - OP_push_0);+            break;+#if 0+        case OP_FMT_npopx:+            js_printf(ctx, " %d", op - OP_call0);+            break;+#endif+        case OP_FMT_label8:+            addr = get_i8(tab + pos);+            goto has_addr1;+        case OP_FMT_label16:+            addr = get_i16(tab + pos);+            goto has_addr1;+        case OP_FMT_label:+            addr = get_u32(tab + pos);+            goto has_addr1;+        has_addr1:+            js_printf(ctx, " %u", addr + pos);+            break;+        case OP_FMT_const8:+            idx = get_u8(tab + pos);+            goto has_pool_idx;+        case OP_FMT_const16:+            idx = get_u16(tab + pos);+            goto has_pool_idx;+        has_pool_idx:+            js_printf(ctx, " %u: ", idx);+            if (idx < cpool->size) {+                JS_PrintValue(ctx, cpool->arr[idx]);+            }+            break;+        case OP_FMT_none_loc:+            idx = (op - OP_get_loc0) % 4;+            goto has_loc;+        case OP_FMT_loc8:+            idx = get_u8(tab + pos);+            goto has_loc;+        case OP_FMT_loc:+            idx = get_u16(tab + pos);+        has_loc:+            js_printf(ctx, " %d: ", idx);+            idx += arg_count;+            if (idx < vars->size) {+                JS_PrintValue(ctx, vars->arr[idx]);+            }+            break;+        case OP_FMT_none_arg:+            idx = (op - OP_get_arg0) % 4;+            goto has_arg;+        case OP_FMT_arg:+            idx = get_u16(tab + pos);+        has_arg:+            js_printf(ctx, " %d: ", idx);+            if (idx < vars->size) {+                JS_PrintValue(ctx, vars->arr[idx]);+            }+            break;+#if 0+        case OP_FMT_none_var_ref:+            idx = (op - OP_get_var_ref0) % 4;+            goto has_var_ref;+#endif            +        case OP_FMT_var_ref:+            idx = get_u16(tab + pos);+            //        has_var_ref:+            js_printf(ctx, " %d: ", idx);+            if (2 * idx < ext_vars->size) {+                JS_PrintValue(ctx, ext_vars->arr[2 * idx]);+            }+            break;+        case OP_FMT_value:+            js_printf(ctx, " ");+            idx = get_u32(tab + pos);+            JS_PrintValue(ctx, idx);+            break;+        default:+            break;+        }+        js_printf(ctx, "\n");+        pos += oi->size - 1;+    }+}+#endif /* DUMP_BYTECODE */++static void next_token(JSParseState *s);++static void __attribute((unused)) dump_token(JSParseState *s,+                                             const JSToken *token)+{+    JSContext *ctx = s->ctx;+    switch(token->val) {+    case TOK_NUMBER:+        /* XXX: TODO */+        js_printf(ctx, "number: %d\n", (int)token->u.d);+        break;+    case TOK_IDENT:+        {+            js_printf(ctx, "ident: ");+            JS_PrintValue(s->ctx, token->value);+            js_printf(ctx, "\n");+        }+        break;+    case TOK_STRING:+        {+            js_printf(ctx, "string: ");+            JS_PrintValue(s->ctx, token->value);+            js_printf(ctx, "\n");+        }+        break;+    case TOK_REGEXP:+        {+            js_printf(ctx, "regexp: ");+            JS_PrintValue(s->ctx, token->value);+            js_printf(ctx, "\n");+        }+        break;+    case TOK_EOF:+        js_printf(ctx, "eof\n");+        break;+    default:+        if (s->token.val >= TOK_FIRST_KEYWORD) {+            js_printf(ctx, "token: ");+            JS_PrintValue(s->ctx, token->value);+            js_printf(ctx, "\n");+        } else if (s->token.val >= 128) {+            js_printf(ctx, "token: %d\n", token->val);+        } else {+            js_printf(ctx, "token: '%c'\n", token->val);+        }+        break;+    }+}++/* return the zero based line and column number in the source. */+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 void __attribute__((format(printf, 2, 3), noreturn)) js_parse_error(JSParseState *s, const char *fmt, ...)+{+    va_list ap;+    va_start(ap, fmt);+    js_vsnprintf(s->error_msg, sizeof(s->error_msg), fmt, ap);+    va_end(ap);+    longjmp(s->jmp_env, 1);+}++static void js_parse_error_mem(JSParseState *s)+{+    return js_parse_error(s, "not enough memory");+}++static void js_parse_error_stack_overflow(JSParseState *s)+{+    return js_parse_error(s, "stack overflow");+}++static void js_parse_expect1(JSParseState *s, int ch)+{+    if (s->token.val != ch)+        js_parse_error(s, "expecting '%c'", ch);+}++static void js_parse_expect(JSParseState *s, int ch)+{+    js_parse_expect1(s, ch);+    next_token(s);+}++static void js_parse_expect_semi(JSParseState *s)+{+    if (s->token.val != ';') {+        /* automatic insertion of ';' */+        if (s->token.val == TOK_EOF || s->token.val == '}' || s->got_lf) {+            return;+        }+        js_parse_error(s, "expecting '%c'", ';');+    }+    next_token(s);+}++#define SKIP_HAS_ARGUMENTS     (1 << 0)+#define SKIP_HAS_FUNC_NAME     (1 << 1)+#define SKIP_HAS_SEMI          (1 << 2) /* semicolon found inside the first level */++/* Skip parenthesis or blocks. The current token should be '(', '[' or+   '{'. 'func_name' can be JS_NULL. */+static int js_skip_parens(JSParseState *s, JSValue *pfunc_name)+{+    uint8_t state[128];+    int level, c, bits = 0;+    +    /* protect from underflow */+    level = 0;+    state[level++] = 0;+    for (;;) {+        switch(s->token.val) {+        case '(':+            c = ')';+            goto add_level;+        case '[':+            c = ']';+            goto add_level;+        case '{':+            c = '}';+        add_level:+            if (level >= sizeof(state)) {+                js_parse_error(s, "too many nested blocks");+            }+            state[level++] = c;+            break;+        case ')':+        case ']':+        case '}':+            c = state[--level];+            if (s->token.val != c)+                js_parse_error(s, "expecting '%c'", c);+            break;+        case TOK_EOF:+            js_parse_error(s, "expecting '%c'", state[level - 1]);+        case TOK_IDENT:+            if (s->token.value == js_get_atom(s->ctx, JS_ATOM_arguments))+                bits |= SKIP_HAS_ARGUMENTS;+            if (pfunc_name && s->token.value == *pfunc_name)+                bits |= SKIP_HAS_FUNC_NAME;+            break;+        case ';':+            if (level == 2)+                bits |= SKIP_HAS_SEMI;+            break;+        }+        next_token(s);+        if (level <= 1)+            break;+    }+    return bits;+}++/* skip an expression until ')' */+static void js_skip_expr(JSParseState *s)+{+    for(;;) {+        switch(s->token.val) {+        case ')':+            return;+        case ';':+        case TOK_EOF:+            js_parse_error(s, "expecting '%c'", ')');+        case '(':+        case '[':+        case '{':+            js_skip_parens(s, NULL);+            break;+        default:+            next_token(s);+            break;+        }+    }+}++typedef struct JSParsePos {+    BOOL got_lf : 8;+    BOOL regexp_allowed : 8;+    uint32_t source_pos;+} JSParsePos;++/* return TRUE if a regexp literal is allowed after this token */+static BOOL is_regexp_allowed(int tok)+{+    switch (tok) {+    case TOK_NUMBER:+    case TOK_STRING:+    case TOK_REGEXP:+    case TOK_DEC:+    case TOK_INC:+    case TOK_NULL:+    case TOK_FALSE:+    case TOK_TRUE:+    case TOK_THIS:+    case TOK_IF:+    case TOK_WHILE:+    case TOK_FOR:+    case TOK_DO:+    case TOK_CASE:+    case TOK_CATCH:+    case ')':+    case ']':+    case TOK_IDENT:+        return FALSE;+    default:+        return TRUE;+    }+}++static void js_parse_get_pos(JSParseState *s, JSParsePos *sp)+{+    sp->source_pos = s->token.source_pos;+    sp->got_lf = s->got_lf;+    sp->regexp_allowed = is_regexp_allowed(s->token.val);+}++static void js_parse_seek_token(JSParseState *s, const JSParsePos *sp)+{+    s->buf_pos = sp->source_pos;+    s->got_lf = sp->got_lf;+    /* the previous token value is only needed so that+       is_regexp_allowed() returns the correct value */+    s->token.val = sp->regexp_allowed ? ' ' : ')';+    next_token(s);+}++/* same as js_skip_parens but go back to the current token */+static int js_parse_skip_parens_token(JSParseState *s)+{+    JSParsePos pos;+    int bits;+    +    js_parse_get_pos(s, &pos);+    bits = js_skip_parens(s, NULL);+    js_parse_seek_token(s, &pos);+    return bits;+}++/* return the escape value or -1 */+static int js_parse_escape(const uint8_t *buf, size_t *plen)+{+    int c;+    const uint8_t *p = buf;+    c = *p++;+    switch(c) {+    case 'b':+        c = '\b';+        break;+    case 'f':+        c = '\f';+        break;+    case 'n':+        c = '\n';+        break;+    case 'r':+        c = '\r';+        break;+    case 't':+        c = '\t';+        break;+    case 'v':+        c = '\v';+        break;+    case '\'':+    case '\"':+    case '\\':+        break;+    case 'x':+        {+            int h0, h1;++            h0 = from_hex(*p++);+            if (h0 < 0)+                return -1;+            h1 = from_hex(*p++);+            if (h1 < 0)+                return -1;+            c = (h0 << 4) | h1;+        }+        break;+    case 'u':+        {+            int h, i;+            +            if (*p == '{') {+                p++;+                c = 0;+                for(;;) {+                    h = from_hex(*p++);+                    if (h < 0)+                        return -1;+                    c = (c << 4) | h;+                    if (c > 0x10FFFF)+                        return -1;+                    if (*p == '}')+                        break;+                }+                p++;+            } else {+                c = 0;+                for(i = 0; i < 4; i++) {+                    h = from_hex(*p++);+                    if (h < 0) {+                        return -1;+                    }+                    c = (c << 4) | h;+                }+            }+        }+        break;+    case '0':+        c -= '0';+        if (c != 0 || is_num(*p))+            return -1;+        break;+    default:+        return -2;+    }+    *plen = p - buf;+    return c;+}++static JSValue js_parse_string(JSParseState *s, uint32_t *ppos, int sep)+{+    JSContext *ctx = s->ctx;+    JSValue res;+    const uint8_t *buf;+    uint32_t pos;+    uint32_t c;+    size_t escape_len = 0; /* avoid warning */+    StringBuffer b_s, *b = &b_s;+    +    if (string_buffer_push(ctx, b, 16))+        js_parse_error_mem(s);+    buf = s->source_buf;+    /* string */+    pos = *ppos;+    for(;;) {+        c = buf[pos];+        if (c == '\0' || c == '\n' || c == '\r') {+            js_parse_error(s, "unexpected end of string");+        }+        pos++;+        if (c == sep)+            break;+        if (c == '\\') {+            if (buf[pos] == '\n') {+                /* ignore escaped newline sequence */+                pos++;+                continue;+            }+            c = js_parse_escape(buf + pos, &escape_len);+            if (c == -1) {+                js_parse_error(s, "invalid escape sequence");+            } else if (c == -2) {+                /* ignore invalid escapes */+                continue;+            }+            pos += escape_len;+        } else if (c >= 0x80) {+            size_t clen;+            pos--;+            c = unicode_from_utf8(buf + pos, UTF8_CHAR_LEN_MAX, &clen);+            pos += clen;+            if (c == -1) {+                js_parse_error(s, "invalid UTF-8 sequence");+            }+        }+        if (string_buffer_putc(ctx, b, c))+            break;+        buf = s->source_buf; /* may be reallocated */+    }+    *ppos = pos;+    res = string_buffer_pop(ctx, b);+    if (JS_IsException(res))+        js_parse_error_mem(s);+    return res;+}++static void js_parse_ident(JSParseState *s, JSToken *token,+                           uint32_t *ppos, int c)+{+    JSContext *ctx = s->ctx;+    uint32_t pos;+    JSValue val, val2;+    JSGCRef val2_ref;+    const uint8_t *buf;+    StringBuffer b_s, *b = &b_s;+    +    if (string_buffer_push(ctx, b, 16))+        js_parse_error_mem(s);+    string_buffer_putc(ctx, b, c); /* no allocation */+    buf = s->source_buf;+    pos = *ppos;+    while (pos < s->buf_len) {+        c = buf[pos];+        if (!is_ident_next(c))+            break;+        pos++;+        if (string_buffer_putc(ctx, b, c))+            break;+        buf = s->source_buf; /* may be reallocated */+    }+    /* convert to token if necessary */+    token->val = TOK_IDENT;+    val2 = string_buffer_pop(ctx, b);+    JS_PUSH_VALUE(ctx, val2);+    val = JS_MakeUniqueString(ctx, val2);+    JS_POP_VALUE(ctx, val2);+    if (JS_IsException(val))+        js_parse_error_mem(s);+    if (val != val2)+        js_free(ctx, JS_VALUE_TO_PTR(val2));+    token->value = val;+    if (JS_IsPtr(val)) {+        const JSWord *atom_start, *atom_last, *ptr;+        atom_start = ctx->atom_table;+        atom_last = atom_start + JS_ATOM_yield;+        ptr = JS_VALUE_TO_PTR(val);+        if (ptr >= atom_start && ptr <= atom_last) {+            token->val = TOK_NULL + (ptr - atom_start);+        }+    }+    *ppos = pos;+}++static void js_parse_regexp_token(JSParseState *s, uint32_t *ppos)+{+    JSContext *ctx = s->ctx;+    uint32_t pos;+    uint32_t c;+    BOOL in_class;+    size_t clen;+    int re_flags, end_pos, start_pos;+    JSString *p;+    +    in_class = FALSE;+    pos = *ppos;+    start_pos = pos;+    for(;;) {+        c = unicode_from_utf8(s->source_buf + pos, UTF8_CHAR_LEN_MAX, &clen);+        if (c == -1) +            js_parse_error(s, "invalid UTF-8 sequence");+        pos += clen;+        if (c == '\0' || c == '\n' || c == '\r') {+            goto invalid_char;+        } else if (c == '/') {+            if (!in_class)+                break;+        } else if (c == '[') {+            in_class = TRUE;+        } else if (c == ']') {+            in_class = FALSE;+        } else if (c == '\\') {+            c = unicode_from_utf8(s->source_buf + pos, UTF8_CHAR_LEN_MAX, &clen);+            if (c == -1) +                js_parse_error(s, "invalid UTF-8 sequence");+            if (c == '\0' || c == '\n' || c == '\r') {+            invalid_char:+                js_parse_error(s, "unexpected line terminator in regexp");+            }+            pos += clen;+        }+    }+    end_pos = pos - 1;+    +    clen = js_parse_regexp_flags(&re_flags, s->source_buf + pos);+    pos += clen;+    if (is_ident_next(s->source_buf[pos]))+        js_parse_error(s, "invalid regular expression flags");++    /* XXX: single char string is not optimized */+    p = js_alloc_string(ctx, end_pos - start_pos);+    if (!p)+        js_parse_error_mem(s);+    p->is_ascii = is_ascii_string((char *)(s->source_buf + start_pos), end_pos - start_pos);+    memcpy(p->buf, s->source_buf + start_pos, end_pos - start_pos);+    +    *ppos = pos;+    s->token.val = TOK_REGEXP;+    s->token.value = JS_VALUE_FROM_PTR(p);+    s->token.u.regexp.re_flags = re_flags;+    s->token.u.regexp.re_end_pos = end_pos;+}++static void next_token(JSParseState *s)+{+    uint32_t pos;+    const uint8_t *p;+    int c;+    +    pos = s->buf_pos;+    s->got_lf = FALSE;+    s->token.value = JS_NULL;+    p = s->source_buf + s->buf_pos;+ redo:+    s->token.source_pos = p - s->source_buf;+    c = *p;+    switch(c) {+    case 0:+        s->token.val = TOK_EOF;+        break;+    case '\"':+    case '\'':+        p++;+        pos = p - s->source_buf;+        s->token.value = js_parse_string(s, &pos, c);+        s->token.val = TOK_STRING;+        p = s->source_buf + pos;+        break;+    case '\n':+        s->got_lf = TRUE;+        p++;+        goto redo;+    case ' ':+    case '\t':+    case '\f':+    case '\v':+    case '\r':+        p++;+        goto redo;+    case '/':+        if (p[1] == '*') {+            /* comment */+            p += 2;+            for(;;) {+                if (*p == '\0')+                    js_parse_error(s, "unexpected end of comment");+                if (p[0] == '*' && p[1] == '/') {+                    p += 2;+                    break;+                }+                p++;+            }+            goto redo;+        } else if (p[1] == '/') {+            /* line comment */+            p += 2;+            for(;;) {+                if (*p == '\0' || *p == '\n')+                    break;+                p++;+            }+            goto redo;+        } else if (is_regexp_allowed(s->token.val)) {+            /* Note: we recognize regexps in the lexer. It does not+               handle all the cases e.g. "({x:1} / 2)" or "a.void / 2" but+               is consistent when we tokenize the input without+               parsing it. */+            p++;+            pos = p - s->source_buf;+            js_parse_regexp_token(s, &pos);+            p = s->source_buf + pos;+        } else if (p[1] == '=') {+            p += 2;+            s->token.val = TOK_DIV_ASSIGN;+        } else {+            p++;+            s->token.val = c;+        }+        break;+    case 'a' ... 'z':+    case 'A' ... 'Z': +    case '_': +    case '$':+        p++;+        pos = p - s->source_buf;+        js_parse_ident(s, &s->token, &pos, c);+        p = s->source_buf + pos;+        break;+    case '.':+        if (is_digit(p[1]))+            goto parse_number;+        else+            goto def_token;+    case '0':+        /* in strict mode, octal literals are not accepted */+        if (is_digit(p[1]))+            goto invalid_number;+        goto parse_number;+    case '1': case '2': case '3': case '4':+    case '5': case '6': case '7': case '8':+    case '9':+        /* number */+        parse_number:+        {+            double d;+            JSByteArray *tmp_arr;+            pos = p - s->source_buf;+            tmp_arr = js_alloc_byte_array(s->ctx, sizeof(JSATODTempMem));+            if (!tmp_arr)+                js_parse_error_mem(s);+            p = s->source_buf + pos;+            d = js_atod((const char *)p, (const char **)&p, 0,+                        JS_ATOD_ACCEPT_BIN_OCT | JS_ATOD_ACCEPT_UNDERSCORES,+                        (JSATODTempMem *)tmp_arr->buf);+            js_free(s->ctx, tmp_arr);+            if (isnan(d)) {+            invalid_number:+                js_parse_error(s, "invalid number literal");+            }+            s->token.val = TOK_NUMBER;+            s->token.u.d = d;+        }+        break;+    case '*':+        if (p[1] == '=') {+            p += 2;+            s->token.val = TOK_MUL_ASSIGN;+        } else if (p[1] == '*') {+            if (p[2] == '=') {+                p += 3;+                s->token.val = TOK_POW_ASSIGN;+            } else {+                p += 2;+                s->token.val = TOK_POW;+            }+        } else {+            goto def_token;+        }+        break;+    case '%':+        if (p[1] == '=') {+            p += 2;+            s->token.val = TOK_MOD_ASSIGN;+        } else {+            goto def_token;+        }+        break;+    case '+':+        if (p[1] == '=') {+            p += 2;+            s->token.val = TOK_PLUS_ASSIGN;+        } else if (p[1] == '+') {+            p += 2;+            s->token.val = TOK_INC;+        } else {+            goto def_token;+        }+        break;+    case '-':+        if (p[1] == '=') {+            p += 2;+            s->token.val = TOK_MINUS_ASSIGN;+        } else if (p[1] == '-') {+            p += 2;+            s->token.val = TOK_DEC;+        } else {+            goto def_token;+        }+        break;+    case '<':+        if (p[1] == '=') {+            p += 2;+            s->token.val = TOK_LTE;+        } else if (p[1] == '<') {+            if (p[2] == '=') {+                p += 3;+                s->token.val = TOK_SHL_ASSIGN;+            } else {+                p += 2;+                s->token.val = TOK_SHL;+            }+        } else {+            goto def_token;+        }+        break;+    case '>':+        if (p[1] == '=') {+            p += 2;+            s->token.val = TOK_GTE;+        } else if (p[1] == '>') {+            if (p[2] == '>') {+                if (p[3] == '=') {+                    p += 4;+                    s->token.val = TOK_SHR_ASSIGN;+                } else {+                    p += 3;+                    s->token.val = TOK_SHR;+                }+            } else if (p[2] == '=') {+                p += 3;+                s->token.val = TOK_SAR_ASSIGN;+            } else {+                p += 2;+                s->token.val = TOK_SAR;+            }+        } else {+            goto def_token;+        }+        break;+    case '=':+        if (p[1] == '=') {+            if (p[2] == '=') {+                p += 3;+                s->token.val = TOK_STRICT_EQ;+            } else {+                p += 2;+                s->token.val = TOK_EQ;+            }+        } else {+            goto def_token;+        }+        break;+    case '!':+        if (p[1] == '=') {+            if (p[2] == '=') {+                p += 3;+                s->token.val = TOK_STRICT_NEQ;+            } else {+                p += 2;+                s->token.val = TOK_NEQ;+            }+        } else {+            goto def_token;+        }+        break;+    case '&':+        if (p[1] == '=') {+            p += 2;+            s->token.val = TOK_AND_ASSIGN;+        } else if (p[1] == '&') {+            p += 2;+            s->token.val = TOK_LAND;+        } else {+            goto def_token;+        }+        break;+    case '^':+        if (p[1] == '=') {+            p += 2;+            s->token.val = TOK_XOR_ASSIGN;+        } else {+            goto def_token;+        }+        break;+    case '|':+        if (p[1] == '=') {+            p += 2;+            s->token.val = TOK_OR_ASSIGN;+        } else if (p[1] == '|') {+            p += 2;+            s->token.val = TOK_LOR;+        } else {+            goto def_token;+        }+        break;+    default:+        if (c >= 128) {+            js_parse_error(s, "unexpected character");+        }+    def_token:+        s->token.val = c;+        p++;+        break;+    }+    s->buf_pos = p - s->source_buf;+#if defined(DUMP_TOKEN)+    dump_token(s, &s->token);+#endif+}++/* test if the current token is a label. XXX: we assume there is no+   space between the identifier and the ':' to avoid having to push+   back a token */+static BOOL is_label(JSParseState *s)+{+    return (s->token.val == TOK_IDENT && s->source_buf[s->buf_pos] == ':');+}++static inline uint8_t *get_byte_code(JSParseState *s)+{+    JSByteArray *arr;+    arr = JS_VALUE_TO_PTR(s->byte_code);+    return arr->buf;+}++static void emit_claim_size(JSParseState *s, int n)+{+    JSValue val;+    val = js_resize_byte_array(s->ctx, s->byte_code, s->byte_code_len + n);+    if (JS_IsException(val))+        js_parse_error_mem(s);+    s->byte_code = val;+}++static void emit_u8(JSParseState *s, uint8_t val)+{+    JSByteArray *arr;+    emit_claim_size(s, 1);+    arr = JS_VALUE_TO_PTR(s->byte_code);+    arr->buf[s->byte_code_len++] = val;+}++static void emit_u16(JSParseState *s, uint16_t val)+{+    JSByteArray *arr;+    emit_claim_size(s, 2);+    arr = JS_VALUE_TO_PTR(s->byte_code);+    put_u16(arr->buf + s->byte_code_len, val);+    s->byte_code_len += 2;+}++static void emit_u32(JSParseState *s, uint32_t val)+{+    JSByteArray *arr;+    emit_claim_size(s, 4);+    arr = JS_VALUE_TO_PTR(s->byte_code);+    put_u32(arr->buf + s->byte_code_len, val);+    s->byte_code_len += 4;+}++/* precondition: 1 <= n <= 25. */+static void pc2line_put_bits_short(JSParseState *s, int n, uint32_t bits)+{+    JSFunctionBytecode *b;+    JSValue val1;+    JSByteArray *arr;+    uint32_t index, pos;+    unsigned int val;+    int shift;+    uint8_t *p;++    index = s->pc2line_bit_len;+    pos = index >> 3;++    /* resize the array if needed */+    b = JS_VALUE_TO_PTR(s->cur_func);+    val1 = js_resize_byte_array(s->ctx, b->pc2line, pos + 4);+    if (JS_IsException(val1))+        js_parse_error_mem(s);+    b = JS_VALUE_TO_PTR(s->cur_func);+    b->pc2line = val1;++    arr = JS_VALUE_TO_PTR(val1);+    p = arr->buf + pos;+    val = get_be32(p);+    shift = (32 - (index & 7) - n);+    val &= ~(((1U << n) - 1) << shift); /* reset the bits */+    val |= bits << shift;+    put_be32(p, val);+    s->pc2line_bit_len = index + n;+}++/* precondition: 1 <= n <= 32 */+static void pc2line_put_bits(JSParseState *s, int n, uint32_t bits)+{+    int n_max = 25;+    if (unlikely(n > n_max)) {+        pc2line_put_bits_short(s, n - n_max, bits >> n_max);+        bits &= (1 << n_max) - 1;+        n = n_max;+    }+    pc2line_put_bits_short(s, n, bits);+}++/* 0 <= v < 2^32-1 */+static void put_ugolomb(JSParseState *s, uint32_t v)+{+    int n;+    //    printf("put_ugolomb: %u\n", v);+    v++;+    n = 32 - clz32(v);+    if (n > 1)+        pc2line_put_bits(s, n - 1, 0);+    pc2line_put_bits(s, n, v);+}++/* v != -2^31 */+static void put_sgolomb(JSParseState *s, int32_t v1)+{+    uint32_t v = v1;+    put_ugolomb(s, (2 * v) ^ -(v >> 31));+}++//#define DUMP_PC2LINE_STATS++#ifdef DUMP_PC2LINE_STATS+static int pc2line_freq[256];+static int pc2line_freq_tot;+#endif++/* return the difference between the line numbers from 'pos1' to+   'pos2'. If the difference is zero, '*pcol_num' contains the+   difference between the column numbers. Otherwise it contains the+   zero based absolute column number.+*/+static int get_line_col_delta(int *pcol_num, const uint8_t *buf,+                              int pos1, int pos2)+{+    int line_num, col_num, c, i;+    line_num = 0;+    col_num = 0;+    if (pos2 >= pos1) {+        line_num = get_line_col(&col_num, buf + pos1, pos2 - pos1);+    } else {+        line_num = get_line_col(&col_num, buf + pos2, pos1 - pos2);+        line_num = -line_num;+        col_num = -col_num;+        if (line_num != 0) {+            /* find the absolute column position */+            col_num = 0;+            for(i = pos2 - 1; i >= 0; i--) {+                c = buf[i];+                if (c == '\n') {+                    break;+                } else if (c < 0x80 || c >= 0xc0) {+                    col_num++;+                }+            }+        }+    }+    *pcol_num = col_num;+    return line_num;+}++static void emit_pc2line(JSParseState *s, JSSourcePos pos)+{+    int line_delta, col_delta;++    line_delta = get_line_col_delta(&col_delta, s->source_buf,+                                    s->pc2line_source_pos, pos);+    put_sgolomb(s, line_delta);+    if (s->has_column) {+        if (line_delta == 0) {+#ifdef DUMP_PC2LINE_STATS+            pc2line_freq[min_int(max_int(col_delta + 128, 0), 255)]++;+            pc2line_freq_tot++;+#endif+            put_sgolomb(s, col_delta);+        } else {+            put_ugolomb(s, col_delta);+        }+    }+    s->pc2line_source_pos = pos;+}++#ifdef DUMP_PC2LINE_STATS+void dump_pc2line(void)+{+    int i;+    for(i = 0; i < 256; i++) {+        if (pc2line_freq[i] != 0) {+            printf("%d: %d %0.2f\n",+                   i - 128, pc2line_freq[i],+                   -log2((double)pc2line_freq[i] / pc2line_freq_tot));+        }+    }+}+#endif++/* warning: pc2line info must be associated to each generated opcode */+static void emit_op_pos(JSParseState *s, uint8_t op, JSSourcePos source_pos)+{+    s->last_opcode_pos = s->byte_code_len;+    s->last_pc2line_pos = s->pc2line_bit_len;+    s->last_pc2line_source_pos = s->pc2line_source_pos;++    emit_pc2line(s, source_pos);+    emit_u8(s, op);+}++static void emit_op(JSParseState *s, uint8_t op)+{+    emit_op_pos(s, op, s->pc2line_source_pos);+}++static void emit_op_param(JSParseState *s, uint8_t op, uint32_t param,+                          JSSourcePos source_pos)+{+    const JSOpCode *oi;++    emit_op_pos(s, op, source_pos);+    oi = &opcode_info[op];+    switch(oi->fmt) {+    case OP_FMT_none:+        break;+    case OP_FMT_npop:+        emit_u16(s, param);+        break;+    default:+        assert(0);+    }+}++/* insert 'n' bytes at position pos */+static void emit_insert(JSParseState *s, int pos, int n)+{+    JSByteArray *arr;+    emit_claim_size(s, n);+    arr = JS_VALUE_TO_PTR(s->byte_code);+    memmove(arr->buf + pos + n, arr->buf + pos, s->byte_code_len - pos);+    s->byte_code_len += n;+}++static inline int get_prev_opcode(JSParseState *s)+{+    if (s->last_opcode_pos < 0) {+        return OP_invalid;+    } else {+        uint8_t *byte_code = get_byte_code(s);+        return byte_code[s->last_opcode_pos];+    }+}++static BOOL js_is_live_code(JSParseState *s) {+    switch (get_prev_opcode(s)) {+    case OP_return:+    case OP_return_undef:+    case OP_throw:+    case OP_goto:+    case OP_ret:+        return FALSE;+    default:+        return TRUE;+    }+}++static void remove_last_op(JSParseState *s)+{+    s->byte_code_len = s->last_opcode_pos;+    s->pc2line_bit_len = s->last_pc2line_pos;+    s->pc2line_source_pos = s->last_pc2line_source_pos;+    s->last_opcode_pos = -1;+}++static void emit_push_short_int(JSParseState *s, int val)+{+    if (val >= -1 && val <= 7) {+        emit_op(s, OP_push_0 + val);+    } else if (val == (int8_t)val) {+        emit_op(s, OP_push_i8);+        emit_u8(s, val);+    } else if (val == (int16_t)val) {+        emit_op(s, OP_push_i16);+        emit_u16(s, val);+    } else {+        emit_op(s, OP_push_value);+        emit_u32(s, JS_NewShortInt(val));+    }+}++static void emit_var(JSParseState *s, int opcode, int var_idx,+                     JSSourcePos source_pos)+{+    switch(opcode) {+    case OP_get_loc:+        if (var_idx < 4) {+            emit_op_pos(s, OP_get_loc0 + var_idx, source_pos);+            return;+        } else if (var_idx < 256) {+            emit_op_pos(s, OP_get_loc8, source_pos);+            emit_u8(s, var_idx);+            return;+        }+        break;+    case OP_put_loc:+        if (var_idx < 4) {+            emit_op_pos(s, OP_put_loc0 + var_idx, source_pos);+            return;+        } else if (var_idx < 256) {+            emit_op_pos(s, OP_put_loc8, source_pos);+            emit_u8(s, var_idx);+            return;+        }+        break;+    case OP_get_arg:+        if (var_idx < 4) {+            emit_op_pos(s, OP_get_arg0 + var_idx, source_pos);+            return;+        }+        break;+    case OP_put_arg:+        if (var_idx < 4) {+            emit_op_pos(s, OP_put_arg0 + var_idx, source_pos);+            return;+        }+        break;+    }+    emit_op_pos(s, opcode, source_pos);+    emit_u16(s, var_idx);+}+++typedef enum {+    JS_PARSE_FUNC_STATEMENT,+    JS_PARSE_FUNC_EXPR,+    JS_PARSE_FUNC_METHOD,+} JSParseFunctionEnum;++static void js_parse_function_decl(JSParseState *s,+                                   JSParseFunctionEnum func_type, JSValue func_name);++/* labels are short integers so they can be used as JSValue. -1 is not+   a valid label. */+#define LABEL_RESOLVED_FLAG (1 << 29)+#define LABEL_OFFSET_MASK ((1 << 29) - 1)++#define LABEL_NONE JS_NewShortInt(-1)++static BOOL label_is_none(JSValue label)+{+    return JS_VALUE_GET_INT(label) < 0;+}++static JSValue new_label(JSParseState *s)+{+    return JS_NewShortInt(LABEL_OFFSET_MASK);+}++static void emit_label_pos(JSParseState *s, JSValue *plabel, int pos)+{+    int label;+    JSByteArray *arr;+    int next;++    label = JS_VALUE_GET_INT(*plabel);+    assert(!(label & LABEL_RESOLVED_FLAG));+    arr = JS_VALUE_TO_PTR(s->byte_code);+    while (label != LABEL_OFFSET_MASK) {+        next = get_u32(arr->buf + label);+        put_u32(arr->buf + label, pos - label);+        label = next;+    }+    *plabel = JS_NewShortInt(pos | LABEL_RESOLVED_FLAG);+}++static void emit_label(JSParseState *s, JSValue *plabel)+{+    emit_label_pos(s, plabel, s->byte_code_len);+    /* prevent get_lvalue from using the last expression as an+       lvalue. */+    s->last_opcode_pos = -1;+}++static void emit_goto(JSParseState *s, int opcode, JSValue *plabel)+{+    int label;+    /* XXX: generate smaller gotos when possible */+    emit_op(s, opcode);+    label = JS_VALUE_GET_INT(*plabel);+    if (label & LABEL_RESOLVED_FLAG) {+        emit_u32(s, (label & LABEL_OFFSET_MASK) - s->byte_code_len);+    } else {+        emit_u32(s, label);+        *plabel = JS_NewShortInt(s->byte_code_len - 4);+    }+}++/* return the constant pool index. 'val' is not duplicated. */+static int cpool_add(JSParseState *s, JSValue val)+{+    JSFunctionBytecode *b;+    JSValueArray *arr;+    int i;+    JSValue new_cpool;+    JSGCRef val_ref;+    +    b = JS_VALUE_TO_PTR(s->cur_func);+    arr = JS_VALUE_TO_PTR(b->cpool);+    /* check if the value is already present */+    for(i = 0; i < s->cpool_len; i++) {+        if (arr->arr[i] == val)+            return i;+    }++    if (s->cpool_len > 65535)+        js_parse_error(s, "too many constants");+    JS_PUSH_VALUE(s->ctx, val);+    new_cpool = js_resize_value_array(s->ctx, b->cpool, max_int(s->cpool_len + 1, 4));+    JS_POP_VALUE(s->ctx, val);+    if (JS_IsException(new_cpool))+        js_parse_error_mem(s);+    b = JS_VALUE_TO_PTR(s->cur_func);+    b->cpool = new_cpool;+    arr = JS_VALUE_TO_PTR(b->cpool);+    arr->arr[s->cpool_len++] = val;+    return s->cpool_len - 1;+}++static void js_emit_push_const(JSParseState *s, JSValue val)+{+    int idx;++    if (JS_IsPtr(val)+#ifdef JS_USE_SHORT_FLOAT+        || JS_IsShortFloat(val)+#endif+        ) {+        /* We use a constant pool to avoid scanning the bytecode+           during the GC. XXX: is it a good choice ? */+        idx = cpool_add(s, val);+        emit_op(s, OP_push_const);+        emit_u16(s, idx);+    } else {+        /* no GC mark */+        emit_op(s, OP_push_value);+        emit_u32(s, val);+    }+}++/* return the local variable index or -1 if not found */+static int find_func_var(JSContext *ctx, JSValue func, JSValue name)+{+    JSFunctionBytecode *b;+    JSValueArray *arr;+    int i;++    b = JS_VALUE_TO_PTR(func);+    if (b->vars == JS_NULL)+        return -1;+    arr = JS_VALUE_TO_PTR(b->vars);+    for(i = 0; i < arr->size; i++) {+        if (arr->arr[i] == name)+            return i;+    }+    return -1;+}++static int find_var(JSParseState *s, JSValue name)+{+    JSFunctionBytecode *b;+    JSValueArray *arr;+    int i;++    b = JS_VALUE_TO_PTR(s->cur_func);+    arr = JS_VALUE_TO_PTR(b->vars);+    for(i = 0; i < s->local_vars_len; i++) {+        if (arr->arr[i] == name)+            return i;+    }+    return -1;+}++static JSValue get_ext_var_name(JSParseState *s, int var_idx)+{+    JSFunctionBytecode *b;+    JSValueArray *arr;++    b = JS_VALUE_TO_PTR(s->cur_func);+    arr = JS_VALUE_TO_PTR(b->ext_vars);+    return arr->arr[2 * var_idx];+}++static int find_func_ext_var(JSParseState *s, JSValue func, JSValue name)+{+    JSFunctionBytecode *b;+    JSValueArray *arr;+    int i;++    b = JS_VALUE_TO_PTR(func);+    arr = JS_VALUE_TO_PTR(b->ext_vars);+    for(i = 0; i < b->ext_vars_len; i++) {+        if (arr->arr[2 * i] == name)+            return i;+    }+    return -1;+}++/* return the external variable index or -1 if not found */+static int find_ext_var(JSParseState *s, JSValue name)+{+    return find_func_ext_var(s, s->cur_func, name);+}++/* return the external variable index */+static int add_func_ext_var(JSParseState *s, JSValue func, JSValue name, int decl)+{+    JSFunctionBytecode *b;+    JSValueArray *arr;+    JSValue new_ext_vars;+    JSGCRef name_ref, func_ref;+    +    b = JS_VALUE_TO_PTR(func);+    if (b->ext_vars_len >= JS_MAX_LOCAL_VARS) +        js_parse_error(s, "too many variable references");+    JS_PUSH_VALUE(s->ctx, func);+    JS_PUSH_VALUE(s->ctx, name);+    new_ext_vars = js_resize_value_array(s->ctx, b->ext_vars, max_int(b->ext_vars_len + 1, 2) * 2);+    JS_POP_VALUE(s->ctx, name);+    JS_POP_VALUE(s->ctx, func);+    if (JS_IsException(new_ext_vars))+        js_parse_error_mem(s);+    b = JS_VALUE_TO_PTR(func);+    b->ext_vars = new_ext_vars;+    arr = JS_VALUE_TO_PTR(b->ext_vars);+    arr->arr[2 * b->ext_vars_len] = name;+    arr->arr[2 * b->ext_vars_len + 1] = JS_NewShortInt(decl);+    b->ext_vars_len++;+    return b->ext_vars_len - 1;+}++/* return the external variable index */+static int add_ext_var(JSParseState *s, JSValue name, int decl)+{+    return add_func_ext_var(s, s->cur_func, name, decl);+}++/* return the local variable index */+static int add_var(JSParseState *s, JSValue name)+{+    JSFunctionBytecode *b;+    JSValueArray *arr;+    JSValue new_vars;+    JSGCRef name_ref;+    +    b = JS_VALUE_TO_PTR(s->cur_func);+    if (s->local_vars_len >= JS_MAX_LOCAL_VARS) +        js_parse_error(s, "too many local variables");+    JS_PUSH_VALUE(s->ctx, name);+    new_vars = js_resize_value_array(s->ctx, b->vars, max_int(s->local_vars_len + 1, 4));+    JS_POP_VALUE(s->ctx, name);+    if (JS_IsException(new_vars))+        js_parse_error_mem(s);+    b = JS_VALUE_TO_PTR(s->cur_func);+    b->vars = new_vars;+    arr = JS_VALUE_TO_PTR(b->vars);+    arr->arr[s->local_vars_len++] = name;+    return s->local_vars_len - 1;+}++static void get_lvalue(JSParseState *s, int *popcode,+                       int *pvar_idx, JSSourcePos *psource_pos, BOOL keep)+{+    int opcode, var_idx;+    JSSourcePos source_pos;+    +    /* we check the last opcode to get the lvalue type */+    opcode = get_prev_opcode(s);+    switch(opcode) {+    case OP_get_loc0:+    case OP_get_loc1:+    case OP_get_loc2:+    case OP_get_loc3:+        var_idx = opcode - OP_get_loc0;+        opcode = OP_get_loc;+        break;+    case OP_get_arg0:+    case OP_get_arg1:+    case OP_get_arg2:+    case OP_get_arg3:+        var_idx = opcode - OP_get_arg0;+        opcode = OP_get_arg;+        break;+    case OP_get_loc8:+        var_idx = get_u8(get_byte_code(s) + s->last_opcode_pos + 1);+        opcode = OP_get_loc;+        break;+    case OP_get_loc:+    case OP_get_arg:+    case OP_get_var_ref:+    case OP_get_field:+        var_idx = get_u16(get_byte_code(s) + s->last_opcode_pos + 1);+        break;+    case OP_get_array_el:+    case OP_get_length:+        var_idx = -1;+        break;+    default:+        js_parse_error(s, "invalid lvalue");+    }+    source_pos = s->pc2line_source_pos;++    /* remove the last opcode */+    remove_last_op(s);++    if (keep) {+        /* get the value but keep the object/fields on the stack */+        switch(opcode) {+        case OP_get_loc:+        case OP_get_arg:+        case OP_get_var_ref:+            emit_var(s, opcode, var_idx, source_pos);+            break;+        case OP_get_field:+            emit_op_pos(s, OP_get_field2, source_pos);+            emit_u16(s, var_idx);+            break;+        case OP_get_length:+            emit_op_pos(s, OP_get_length2, source_pos);+            break;+        case OP_get_array_el:+            emit_op(s, OP_dup2);+            emit_op_pos(s, OP_get_array_el, source_pos); /* XXX: add OP_get_array_el3 but need to modify tail call */+            break;+        default:+            abort();+        }+    }++    *popcode = opcode;+    *pvar_idx = var_idx;+    *psource_pos = source_pos;+}++typedef enum {+    PUT_LVALUE_KEEP_TOP,  /* [depth] v -> v */+    PUT_LVALUE_NOKEEP_TOP, /* [depth] v -> */+    PUT_LVALUE_KEEP_SECOND, /* [depth] v0 v -> v0 */+    PUT_LVALUE_NOKEEP_BOTTOM, /* v [depth] -> */+} PutLValueEnum;++static void put_lvalue(JSParseState *s, int opcode,+                       int var_idx, JSSourcePos source_pos,+                       PutLValueEnum special)+{+    switch(opcode) {+    case OP_get_loc:+    case OP_get_arg:+    case OP_get_var_ref:+        if (special == PUT_LVALUE_KEEP_TOP)+            emit_op(s, OP_dup);+        if (opcode == OP_get_var_ref && s->is_repl)+            opcode = OP_put_var_ref_nocheck; /* an assignment defines the variable in the REPL */+        else+            opcode++;+        emit_var(s, opcode, var_idx, source_pos);+        break;+    case OP_get_field:+    case OP_get_length:+        switch(special) {+        case PUT_LVALUE_KEEP_TOP:+            emit_op(s, OP_insert2); /* obj a -> a obj a */+            break;+        case PUT_LVALUE_NOKEEP_TOP:+            break;+        case PUT_LVALUE_NOKEEP_BOTTOM:+            emit_op(s, OP_swap); /* a obj -> obj a */+            break;+        default:+        case PUT_LVALUE_KEEP_SECOND:+            emit_op(s, OP_perm3); /* obj a b -> a obj b */+            break;+        }+        emit_op_pos(s, OP_put_field, source_pos);+        if (opcode == OP_get_length) {+            emit_u16(s, cpool_add(s, js_get_atom(s->ctx, JS_ATOM_length)));+        } else {+            emit_u16(s, var_idx);+        }+        break;+    case OP_get_array_el:+        switch(special) {+        case PUT_LVALUE_KEEP_TOP:+            emit_op(s, OP_insert3); /* obj prop a -> a obj prop a */+            break;+        case PUT_LVALUE_NOKEEP_TOP:+            break;+        case PUT_LVALUE_NOKEEP_BOTTOM: /* a obj prop -> obj prop a */+            emit_op(s, OP_rot3l); /* obj prop a b -> a obj prop b */+            break;+        default:+        case PUT_LVALUE_KEEP_SECOND:+            emit_op(s, OP_perm4); /* obj prop a b -> a obj prop b */+            break;+        }+        emit_op_pos(s, OP_put_array_el, source_pos);+        break;+    default:+        abort();+    }+}++enum {+    PARSE_PROP_FIELD,+    PARSE_PROP_GET,+    PARSE_PROP_SET,+    PARSE_PROP_METHOD,+};++static int js_parse_property_name(JSParseState *s, JSValue *pname)+{+    JSContext *ctx = s->ctx;+    JSValue name;+    JSGCRef name_ref;+    int prop_type;++    prop_type = PARSE_PROP_FIELD;++    if (s->token.val == TOK_IDENT) {+        int is_set;+        if (s->token.value == js_get_atom(ctx, JS_ATOM_get))+            is_set = 0;+        else if (s->token.value == js_get_atom(ctx, JS_ATOM_set))+            is_set = 1;+        else+            is_set = -1;+        if (is_set >= 0) {+            next_token(s);+            if (s->token.val == ':' || s->token.val == ',' ||+                s->token.val == '}' || s->token.val == '(') {+                /* not a get set */+                name = js_get_atom(ctx, is_set ? JS_ATOM_set : JS_ATOM_get);+                goto done;+            }+            prop_type = PARSE_PROP_GET + is_set;+        }+    }++    if (s->token.val == TOK_IDENT || s->token.val >= TOK_FIRST_KEYWORD) {+        name = s->token.value;+    } else if (s->token.val == TOK_STRING) {+        name = s->token.value;+    } else if (s->token.val == TOK_NUMBER) {+        name = JS_NewFloat64(s->ctx, s->token.u.d);+        if (JS_IsException(name))+            js_parse_error_mem(s);+    } else {+        js_parse_error(s, "invalid property name");+    }+    name = JS_ToPropertyKey(s->ctx, name);+    if (JS_IsException(name))+        js_parse_error_mem(s);+    JS_PUSH_VALUE(ctx, name);+    next_token(s);+    JS_POP_VALUE(ctx, name);+ done:+    if (prop_type == PARSE_PROP_FIELD && s->token.val == '(')+        prop_type = PARSE_PROP_METHOD;+    *pname = name;+    return prop_type;+}++/* recursion free parser definitions */++#define PF_NO_IN         (1 << 0) /* the 'in' operator is not accepted*/+#define PF_DROP          (1 << 1) /* drop result */+#define PF_ACCEPT_LPAREN (1 << 2) /* js_parse_postfix_expr only */+#define PF_LEVEL_SHIFT 4 /* optional level parameter */+#define PF_LEVEL_MASK  (0xf << PF_LEVEL_SHIFT)++typedef enum {+    PARSE_FUNC_js_parse_expr_comma,+    PARSE_FUNC_js_parse_assign_expr,+    PARSE_FUNC_js_parse_cond_expr,+    PARSE_FUNC_js_parse_logical_and_or,+    PARSE_FUNC_js_parse_expr_binary,+    PARSE_FUNC_js_parse_unary,+    PARSE_FUNC_js_parse_postfix_expr,+    PARSE_FUNC_js_parse_statement,+    PARSE_FUNC_js_parse_block,+    PARSE_FUNC_js_parse_json_value,+    PARSE_FUNC_re_parse_alternative,+    PARSE_FUNC_re_parse_disjunction,+} ParseExprFuncEnum;++typedef int JSParseFunc(JSParseState *s, int state, int param);++#define PARSE_STATE_INIT 0xfe+#define PARSE_STATE_RET  0xff++/* may trigger a gc */+static JSValue parse_stack_alloc(JSParseState *s, JSValue val)+{+    JSGCRef val_ref;+    +    JS_PUSH_VALUE(s->ctx, val);+    if (JS_StackCheck(s->ctx, 1))+        js_parse_error_stack_overflow(s);+    JS_POP_VALUE(s->ctx, val);+    return val;+}++/* WARNING: 'val' may be modified after this val if it is a pointer */+static void js_parse_push_val(JSParseState *s, JSValue val)+{+    JSContext *ctx = s->ctx;+    if (unlikely(ctx->sp <= ctx->stack_bottom)) {+        val = parse_stack_alloc(s, val);+    }+    *--(ctx->sp) = val;+}++/* update the stack bottom when there is a large stack space */+static JSValue js_parse_pop_val(JSParseState *s)+{+    JSContext *ctx = s->ctx;+    JSValue val;+    val = *(ctx->sp)++;+    if (unlikely(ctx->sp - JS_STACK_SLACK > ctx->stack_bottom))+        ctx->stack_bottom = ctx->sp - JS_STACK_SLACK;+    return val;+}++#define PARSE_PUSH_VAL(s, v) js_parse_push_val(s, v)+#define PARSE_POP_VAL(s, v) v = js_parse_pop_val(s)++#define PARSE_PUSH_INT(s, v) js_parse_push_val(s, JS_NewShortInt(v))+#define PARSE_POP_INT(s, v) v = JS_VALUE_GET_INT(js_parse_pop_val(s))++#define PARSE_START1()                          \+    switch(state) {\+    case PARSE_STATE_INIT: break;\+    default: abort();\+    case 0: goto parse_state0;\+    }++#define PARSE_START2()                          \+    switch(state) {\+    case PARSE_STATE_INIT: break;\+    default: abort();\+    case 0: goto parse_state0;\+    case 1: goto parse_state1;\+    }++#define PARSE_START3()                          \+    switch(state) {\+    case PARSE_STATE_INIT: break;\+    default: abort();\+    case 0: goto parse_state0;\+    case 1: goto parse_state1;\+    case 2: goto parse_state2;\+    }++#define PARSE_START7()                          \+    switch(state) {\+    case PARSE_STATE_INIT: break;\+    default: abort();\+    case 0: goto parse_state0;\+    case 1: goto parse_state1;\+    case 2: goto parse_state2;\+    case 3: goto parse_state3;                  \+    case 4: goto parse_state4;\+    case 5: goto parse_state5;\+    case 6: goto parse_state6;\+    }++#define PARSE_START12()                          \+    switch(state) {\+    case PARSE_STATE_INIT: break;\+    default: abort();\+    case 0: goto parse_state0;\+    case 1: goto parse_state1;\+    case 2: goto parse_state2;\+    case 3: goto parse_state3;                  \+    case 4: goto parse_state4;\+    case 5: goto parse_state5;\+    case 6: goto parse_state6;\+    case 7: goto parse_state7;                  \+    case 8: goto parse_state8;\+    case 9: goto parse_state9;\+    case 10: goto parse_state10;\+    case 11: goto parse_state11;\+    }++/* WARNING: local variables are not preserved across PARSE_CALL(). So+   they must be explicitly saved and restored */+#define PARSE_CALL(s, cur_state, func, param) return (cur_state | (PARSE_FUNC_ ## func << 8) | ((param) << 16)); parse_state ## cur_state : ;++/* preserve var1, ... across the call */+#define PARSE_CALL_SAVE1(s, cur_state, func, param, var1) \+    PARSE_PUSH_INT(s, var1);                                    \+    PARSE_CALL(s, cur_state, func, param);                      \+    PARSE_POP_INT(s, var1);++#define PARSE_CALL_SAVE2(s, cur_state, func, param, var1, var2) \+    PARSE_PUSH_INT(s, var1);                                    \+    PARSE_PUSH_INT(s, var2);                                    \+    PARSE_CALL(s, cur_state, func, param);                      \+    PARSE_POP_INT(s, var2);                                     \+    PARSE_POP_INT(s, var1);++#define PARSE_CALL_SAVE3(s, cur_state, func, param, var1, var2, var3)        \+    PARSE_PUSH_INT(s, var1);                                    \+    PARSE_PUSH_INT(s, var2);                                    \+    PARSE_PUSH_INT(s, var3);                                    \+    PARSE_CALL(s, cur_state, func, param);                      \+    PARSE_POP_INT(s, var3);                                     \+    PARSE_POP_INT(s, var2);                                     \+    PARSE_POP_INT(s, var1);++#define PARSE_CALL_SAVE4(s, cur_state, func, param, var1, var2, var3, var4)  \+    PARSE_PUSH_INT(s, var1);                                    \+    PARSE_PUSH_INT(s, var2);                                    \+    PARSE_PUSH_INT(s, var3);                                    \+    PARSE_PUSH_INT(s, var4);                                    \+    PARSE_CALL(s, cur_state, func, param);                      \+    PARSE_POP_INT(s, var4);                                     \+    PARSE_POP_INT(s, var3);                                     \+    PARSE_POP_INT(s, var2);                                     \+    PARSE_POP_INT(s, var1);++#define PARSE_CALL_SAVE5(s, cur_state, func, param, var1, var2, var3, var4, var5) \+    PARSE_PUSH_INT(s, var1);                                    \+    PARSE_PUSH_INT(s, var2);                                    \+    PARSE_PUSH_INT(s, var3);                                    \+    PARSE_PUSH_INT(s, var4);                                    \+    PARSE_PUSH_INT(s, var5);                                    \+    PARSE_CALL(s, cur_state, func, param);                      \+    PARSE_POP_INT(s, var5);                                     \+    PARSE_POP_INT(s, var4);                                     \+    PARSE_POP_INT(s, var3);                                     \+    PARSE_POP_INT(s, var2);                                     \+    PARSE_POP_INT(s, var1);++#define PARSE_CALL_SAVE6(s, cur_state, func, param, var1, var2, var3, var4, var5, var6) \+    PARSE_PUSH_INT(s, var1);                                    \+    PARSE_PUSH_INT(s, var2);                                    \+    PARSE_PUSH_INT(s, var3);                                    \+    PARSE_PUSH_INT(s, var4);                                    \+    PARSE_PUSH_INT(s, var5);                                    \+    PARSE_PUSH_INT(s, var6);                                    \+    PARSE_CALL(s, cur_state, func, param);                      \+    PARSE_POP_INT(s, var6);                                     \+    PARSE_POP_INT(s, var5);                                     \+    PARSE_POP_INT(s, var4);                                     \+    PARSE_POP_INT(s, var3);                                     \+    PARSE_POP_INT(s, var2);                                     \+    PARSE_POP_INT(s, var1);++static JSParseFunc *parse_func_table[];++static void js_parse_call(JSParseState *s, ParseExprFuncEnum func_idx,+                          int param)+{+    JSContext *ctx = s->ctx;+    int ret, state;+    JSValue *stack_top;++    stack_top = ctx->sp;+    state = PARSE_STATE_INIT;+    for(;;) {+        ret = parse_func_table[func_idx](s, state, param);+        state = ret & 0xff;+        if (state == PARSE_STATE_RET) {+            /* the function terminated: go back to the calling+               function if any */+            if (ctx->sp == stack_top)+                break;+            PARSE_POP_INT(s, ret);+            state = ret & 0xff;+            func_idx = (ret >> 8) & 0xff;+            param = -1; /* the parameter is not saved */+        } else {+            /* push the call position and call another function */+            PARSE_PUSH_INT(s, state | (func_idx << 8));+            state = PARSE_STATE_INIT;+            func_idx = (ret >> 8) & 0xff;+            param = (ret >> 16);+        }+    }+}++static BOOL may_drop_result(JSParseState *s, int parse_flags)+{+    return ((parse_flags & PF_DROP) &&+            (s->token.val == ';' || s->token.val == ')' ||+             s->token.val == ','));+}++static void js_emit_push_number(JSParseState *s, double d)+{+    JSValue val;+    +    val = JS_NewFloat64(s->ctx, d);+    if (JS_IsException(val))+        js_parse_error_mem(s);+    if (JS_IsInt(val)) {+        emit_push_short_int(s, JS_VALUE_GET_INT(val));+    } else {+        js_emit_push_const(s, val);+    }+}++static int js_parse_postfix_expr(JSParseState *s, int state, int parse_flags)+{+    BOOL is_new = FALSE;++    PARSE_START7();+    switch(s->token.val) {+    case TOK_NUMBER:+        js_emit_push_number(s, s->token.u.d);+        next_token(s);+        break;+    case TOK_STRING:+        {+            js_emit_push_const(s, s->token.value);+            next_token(s);+        }+        break;+    case TOK_REGEXP:+        {+            uint32_t saved_buf_pos, saved_buf_len;+            uint32_t saved_byte_code_len;+            JSValue byte_code;+            JSFunctionBytecode *b;++            js_emit_push_const(s, s->token.value); /* regexp source */++            saved_buf_pos = s->buf_pos;+            saved_buf_len = s->buf_len;+            /* save the current bytecode back to the function */+            b = JS_VALUE_TO_PTR(s->cur_func);+            b->byte_code = s->byte_code;+            saved_byte_code_len = s->byte_code_len;+            +            /* modify the parser to parse the regexp. This way we+               avoid instantiating a new JSParseState */+            /* XXX: find a better way as it relies on the regexp+               parser to correctly handle the end of regexp */+            s->buf_pos = s->token.source_pos + 1;+            s->buf_len = s->token.u.regexp.re_end_pos;+            byte_code = js_parse_regexp(s, s->token.u.regexp.re_flags);++            s->buf_pos = saved_buf_pos;+            s->buf_len = saved_buf_len;+            b = JS_VALUE_TO_PTR(s->cur_func);+            s->byte_code = b->byte_code;+            s->byte_code_len = saved_byte_code_len;+            +            js_emit_push_const(s, byte_code);+            emit_op(s, OP_regexp);+            next_token(s);+        }+        break;+    case '(':+        next_token(s);+        PARSE_CALL_SAVE1(s, 0, js_parse_expr_comma, 0, parse_flags);+        js_parse_expect(s, ')');+        break;+    case TOK_FUNCTION:+        js_parse_function_decl(s, JS_PARSE_FUNC_EXPR, JS_NULL);+        break;+    case TOK_NULL:+        emit_op(s, OP_null);+        next_token(s);+        break;+    case TOK_THIS:+        emit_op(s, OP_push_this);+        next_token(s);+        break;+    case TOK_FALSE:+    case TOK_TRUE:+        emit_op(s, OP_push_false + (s->token.val == TOK_TRUE));+        next_token(s);+        break;+    case TOK_IDENT:+        {+            JSFunctionBytecode *b;+            JSValue name;+            int var_idx, arg_count, opcode;++            b = JS_VALUE_TO_PTR(s->cur_func);+            arg_count = b->arg_count;+            +            name = s->token.value;+            +            var_idx = find_var(s, name);+            if (var_idx >= 0) {+                if (var_idx < arg_count) {+                    opcode = OP_get_arg;+                } else {+                    opcode = OP_get_loc;+                    var_idx -= arg_count;+                }+            } else {+                var_idx = find_ext_var(s, name);+                if (var_idx < 0) {+                    var_idx = add_ext_var(s, name, (JS_VARREF_KIND_GLOBAL << 16) | 0);+                }+                opcode = OP_get_var_ref;+            }+            emit_var(s, opcode, var_idx, s->token.source_pos);+            next_token(s);+        }+        break;+    case '{':+        {+            JSValue name;+            int prop_idx, prop_type, count_pos;+            BOOL has_proto;+            +            next_token(s);+            emit_op(s, OP_object);+            count_pos = s->byte_code_len;+            emit_u16(s, 0);++            has_proto = FALSE;+            while (s->token.val != '}') {+                prop_type = js_parse_property_name(s, &name);+                if (prop_type == PARSE_PROP_FIELD &&+                    name == js_get_atom(s->ctx, JS_ATOM___proto__)) {+                    if (has_proto)+                        js_parse_error(s, "duplicate __proto__ property name");+                    has_proto = TRUE;+                    prop_idx = -1;+                } else {+                    uint8_t *byte_code;+                    int count;+                    prop_idx = cpool_add(s, name);+                    /* increment the count */+                    byte_code = get_byte_code(s);+                    count = get_u16(byte_code + count_pos);+                    put_u16(byte_code + count_pos, min_int(count + 1, 0xffff));+                }+                if (prop_type == PARSE_PROP_FIELD) {+                    js_parse_expect(s, ':');+                    PARSE_CALL_SAVE4(s, 1, js_parse_assign_expr, 0, prop_idx, parse_flags, has_proto, count_pos);+                    if (prop_idx >= 0) {+                        emit_op(s, OP_define_field);+                        emit_u16(s, prop_idx);+                    } else {+                        emit_op(s, OP_set_proto);+                    }+                } else {+                    /* getter/setter/method */+                    js_parse_function_decl(s, JS_PARSE_FUNC_METHOD, name);+                    if (prop_type == PARSE_PROP_METHOD)+                        emit_op(s, OP_define_field);+                    else if (prop_type == PARSE_PROP_GET)+                        emit_op(s, OP_define_getter);+                    else+                        emit_op(s, OP_define_setter);+                    emit_u16(s, prop_idx);+                }+                if (s->token.val != ',')+                    break;+                next_token(s);+            }+            js_parse_expect(s, '}');+        }+        break;+    case '[':+        {+            uint32_t idx;+            +            next_token(s);+            /* small regular arrays are created on the stack */+            idx = 0;+            while (s->token.val != ']' && idx < 32) {+                /* SPEC: we don't accept empty elements */+                PARSE_CALL_SAVE2(s, 2, js_parse_assign_expr, 0, idx, parse_flags);+                idx++;+                /* accept trailing comma */+                if (s->token.val == ',') {+                    next_token(s);+                } else if (s->token.val != ']') {+                    goto done;+                }+            }+            +            emit_op_param(s, OP_array_from, idx, s->pc2line_source_pos);+            +            while (s->token.val != ']') {+                if (idx >= JS_SHORTINT_MAX)+                    js_parse_error(s, "too many elements");+                emit_op(s, OP_dup);+                emit_push_short_int(s, idx);+                PARSE_CALL_SAVE2(s, 3, js_parse_assign_expr, 0, idx, parse_flags);+                emit_op(s, OP_put_array_el);+                idx++;+                /* accept trailing comma */+                if (s->token.val == ',') {+                    next_token(s);+                }+            }+        done:+            js_parse_expect(s, ']');+        }+        break;+    case TOK_NEW:+        next_token(s);+        if (s->token.val == '.') {+            next_token(s);+            if (s->token.val != TOK_IDENT ||+                s->token.value != js_get_atom(s->ctx, JS_ATOM_target)) {+                js_parse_error(s, "expecting target");+            }+            next_token(s);+            emit_op(s, OP_new_target);+        } else {+            PARSE_CALL_SAVE1(s, 4, js_parse_postfix_expr, 0, parse_flags);+            if (s->token.val != '(') {+                /* new operator on an object */+                emit_op_param(s, OP_call_constructor, 0, s->token.source_pos);+            } else {+                is_new = TRUE;+                break;+            }+        }+        break;+    default:+        js_parse_error(s, "unexpected character in expression");+    }++    for(;;) {+        if (s->token.val == '(' && (parse_flags & PF_ACCEPT_LPAREN)) {+            int opcode, arg_count;+            uint8_t *byte_code;+            JSSourcePos op_source_pos;+            +            /* function call */+            op_source_pos = s->token.source_pos;+            next_token(s);++            if (!is_new) {+                opcode = get_prev_opcode(s);+                byte_code = get_byte_code(s);+                switch(opcode) {+                case OP_get_field:+                    byte_code[s->last_opcode_pos] = OP_get_field2;+                    break;+                case OP_get_length:+                    byte_code[s->last_opcode_pos] = OP_get_length2;+                    break;+                case OP_get_array_el:+                    byte_code[s->last_opcode_pos] = OP_get_array_el2;+                    break;+                case OP_get_var_ref:+                    {+                        int var_idx = get_u16(byte_code + s->last_opcode_pos + 1);+                        if (get_ext_var_name(s, var_idx) == js_get_atom(s->ctx, JS_ATOM_eval)) {+                            js_parse_error(s, "direct eval is not supported. Use (1,eval) instead for indirect eval");+                        }+                    }+                    /* fall thru */+                default:+                    opcode = OP_invalid;+                    break;+                }+            } else {+                opcode = OP_invalid;+            }+            +            arg_count = 0;+            if (s->token.val != ')') {+                for(;;) {+                    if (arg_count >= JS_MAX_ARGC)+                        js_parse_error(s, "too many call arguments");+                    arg_count++;+                    PARSE_CALL_SAVE5(s, 5, js_parse_assign_expr, 0,+                                     parse_flags, arg_count, opcode, is_new, op_source_pos);+                    if (s->token.val == ')')+                        break;+                    js_parse_expect(s, ',');+                }+            }+            next_token(s);+            if (opcode == OP_get_field ||+                opcode == OP_get_length ||+                opcode == OP_get_array_el) {+                emit_op_param(s, OP_call_method, arg_count, op_source_pos);+            } else {+                if (is_new) {+                    emit_op_param(s, OP_call_constructor, arg_count, op_source_pos);+                } else {+                    emit_op_param(s, OP_call, arg_count, op_source_pos);+                }+            }+            is_new = FALSE;+        } else if (s->token.val == '.') {+            JSSourcePos op_source_pos;+            int prop_idx;+            +            op_source_pos = s->token.source_pos;+            next_token(s);+            if (!(s->token.val == TOK_IDENT || s->token.val >= TOK_FIRST_KEYWORD)) {+                js_parse_error(s, "expecting field name");+            }+            /* we ensure that no numeric property is used with+               OP_get_field to enable some optimizations. The only+               possible identifiers are NaN and Infinity */+            if (s->token.value == js_get_atom(s->ctx, JS_ATOM_NaN) ||+                s->token.value == js_get_atom(s->ctx, JS_ATOM_Infinity)) {+                js_emit_push_const(s, s->token.value);+                emit_op_pos(s, OP_get_array_el, op_source_pos);+            } else if (s->token.value == js_get_atom(s->ctx, JS_ATOM_length)) {+                emit_op_pos(s, OP_get_length, op_source_pos);+            } else {+                prop_idx = cpool_add(s, s->token.value);+                emit_op_pos(s, OP_get_field, op_source_pos);+                emit_u16(s, prop_idx);+            }+            next_token(s);+        } else if (s->token.val == '[') {+            JSSourcePos op_source_pos;+            op_source_pos = s->token.source_pos;+            next_token(s);+            PARSE_CALL_SAVE3(s, 6, js_parse_expr_comma, 0,+                             parse_flags, is_new, op_source_pos);+            js_parse_expect(s, ']');+            emit_op_pos(s, OP_get_array_el, op_source_pos);+        } else if (!s->got_lf && (s->token.val == TOK_DEC || s->token.val == TOK_INC)) {+            int opcode, op, var_idx;+            JSSourcePos op_source_pos, source_pos;+            +            op = s->token.val;+            op_source_pos = s->token.source_pos;+            next_token(s);+            get_lvalue(s, &opcode, &var_idx, &source_pos, TRUE);+            if (may_drop_result(s, parse_flags)) {+                s->dropped_result = TRUE;+                emit_op_pos(s, OP_dec + op - TOK_DEC, op_source_pos);+                put_lvalue(s, opcode, var_idx, source_pos, PUT_LVALUE_NOKEEP_TOP);+            } else {+                emit_op_pos(s, OP_post_dec + op - TOK_DEC, op_source_pos);+                put_lvalue(s, opcode, var_idx, source_pos, PUT_LVALUE_KEEP_SECOND);+            }+        } else {+            break;+        }+    }+    return PARSE_STATE_RET;+}++static void js_emit_delete(JSParseState *s)+{+    int opcode;+    +    opcode = get_prev_opcode(s);+    switch(opcode) {+    case OP_get_field:+        {+            JSByteArray *byte_code;+            int prop_idx;+            byte_code = JS_VALUE_TO_PTR(s->byte_code);+            prop_idx = get_u16(byte_code->buf + s->last_opcode_pos + 1);+            remove_last_op(s);+            emit_op(s, OP_push_const);+            emit_u16(s, prop_idx);+        }+        break;+    case OP_get_length:+        remove_last_op(s);+        js_emit_push_const(s, js_get_atom(s->ctx, JS_ATOM_length));+        break;+    case OP_get_array_el:+        remove_last_op(s);+        break;+    default:+        js_parse_error(s, "invalid lvalue for delete");+    }+    emit_op(s, OP_delete);+}++static int js_parse_unary(JSParseState *s, int state, int parse_flags)+{+    PARSE_START7();++    switch(s->token.val) {+    case '+':+    case '-':+    case '!':+    case '~':+        {+            int op;+            JSSourcePos op_source_pos;+            +            op = s->token.val;+            op_source_pos = s->token.source_pos;+            next_token(s);+            +            /* XXX: could handle more cases */+            if (s->token.val == TOK_NUMBER && (op == '-' || op == '+')) {+                double d = s->token.u.d;+                if (op == '-')+                    d = -d;+                js_emit_push_number(s, d);+                next_token(s);+            } else {+                PARSE_CALL_SAVE2(s, 0, js_parse_unary, 0, op, op_source_pos);+                switch(op) {+                case '-':+                    emit_op_pos(s, OP_neg, op_source_pos);+                    break;+                case '+':+                    emit_op_pos(s, OP_plus, op_source_pos);+                    break;+                case '!':+                    emit_op_pos(s, OP_lnot, op_source_pos);+                    break;+                case '~':+                    emit_op_pos(s, OP_not, op_source_pos);+                    break;+                default:+                    abort();+                }+            }+        }+        break;+    case TOK_VOID:+        next_token(s);+        PARSE_CALL(s, 1, js_parse_unary, 0);+        emit_op(s, OP_drop);+        emit_op(s, OP_undefined);+        break;+    case TOK_DEC:+    case TOK_INC:+        {+            int opcode, op, var_idx;+            PutLValueEnum special;+            JSSourcePos op_source_pos, source_pos;+            +            op = s->token.val;+            op_source_pos = s->token.source_pos;+            next_token(s);+            PARSE_CALL_SAVE3(s, 2, js_parse_unary, 0, op, parse_flags, op_source_pos);+            get_lvalue(s, &opcode, &var_idx, &source_pos, TRUE);+            emit_op_pos(s, OP_dec + op - TOK_DEC, op_source_pos);++            if (may_drop_result(s, parse_flags)) {+                special = PUT_LVALUE_NOKEEP_TOP;+                s->dropped_result = TRUE;+            } else {+                special = PUT_LVALUE_KEEP_TOP;+            }+            put_lvalue(s, opcode, var_idx, source_pos, special);+        }+        break;+    case TOK_TYPEOF:+        {+            next_token(s);+            PARSE_CALL(s, 3, js_parse_unary, 0);+            /* access to undefined variable should not return an+               exception, so we patch the get_var */+            if (get_prev_opcode(s) == OP_get_var_ref) {+                uint8_t *byte_code = get_byte_code(s);+                byte_code[s->last_opcode_pos] = OP_get_var_ref_nocheck;+            }+            emit_op(s, OP_typeof);+        }+        break;+    case TOK_DELETE:+        next_token(s);+        PARSE_CALL(s, 4, js_parse_unary, 0);+        js_emit_delete(s);+        break;+    default:+        PARSE_CALL(s, 5, js_parse_postfix_expr, parse_flags | PF_ACCEPT_LPAREN);+        /* XXX: we do not follow the ES7 grammar in order to have a+         * more natural expression */+        if (s->token.val == TOK_POW) {+            JSSourcePos op_source_pos;+            op_source_pos = s->token.source_pos;+            next_token(s);+            PARSE_CALL_SAVE1(s, 6, js_parse_unary, 0, op_source_pos);+            emit_op_pos(s, OP_pow, op_source_pos);+        }+        break;+    }+    return PARSE_STATE_RET;+}++static int js_parse_expr_binary(JSParseState *s, int state, int parse_flags)+{+    int op, opcode, level;+    JSSourcePos op_source_pos;+    +    PARSE_START3();+    level = (parse_flags & PF_LEVEL_MASK) >> PF_LEVEL_SHIFT;+    if (level == 0) {+        PARSE_CALL(s, 0, js_parse_unary, parse_flags);+        return PARSE_STATE_RET;+    }+    PARSE_CALL_SAVE1(s, 1, js_parse_expr_binary, parse_flags - (1 << PF_LEVEL_SHIFT), parse_flags);+    parse_flags &= ~PF_DROP;+    for(;;) {+        op = s->token.val;+        op_source_pos = s->token.source_pos;+        level = (parse_flags & PF_LEVEL_MASK) >> PF_LEVEL_SHIFT;+        switch(level) {+        case 1:+            switch(op) {+            case '*':+                opcode = OP_mul;+                break;+            case '/':+                opcode = OP_div;+                break;+            case '%':+                opcode = OP_mod;+                break;+            default:+                return PARSE_STATE_RET;+            }+            break;+        case 2:+            switch(op) {+            case '+':+                opcode = OP_add;+                break;+            case '-':+                opcode = OP_sub;+                break;+            default:+                return PARSE_STATE_RET;+            }+            break;+        case 3:+            switch(op) {+            case TOK_SHL:+                opcode = OP_shl;+                break;+            case TOK_SAR:+                opcode = OP_sar;+                break;+            case TOK_SHR:+                opcode = OP_shr;+                break;+            default:+                return PARSE_STATE_RET;+            }+            break;+        case 4:+            switch(op) {+            case '<':+                opcode = OP_lt;+                break;+            case '>':+                opcode = OP_gt;+                break;+            case TOK_LTE:+                opcode = OP_lte;+                break;+            case TOK_GTE:+                opcode = OP_gte;+                break;+            case TOK_INSTANCEOF:+                opcode = OP_instanceof;+                break;+            case TOK_IN:+                if (!(parse_flags & PF_NO_IN)) {+                    opcode = OP_in;+                } else {+                    return PARSE_STATE_RET;+                }+                break;+            default:+                return PARSE_STATE_RET;+            }+            break;+        case 5:+            switch(op) {+            case TOK_EQ:+                opcode = OP_eq;+                break;+            case TOK_NEQ:+                opcode = OP_neq;+                break;+            case TOK_STRICT_EQ:+                opcode = OP_strict_eq;+                break;+            case TOK_STRICT_NEQ:+                opcode = OP_strict_neq;+                break;+            default:+                return PARSE_STATE_RET;+            }+            break;+        case 6:+            switch(op) {+            case '&':+                opcode = OP_and;+                break;+            default:+                return PARSE_STATE_RET;+            }+            break;+        case 7:+            switch(op) {+            case '^':+                opcode = OP_xor;+                break;+            default:+                return PARSE_STATE_RET;+            }+            break;+        case 8:+            switch(op) {+            case '|':+                opcode = OP_or;+                break;+            default:+                return PARSE_STATE_RET;+            }+            break;+        default:+            abort();+        }+        next_token(s);+        PARSE_CALL_SAVE3(s, 2, js_parse_expr_binary, parse_flags - (1 << PF_LEVEL_SHIFT), parse_flags, opcode, op_source_pos);+        emit_op_pos(s, opcode, op_source_pos);+    }+    return PARSE_STATE_RET;+}++static int js_parse_logical_and_or(JSParseState *s, int state, int parse_flags)+{+    JSValue label1;+    int level, op;++    PARSE_START3();+    level = (parse_flags & PF_LEVEL_MASK) >> PF_LEVEL_SHIFT;+    if (level == 0) {+        PARSE_CALL(s, 0, js_parse_expr_binary, (parse_flags & ~PF_LEVEL_MASK) | (8 << PF_LEVEL_SHIFT));+        return PARSE_STATE_RET;+    }++    PARSE_CALL_SAVE1(s, 1, js_parse_logical_and_or, parse_flags - (1 << PF_LEVEL_SHIFT), parse_flags);++    level = (parse_flags & PF_LEVEL_MASK) >> PF_LEVEL_SHIFT;+    if (level == 1)+        op = TOK_LAND;+    else+        op = TOK_LOR;+    parse_flags &= ~PF_DROP;+    if (s->token.val == op) {+        label1 = new_label(s);++        for(;;) {+            next_token(s);+            emit_op(s, OP_dup);+            emit_goto(s, op == TOK_LAND ? OP_if_false : OP_if_true, &label1);+            emit_op(s, OP_drop);+            +            PARSE_PUSH_VAL(s, label1);+            PARSE_CALL_SAVE1(s, 2, js_parse_logical_and_or, parse_flags - (1 << PF_LEVEL_SHIFT), parse_flags);+            PARSE_POP_VAL(s, label1);++            level = (parse_flags & PF_LEVEL_MASK) >> PF_LEVEL_SHIFT;+            if (level == 1)+                op = TOK_LAND;+            else+                op = TOK_LOR;+            +            if (s->token.val != op)+                break;+        }++        emit_label(s, &label1);+    }+    return PARSE_STATE_RET;+}++static int js_parse_cond_expr(JSParseState *s, int state, int parse_flags)+{+    JSValue label1, label2;+    +    PARSE_START3();++    PARSE_CALL_SAVE1(s, 2, js_parse_logical_and_or, parse_flags | (2 << PF_LEVEL_SHIFT), parse_flags);+    +    parse_flags &= ~PF_DROP;+    if (s->token.val == '?') {+        next_token(s);+        label1 = new_label(s);+        emit_goto(s, OP_if_false, &label1);+        +        PARSE_PUSH_VAL(s, label1);+        PARSE_CALL_SAVE1(s, 0, js_parse_assign_expr, parse_flags,+                         parse_flags);+        PARSE_POP_VAL(s, label1);++        label2 = new_label(s);+        emit_goto(s, OP_goto, &label2);++        js_parse_expect(s, ':');+        +        emit_label(s, &label1);+        +        PARSE_PUSH_VAL(s, label2);+        PARSE_CALL_SAVE1(s, 1, js_parse_assign_expr, parse_flags,+                         parse_flags);+        PARSE_POP_VAL(s, label2);++        emit_label(s, &label2);+    }+    return PARSE_STATE_RET;+}++static int js_parse_assign_expr(JSParseState *s, int state, int parse_flags)+{+    int opcode, op, var_idx;+    PutLValueEnum special;+    JSSourcePos op_source_pos, source_pos;+    +    PARSE_START2();++    PARSE_CALL_SAVE1(s, 1, js_parse_cond_expr, parse_flags, parse_flags);+    +    op = s->token.val;+    if (op == '=' || (op >= TOK_MUL_ASSIGN && op <= TOK_OR_ASSIGN)) {+        op_source_pos = s->token.source_pos;+        next_token(s);+        get_lvalue(s, &opcode, &var_idx, &source_pos, (op != '='));++        PARSE_CALL_SAVE6(s, 0, js_parse_assign_expr, parse_flags & ~PF_DROP,+                         op, opcode, var_idx, parse_flags,+                         op_source_pos, source_pos);++        if (op != '=') {+            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,+                OP_pow,+            };+            emit_op_pos(s, assign_opcodes[op - TOK_MUL_ASSIGN], op_source_pos);+        }++        if (may_drop_result(s, parse_flags)) {+            special = PUT_LVALUE_NOKEEP_TOP;+            s->dropped_result = TRUE;+        } else {+            special = PUT_LVALUE_KEEP_TOP;+        }+        put_lvalue(s, opcode, var_idx, source_pos, special);+    }+    return PARSE_STATE_RET;+}++static int js_parse_expr_comma(JSParseState *s, int state, int parse_flags)+{+    BOOL comma = FALSE;++    PARSE_START1();++    for(;;) {+        s->dropped_result = FALSE;+        PARSE_CALL_SAVE2(s, 0, js_parse_assign_expr, parse_flags,+                         comma, parse_flags);+        if (comma) {+            /* prevent get_lvalue from using the last expression as an+               lvalue. */+            s->last_opcode_pos = -1;+        }+        if (s->token.val != ',')+            break;+        comma = TRUE;+        if (!s->dropped_result)+            emit_op(s, OP_drop);+        next_token(s);+    }+    if ((parse_flags & PF_DROP) && !s->dropped_result) {+        emit_op(s, OP_drop);+    }+    return PARSE_STATE_RET;+}++static void js_parse_assign_expr2(JSParseState *s, int parse_flags)+{+    js_parse_call(s, PARSE_FUNC_js_parse_assign_expr, parse_flags);+}++static void js_parse_expr2(JSParseState *s, int parse_flags)+{+    js_parse_call(s, PARSE_FUNC_js_parse_expr_comma, parse_flags);+}++static void js_parse_expr(JSParseState *s)+{+    js_parse_expr2(s, 0);+}++static void js_parse_expr_paren(JSParseState *s)+{+    js_parse_expect(s, '(');+    js_parse_expr(s);+    js_parse_expect(s, ')');+}++static BlockEnv *push_break_entry(JSParseState *s, JSValue label_name,+                                  JSValue label_break, JSValue label_cont,+                                  int drop_count)+{+    JSContext *ctx = s->ctx;+    JSGCRef label_name_ref;+    int ret, block_env_len;+    BlockEnv *be;+    +    block_env_len = sizeof(BlockEnv) / sizeof(JSValue);+    JS_PUSH_VALUE(ctx, label_name);+    ret = JS_StackCheck(ctx, block_env_len);+    JS_POP_VALUE(ctx, label_name);+    if (ret)+        js_parse_error_stack_overflow(s);+    ctx->sp -= block_env_len;+    be = (BlockEnv *)ctx->sp;+    be->prev = s->top_break;+    s->top_break = SP_TO_VALUE(ctx, be);+    be->label_name = label_name;+    be->label_break = label_break;+    be->label_cont = label_cont;+    be->label_finally = LABEL_NONE;+    be->drop_count = JS_NewShortInt(drop_count);+    return be;+}++static void pop_break_entry(JSParseState *s)+{+    JSContext *ctx = s->ctx;+    BlockEnv *be;+    +    be = VALUE_TO_SP(ctx, s->top_break);+    s->top_break = be->prev;+    ctx->sp += sizeof(BlockEnv) / sizeof(JSValue);+    ctx->stack_bottom = ctx->sp;+}++static void emit_return(JSParseState *s, BOOL hasval, JSSourcePos source_pos)+{+    JSValue top_val;+    BlockEnv *top;+    int i, drop_count;++    drop_count = 0;+    top_val = s->top_break;+    while (!JS_IsNull(top_val)) {+        top = VALUE_TO_SP(s->ctx, top_val);+        /* no need to drop if no "finally" */+        drop_count += JS_VALUE_GET_INT(top->drop_count); ++        if (!label_is_none(top->label_finally)) {+            if (!hasval) {+                emit_op(s, OP_undefined);+                hasval = TRUE;+            }+            for(i = 0; i < drop_count; i++)+                emit_op(s, OP_nip); /* must keep the stack stop */+            drop_count = 0;+            /* execute the "finally" block */+            emit_goto(s, OP_gosub, &top->label_finally);+        }+        top_val = top->prev;+    }+    emit_op_pos(s, hasval ? OP_return : OP_return_undef, source_pos);+}++static void emit_break(JSParseState *s, JSValue label_name, int is_cont)+{+    JSValue top_val;+    BlockEnv *top;+    int i;+    JSValue *plabel;+    JSGCRef label_name_ref;+    BOOL is_labelled_stmt;+    +    top_val = s->top_break;+    while (!JS_IsNull(top_val)) {+        top = VALUE_TO_SP(s->ctx, top_val);+        is_labelled_stmt = (top->label_cont == LABEL_NONE &&+                            JS_VALUE_GET_INT(top->drop_count) == 0);+        if ((label_name == JS_NULL && !is_labelled_stmt) ||+            top->label_name == label_name) {+            if (is_cont)+                plabel = &top->label_cont;+            else+                plabel = &top->label_break;+            if (!label_is_none(*plabel)) {+                emit_goto(s, OP_goto, plabel);+                return;+            }+        }+        JS_PUSH_VALUE(s->ctx, label_name);+        for(i = 0; i < JS_VALUE_GET_INT(top->drop_count); i++)+            emit_op(s, OP_drop);+        if (!label_is_none(top->label_finally)) {+            /* must push dummy value to keep same stack depth */+            emit_op(s, OP_undefined);+            emit_goto(s, OP_gosub, &top->label_finally);+            emit_op(s, OP_drop);+        }+        JS_POP_VALUE(s->ctx, label_name);+        top_val = top->prev;+    }+    if (label_name == JS_NULL) {+        if (is_cont)+            js_parse_error(s, "continue must be inside loop");+        else+            js_parse_error(s, "break must be inside loop or switch");+    } else {+        js_parse_error(s, "break/continue label not found");+    }+}++static int define_var(JSParseState *s, JSVarRefKindEnum *pvar_kind, JSValue name)+{+    JSVarRefKindEnum var_kind;+    int var_idx;++    if (s->is_eval) {+        var_idx = find_ext_var(s, name);+        if (var_idx < 0) {+            var_idx = add_ext_var(s, name, (JS_VARREF_KIND_GLOBAL << 16) | 1);+        } else {+            JSFunctionBytecode *b = JS_VALUE_TO_PTR(s->cur_func);+            JSValueArray *arr = JS_VALUE_TO_PTR(b->ext_vars);+            arr->arr[2 * var_idx + 1] = JS_NewShortInt((JS_VARREF_KIND_GLOBAL << 16) | 1);+        }+        var_kind = JS_VARREF_KIND_VAR_REF;+    } else {+        JSFunctionBytecode *b;+        int arg_count;++        b = JS_VALUE_TO_PTR(s->cur_func);+        arg_count = b->arg_count;+        +        var_idx = find_var(s, name);+        if (var_idx >= 0) {+            if (var_idx < arg_count) {+                var_kind = JS_VARREF_KIND_ARG;+            } else {+                var_kind = JS_VARREF_KIND_VAR;+                var_idx -= arg_count;+            }+        } else {+            var_idx = add_var(s, name);+            var_kind = JS_VARREF_KIND_VAR;+            var_idx -= arg_count;+        }+    }+    *pvar_kind = var_kind;+    return var_idx;+}++static void put_var(JSParseState *s, JSVarRefKindEnum var_kind, int var_idx, JSSourcePos source_pos)+{+    int opcode;+    if (var_kind == JS_VARREF_KIND_ARG)+        opcode = OP_put_arg;+    else if (var_kind == JS_VARREF_KIND_VAR)+        opcode = OP_put_loc;+    else+        opcode = OP_put_var_ref_nocheck;+    emit_var(s, opcode, var_idx, source_pos);+}++static void js_parse_var(JSParseState *s, BOOL in_accepted)+{+    JSVarRefKindEnum var_kind;+    int var_idx;+    JSSourcePos ident_source_pos;+    +    for(;;) {+        ident_source_pos = s->token.source_pos;+        if (s->token.val != TOK_IDENT)+            js_parse_error(s, "variable name expected");+        if (s->token.value == js_get_atom(s->ctx, JS_ATOM_arguments))+            js_parse_error(s, "invalid variable name");+        var_idx = define_var(s, &var_kind, s->token.value);+        next_token(s);+        if (s->token.val == '=') {+            next_token(s);+            js_parse_assign_expr2(s, in_accepted ? 0 : PF_NO_IN);+            put_var(s, var_kind, var_idx, ident_source_pos);+        }+        if (s->token.val != ',')+            break;+        next_token(s);+    }+}++static void set_eval_ret_undefined(JSParseState *s)+{+    if (s->eval_ret_idx >= 0) {+        emit_op(s, OP_undefined);+        emit_var(s, OP_put_loc, s->eval_ret_idx, s->pc2line_source_pos);+    }+}++static int js_parse_block(JSParseState *s, int state, int dummy_param)+{+    PARSE_START1();+    js_parse_expect(s, '{');+    if (s->token.val != '}') {+        for(;;) {+            PARSE_CALL(s, 0, js_parse_statement, 0);+            if (s->token.val == '}')+                break;+        }+    }+    next_token(s);+    return PARSE_STATE_RET;+}++/* The statement parser assumes that the stack contains the result of+   the last statement. Note: if not in eval code, the return value of+   a statement does not matter */+static int js_parse_statement(JSParseState *s, int state, int dummy_param)+{+    JSValue label_name;+    JSGCRef label_name_ref;+    +    PARSE_START12();+    +    /* specific label handling */+    if (is_label(s)) {+        JSValue top_val;+        BlockEnv *top;+        +        label_name = s->token.value;+        JS_PUSH_VALUE(s->ctx, label_name);+        next_token(s);+        js_parse_expect(s, ':');+        JS_POP_VALUE(s->ctx, label_name);++        for(top_val = s->top_break; !JS_IsNull(top_val); top_val = top->prev) {+            top = VALUE_TO_SP(s->ctx, top_val);+            if (top->label_name == label_name)+                js_parse_error(s, "duplicate label name");+        }++        if (s->token.val != TOK_FOR &&+            s->token.val != TOK_DO &&+            s->token.val != TOK_WHILE) {+            /* labelled regular statement */+            BlockEnv *be;+            push_break_entry(s, label_name, new_label(s), LABEL_NONE, 0);++            PARSE_CALL(s, 11, js_parse_statement, 0);++            be = VALUE_TO_SP(s->ctx, s->top_break);+            emit_label(s, &be->label_break);+            pop_break_entry(s);+            goto done;+        }+    } else {+        label_name = JS_NULL;+    }+    +    switch(s->token.val) {+    case '{':+        PARSE_CALL(s, 0, js_parse_block, 0);+        break;+    case TOK_RETURN:+        {+            BOOL has_val;+            JSSourcePos op_source_pos;+            if (s->is_eval)+                js_parse_error(s, "return not in a function");+            op_source_pos = s->token.source_pos;+            next_token(s);+            if (s->token.val != ';' && s->token.val != '}' && !s->got_lf) {+                js_parse_expr(s);+                has_val = TRUE;+            } else {+                has_val = FALSE;+            }+            emit_return(s, has_val, op_source_pos);+            js_parse_expect_semi(s);+        }+        break;+    case TOK_THROW:+        {+            JSSourcePos op_source_pos;+            op_source_pos = s->token.source_pos;+            next_token(s);+            if (s->got_lf)+                js_parse_error(s, "line terminator not allowed after throw");+            js_parse_expr(s);+            emit_op_pos(s, OP_throw, op_source_pos);+            js_parse_expect_semi(s);+        }+        break;+    case TOK_VAR:+        next_token(s);+        js_parse_var(s, TRUE);+        js_parse_expect_semi(s);+        break;+    case TOK_IF:+        {+            JSValue label1, label2;+            next_token(s);+            set_eval_ret_undefined(s);+            js_parse_expr_paren(s);+            label1 = new_label(s);+            emit_goto(s, OP_if_false, &label1);++            PARSE_PUSH_VAL(s, label1);+            PARSE_CALL(s, 1, js_parse_statement, 0);+            PARSE_POP_VAL(s, label1);+            +            if (s->token.val == TOK_ELSE) {+                next_token(s);+                +                label2 = new_label(s);+                emit_goto(s, OP_goto, &label2);++                emit_label(s, &label1);+                +                PARSE_PUSH_VAL(s, label2);+                PARSE_CALL(s, 2, js_parse_statement, 0);+                PARSE_POP_VAL(s, label2);+                +                label1 = label2;+            }+            emit_label(s, &label1);+        }+        break;+    case TOK_WHILE:+        {+            BlockEnv *be;+            +            be = push_break_entry(s, label_name, new_label(s), new_label(s), 0);+            next_token(s);++            set_eval_ret_undefined(s);++            emit_label(s, &be->label_cont);+            js_parse_expr_paren(s);+            emit_goto(s, OP_if_false, &be->label_break);+            +            PARSE_CALL(s, 3, js_parse_statement, 0);++            be = VALUE_TO_SP(s->ctx, s->top_break);+            emit_goto(s, OP_goto, &be->label_cont);++            emit_label(s, &be->label_break);++            pop_break_entry(s);+        }+        break;+    case TOK_DO:+        {+            JSValue label1;+            BlockEnv *be;++            be = push_break_entry(s, label_name, new_label(s), new_label(s), 0);+            +            label1 = new_label(s);+            +            next_token(s);+            set_eval_ret_undefined(s);++            emit_label(s, &label1);++            PARSE_PUSH_VAL(s, label1);+            PARSE_CALL(s, 4, js_parse_statement, 0);+            PARSE_POP_VAL(s, label1);++            be = VALUE_TO_SP(s->ctx, s->top_break);+            emit_label(s, &be->label_cont);+            js_parse_expect(s, TOK_WHILE);+            js_parse_expr_paren(s);+            /* Insert semicolon if missing */+            if (s->token.val == ';') {+                next_token(s);+            }+            emit_goto(s, OP_if_true, &label1);++            emit_label(s, &be->label_break);++            pop_break_entry(s);+        }+        break;+    case TOK_FOR:+        {+            int bits;+            BlockEnv *be;+            +            be = push_break_entry(s, label_name, new_label(s), new_label(s), 0);+            +            next_token(s);+            set_eval_ret_undefined(s);++            js_parse_expect1(s, '(');+            bits = js_parse_skip_parens_token(s);+            next_token(s);+            +            if (!(bits & SKIP_HAS_SEMI)) {+                JSValue label_expr, label_body, label_next;+                int opcode, var_idx;+                +                be->drop_count = JS_NewShortInt(1);+                +                label_expr = new_label(s);+                label_body = new_label(s);+                label_next = new_label(s);+                +                emit_goto(s, OP_goto, &label_expr);+                +                emit_label(s, &label_next);+                +                if (s->token.val == TOK_VAR) {+                    JSVarRefKindEnum var_kind;+                    next_token(s);+                    var_idx = define_var(s, &var_kind, s->token.value);+                    put_var(s, var_kind, var_idx, s->pc2line_source_pos);+                    +                    next_token(s);+                } else {+                    JSSourcePos source_pos;+                    +                    /* XXX: js_parse_left_hand_side_expr */+                    js_parse_assign_expr2(s, PF_NO_IN);+                    +                    get_lvalue(s, &opcode, &var_idx, &source_pos, FALSE);+                    put_lvalue(s, opcode, var_idx, source_pos,+                               PUT_LVALUE_NOKEEP_BOTTOM);+                }+                +                emit_goto(s, OP_goto, &label_body);+                +                if (s->token.val == TOK_IN) {+                    opcode = OP_for_in_start;+                } else if (s->token.val == TOK_IDENT &&+                           s->token.value == js_get_atom(s->ctx, JS_ATOM_of)) {+                    opcode = OP_for_of_start;+                } else {+                    js_parse_error(s, "expected 'of' or 'in' in for control expression");+                }+                +                next_token(s);+                +                emit_label(s, &label_expr);+                js_parse_expr(s);+                emit_op(s, opcode);+                +                emit_goto(s, OP_goto, &be->label_cont);+                +                js_parse_expect(s, ')');+                +                emit_label(s, &label_body);+                +                PARSE_PUSH_VAL(s, label_next);+                PARSE_CALL(s, 5, js_parse_statement, 0);+                PARSE_POP_VAL(s, label_next);+                +                be = VALUE_TO_SP(s->ctx, s->top_break);+                emit_label(s, &be->label_cont);+                emit_op(s, OP_for_of_next);+                +                /* on stack: enum_rec / enum_obj value bool */+                emit_goto(s, OP_if_false, &label_next);+                /* drop the undefined value from for_xx_next */+                emit_op(s, OP_drop);++                emit_label(s, &be->label_break);+                emit_op(s, OP_drop);+            } else {+                JSValue label_test;+                JSParsePos expr3_pos;+                int tmp_val;+                +                /* initial expression */+                if (s->token.val != ';') {+                    if (s->token.val == TOK_VAR) {+                        next_token(s);+                        js_parse_var(s, FALSE);+                    } else {+                        js_parse_expr2(s, PF_NO_IN | PF_DROP);+                    }+                }+                js_parse_expect(s, ';');+                +                label_test = new_label(s);+                +                /* test expression */+                emit_label(s, &label_test);+                if (s->token.val != ';') {+                    js_parse_expr(s);+                    emit_goto(s, OP_if_false, &be->label_break);+                }+                js_parse_expect(s, ';');++                if (s->token.val != ')') {+                    /* skip the third expression if present */+                    js_parse_get_pos(s, &expr3_pos);+                    js_skip_expr(s);+                } else {+                    expr3_pos.source_pos = -1;+                    expr3_pos.got_lf = 0; /* avoid warning */+                    expr3_pos.regexp_allowed = 0; /* avoid warning */+                }+                js_parse_expect(s, ')');++                PARSE_PUSH_VAL(s, label_test);+                PARSE_PUSH_INT(s, expr3_pos.got_lf | (expr3_pos.regexp_allowed << 1));+                PARSE_PUSH_INT(s, expr3_pos.source_pos);+                PARSE_CALL(s, 6, js_parse_statement, 0);+                PARSE_POP_INT(s, expr3_pos.source_pos);+                PARSE_POP_INT(s, tmp_val);+                expr3_pos.got_lf = tmp_val & 1;+                expr3_pos.regexp_allowed = tmp_val >> 1;+                PARSE_POP_VAL(s, label_test);+                +                be = VALUE_TO_SP(s->ctx, s->top_break);+                emit_label(s, &be->label_cont);++                /* parse the third expression, if present, after the+                   statement */+                if (expr3_pos.source_pos != -1) {+                    JSParsePos end_pos;+                    js_parse_get_pos(s, &end_pos);+                    js_parse_seek_token(s, &expr3_pos);+                    js_parse_expr2(s, PF_DROP);+                    js_parse_seek_token(s, &end_pos);+                }++                emit_goto(s, OP_goto, &label_test);+                +                be = VALUE_TO_SP(s->ctx, s->top_break);+                emit_label(s, &be->label_break);+            }+            pop_break_entry(s);+        }+        break;+    case TOK_BREAK:+    case TOK_CONTINUE:+        {+            int is_cont = (s->token.val == TOK_CONTINUE);+            JSValue label_name;+            +            next_token(s);+            if (!s->got_lf && s->token.val == TOK_IDENT)+                label_name = s->token.value;+            else+                label_name = JS_NULL;+            emit_break(s, label_name, is_cont);+            if (label_name != JS_NULL) {+                next_token(s);+            }+            js_parse_expect_semi(s);+        }+        break;+    case TOK_SWITCH:+        {+            JSValue label_case;+            int default_label_pos;+            BlockEnv *be;++            be = push_break_entry(s, label_name, new_label(s), LABEL_NONE, 1);++            next_token(s);+            set_eval_ret_undefined(s);++            js_parse_expr_paren(s);++            js_parse_expect(s, '{');+            default_label_pos = -1;+            label_case = LABEL_NONE; /* label to the next case */+            while (s->token.val != '}') {+                if (s->token.val == TOK_CASE) {+                    JSValue label1 = LABEL_NONE;+                    if (!label_is_none(label_case)) {+                        /* skip the case if needed */+                        label1 = new_label(s);+                        emit_goto(s, OP_goto, &label1);+                        emit_label(s, &label_case);+                        label_case = LABEL_NONE;+                    }+                    for (;;) {+                        /* parse a sequence of case clauses */+                        next_token(s);+                        emit_op(s, OP_dup);+                        js_parse_expr(s);+                        js_parse_expect(s, ':');+                        emit_op(s, OP_strict_eq);+                        if (s->token.val == TOK_CASE) {+                            if (label_is_none(label1))+                                label1 = new_label(s);+                            emit_goto(s, OP_if_true, &label1);+                        } else {+                            label_case = new_label(s);+                            emit_goto(s, OP_if_false, &label_case);+                            if (!label_is_none(label1))+                                emit_label(s, &label1);+                            break;+                        }+                    }+                } else if (s->token.val == TOK_DEFAULT) {+                    next_token(s);+                    js_parse_expect(s, ':');+                    if (default_label_pos >= 0)+                        js_parse_error(s, "duplicate default");+                    if (label_is_none(label_case)) {+                        /* falling thru direct from switch expression */+                        label_case = new_label(s);+                        emit_goto(s, OP_goto, &label_case);+                    }+                    default_label_pos = s->byte_code_len; +                } else {+                    if (label_is_none(label_case))+                        js_parse_error(s, "invalid switch statement");+                    PARSE_PUSH_VAL(s, label_case);+                    PARSE_CALL_SAVE1(s, 7, js_parse_statement, 0,+                                     default_label_pos);+                    PARSE_POP_VAL(s, label_case);+                }+            }+            js_parse_expect(s, '}');+            if (default_label_pos >= 0) {+                /* patch the default label */+                emit_label_pos(s, &label_case, default_label_pos);+            } else if (!label_is_none(label_case)) {+                emit_label(s, &label_case);+            }+            be = VALUE_TO_SP(s->ctx, s->top_break);+            emit_label(s, &be->label_break);+            emit_op(s, OP_drop); /* drop the switch expression */++            pop_break_entry(s);+        }+        break;+    case TOK_TRY:+        {+            JSValue label_catch, label_finally, label_end;+            BlockEnv *be;+            +            set_eval_ret_undefined(s);+            next_token(s);+            label_catch = new_label(s);+            label_finally = new_label(s);++            emit_goto(s, OP_catch, &label_catch);+            +            be = push_break_entry(s, JS_NULL, LABEL_NONE, LABEL_NONE, 1);+            be->label_finally = label_finally;++            PARSE_PUSH_VAL(s, label_catch);+            PARSE_CALL(s, 8, js_parse_block, 0);+            PARSE_POP_VAL(s, label_catch);++            be = VALUE_TO_SP(s->ctx, s->top_break);+            label_finally = be->label_finally;+            pop_break_entry(s);++            /* drop the catch offset */+            emit_op(s, OP_drop);++            /* must push dummy value to keep same stack size */+            emit_op(s, OP_undefined);+            emit_goto(s, OP_gosub, &label_finally);+            emit_op(s, OP_drop);++            label_end = new_label(s);+            emit_goto(s, OP_goto, &label_end);+            +            if (s->token.val == TOK_CATCH) {+                JSValue label_catch2;+                int var_idx;+                JSValue name;++                label_catch2 = new_label(s);++                next_token(s);+                js_parse_expect(s, '(');+                if (s->token.val != TOK_IDENT)+                    js_parse_error(s, "identifier expected");+                name = s->token.value;+                /* XXX: the local scope is not implemented, so we add+                   a normal variable */+                if (find_var(s, name) >= 0 || find_ext_var(s, name) >= 0) {+                    js_parse_error(s, "catch variable already exists");+                }+                var_idx = add_var(s, name);+                next_token(s);+                js_parse_expect(s, ')');+                +                /* store the exception value in the variable */+                emit_label(s, &label_catch);+                {+                    JSFunctionBytecode *b = JS_VALUE_TO_PTR(s->cur_func);+                    emit_var(s, OP_put_loc, var_idx - b->arg_count, s->pc2line_source_pos);+                }++                emit_goto(s, OP_catch, &label_catch2);+                +                be = push_break_entry(s, JS_NULL, LABEL_NONE, LABEL_NONE, 1);+                be->label_finally = label_finally;+                +                PARSE_PUSH_VAL(s, label_end);+                PARSE_PUSH_VAL(s, label_catch2);+                PARSE_CALL(s, 9, js_parse_block, 0);+                PARSE_POP_VAL(s, label_catch2);+                PARSE_POP_VAL(s, label_end);++                be = VALUE_TO_SP(s->ctx, s->top_break);+                label_finally = be->label_finally;+                pop_break_entry(s);++                /* drop the catch2 offset */+                emit_op(s, OP_drop);+                /* must push dummy value to keep same stack size */+                emit_op(s, OP_undefined);+                emit_goto(s, OP_gosub, &label_finally);+                emit_op(s, OP_drop);+                emit_goto(s, OP_goto, &label_end);++                /* catch exceptions thrown in the catch block to execute the+                 * finally clause and rethrow the exception */+                emit_label(s, &label_catch2);+                /* catch value is at TOS, no need to push undefined */+                emit_goto(s, OP_gosub, &label_finally);+                emit_op(s, OP_throw);+                +            } else if (s->token.val == TOK_FINALLY) {+                /* finally without catch : execute the finally clause+                 * and rethrow the exception */+                emit_label(s, &label_catch);+                /* catch value is at TOS, no need to push undefined */+                emit_goto(s, OP_gosub, &label_finally);+                emit_op(s, OP_throw);+            } else {+                js_parse_error(s, "expecting catch or finally");+            }++            emit_label(s, &label_finally);+            if (s->token.val == TOK_FINALLY) {+                next_token(s);+                /* XXX: we don't return the correct value in eval() */+                /* on the stack: ret_value gosub_ret_value */+                push_break_entry(s, JS_NULL, LABEL_NONE, LABEL_NONE, 2);++                PARSE_PUSH_VAL(s, label_end);+                PARSE_CALL(s, 10, js_parse_block, 0);+                PARSE_POP_VAL(s, label_end);++                pop_break_entry(s);+            }+            emit_op(s, OP_ret);+            emit_label(s, &label_end);+        }+        break;+    case ';':+        /* empty statement */+        next_token(s);+        break;+    default:+        if (s->eval_ret_idx >= 0) {+            /* store the expression value so that it can be returned+               by eval() */+            js_parse_expr(s);+            emit_var(s, OP_put_loc, s->eval_ret_idx, s->pc2line_source_pos);+        } else {+            js_parse_expr2(s, PF_DROP);+        }+        js_parse_expect_semi(s);+        break;+    }+ done:+    return PARSE_STATE_RET;+}++static JSParseFunc *parse_func_table[] = {+    js_parse_expr_comma,+    js_parse_assign_expr,+    js_parse_cond_expr,+    js_parse_logical_and_or,+    js_parse_expr_binary,+    js_parse_unary,+    js_parse_postfix_expr,+    js_parse_statement,+    js_parse_block,+    js_parse_json_value,+    re_parse_alternative,+    re_parse_disjunction,+};++static void js_parse_source_element(JSParseState *s)+{+    if (s->token.val == TOK_FUNCTION) {+        js_parse_function_decl(s, JS_PARSE_FUNC_STATEMENT, JS_NULL);+    } else {+        js_parse_call(s, PARSE_FUNC_js_parse_statement, 0);+    }+}+    +static JSFunctionBytecode *js_alloc_function_bytecode(JSContext *ctx)+{+    JSFunctionBytecode *b;+    b = js_mallocz(ctx, sizeof(JSFunctionBytecode), JS_MTAG_FUNCTION_BYTECODE);+    if (!b)+        return NULL;+    b->func_name = JS_NULL;+    b->byte_code = JS_NULL;+    b->cpool = JS_NULL;+    b->vars = JS_NULL;+    b->ext_vars = JS_NULL;+    b->filename = JS_NULL;+    b->pc2line = JS_NULL;+    return b;+}++/* the current token must be TOK_FUNCTION for JS_PARSE_FUNC_STATEMENT+   or JS_PARSE_FUNC_EXPR. Otherwise it is '('. */+static void js_parse_function_decl(JSParseState *s,+                                   JSParseFunctionEnum func_type, JSValue func_name)+{+    JSContext *ctx = s->ctx;+    BOOL is_expr;+    JSFunctionBytecode *b;+    int idx, skip_bits;+    JSVarRefKindEnum var_kind;+    JSValue bfunc;+    JSGCRef func_name_ref, bfunc_ref;+    +    is_expr = (func_type != JS_PARSE_FUNC_STATEMENT);++    if (func_type == JS_PARSE_FUNC_STATEMENT ||+        func_type == JS_PARSE_FUNC_EXPR) {+        next_token(s);+        if (s->token.val != TOK_IDENT && !is_expr)+            js_parse_error(s, "function name expected");+        if (s->token.val == TOK_IDENT) {+            func_name = s->token.value;+            JS_PUSH_VALUE(ctx, func_name);+            next_token(s);+            JS_POP_VALUE(ctx, func_name);+        }+    }++    JS_PUSH_VALUE(ctx, func_name);+    b = js_alloc_function_bytecode(s->ctx);+    if (!b)+        js_parse_error_mem(s);+    bfunc = JS_VALUE_FROM_PTR(b);+    JS_PUSH_VALUE(ctx, bfunc);++    b->filename = s->filename_str;+    b->func_name = func_name_ref.val;+    b->source_pos = s->token.source_pos;+    b->has_column = s->has_column;+    +    js_parse_expect1(s, '(');+    /* skip the arguments */+    js_skip_parens(s, NULL);+    +    js_parse_expect1(s, '{');++    /* skip the code */+    skip_bits = js_skip_parens(s, is_expr ? &func_name_ref.val : NULL);+                  +    b = JS_VALUE_TO_PTR(bfunc_ref.val);+    b->has_arguments = ((skip_bits & SKIP_HAS_ARGUMENTS) != 0);+    b->has_local_func_name = ((skip_bits & SKIP_HAS_FUNC_NAME) != 0);+    +    idx = cpool_add(s, bfunc_ref.val);+    if (is_expr) {+        /* create the function object */+        emit_op(s, OP_fclosure);+        emit_u16(s, idx);+    } else {+        idx = define_var(s, &var_kind, func_name_ref.val);+        /* size of hoisted for OP_fclosure + OP_put_loc/OP_put_arg/OP_put_ref */+        s->hoisted_code_len += 3 + 3;+        if (var_kind == JS_VARREF_KIND_VAR) {+            b = JS_VALUE_TO_PTR(s->cur_func);+            idx += b->arg_count;+        }+        b = JS_VALUE_TO_PTR(bfunc_ref.val);+        /* hoisted function definition: save the variable index to+           define it at the start of the function */+        b->arg_count = idx + 1;+    }+    JS_POP_VALUE(ctx, bfunc);+    JS_POP_VALUE(ctx, func_name);+}++static void define_hoisted_functions(JSParseState *s, BOOL is_eval)+{+    JSValueArray *cpool;+    JSValue val;+    JSFunctionBytecode *b;+    int idx, saved_byte_code_len, arg_count, i, op;+    +    /* add pc2line info */+    b = JS_VALUE_TO_PTR(s->cur_func);+    if (b->pc2line != JS_NULL) {+        int h, n;++        /* byte align */+        n = (-s->pc2line_bit_len) & 7;+        if (n != 0)+            pc2line_put_bits(s, n, 0);++        n = s->hoisted_code_len;+        h = 0;+        for(;;) {+            pc2line_put_bits(s, 8, (n & 0x7f) | h);+            n >>= 7;+            if (n == 0)+                break;+            h |= 0x80;+        }+    }++    if (s->hoisted_code_len == 0)+        return;+    emit_insert(s, 0, s->hoisted_code_len);++    b = JS_VALUE_TO_PTR(s->cur_func);+    arg_count = b->arg_count;++    saved_byte_code_len = s->byte_code_len;+    s->byte_code_len = 0;+    cpool = JS_VALUE_TO_PTR(b->cpool);+    for(i = 0; i < s->cpool_len; i++) {+        val = cpool->arr[i];+        if (JS_IsPtr(val)) {+            b = JS_VALUE_TO_PTR(val);+            if (b->mtag == JS_MTAG_FUNCTION_BYTECODE &&+                b->arg_count != 0) {+                idx = b->arg_count - 1;+                /* XXX: could use smaller opcodes */+                if (is_eval) {+                    op = OP_put_var_ref_nocheck;+                } else if (idx < arg_count) {+                    op = OP_put_arg;+                } else {+                    idx -= arg_count;+                    op = OP_put_loc;+                }+                /* no realloc possible here */+                emit_u8(s, OP_fclosure);+                emit_u16(s, i);++                emit_u8(s, op);+                emit_u16(s, idx);+            }+        }+    }+    s->byte_code_len = saved_byte_code_len;+}++static void js_parse_function(JSParseState *s)+{+    JSFunctionBytecode *b;+    int arg_count;+    +    next_token(s);++    js_parse_expect(s, '(');++    while (s->token.val != ')') {+        JSValue name;+        /* XXX: gc */+        if (s->token.val != TOK_IDENT)+            js_parse_error(s, "missing formal parameter");+        name = s->token.value;+        if (name == js_get_atom(s->ctx, JS_ATOM_eval) ||+            name == js_get_atom(s->ctx, JS_ATOM_arguments)) {+            js_parse_error(s, "invalid argument name");+        }+        if (find_var(s, name) >= 0)+            js_parse_error(s, "duplicate argument name");+        add_var(s, name);+        next_token(s);+        if (s->token.val == ')')+            break;+        js_parse_expect(s, ',');+    }+    b = JS_VALUE_TO_PTR(s->cur_func);+    arg_count = b->arg_count = s->local_vars_len;++    next_token(s);+    +    js_parse_expect(s, '{');++    /* initialize the arguments */+    b = JS_VALUE_TO_PTR(s->cur_func);+    if (b->has_arguments) {+        int var_idx;+        var_idx = add_var(s, js_get_atom(s->ctx, JS_ATOM_arguments));+        emit_op(s, OP_arguments);+        put_var(s, JS_VARREF_KIND_VAR, var_idx - arg_count, s->pc2line_source_pos);+    }++    /* XXX: initialize the function name */+    b = JS_VALUE_TO_PTR(s->cur_func);+    if (b->has_local_func_name) {+        int var_idx;+        /* XXX: */+        var_idx = add_var(s, b->func_name);+        emit_op(s, OP_this_func);+        put_var(s, JS_VARREF_KIND_VAR, var_idx - arg_count, s->pc2line_source_pos);+    }+    +    while (s->token.val != '}') {+        js_parse_source_element(s);+    }++    if (js_is_live_code(s))+        emit_op(s, OP_return_undef);++    next_token(s);++    define_hoisted_functions(s, FALSE);+    +    /* save the bytecode to the function */+    b = JS_VALUE_TO_PTR(s->cur_func);+    b->byte_code = s->byte_code;+}++static void js_parse_program(JSParseState *s)+{+    JSFunctionBytecode *b;++    next_token(s);++    /* hidden variable for the return value */+    if (s->has_retval) {+        s->eval_ret_idx = add_var(s, js_get_atom(s->ctx, JS_ATOM__ret_));+    }+    +    while (s->token.val != TOK_EOF) {+        js_parse_source_element(s);+    }++    if (s->eval_ret_idx >= 0) {+        emit_var(s, OP_get_loc, s->eval_ret_idx, s->pc2line_source_pos);+        emit_op(s, OP_return);+    } else {+        emit_op(s, OP_return_undef);+    }++    define_hoisted_functions(s, TRUE);++    /* save the bytecode to the function */+    b = JS_VALUE_TO_PTR(s->cur_func);+    b->byte_code = s->byte_code;+}++#define CVT_VAR_SIZE_MAX 16++typedef struct {+    uint16_t new_var_idx; /* new local var index */+    uint8_t is_local;+} ConvertVarEntry;++static void convert_ext_vars_to_local_vars_bytecode(JSParseState *s,+                                                    uint8_t *byte_code, int byte_code_len,+                                                    int var_start, const ConvertVarEntry *cvt_tab,+                                                    int tab_len)+{+    int pos, var_end, j, op, var_idx;+    const JSOpCode *oi;+    +    var_end = var_start + tab_len;+    pos = 0;+    while (pos < byte_code_len) {+        op = byte_code[pos];+        oi = &opcode_info[op];+        switch(op) {+        case OP_get_var_ref:+        case OP_put_var_ref:+        case OP_get_var_ref_nocheck:+        case OP_put_var_ref_nocheck:+            var_idx = get_u16(byte_code + pos + 1);+            if (var_idx >= var_start && var_idx < var_end) {+                j = var_idx - var_start;+                put_u16(byte_code + pos + 1, cvt_tab[j].new_var_idx);+                if (cvt_tab[j].is_local) {+                    if (op == OP_get_var_ref || op == OP_get_var_ref_nocheck) {+                        byte_code[pos] = OP_get_loc;+                    } else {+                        byte_code[pos] = OP_put_loc;+                    }+                }+            }+            break;+        default:+            break;+        }+        pos += oi->size;+    }+}++/* no allocation */+static void convert_ext_vars_to_local_vars(JSParseState *s)+{+    JSValueArray *ext_vars;+    JSFunctionBytecode *b;+    JSByteArray *bc_arr;+    JSValue var_name, decl;+    int i0, i, j, var_idx, l;+    ConvertVarEntry cvt_tab[CVT_VAR_SIZE_MAX];+    +    b = JS_VALUE_TO_PTR(s->cur_func);+    if (s->local_vars_len == 0 || b->ext_vars_len == 0)+        return;+    bc_arr = JS_VALUE_TO_PTR(b->byte_code);+    ext_vars = JS_VALUE_TO_PTR(b->ext_vars);++    /* do it by parts to save memory */+    j = 0;+    for(i0 = 0; i0 < b->ext_vars_len; i0 += CVT_VAR_SIZE_MAX) {+        l = min_int(b->ext_vars_len - i0, CVT_VAR_SIZE_MAX);+        for(i = 0; i < l; i++) {+            var_name = ext_vars->arr[2 * (i0 + i)];+            decl = ext_vars->arr[2 * (i0 + i) + 1];+            var_idx = find_var(s, var_name);+            /* fail safe: we avoid arguments even if they cannot appear */+            if (var_idx >= b->arg_count) {+                cvt_tab[i].new_var_idx = var_idx - b->arg_count;+                cvt_tab[i].is_local = TRUE;+            } else {+                cvt_tab[i].new_var_idx = j;+                cvt_tab[i].is_local = FALSE;+                ext_vars->arr[2 * j] = var_name;+                ext_vars->arr[2 * j + 1] = decl;+                j++;+            }+        }+        if (j != (i0 + l)) {+            convert_ext_vars_to_local_vars_bytecode(s, bc_arr->buf, s->byte_code_len,+                                                    i0, cvt_tab, l);+        }+    }+    b->ext_vars_len = j;+}++/* prepare the analysis of the code starting at position 'pos' */+static void compute_stack_size_push(JSParseState *s, +                                    JSByteArray *arr,+                                    uint8_t *explore_tab,+                                    uint32_t pos, int stack_len)+{+    int short_stack_len;+    +#if 0+    js_printf(s->ctx, "%5d: %d\n", pos, stack_len);+#endif+    if (pos >= (uint32_t)arr->size)+        js_parse_error(s, "bytecode buffer overflow (pc=%d)", pos);+    /* XXX: could avoid the division */+    short_stack_len = 1 + ((unsigned)stack_len % 255);+    if (explore_tab[pos] != 0) {+        /* already explored: check that the stack size is consistent */+        if (explore_tab[pos] != short_stack_len) {+            js_parse_error(s, "inconsistent stack size: %d %d (pc=%d)", explore_tab[pos] - 1, short_stack_len - 1, (int)pos);+        }+    } else {+        explore_tab[pos] = short_stack_len;+        /* may initiate a GC */+        PARSE_PUSH_INT(s, pos);+        PARSE_PUSH_INT(s, stack_len);+    }+}++static void compute_stack_size(JSParseState *s, JSValue *pfunc)+{+    JSContext *ctx = s->ctx;+    JSByteArray *explore_arr, *arr;+    JSFunctionBytecode *b;+    uint8_t *explore_tab;+    JSValue *stack_top, explore_arr_val;+    uint32_t pos;+    int op, op_len, pos1, n_pop, stack_len;+    const JSOpCode *oi;+    JSGCRef explore_arr_val_ref;+    +    b = JS_VALUE_TO_PTR(*pfunc);+    arr = JS_VALUE_TO_PTR(b->byte_code);++    explore_arr = js_alloc_byte_array(s->ctx, arr->size);+    if (!explore_arr)+        js_parse_error_mem(s);++    b = JS_VALUE_TO_PTR(*pfunc);+    arr = JS_VALUE_TO_PTR(b->byte_code);++    explore_arr_val = JS_VALUE_FROM_PTR(explore_arr);+    explore_tab = explore_arr->buf;+    memset(explore_tab, 0, arr->size);++    JS_PUSH_VALUE(ctx, explore_arr_val);++    stack_top = ctx->sp;++    compute_stack_size_push(s, arr, explore_tab, 0, 0);++    while (ctx->sp < stack_top) {+        PARSE_POP_INT(s, stack_len);+        PARSE_POP_INT(s, pos);+        +        /* compute_stack_size_push may have initiated a GC */+        b = JS_VALUE_TO_PTR(*pfunc);+        arr = JS_VALUE_TO_PTR(b->byte_code);+        explore_arr = JS_VALUE_TO_PTR(explore_arr_val_ref.val);+        explore_tab = explore_arr->buf;+        +        op = arr->buf[pos++];+        if (op == OP_invalid || op >= OP_COUNT)+            js_parse_error(s, "invalid opcode (pc=%d)", (int)(pos - 1));+        oi = &opcode_info[op];+        op_len = oi->size;+        if ((pos + op_len - 1) > arr->size) {+            js_parse_error(s, "bytecode buffer overflow (pc=%d)", (int)(pos - 1));+        }+        n_pop = oi->n_pop;+        if (oi->fmt == OP_FMT_npop)+            n_pop += get_u16(arr->buf + pos);++        if (stack_len < n_pop) {+            js_parse_error(s, "stack underflow (pc=%d)", (int)(pos - 1));+        }+        stack_len += oi->n_push - n_pop;+        if (stack_len > b->stack_size) {+            if (stack_len > JS_MAX_FUNC_STACK_SIZE)+                js_parse_error(s, "stack overflow (pc=%d)", (int)(pos - 1));+            b->stack_size = stack_len;+        }+        switch(op) {+        case OP_return:+        case OP_return_undef:+        case OP_throw:+        case OP_ret:+            goto done; /* no code after */+        case OP_goto:+            pos += get_u32(arr->buf + pos);+            break;+        case OP_if_true:+        case OP_if_false:+            pos1 = pos + get_u32(arr->buf + pos);+            compute_stack_size_push(s, arr, explore_tab, pos1, stack_len);+            pos += op_len - 1;+            break;+        case OP_gosub:+            pos1 = pos + get_u32(arr->buf + pos);+            compute_stack_size_push(s, arr, explore_tab, pos1, stack_len + 1);+            pos += op_len - 1;+            break;+        default:+            pos += op_len - 1;+            break;+        }+        compute_stack_size_push(s, arr, explore_tab, pos, stack_len);+    done: ;+    }++    JS_POP_VALUE(ctx, explore_arr_val);+    explore_arr = JS_VALUE_TO_PTR(explore_arr_val);+    js_free(s->ctx, explore_arr);+}++static void resolve_var_refs(JSParseState *s, JSValue *pfunc, JSValue *pparent_func)+{+    JSContext *ctx = s->ctx;+    int i, decl, var_idx, arg_count, ext_vars_len;+    JSValueArray *ext_vars;+    JSValue var_name;+    JSFunctionBytecode *b1, *b;++    b = JS_VALUE_TO_PTR(*pfunc);+    if (b->ext_vars_len == 0)+        return;+    b1 = JS_VALUE_TO_PTR(*pparent_func);+    arg_count = b1->arg_count;+    +    ext_vars = JS_VALUE_TO_PTR(b->ext_vars);+    ext_vars_len = b->ext_vars_len;+    +    for(i = 0; i < ext_vars_len; i++) {+        b = JS_VALUE_TO_PTR(*pfunc);+        ext_vars = JS_VALUE_TO_PTR(b->ext_vars);+        var_name = ext_vars->arr[2 * i];+        var_idx = find_func_var(ctx, *pparent_func, var_name);+        if (var_idx >= 0) {+            if (var_idx < arg_count) {+                decl = (JS_VARREF_KIND_ARG << 16) | var_idx;+            } else {+                decl = (JS_VARREF_KIND_VAR << 16) | (var_idx - arg_count);+            }+        } else {+            var_idx = find_func_ext_var(s, *pparent_func, var_name);+            if (var_idx < 0) {+                /* the global type may be patched later */+                var_idx = add_func_ext_var(s, *pparent_func, var_name,+                                           (JS_VARREF_KIND_GLOBAL << 16));+            }+            decl = (JS_VARREF_KIND_VAR_REF << 16) | var_idx;+        }+        b = JS_VALUE_TO_PTR(*pfunc);+        ext_vars = JS_VALUE_TO_PTR(b->ext_vars);+        ext_vars->arr[2 * i + 1] = JS_NewShortInt(decl);+    }+}++static void reset_parse_state(JSParseState *s, uint32_t input_pos,+                              JSValue cur_func)+{+    s->buf_pos = input_pos;+    s->token.val = ' ';++    s->cur_func = cur_func;+    s->byte_code = JS_NULL;+    s->byte_code_len = 0;+    s->last_opcode_pos = -1;++    s->pc2line_bit_len = 0;+    s->pc2line_source_pos = 0;+    +    s->cpool_len = 0;+    s->hoisted_code_len = 0;+    +    s->local_vars_len = 0;++    s->eval_ret_idx = -1;+}++static void js_parse_local_functions(JSParseState *s, JSValue *pfunc)+{+    JSContext *ctx = s->ctx;+    JSValue *pparent_func;+    JSValueArray *cpool;+    int err, cpool_pos;+    JSValue func;+    JSFunctionBytecode *b, *b1;+    JSGCRef func_ref;+    JSValue *stack_top;+    +    err = JS_StackCheck(ctx, 3);+    if (err)+        js_parse_error_stack_overflow(s);+    stack_top = ctx->sp;+    +    *--ctx->sp = JS_NULL; /* parent_func */+    *--ctx->sp = *pfunc; /* func */+    *--ctx->sp = JS_NewShortInt(0); /* cpool_pos */++    while (ctx->sp < stack_top) {+        pparent_func = &ctx->sp[2];+        pfunc = &ctx->sp[1];+        cpool_pos = JS_VALUE_GET_INT(ctx->sp[0]);+#if 0+        JS_DumpValue(ctx, "func", *pfunc);+        JS_DumpValue(ctx, "parent", *pparent_func);+        JS_DumpValue(ctx, "cpool_pos", ctx->sp[0]);+#endif+        if (cpool_pos == 0) {+            b = JS_VALUE_TO_PTR(*pfunc);+            +            convert_ext_vars_to_local_vars(s);+            +            js_shrink_byte_array(ctx, &b->byte_code, s->byte_code_len);+            js_shrink_value_array(ctx, &b->cpool, s->cpool_len);+            js_shrink_value_array(ctx, &b->vars, s->local_vars_len);+            js_shrink_byte_array(ctx, &b->pc2line, (s->pc2line_bit_len + 7) / 8);+            +            compute_stack_size(s, pfunc);+        }++        b = JS_VALUE_TO_PTR(*pfunc);+        if (b->cpool != JS_NULL) {+            int cpool_size;+            cpool = JS_VALUE_TO_PTR(b->cpool);+            cpool_size = cpool->size;+            for(; cpool_pos < cpool_size; cpool_pos++) {+                b = JS_VALUE_TO_PTR(*pfunc);+                cpool = JS_VALUE_TO_PTR(b->cpool);+                func = cpool->arr[cpool_pos];+                if (!JS_IsPtr(func))+                    continue;+                b1 = JS_VALUE_TO_PTR(func);+                if (b1->mtag != JS_MTAG_FUNCTION_BYTECODE)+                    continue;+                +                reset_parse_state(s, b1->source_pos, func);+                +                s->is_eval = FALSE;+                s->is_repl = FALSE;+                s->has_retval = FALSE;+                +                JS_PUSH_VALUE(ctx, func);+                js_parse_function(s);+                +                /* parse a local function */+                err = JS_StackCheck(ctx, 3);+                JS_POP_VALUE(ctx, func);+                if (err)+                    js_parse_error_stack_overflow(s);+                /* set the next cpool position */+                *ctx->sp = JS_NewShortInt(cpool_pos + 1); ++                *--ctx->sp = *pfunc; /* parent_func */+                *--ctx->sp = func; /* func */+                *--ctx->sp = JS_NewShortInt(0); /* cpool_pos */+                goto next;+            }+        }+        +        if (*pparent_func != JS_NULL) {+            resolve_var_refs(s, pfunc, pparent_func);+        }+        /* now we can shrink the external vars */+        b = JS_VALUE_TO_PTR(*pfunc);+        js_shrink_value_array(ctx, &b->ext_vars, 2 * b->ext_vars_len);+#ifdef DUMP_FUNC_BYTECODE+        dump_byte_code(ctx, b);+#endif+        /* remove the stack entry */+        ctx->sp += 3;+        ctx->stack_bottom = ctx->sp;+    next: ;+    }+}++/* return the parsed value in s->token.value */+/* XXX: use exact JSON white space definition */+static int js_parse_json_value(JSParseState *s, int state, int dummy_param)+{+    JSContext *ctx = s->ctx;+    const uint8_t *p;+    JSValue val;++    PARSE_START2();+    +    p = s->source_buf + s->buf_pos;+    p += skip_spaces((const char *)p);+    s->buf_pos = p - s->source_buf;+    if ((*p >= '0' && *p <= '9') || *p == '-') {+        double d;+        JSByteArray *tmp_arr;+        tmp_arr = js_alloc_byte_array(s->ctx, sizeof(JSATODTempMem));+        if (!tmp_arr)+            js_parse_error_mem(s);+        p = s->source_buf + s->buf_pos;+        d = js_atod((const char *)p, (const char **)&p, 10, 0,+                    (JSATODTempMem *)tmp_arr->buf);+        js_free(s->ctx, tmp_arr);+        if (isnan(d))+            js_parse_error(s, "invalid number literal");+        val = JS_NewFloat64(s->ctx, d);+    } else if (*p == 't' &&+               p[1] == 'r' && p[2] == 'u' && p[3] == 'e') {+        p += 4;+        val = JS_TRUE;+    } else if (*p == 'f' &&+               p[1] == 'a' && p[2] == 'l' && p[3] == 's' && p[4] == 'e') {+        p += 5;+        val = JS_FALSE;+    } else if (*p == 'n' &&+               p[1] == 'u' && p[2] == 'l' && p[3] == 'l') {+        p += 4;+        val = JS_NULL;+    } else if (*p == '\"') {+        uint32_t pos;+        pos = p + 1 - s->source_buf;+        val = js_parse_string(s, &pos, '\"');+        p = s->source_buf + pos;+    } else if (*p == '[') {+        JSValue val2;+        uint32_t idx;+        +        val = JS_NewArray(ctx, 0);+        if (JS_IsException(val))+            js_parse_error_mem(s);+        PARSE_PUSH_VAL(s, val); /* 'val' is not usable after this call */+        p = s->source_buf + s->buf_pos + 1;+        p += skip_spaces((const char *)p);+        if (*p != ']') {+            idx = 0;+            for(;;) {+                s->buf_pos = p - s->source_buf;+                PARSE_PUSH_INT(s, idx);+                PARSE_CALL(s, 0, js_parse_json_value, 0);+                PARSE_POP_INT(s, idx);+                val2 = s->token.value;+                val2 = JS_SetPropertyUint32(ctx, *ctx->sp, idx, val2);+                if (JS_IsException(val2))+                    js_parse_error_mem(s);+                idx++;+                p = s->source_buf + s->buf_pos;+                p += skip_spaces((const char *)p);+                if (*p != ',')+                    break;+                p++;+            }+        }+        if (*p != ']')+            js_parse_error(s, "expecting ']'");+        p++;+        PARSE_POP_VAL(s, val);+    } else if (*p == '{') {+        JSValue val2, prop;+        uint32_t pos;+        +        val = JS_NewObject(ctx);+        if (JS_IsException(val))+            js_parse_error_mem(s);+        PARSE_PUSH_VAL(s, val); /* 'val' is not usable after this call */+        p = s->source_buf + s->buf_pos + 1;+        p += skip_spaces((const char *)p);+        if (*p != '}') {+            for(;;) {+                p += skip_spaces((const char *)p);+                s->buf_pos = p - s->source_buf;+                if (*p != '\"')+                    js_parse_error(s, "expecting '\"'");+                pos = p + 1 - s->source_buf;+                prop = js_parse_string(s, &pos, '\"');+                prop = JS_ToPropertyKey(ctx, prop);+                if (JS_IsException(prop))+                    js_parse_error_mem(s);+                p = s->source_buf + pos;+                p += skip_spaces((const char *)p);+                if (*p != ':')+                    js_parse_error(s, "expecting ':'");+                p++;+                s->buf_pos = p - s->source_buf;+                PARSE_PUSH_VAL(s, prop);+                PARSE_CALL(s, 1, js_parse_json_value, 0);+                val2 = s->token.value;+                PARSE_POP_VAL(s, prop);+                val2 = JS_DefinePropertyValue(ctx, *ctx->sp, prop, val2);+                if (JS_IsException(val2))+                    js_parse_error_mem(s);+                p = s->source_buf + s->buf_pos;+                p += skip_spaces((const char *)p);+                if (*p != ',')+                    break;+                p++;+            }+        }+        if (*p != '}')+            js_parse_error(s, "expecting '}'");+        p++;+        PARSE_POP_VAL(s, val);+    } else {+        js_parse_error(s, "unexpected character");+    }+    s->buf_pos = p - s->source_buf;+    s->token.value = val;+    return PARSE_STATE_RET;+}++static JSValue js_parse_json(JSParseState *s)+{+    s->buf_pos = 0;+    js_parse_call(s, PARSE_FUNC_js_parse_json_value, 0);+    s->buf_pos += skip_spaces((const char *)(s->source_buf + s->buf_pos));+    if (s->buf_pos != s->buf_len) {+        js_parse_error(s, "unexpected character");+    }+    return s->token.value;+}++/* source_str must be a string or JS_NULL. (input, input_len) is+   meaningful only if source_str is JS_NULL. */+static JSValue JS_Parse2(JSContext *ctx, JSValue source_str,+                         const char *input, size_t input_len,+                         const char *filename, int eval_flags)+{+    JSParseState parse_state, *s;+    JSFunctionBytecode *b;+    JSValue top_func, *saved_sp;+    JSGCRef top_func_ref, *saved_top_gc_ref;+    uint8_t str_buf[5];+    +    /* XXX: start gc at the start of parsing ? */+    /* XXX: if the parse state is too large, move it to JSContext */+    s = &parse_state;+    memset(s, 0, sizeof(*s));+    +    s->ctx = ctx;+    ctx->parse_state = s;+    s->source_str = JS_NULL;+    s->filename_str = JS_NULL;+    s->has_column = ((eval_flags & JS_EVAL_STRIP_COL) == 0);++    if (JS_IsPtr(source_str)) {+        JSString *p = JS_VALUE_TO_PTR(source_str);+        s->source_str = source_str;+        s->buf_len = p->len;+        s->source_buf = p->buf;+    } else if (JS_VALUE_GET_SPECIAL_TAG(source_str) == JS_TAG_STRING_CHAR) {+        s->buf_len = get_short_string(str_buf, source_str);+        s->source_buf = str_buf;+    } else {+        s->buf_len = input_len;+        s->source_buf = (const uint8_t *)input;+    }+    s->top_break = JS_NULL;+    saved_top_gc_ref = ctx->top_gc_ref;+    saved_sp = ctx->sp;+    +    if (setjmp(s->jmp_env)) {+        int line_num, col_num;+        JSValue val;++        ctx->parse_state = NULL;+        ctx->top_gc_ref = saved_top_gc_ref;+        ctx->sp = saved_sp;+        ctx->stack_bottom = ctx->sp;+        +        line_num = get_line_col(&col_num, s->source_buf,+                                (eval_flags & (JS_EVAL_JSON | JS_EVAL_REGEXP)) ?+                                s->buf_pos : s->token.source_pos);+        val = JS_ThrowError(ctx, JS_CLASS_SYNTAX_ERROR, "%s", s->error_msg);+        build_backtrace(ctx, ctx->current_exception, filename, line_num + 1, col_num + 1, 0);+        return val;+    }++    if (eval_flags & JS_EVAL_JSON) {+        top_func = js_parse_json(s);+    } else if (eval_flags & JS_EVAL_REGEXP) {+        top_func = js_parse_regexp(s, eval_flags >> JS_EVAL_REGEXP_FLAGS_SHIFT);+    } else {+        s->filename_str = JS_NewString(ctx, filename);+        if (JS_IsException(s->filename_str))+            js_parse_error_mem(s);+        +        b = js_alloc_function_bytecode(ctx);+        if (!b)+            js_parse_error_mem(s);+        b->filename = s->filename_str;+        b->func_name = js_get_atom(ctx, JS_ATOM__eval_);+        b->has_column = s->has_column;+        top_func = JS_VALUE_FROM_PTR(b);+        +        reset_parse_state(s, 0, top_func);+        +        s->is_eval = TRUE;+        s->has_retval = ((eval_flags & JS_EVAL_RETVAL) != 0);+        s->is_repl = ((eval_flags & JS_EVAL_REPL) != 0);+        +        JS_PUSH_VALUE(ctx, top_func);+        +        js_parse_program(s);+        +        js_parse_local_functions(s, &top_func_ref.val);+        +        JS_POP_VALUE(ctx, top_func);+    }+    ctx->parse_state = NULL;+    return top_func;+}++/* warning: it is assumed that input[input_len] = '\0' */+JSValue JS_Parse(JSContext *ctx, const char *input, size_t input_len,+                 const char *filename, int eval_flags)+{+    return JS_Parse2(ctx, JS_NULL, input, input_len, filename, eval_flags);+}++JSValue JS_Run(JSContext *ctx, JSValue val)+{+    JSFunctionBytecode *b;+    JSGCRef val_ref;+    int err;+    +    if (!JS_IsPtr(val))+        goto fail;+    b = JS_VALUE_TO_PTR(val);+    if (b->mtag != JS_MTAG_FUNCTION_BYTECODE) {+    fail:+        return JS_ThrowTypeError(ctx, "bytecode function expected");+    }++    val = js_closure(ctx, val, NULL);+    if (JS_IsException(val))+        return val;+    JS_PUSH_VALUE(ctx, val);+    err = JS_StackCheck(ctx, 2);+    JS_POP_VALUE(ctx, val);+    if (err)+        return JS_EXCEPTION;+    JS_PushArg(ctx, val);+    JS_PushArg(ctx, JS_NULL);+    val = JS_Call(ctx, 0);+    return val;+}++/* warning: it is assumed that input[input_len] = '\0' */+JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,+                const char *filename, int eval_flags)+{+    JSValue val;+    val = JS_Parse(ctx, input, input_len, filename, eval_flags);+    if (JS_IsException(val))+        return val;+    return JS_Run(ctx, val);+}++/**********************************************************************/+/* garbage collector */++/* return the size in bytes */+static int get_mblock_size(const void *ptr)+{+    int mtag = ((JSMemBlockHeader *)ptr)->mtag;+    int size;+    switch(mtag) {+    case JS_MTAG_OBJECT:+        {+            const JSObject *p = ptr;+            size = offsetof(JSObject, u) + p->extra_size * JSW;+        }+        break;+    case JS_MTAG_FLOAT64:+        size = sizeof(JSFloat64);+        break;+    case JS_MTAG_STRING:+        {+            const JSString *p = ptr;+            size = sizeof(JSString) + ((p->len + JSW) & ~(JSW - 1));+        }+        break;+    case JS_MTAG_BYTE_ARRAY:+        {+            const JSByteArray *p = ptr;+            size = sizeof(JSByteArray) + ((p->size + JSW - 1) & ~(JSW - 1));+        }+        break;+    case JS_MTAG_VALUE_ARRAY:+        {+            const JSValueArray *p = ptr;+            size = sizeof(JSValueArray) + p->size * sizeof(p->arr[0]);+        }+        break;+    case JS_MTAG_FREE:+        {+            const JSFreeBlock *p = ptr;+            size = sizeof(JSFreeBlock) + p->size * sizeof(JSWord);+        }+        break;+    case JS_MTAG_VARREF:+        {+            const JSVarRef *p = ptr;+            size = sizeof(JSVarRef);+            if (p->is_detached)+                size -= sizeof(JSValue);+        }+        break;+    case JS_MTAG_FUNCTION_BYTECODE:+        size = sizeof(JSFunctionBytecode);+        break;+    default:+        size = 0;+        assert(0);+    }+    return size;+}++/* gc mark pass */++typedef struct {+    JSContext *ctx;+    JSValue *gsp;+    JSValue *gs_bottom;+    JSValue *gs_top;+    BOOL overflow;+} GCMarkState;++static BOOL mtag_has_references(int mtag)+{+    return (mtag == JS_MTAG_OBJECT ||+            mtag == JS_MTAG_VALUE_ARRAY ||+            mtag == JS_MTAG_VARREF ||+            mtag == JS_MTAG_FUNCTION_BYTECODE);+}++static void gc_mark(GCMarkState *s, JSValue val)+{+    JSContext *ctx = s->ctx;+    void *ptr;+    JSMemBlockHeader *mb;++    if (!JS_IsPtr(val))+        return;+    ptr = JS_VALUE_TO_PTR(val);+    if (JS_IS_ROM_PTR(ctx, ptr))+        return;+    mb = ptr;+    if (mb->gc_mark)+        return;+    mb->gc_mark = 1;+    if (mtag_has_references(mb->mtag)) {+        if (mb->mtag == JS_MTAG_VALUE_ARRAY) {+            /* value array are handled specifically to save stack space */+            if ((s->gsp - s->gs_bottom) < 2) {+                s->overflow = TRUE;+            } else {+                *--s->gsp = 0;+                *--s->gsp = val;+            }+        } else {+            if ((s->gsp - s->gs_bottom) < 1) {+                s->overflow = TRUE;+            } else {+                *--s->gsp = val;+            }+        }+    }+}++/* flush the GC mark stack */+static void gc_mark_flush(GCMarkState *s)+{+    void *ptr;+    JSMemBlockHeader *mb;+    JSValue val;+    +    while (s->gsp < s->gs_top) {+        val = *s->gsp++;+        ptr = JS_VALUE_TO_PTR(val);+        mb = ptr;++        switch(mb->mtag) {+        case JS_MTAG_OBJECT:+            {+                const JSObject *p = ptr;+                gc_mark(s, p->proto);+                gc_mark(s, p->props);+                switch(p->class_id) {+                case JS_CLASS_CLOSURE:+                    {+                        int i;+                        gc_mark(s, p->u.closure.func_bytecode);+                        for(i = 0; i < p->extra_size - 1; i++)+                            gc_mark(s, p->u.closure.var_refs[i]);+                    }+                    break;+                case JS_CLASS_C_FUNCTION:+                    if (p->extra_size > 1)+                        gc_mark(s, p->u.cfunc.params);+                    break;+                case JS_CLASS_ARRAY:+                    gc_mark(s, p->u.array.tab);+                    break;+                case JS_CLASS_ERROR:+                    gc_mark(s, p->u.error.message);+                    gc_mark(s, p->u.error.stack);+                    break;+                case JS_CLASS_ARRAY_BUFFER:+                    gc_mark(s, p->u.array_buffer.byte_buffer);+                    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_FLOAT32_ARRAY:+                case JS_CLASS_FLOAT64_ARRAY:+                    gc_mark(s, p->u.typed_array.buffer);+                    break;+                case JS_CLASS_REGEXP:+                    gc_mark(s, p->u.regexp.source);+                    gc_mark(s, p->u.regexp.byte_code);+                    break;+                }+            }+            break;+        case JS_MTAG_VALUE_ARRAY:+            {+                const JSValueArray *p = ptr;+                int pos;++                pos = *s->gsp++;++                /* fast path to skip non objects */+                while (pos < p->size && !JS_IsPtr(p->arr[pos]))+                    pos++;++                if (pos < p->size) {+                    if ((pos + 1) < p->size) {+                        /* the next element needs to be scanned */+                        *--s->gsp = pos + 1;+                        *--s->gsp = val;+                    }+                    /* mark the current element */+                    gc_mark(s, p->arr[pos]);+                }+            }+            break;+        case JS_MTAG_VARREF:+            {+                const JSVarRef *p = ptr;+                gc_mark(s, p->u.value);+            }+            break;+        case JS_MTAG_FUNCTION_BYTECODE:+            {+                const JSFunctionBytecode *b = ptr;+                gc_mark(s, b->func_name);+                gc_mark(s, b->byte_code);+                gc_mark(s, b->cpool);+                gc_mark(s, b->vars);+                gc_mark(s, b->ext_vars);+                gc_mark(s, b->filename);+                gc_mark(s, b->pc2line);+            }+            break;+        default:+            break;+        }+    }+}++static void gc_mark_root(GCMarkState *s, JSValue val)+{+    gc_mark(s, val);+    gc_mark_flush(s);+}++/* return true if the memory block is marked i.e. it won't be freed by the GC */+static BOOL gc_mb_is_marked(JSValue val)+{+    JSFreeBlock *b;+    if (!JS_IsPtr(val))+        return FALSE;+    b = (JSFreeBlock *)JS_VALUE_TO_PTR(val);+    return b->gc_mark;+}++static void gc_mark_all(JSContext *ctx, BOOL keep_atoms)+{+    GCMarkState s_s, *s = &s_s;+    JSValue *sp, *sp_end;++    s->ctx = ctx;+    /* initialize the GC stack */+    s->overflow = FALSE;+    s->gs_top = ctx->sp;+    s->gsp = s->gs_top;+#if 1+    s->gs_bottom = (JSValue *)ctx->heap_free;+#else+    s->gs_bottom = s->gs_top - 3; /* TEST small stack space */+#endif++    /* keep the atoms if they are in RAM (only used when compiling to file) */+    if ((uint8_t *)ctx->atom_table == ctx->heap_base &&+        keep_atoms) {+        uint8_t *ptr;+        for(ptr = (uint8_t *)ctx->atom_table;+            ptr < (uint8_t *)(ctx->atom_table + JS_ATOM_END);+            ptr += get_mblock_size(ptr)) {+            gc_mark_root(s, JS_VALUE_FROM_PTR(ptr));+        }+    }+    +    /* mark all the memory blocks */+    sp_end = ctx->class_proto + 2 * ctx->class_count;+    for(sp = &ctx->current_exception; sp < sp_end; sp++) {+        gc_mark_root(s, *sp);+    }++    for(sp = ctx->sp; sp < (JSValue *)ctx->stack_top; sp++) {+        gc_mark_root(s, *sp);+    }++    {+        JSGCRef *ref;+        for(ref = ctx->top_gc_ref; ref != NULL; ref = ref->prev) {+            gc_mark_root(s, ref->val);+        }+        for(ref = ctx->last_gc_ref; ref != NULL; ref = ref->prev) {+            gc_mark_root(s, ref->val);+        }+    }+    if (ctx->parse_state) {+        JSParseState *ps = ctx->parse_state;++        gc_mark_root(s, ps->source_str);+        gc_mark_root(s, ps->filename_str);+        gc_mark_root(s, ps->token.value);+        gc_mark_root(s, ps->cur_func);+        gc_mark_root(s, ps->byte_code);+    }++    /* if the mark stack overflowed, need to scan the heap */+    while (s->overflow) {+        uint8_t *ptr;+        int size;+        JSMemBlockHeader *mb;+        +        s->overflow = FALSE;+        +        ptr = ctx->heap_base;+        while (ptr < ctx->heap_free) {+            size = get_mblock_size(ptr);+            mb = (JSMemBlockHeader *)ptr;+            if (mb->gc_mark && mtag_has_references(mb->mtag)) {+                if (mb->mtag == JS_MTAG_VALUE_ARRAY)+                    *--s->gsp = 0;+                *--s->gsp = JS_VALUE_FROM_PTR(ptr);+                gc_mark_flush(s);+            }+            ptr += size;+        }+    }++    /* update the unique string table (its elements are considered as+       weak string references) */+    if (!JS_IsNull(ctx->unique_strings)) {+        JSValueArray *arr = JS_VALUE_TO_PTR(ctx->unique_strings);+        int i, j;++        j = 0;+        for(i = 0; i < arr->size; i++) {+            if (gc_mb_is_marked(arr->arr[i])) {+                arr->arr[j++] = arr->arr[i];+            }+        }+        ctx->unique_strings_len = j;+        if (j > 0) {+            arr->gc_mark = 1;+            if (j < arr->size) {+                /* shrink the array */+                set_free_block(&arr->arr[j], (arr->size - j) * sizeof(JSValue));+                arr->size = j;+            }+        } else {+            arr->gc_mark = 0;+            ctx->unique_strings = JS_NULL;+        }+    }++    /* update the weak references in the string position cache  */+    {+        int i;+        JSStringPosCacheEntry *ce;+        for(i = 0; i < JS_STRING_POS_CACHE_SIZE; i++) {+            ce = &ctx->string_pos_cache[i];+            if (!gc_mb_is_marked(ce->str))+                ce->str = JS_NULL;+        }+    }+    +    /* reset the gc marks and mark the free blocks as free */+    {+        uint8_t *ptr, *ptr1;+        int size;+        JSFreeBlock *b;++        ptr = ctx->heap_base;+        while (ptr < ctx->heap_free) {+            size = get_mblock_size(ptr);+            b = (JSFreeBlock *)ptr;+            if (b->gc_mark) {+                b->gc_mark = 0;+            } else {+                JSObject *p = (void *)ptr;+                /* call the user finalizer if needed */+                if (p->mtag == JS_MTAG_OBJECT && p->class_id >= JS_CLASS_USER &&+                    ctx->c_finalizer_table[p->class_id - JS_CLASS_USER] != NULL) {+                    ctx->c_finalizer_table[p->class_id - JS_CLASS_USER](ctx, p->u.user.opaque);+                }+                /* merge all the consecutive free blocks */+                ptr1 = ptr + size;+                while (ptr1 < ctx->heap_free && ((JSFreeBlock *)ptr1)->gc_mark == 0) {+                    ptr1 += get_mblock_size(ptr1);+                }+                size = ptr1 - ptr;+                set_free_block(b, size);+            }+            ptr += size;+        }+    }+}++static JSValue js_value_from_pval(JSContext *ctx, JSValue *pval)+{+    return JS_VALUE_FROM_PTR(pval);+}++static JSValue *js_value_to_pval(JSContext *ctx, JSValue val)+{+    return JS_VALUE_TO_PTR(val);+}++static void gc_thread_pointer(JSContext *ctx, JSValue *pval)+{+    JSValue val;+    JSValue *ptr;+    +    val = *pval;+    if (!JS_IsPtr(val))+        return;+    ptr = JS_VALUE_TO_PTR(val);+    if (JS_IS_ROM_PTR(ctx, ptr))+        return;+    /* gc_mark = 0 indicates a normal memory block header, gc_mark = 1+       indicates a pointer to another element */+    *pval = *ptr;+    *ptr = js_value_from_pval(ctx, pval);+}++static void gc_update_threaded_pointers(JSContext *ctx,+                                        void *ptr, void *new_ptr)+{+    JSValue val, *pv;++    val = *(JSValue *)ptr;+    if (JS_IsPtr(val)) {+        /* update the threaded pointers to the node 'ptr' and+           unthread it. */+        for(;;) {+            pv = js_value_to_pval(ctx, val);+            val = *pv;+            *pv = JS_VALUE_FROM_PTR(new_ptr);+            if (!JS_IsPtr(val))+                break;+        }+        *(JSValue *)ptr = val;+    }+}++static void gc_thread_block(JSContext *ctx, void *ptr)+{+    int mtag;+    +    mtag = ((JSMemBlockHeader *)ptr)->mtag;+    switch(mtag) {+    case JS_MTAG_OBJECT:+        {+            JSObject *p = ptr;+            gc_thread_pointer(ctx, &p->proto);+            gc_thread_pointer(ctx, &p->props);+            switch(p->class_id) {+            case JS_CLASS_CLOSURE:+                {+                    int i;+                    gc_thread_pointer(ctx, &p->u.closure.func_bytecode);+                    for(i = 0; i < p->extra_size - 1; i++)+                        gc_thread_pointer(ctx, &p->u.closure.var_refs[i]);+                }+                break;+            case JS_CLASS_C_FUNCTION:+                if (p->extra_size > 1)+                    gc_thread_pointer(ctx, &p->u.cfunc.params);+                break;+            case JS_CLASS_ARRAY:+                gc_thread_pointer(ctx, &p->u.array.tab);+                break;+            case JS_CLASS_ERROR:+                gc_thread_pointer(ctx, &p->u.error.message);+                gc_thread_pointer(ctx, &p->u.error.stack);+                break;+            case JS_CLASS_ARRAY_BUFFER:+                gc_thread_pointer(ctx, &p->u.array_buffer.byte_buffer);+                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_FLOAT32_ARRAY:+            case JS_CLASS_FLOAT64_ARRAY:+                gc_thread_pointer(ctx, &p->u.typed_array.buffer);+                break;+            case JS_CLASS_REGEXP:+                gc_thread_pointer(ctx, &p->u.regexp.source);+                gc_thread_pointer(ctx, &p->u.regexp.byte_code);+                break;+            }+        }+        break;+    case JS_MTAG_VALUE_ARRAY:+        {+            JSValueArray *p = ptr;+            int i;+            for(i = 0; i < p->size; i++) {+                gc_thread_pointer(ctx, &p->arr[i]);+            }+        }+        break;+    case JS_MTAG_VARREF:+        {+            JSVarRef *p = ptr;+            gc_thread_pointer(ctx, &p->u.value);+        }+        break;+    case JS_MTAG_FUNCTION_BYTECODE:+        {+            JSFunctionBytecode *b = ptr;+            gc_thread_pointer(ctx, &b->func_name);+            gc_thread_pointer(ctx, &b->byte_code);+            gc_thread_pointer(ctx, &b->cpool);+            gc_thread_pointer(ctx, &b->vars);+            gc_thread_pointer(ctx, &b->ext_vars);+            gc_thread_pointer(ctx, &b->filename);+            gc_thread_pointer(ctx, &b->pc2line);+        }+        break;+    default:+        break;+    }+}++/* Heap compaction using Jonkers algorithm */+static void gc_compact_heap(JSContext *ctx)+{+    uint8_t *ptr, *new_ptr;+    int size;+    JSValue *sp, *sp_end;+    +    /* thread all the external pointers */+    sp_end = ctx->class_proto + 2 * ctx->class_count;+    for(sp = &ctx->unique_strings; sp < sp_end; sp++) {+        gc_thread_pointer(ctx, sp);+    }+    {+        int i;+        JSStringPosCacheEntry *ce;+        for(i = 0; i < JS_STRING_POS_CACHE_SIZE; i++) {+            ce = &ctx->string_pos_cache[i];+            gc_thread_pointer(ctx, &ce->str);+        }+    }+    +    for(sp = ctx->sp; sp < (JSValue *)ctx->stack_top; sp++) {+        gc_thread_pointer(ctx, sp);+    }++    {+        JSGCRef *ref;+        for(ref = ctx->top_gc_ref; ref != NULL; ref = ref->prev) {+            gc_thread_pointer(ctx, &ref->val);+        }+        for(ref = ctx->last_gc_ref; ref != NULL; ref = ref->prev) {+            gc_thread_pointer(ctx, &ref->val);+        }+    }++    if (ctx->parse_state) {+        JSParseState *ps = ctx->parse_state;++        gc_thread_pointer(ctx, &ps->source_str);+        gc_thread_pointer(ctx, &ps->filename_str);+        gc_thread_pointer(ctx, &ps->token.value);+        gc_thread_pointer(ctx, &ps->cur_func);+        gc_thread_pointer(ctx, &ps->byte_code);+    }++    /* pass 1: thread the pointers and update the previous ones */+    new_ptr = ctx->heap_base;+    ptr = ctx->heap_base;+    while (ptr < ctx->heap_free) {+        gc_update_threaded_pointers(ctx, ptr, new_ptr);+        size = get_mblock_size(ptr);+        if (js_get_mtag(ptr) != JS_MTAG_FREE) {+            gc_thread_block(ctx, ptr);+            new_ptr += size;+        }+        ptr += size;+    }+    +    /* pass 2: update the threaded pointers and move the block to its+       final position */+    new_ptr = ctx->heap_base;+    ptr = ctx->heap_base;+    while (ptr < ctx->heap_free) {+        gc_update_threaded_pointers(ctx, ptr, new_ptr);+        size = get_mblock_size(ptr);+        if (js_get_mtag(ptr) != JS_MTAG_FREE) {+            if (new_ptr != ptr) {+                memmove(new_ptr, ptr, size);+            }+            new_ptr += size;+        }+        ptr += size;+    }+    ctx->heap_free = new_ptr;++    /* update the source pointer in the parser */+    if (ctx->parse_state) {+        JSParseState *ps = ctx->parse_state;+        if (JS_IsPtr(ps->source_str)) {+            JSString *p = JS_VALUE_TO_PTR(ps->source_str);+            ps->source_buf = p->buf;+        }+    }+    +    /* rehash the object properties */+    /* XXX: try to do it in the previous pass (add a specific tag ?) */+    ptr = ctx->heap_base;+    while (ptr < ctx->heap_free) {+        size = get_mblock_size(ptr);+        if (js_get_mtag(ptr) == JS_MTAG_OBJECT) {+            js_rehash_props(ctx, (JSObject *)ptr, TRUE);+        }+        ptr += size;+    }+}++static void JS_GC2(JSContext *ctx, BOOL keep_atoms)+{+#ifdef DUMP_GC+    js_printf(ctx, "GC   : heap size=%u/%u stack_size=%u\n",+           (uint32_t)(ctx->heap_free - ctx->heap_base),+           (uint32_t)(ctx->stack_top - ctx->heap_base),+           (uint32_t)(ctx->stack_top - (uint8_t *)ctx->sp));+#endif+#if defined(DEBUG_GC)+    /* reduce the dummy block size at each GC to change the addresses+       after compaction */+    /* XXX: only works a finite number of times */+    {+        JSByteArray *arr;+        if (JS_IsPtr(ctx->dummy_block)) {+            arr = JS_VALUE_TO_PTR(ctx->dummy_block);+            if (arr->size >= 8) {+                js_shrink_byte_array(ctx, &ctx->dummy_block, arr->size - 4);+                if (arr->size == 4) {+                    js_printf(ctx, "WARNING: debug GC: no longer modifying the addresses\n");+                }+            }+        }+    }+#endif+    gc_mark_all(ctx, keep_atoms);+    gc_compact_heap(ctx);+#ifdef DUMP_GC+    js_printf(ctx, "AFTER: heap size=%u/%u stack_size=%u\n",+           (uint32_t)(ctx->heap_free - ctx->heap_base),+           (uint32_t)(ctx->stack_top - ctx->heap_base),+           (uint32_t)(ctx->stack_top - (uint8_t *)ctx->sp));+#endif+}++void JS_GC(JSContext *ctx)+{+    JS_GC2(ctx, TRUE);+}++/* bytecode saving and loading */++#define JS_BYTECODE_VERSION_32 0x0001+/* bit 15 of bytecode version is a 64-bit indicator */+#define JS_BYTECODE_VERSION (JS_BYTECODE_VERSION_32 | ((JSW & 8) << 12))++void JS_PrepareBytecode(JSContext *ctx,+                        JSBytecodeHeader *hdr,+                        const uint8_t **pdata_buf, uint32_t *pdata_len,+                        JSValue eval_code)+{+    JSGCRef eval_code_ref;+    int i;+    +    /* remove all the objects except the compiled code */+    ctx->empty_props = JS_NULL;+    for(i = 0; i < ctx->class_count; i++) {+        ctx->class_proto[i] = JS_NULL;+        ctx->class_obj[i] = JS_NULL;+    }+    ctx->global_obj = JS_NULL;+#ifdef DEBUG_GC+    ctx->dummy_block = JS_NULL;+#endif+    +    JS_PUSH_VALUE(ctx, eval_code);+    JS_GC2(ctx, FALSE);+    JS_POP_VALUE(ctx, eval_code);++    hdr->magic = JS_BYTECODE_MAGIC;+    hdr->version = JS_BYTECODE_VERSION;+    hdr->base_addr = (uintptr_t)ctx->heap_base;+    hdr->unique_strings =  ctx->unique_strings;+    hdr->main_func = eval_code;++    *pdata_buf = ctx->heap_base;+    *pdata_len = ctx->heap_free - ctx->heap_base;+}++#if JSW == 8++typedef uint32_t JSValue_32;+typedef uint32_t JSWord_32;++#define JS_MB_HEADER_32  \+    JSWord_32 gc_mark: 1; \+    JSWord_32 mtag: (JS_MTAG_BITS - 1)++#define JS_MB_PAD_32(n)  (32 - (n))++typedef struct {+    JS_MB_HEADER_32;+    JSWord_32 dummy: JS_MB_PAD_32(JS_MTAG_BITS);+} JSMemBlockHeader_32;++typedef struct {+    JS_MB_HEADER_32;+    JSWord_32 size: JS_MB_PAD_32(JS_MTAG_BITS);+    JSValue_32 arr[];+} JSValueArray_32;++typedef struct {+    JS_MB_HEADER_32;+    JSWord_32 size: JS_MB_PAD_32(JS_MTAG_BITS);+    uint8_t buf[];+} JSByteArray_32;++typedef struct {+    JS_MB_HEADER_32;+    JSWord_32 dummy: JS_MB_PAD_32(JS_MTAG_BITS);+    /* unaligned 64 bit access in 32-bit mode */+    struct __attribute__((packed)) {+        double dval;+    } u;+} JSFloat64_32;++#define JS_STRING_LEN_MAX_32 ((1 << (32 - JS_MTAG_BITS - 3)) - 1)++typedef struct {+    JS_MB_HEADER_32;+    JSWord_32 is_unique: 1;+    JSWord_32 is_ascii: 1;+    /* true if the string content represents a number, only meaningful+       is is_unique = true */+    JSWord_32 is_numeric: 1;+    JSWord_32 len: JS_MB_PAD_32(JS_MTAG_BITS + 3);+    uint8_t buf[];+} JSString_32;++typedef struct {+    JS_MB_HEADER_32;+    JSWord_32 has_arguments : 1; /* only used during parsing */+    JSWord_32 has_local_func_name : 1; /* only used during parsing */+    JSWord_32 has_column : 1; /* column debug info is present */+    JSWord_32 arg_count : 16;+    JSWord_32 dummy: JS_MB_PAD_32(JS_MTAG_BITS + 3 + 16);++    JSValue_32 func_name; /* JS_NULL if anonymous function */+    JSValue_32 byte_code; /* JS_NULL if the function is not parsed yet */+    JSValue_32 cpool; /* constant pool */+    JSValue_32 vars; /* only for debug */+    JSValue_32 ext_vars; /* records of (var_name, var_kind (2 bits) var_idx (16 bits)) */+    uint16_t stack_size; /* maximum stack size */+    uint16_t ext_vars_len; /* XXX: only used during parsing */+    JSValue_32 filename; /* filename in which the function is defined */+    JSValue_32 pc2line; /* JSByteArray or JS_NULL if not initialized */+    uint32_t source_pos; /* only used during parsing (XXX: shrink) */+} JSFunctionBytecode_32;++/* warning: ptr1 and ptr may overlap. However there is always: ptr1 <= ptr. Return 0 if OK. */+static int convert_mblock_64to32(void *ptr1, const void *ptr)+{+    int mtag, i;++    mtag = ((JSMemBlockHeader*)ptr)->mtag;+    switch(mtag) {+    case JS_MTAG_FUNCTION_BYTECODE:+        {+            const JSFunctionBytecode *b = ptr;+            JSFunctionBytecode_32 *b1 = ptr1;+            b1->gc_mark = b->gc_mark;+            b1->mtag = b->mtag;+            b1->has_arguments = b->has_arguments;+            b1->has_local_func_name = b->has_local_func_name;+            b1->has_column = b->has_column;+            b1->arg_count = b->arg_count;+            b1->dummy = 0;+            b1->func_name = b->func_name;+            b1->byte_code = b->byte_code;+            b1->cpool = b->cpool;+            b1->vars = b->vars;+            b1->ext_vars = b->ext_vars;+            b1->stack_size = b->stack_size;+            b1->ext_vars_len = b->ext_vars_len;+            b1->filename = b->filename;+            b1->pc2line = b->pc2line;+            b1->source_pos = b->source_pos;+        }+        break;+    case JS_MTAG_FLOAT64:+        {+            const JSFloat64 *b = ptr;+            JSFloat64_32 *b1 = ptr1;++            b1->gc_mark = b->gc_mark;+            b1->mtag = b->mtag;+            b1->dummy = 0;+            b1->u.dval = b->u.dval;+        }+        break;+    case JS_MTAG_VALUE_ARRAY:+        {+            const JSValueArray *b = ptr;+            JSValueArray_32 *b1 = ptr1;++            b1->gc_mark = b->gc_mark;+            b1->mtag = b->mtag;+            b1->size = b->size; /* no test needed as long as JS_VALUE_ARRAY_SIZE_MAX is identical */+            for(i = 0; i < b1->size; i++)+                b1->arr[i] = b->arr[i];+        }+        break;+    case JS_MTAG_BYTE_ARRAY:+        {+            const JSByteArray *b = ptr;+            JSByteArray_32 *b1 = ptr1;++            b1->gc_mark = b->gc_mark;+            b1->mtag = b->mtag;+            b1->size = b->size; /* no test needed as long as JS_BYTE_ARRAY_SIZE_MAX is identical */+            memmove(b1->buf, b->buf, b1->size);+        }+        break;+    case JS_MTAG_STRING:+        {+            const JSString *b = ptr;+            JSString_32 *b1 = ptr1;++            if (b->len > JS_STRING_LEN_MAX_32)+                return -1;+            b1->gc_mark = b->gc_mark;+            b1->mtag = b->mtag;+            b1->is_unique = b->is_unique;+            b1->is_ascii = b->is_ascii;+            b1->is_numeric = b->is_numeric;+            b1->len = b->len;+            memmove(b1->buf, b->buf, b1->len + 1);+        }+        break;+    default:+        abort();+    }+    return 0;+}++/* return the size in bytes */+static int get_mblock_size_32(const void *ptr)+{+    int mtag = ((JSMemBlockHeader_32 *)ptr)->mtag;+    int size;+    switch(mtag) {+    case JS_MTAG_FLOAT64:+        size = sizeof(JSFloat64_32);+        break;+    case JS_MTAG_STRING:+        {+            const JSString_32 *p = ptr;+            size = sizeof(JSString_32) + ((p->len + 4) & ~(4 - 1));+        }+        break;+    case JS_MTAG_BYTE_ARRAY:+        {+            const JSByteArray_32 *p = ptr;+            size = sizeof(JSByteArray_32) + ((p->size + 4 - 1) & ~(4 - 1));+        }+        break;+    case JS_MTAG_VALUE_ARRAY:+        {+            const JSValueArray_32 *p = ptr;+            size = sizeof(JSValueArray_32) + p->size * sizeof(p->arr[0]);+        }+        break;+    case JS_MTAG_FUNCTION_BYTECODE:+        size = sizeof(JSFunctionBytecode_32);+        break;+    default:+        size = 0;+        assert(0);+    }+    return size;+}++/* Compact and convert a 64 bit heap to a 32 bit heap at offset+   0. Only used for code compilation. Return 0 if OK. */+static int gc_compact_heap_64to32(JSContext *ctx)+{+    uint8_t *ptr;+    int size, size_32;+    uintptr_t new_offset;+    +    gc_thread_pointer(ctx, &ctx->unique_strings);++    /* thread all the external pointers */+    {+        JSGCRef *ref;+        /* necessary because JS_PUSH_VAL() is called before+           gc_compact_heap_64to32() */+        for(ref = ctx->top_gc_ref; ref != NULL; ref = ref->prev) {+            gc_thread_pointer(ctx, &ref->val);+        }+    }++    /* pass 1: thread the pointers and update the previous ones */+    new_offset = 0;+    ptr = ctx->heap_base;+    while (ptr < ctx->heap_free) {+        gc_update_threaded_pointers(ctx, ptr, (uint8_t *)new_offset);+        size = get_mblock_size(ptr);+        if (js_get_mtag(ptr) != JS_MTAG_FREE) {+            gc_thread_block(ctx, ptr);+            size_32 = get_mblock_size_32(ptr);+            new_offset += size_32;+        }+        ptr += size;+    }+    +    /* pass 2: update the threaded pointers and move the block to its+       final position */+    new_offset = 0;+    ptr = ctx->heap_base;+    while (ptr < ctx->heap_free) {+        gc_update_threaded_pointers(ctx, ptr, (uint8_t *)new_offset);+        size = get_mblock_size(ptr);+        if (js_get_mtag(ptr) != JS_MTAG_FREE) {+            size_32 = get_mblock_size_32(ptr);+            if (convert_mblock_64to32(ctx->heap_base + new_offset, ptr))+                return -1;+            new_offset += size_32;+        }+        ptr += size;+    }+    ctx->heap_free = ctx->heap_base + new_offset;+    return 0;+}++#ifdef JS_USE_SHORT_FLOAT++static int expand_short_float(JSContext *ctx, JSValue *pval)+{+    JSFloat64 *f;+    if (JS_IsShortFloat(*pval)) {+        f = js_malloc(ctx, sizeof(JSFloat64), JS_MTAG_FLOAT64);+        if (!f)+            return -1;+        f->u.dval = js_get_short_float(*pval);+        *pval = JS_VALUE_FROM_PTR(f);+    }+    return 0;+}++/* Expand all the short floats to JSFloat64 structures. Return < 0 if+   not enough memory. */+static int expand_short_floats(JSContext *ctx)+{+    uint8_t *ptr, *p_end;+    int mtag, size;+    +    ptr = ctx->heap_base;+    p_end = ctx->heap_free;+    while (ptr < p_end) {+        size = get_mblock_size(ptr);+        mtag = ((JSMemBlockHeader *)ptr)->mtag;+        switch(mtag) {+        case JS_MTAG_FUNCTION_BYTECODE:+            /* we assume no short floats here */+            break;+        case JS_MTAG_VALUE_ARRAY:+            {+                JSValueArray *p = (JSValueArray *)ptr;+                int i;+                for(i = 0; i < p->size; i++) {+                    if (expand_short_float(ctx, &p->arr[i]))+                        return -1;+                }+            }+            break;+        case JS_MTAG_STRING:+        case JS_MTAG_FLOAT64:+        case JS_MTAG_BYTE_ARRAY:+            break;+        default:+            abort();+        }+        ptr += size;+    }+    return 0;+}++#endif /* JS_USE_SHORT_FLOAT */++int JS_PrepareBytecode64to32(JSContext *ctx,+                             JSBytecodeHeader32 *hdr,+                             const uint8_t **pdata_buf, uint32_t *pdata_len,+                             JSValue eval_code)+{+    JSGCRef eval_code_ref;+    int i;+    +    /* remove all the objects except the compiled code */+    ctx->empty_props = JS_NULL;+    for(i = 0; i < ctx->class_count; i++) {+        ctx->class_proto[i] = JS_NULL;+        ctx->class_obj[i] = JS_NULL;+    }+    ctx->global_obj = JS_NULL;+#ifdef DEBUG_GC+    ctx->dummy_block = JS_NULL;+#endif+    +    JS_PUSH_VALUE(ctx, eval_code);+#ifdef JS_USE_SHORT_FLOAT+    JS_GC2(ctx, FALSE);+    if (expand_short_floats(ctx))+        return -1;+#else+    gc_mark_all(ctx, FALSE);+#endif    +    if (gc_compact_heap_64to32(ctx))+        return -1;+    JS_POP_VALUE(ctx, eval_code);++    hdr->magic = JS_BYTECODE_MAGIC;+    hdr->version = JS_BYTECODE_VERSION_32;+    hdr->base_addr = 0;+    hdr->unique_strings =  ctx->unique_strings;+    hdr->main_func = eval_code;++    *pdata_buf = ctx->heap_base;+    *pdata_len = ctx->heap_free - ctx->heap_base;+    return 0;+}+#endif /* JSW == 8 */++BOOL JS_IsBytecode(const uint8_t *buf, size_t buf_len)+{+    const JSBytecodeHeader *hdr = (const JSBytecodeHeader *)buf;+    return (buf_len >= sizeof(*hdr) && hdr->magic == JS_BYTECODE_MAGIC);+}++typedef struct {+    JSContext *ctx;+    uintptr_t offset;+    BOOL update_atoms;+} BCRelocState;++static void bc_reloc_value(BCRelocState *s, JSValue *pval)+{+    JSContext *ctx = s->ctx;+    JSString *p;+    JSValue val, str;++    val = *pval;+    if (JS_IsPtr(val)) {+        val += s->offset;++        /* unique strings must be unique, so modify the unique string+           value if it already exists in the context */+        if (s->update_atoms) {+            p = JS_VALUE_TO_PTR(val);+            if (p->mtag == JS_MTAG_STRING && p->is_unique) {+                const JSValueArray *arr1;+                int a, i;+                for(i = 0; i < ctx->n_rom_atom_tables; i++) {+                    arr1 = ctx->rom_atom_tables[i];+                    str = find_atom(ctx, &a, arr1, arr1->size, val); +                    if (!JS_IsNull(str)) {+                        val = str;+                        break;+                    }+                }+            }+        }+        *pval = val;+    }+}++int JS_RelocateBytecode2(JSContext *ctx, JSBytecodeHeader *hdr,+                         uint8_t *buf, uint32_t buf_len,+                         uintptr_t new_base_addr, BOOL update_atoms)+{+    uint8_t *ptr, *p_end;+    int size, mtag;+    BCRelocState ss, *s = &ss;+    +    if (hdr->magic != JS_BYTECODE_MAGIC)+        return -1;+    if (hdr->version != JS_BYTECODE_VERSION)+        return -1;++    /* XXX: add atom checksum to avoid problems if the stdlib is+       modified */+    s->ctx = ctx;+    s->offset = new_base_addr - hdr->base_addr;+    s->update_atoms = update_atoms;++    bc_reloc_value(s, &hdr->unique_strings);+    bc_reloc_value(s, &hdr->main_func);++    ptr = buf;+    p_end = buf + buf_len;+    while (ptr < p_end) {+        size = get_mblock_size(ptr);+        mtag = ((JSMemBlockHeader *)ptr)->mtag;+        switch(mtag) {+        case JS_MTAG_FUNCTION_BYTECODE:+            {+                JSFunctionBytecode *b = (JSFunctionBytecode *)ptr;+                bc_reloc_value(s, &b->func_name);+                bc_reloc_value(s, &b->byte_code);+                bc_reloc_value(s, &b->cpool);+                bc_reloc_value(s, &b->vars);+                bc_reloc_value(s, &b->ext_vars);+                bc_reloc_value(s, &b->filename);+                bc_reloc_value(s, &b->pc2line);+            }+            break;+        case JS_MTAG_VALUE_ARRAY:+            {+                JSValueArray *p = (JSValueArray *)ptr;+                int i;+                for(i = 0; i < p->size; i++) {+                    bc_reloc_value(s, &p->arr[i]);+                }+            }+            break;+        case JS_MTAG_STRING:+        case JS_MTAG_FLOAT64:+        case JS_MTAG_BYTE_ARRAY:+            break;+        default:+            abort();+        }+        ptr += size;+    }+    hdr->base_addr = new_base_addr;+    return 0;+}++/* Relocate the bytecode in 'buf' so that it can be executed+   later. Return 0 if OK, != 0 if error */+int JS_RelocateBytecode(JSContext *ctx,+                        uint8_t *buf, uint32_t buf_len)+{+    uint8_t *data_ptr;++    if (buf_len < sizeof(JSBytecodeHeader))+        return -1;+    data_ptr = buf + sizeof(JSBytecodeHeader);+    return JS_RelocateBytecode2(ctx, (JSBytecodeHeader *)buf,+                                data_ptr,+                                buf_len - sizeof(JSBytecodeHeader),+                                (uintptr_t)data_ptr, TRUE);+}++/* Load the precompiled bytecode from 'buf'. 'buf' must be allocated+   as long as the JSContext exists. Use JS_Run() to execute+   it. warning: the bytecode is not checked so it should come from a+   trusted source. */+JSValue JS_LoadBytecode(JSContext *ctx, const uint8_t *buf)+{+    const JSBytecodeHeader *hdr = (const JSBytecodeHeader *)buf;+    +    if (ctx->unique_strings_len != 0)+        return JS_ThrowInternalError(ctx, "no atom must be defined in RAM");+    /* XXX: could stack atom_tables */+    if (ctx->n_rom_atom_tables >= N_ROM_ATOM_TABLES_MAX)+        return JS_ThrowInternalError(ctx, "too many rom atom tables");+    if (hdr->magic != JS_BYTECODE_MAGIC)+        return JS_ThrowInternalError(ctx, "invalid bytecode magic");+    if ((hdr->version & 0x8000) != (JS_BYTECODE_VERSION & 0x8000))+        return JS_ThrowInternalError(ctx, "bytecode not saved for %d-bit", JSW * 8);+    if (hdr->version != JS_BYTECODE_VERSION)+        return JS_ThrowInternalError(ctx, "invalid bytecode version");+    if (hdr->base_addr != (uintptr_t)(hdr + 1))+        return JS_ThrowInternalError(ctx, "bytecode not relocated");+    ctx->rom_atom_tables[ctx->n_rom_atom_tables++] = (JSValueArray *)JS_VALUE_TO_PTR(hdr->unique_strings);+    return hdr->main_func;+}++/**********************************************************************/+/* runtime */++JSValue js_function_constructor(JSContext *ctx, JSValue *this_val,+                                int argc, JSValue *argv)+{+    StringBuffer b_s, *b = &b_s;+    JSValue val;+    int i, n;+    +    argc &= ~FRAME_CF_CTOR;+    string_buffer_push(ctx, b, 0);+    string_buffer_puts(ctx, b, "(function anonymous(");+    n = argc - 1;+    for(i = 0; i < n; i++) {+        if (i != 0) {+            string_buffer_putc(ctx, b, ',');+        }+        if (string_buffer_concat(ctx, b, argv[i]))+            goto done;+    }+    string_buffer_puts(ctx, b, "\n) {\n");+    if (n >= 0) {+        if (string_buffer_concat(ctx, b, argv[n]))+            goto done;+    }+    string_buffer_puts(ctx, b, "\n})");+ done:+    val = string_buffer_pop(ctx, b);+    if (JS_IsException(val))+        return val;+    val = JS_Parse2(ctx, val, NULL, 0, "<input>", JS_EVAL_RETVAL);+    if (JS_IsException(val))+        return val;+    return JS_Run(ctx, val);+}++JSValue js_function_get_prototype(JSContext *ctx, JSValue *this_val,+                                  int argc, JSValue *argv)+{+    JSValue obj;+    JSGCRef obj_ref;+    +    if (!JS_IsPtr(*this_val)) {+        if (JS_VALUE_GET_SPECIAL_TAG(*this_val) != JS_TAG_SHORT_FUNC)+            goto fail;+        return JS_UNDEFINED;+    } else {+        JSObject *p = JS_VALUE_TO_PTR(*this_val);+        if (p->mtag != JS_MTAG_OBJECT)+            goto fail;+        if (p->class_id == JS_CLASS_CLOSURE) {+            obj = JS_NewObject(ctx);+            if (JS_IsException(obj))+                return obj;+        } else if (p->class_id == JS_CLASS_C_FUNCTION) {+            /* for C constructors, the prototype property is already present */+            return JS_UNDEFINED;+        } else {+        fail:+            return JS_ThrowTypeError(ctx, "not a function");+        }+        JS_PUSH_VALUE(ctx, obj);+        JS_DefinePropertyValue(ctx, obj, js_get_atom(ctx, JS_ATOM_constructor),+                               *this_val);+        JS_POP_VALUE(ctx, obj);+        JS_PUSH_VALUE(ctx, obj);+        JS_DefinePropertyValue(ctx, *this_val, js_get_atom(ctx, JS_ATOM_prototype),+                               obj);+        JS_POP_VALUE(ctx, obj);+    }+    return obj;+}++JSValue js_function_set_prototype(JSContext *ctx, JSValue *this_val,+                                  int argc, JSValue *argv)+{+    if (!JS_IsFunctionObject(ctx, *this_val))+        return JS_ThrowTypeError(ctx, "not a function");++    JS_DefinePropertyValue(ctx, *this_val, js_get_atom(ctx, JS_ATOM_prototype),+                           argv[0]);+    return JS_UNDEFINED;+}++JSValue js_function_get_length_name(JSContext *ctx, JSValue *this_val,+                                    int argc, JSValue *argv, int is_name)+{+    JSFunctionBytecode *b;+    JSValue ret = js_function_get_length_name1(ctx, this_val, is_name, &b);+    if (JS_IsNull(ret))+        return JS_ThrowTypeError(ctx, "not a function");+    return ret;+}++JSValue js_function_toString(JSContext *ctx, JSValue *this_val,+                             int argc, JSValue *argv)+{+    JSValue str, val;+    JSGCRef str_ref;++    str = js_function_get_length_name(ctx, this_val, 0, NULL, 1);+    if (JS_IsException(str))+        return str;+    JS_PUSH_VALUE(ctx, str);+    val = JS_NewString(ctx, "function ");+    JS_POP_VALUE(ctx, str);+    str = JS_ConcatString(ctx, val, str);+    JS_PUSH_VALUE(ctx, str);+    val = JS_NewString(ctx, "() {\n    [native code]\n}");+    JS_POP_VALUE(ctx, str);+    return JS_ConcatString(ctx, str, val);+}++JSValue js_function_call(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv)+{+    int i;+    argc = max_int(argc, 1);+    if (JS_StackCheck(ctx, argc + 1))+        return JS_EXCEPTION;+    for(i = 0; i < argc - 1; i++)+        JS_PushArg(ctx, argv[argc - 1 - i]);+    JS_PushArg(ctx, *this_val);+    JS_PushArg(ctx, argv[0]);+    /* we avoid recursing on the C stack */+    return JS_NewTailCall(argc - 1);+}++JSValue js_function_apply(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv)+{+    JSValueArray *arr;+    JSObject *p;+    int len, i;+    p = js_get_object_class(ctx, argv[1], JS_CLASS_ARRAY);+    if (!p)+        return JS_ThrowTypeError(ctx, "not an array");+    arr = JS_VALUE_TO_PTR(p->u.array.tab);+    len = p->u.array.len;+    if (len > JS_MAX_ARGC)+        return JS_ThrowTypeError(ctx, "too many call arguments");+    if (JS_StackCheck(ctx, len + 2))+        return JS_EXCEPTION;+    p = JS_VALUE_TO_PTR(argv[1]);+    arr = JS_VALUE_TO_PTR(p->u.array.tab);+    for(i = 0; i < len; i++)+        JS_PushArg(ctx, arr->arr[len - 1 - i]);+    JS_PushArg(ctx, *this_val);+    JS_PushArg(ctx, argv[0]);+    /* we avoid recursing on the C stack */+    return JS_NewTailCall(len);+}++JSValue js_function_bind(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv)+{+    int arg_count;+    JSValueArray *arr;+    int i;+    +    arg_count = max_int(argc - 1, 0);+    arr = js_alloc_value_array(ctx, 0, 2 + arg_count);+    if (!arr)+        return JS_EXCEPTION;+    /* arr[0] = func, arr[1] = this */+    arr->arr[0] = *this_val;+    for(i = 0; i < arg_count + 1; i++)+        arr->arr[1 + i] = argv[i];+    return JS_NewCFunctionParams(ctx, JS_CFUNCTION_bound, JS_VALUE_FROM_PTR(arr));+}++/* XXX: handle constructor case */+JSValue js_function_bound(JSContext *ctx, JSValue *this_val,+                          int argc, JSValue *argv, JSValue params)+{+    JSValueArray *arr;+    JSGCRef params_ref;+    int i, err, size, argc2;+    +    arr = JS_VALUE_TO_PTR(params);+    size = arr->size;+    JS_PUSH_VALUE(ctx, params);+    err = JS_StackCheck(ctx, size + argc);+    JS_POP_VALUE(ctx, params);+    if (err)+        return JS_EXCEPTION;+    argc2 = size - 2 + argc;+    if (argc2 > JS_MAX_ARGC)+        return JS_ThrowTypeError(ctx, "too many call arguments");+    arr = JS_VALUE_TO_PTR(params);+    for(i = argc - 1; i >= 0; i--)+        JS_PushArg(ctx, argv[i]);+    for(i = size - 1; i >= 2; i--) {+        JS_PushArg(ctx, arr->arr[i]);+    }+    JS_PushArg(ctx, arr->arr[0]); /* func */+    JS_PushArg(ctx, arr->arr[1]); /* this_val */+    /* we avoid recursing on the C stack */+    return JS_NewTailCall(argc2);+}++/**********************************************************************/++JSValue js_number_constructor(JSContext *ctx, JSValue *this_val,+                              int argc, JSValue *argv)+{+    double d;+    if (argc & FRAME_CF_CTOR)+        return JS_ThrowTypeError(ctx, "number constructor not supported");+    if (argc == 0) {+        return JS_NewShortInt(0);+    } else {+        if (JS_ToNumber(ctx, &d, argv[0]))+            return JS_EXCEPTION;+        return JS_NewFloat64(ctx, d);+    }+}++static int js_thisNumberValue(JSContext *ctx, double *pres, JSValue val)+{+    if (!JS_IsNumber(ctx, val)) {+        JS_ThrowTypeError(ctx, "not a number");+        return -1;+    }+    return JS_ToNumber(ctx, pres, val);+}++JSValue js_number_toString(JSContext *ctx, JSValue *this_val,+                           int argc, JSValue *argv)+{+    int radix, flags;+    double d;+    +    if (js_thisNumberValue(ctx, &d, *this_val))+        return JS_EXCEPTION;+    if (JS_IsUndefined(argv[0])) {+        radix = 10;+    } else {+        if (JS_ToInt32Sat(ctx, &radix, argv[0]))+            return JS_EXCEPTION;+        if (radix < 2 || radix > 36)+            return JS_ThrowRangeError(ctx, "radix must be between 2 and 36");+    }+    /* cannot fail */+    flags = JS_DTOA_FORMAT_FREE;+    if (radix != 10)+        flags |=  JS_DTOA_EXP_DISABLED;+    return js_dtoa2(ctx, d, radix, 0, flags);+}++JSValue js_number_toFixed(JSContext *ctx, JSValue *this_val,+                          int argc, JSValue *argv)+{+    int f, flags;+    double d;++    if (js_thisNumberValue(ctx, &d, *this_val))+        return JS_EXCEPTION;+    if (JS_ToInt32Sat(ctx, &f, argv[0]))+        return JS_EXCEPTION;+    if (f < 0 || f > 100)+        return JS_ThrowRangeError(ctx, "invalid number of digits");+    if (fabs(d) >= 1e21) {+        flags = JS_DTOA_FORMAT_FREE;+    } else {+        flags = JS_DTOA_FORMAT_FRAC;+    }+    return js_dtoa2(ctx, d, 10, f, flags);+}++JSValue js_number_toExponential(JSContext *ctx, JSValue *this_val,+                                int argc, JSValue *argv)+{+    int f, flags;+    double d;++    if (js_thisNumberValue(ctx, &d, *this_val))+        return JS_EXCEPTION;+    if (JS_ToInt32Sat(ctx, &f, argv[0]))+        return JS_EXCEPTION;+    if (JS_IsUndefined(argv[0]) || !isfinite(d)) {+        f = 0;+        flags = JS_DTOA_FORMAT_FREE;+    } else {+        if (f < 0 || f > 100)+            return JS_ThrowRangeError(ctx, "invalid number of digits");+        f++;+        flags = JS_DTOA_FORMAT_FIXED;+    }+    return js_dtoa2(ctx, d, 10, f, flags | JS_DTOA_EXP_ENABLED);+}++JSValue js_number_toPrecision(JSContext *ctx, JSValue *this_val,+                              int argc, JSValue *argv)+{+    int p, flags;+    double d;++    if (js_thisNumberValue(ctx, &d, *this_val))+        return JS_EXCEPTION;+    if (JS_IsUndefined(argv[0])) {+        flags = JS_DTOA_FORMAT_FREE;+        p = 0;+    } else {+        if (JS_ToInt32Sat(ctx, &p, argv[0]))+            return JS_EXCEPTION;+        if (!isfinite(d)) {+            flags = JS_DTOA_FORMAT_FREE;+        } else {+            if (p < 1 || p > 100)+                return JS_ThrowRangeError(ctx, "invalid number of digits");+            flags = JS_DTOA_FORMAT_FIXED;+        }+    }+    return js_dtoa2(ctx, d, 10, p, flags);+}++JSValue js_number_parseInt(JSContext *ctx, JSValue *this_val,+                           int argc, JSValue *argv)+{+    int radix;+    double d;+    +    argv[0] = JS_ToString(ctx, argv[0]);+    if (JS_IsException(argv[0]))+        return JS_EXCEPTION;+    if (JS_ToInt32(ctx, &radix, argv[1]))+        return JS_EXCEPTION;+    if (radix != 0 && (radix < 2 || radix > 36)) {+        d = NAN;+    } else {+        if (js_atod1(ctx, &d, argv[0], radix, JS_ATOD_INT_ONLY))+            return JS_EXCEPTION;+    }+    return JS_NewFloat64(ctx, d);+}++JSValue js_number_parseFloat(JSContext *ctx, JSValue *this_val,+                             int argc, JSValue *argv)+{+    double d;+    +    argv[0] = JS_ToString(ctx, argv[0]);+    if (JS_IsException(argv[0]))+        return JS_EXCEPTION;+    if (js_atod1(ctx, &d, argv[0], 10, 0))+        return JS_EXCEPTION;+    return JS_NewFloat64(ctx, d);+}++/**********************************************************************/++JSValue js_boolean_constructor(JSContext *ctx, JSValue *this_val,+                               int argc, JSValue *argv)+{+    if (argc & FRAME_CF_CTOR)+        return JS_ThrowTypeError(ctx, "Boolean constructor not supported");+    return JS_NewBool(JS_ToBool(ctx, argv[0]));+}++/**********************************************************************/++JSValue js_string_get_length(JSContext *ctx, JSValue *this_val,+                             int argc, JSValue *argv)+{+    int len;+    +    if (!JS_IsString(ctx, *this_val))+        return JS_ThrowTypeError(ctx, "not a string");+    len = js_string_len(ctx, *this_val);+    return JS_NewShortInt(len);+}++JSValue js_string_set_length(JSContext *ctx, JSValue *this_val,+                            int argc, JSValue *argv)+{+    return JS_UNDEFINED; /* ignored */+}++JSValue js_string_slice(JSContext *ctx, JSValue *this_val,+                        int argc, JSValue *argv)+{+    int len, start, end;+    +    *this_val = JS_ToStringCheckObject(ctx, *this_val);+    if (JS_IsException(*this_val))+        return JS_EXCEPTION;+    len = js_string_len(ctx, *this_val);+    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))+        return JS_EXCEPTION;+    end = len;+    if (!JS_IsUndefined(argv[1])) {+        if (JS_ToInt32Clamp(ctx, &end, argv[1], 0, len, len))+            return JS_EXCEPTION;+    }+    return js_sub_string(ctx, *this_val, start, max_int(end, start));+}++JSValue js_string_substring(JSContext *ctx, JSValue *this_val,+                            int argc, JSValue *argv)+{+    int a, b, start, end, len;++    *this_val = JS_ToStringCheckObject(ctx, *this_val);+    if (JS_IsException(*this_val))+        return JS_EXCEPTION;+    len = js_string_len(ctx, *this_val);+    if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, len, 0))+        return JS_EXCEPTION;+    b = len;+    if (!JS_IsUndefined(argv[1])) {+        if (JS_ToInt32Clamp(ctx, &b, argv[1], 0, len, 0))+            return JS_EXCEPTION;+    }+    if (a < b) {+        start = a;+        end = b;+    } else {+        start = b;+        end = a;+    }+    return js_sub_string(ctx, *this_val, start, end);+}++JSValue js_string_charAt(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv, int magic)+{+    JSValue ret;+    int idx, c;+    +    *this_val = JS_ToStringCheckObject(ctx, *this_val);+    if (JS_IsException(*this_val))+        return JS_EXCEPTION;+    if (JS_ToInt32Sat(ctx, &idx, argv[0]))+        return JS_EXCEPTION;+    if (idx < 0)+        goto ret_undef;+    c = string_getcp(ctx, *this_val, idx, (magic == magic_codePointAt));+    if (c == -1) {+    ret_undef:+        if (magic == magic_charCodeAt)+            ret = JS_NewFloat64(ctx, NAN);+        else if (magic == magic_charAt)+            ret = js_get_atom(ctx, JS_ATOM_empty);+        else+            ret = JS_UNDEFINED;+    } else {+        if (magic == magic_charCodeAt || magic == magic_codePointAt)+            ret = JS_NewShortInt(c);+        else+            ret = JS_NewStringChar(c);+    }+    //    dump_string_pos_cache(ctx);    +    return ret;+}++JSValue js_string_constructor(JSContext *ctx, JSValue *this_val,+                              int argc, JSValue *argv)+{+    if (argc & FRAME_CF_CTOR)+        return JS_ThrowTypeError(ctx, "string constructor not supported");+    if (argc <= 0) {+        return js_get_atom(ctx, JS_ATOM_empty);+    } else {+        return JS_ToString(ctx, argv[0]);+    }+}++JSValue js_string_fromCharCode(JSContext *ctx, JSValue *this_val,+                               int argc, JSValue *argv, int is_fromCodePoint)+{+    int i;+    StringBuffer b_s, *b = &b_s;++    string_buffer_push(ctx, b, 0);+    for(i = 0; i < argc; i++) {+        int c;+        if (JS_ToInt32(ctx, &c, argv[i]))+            goto fail;+        if (is_fromCodePoint) {+            if (c < 0 || c > 0x10ffff) {+                JS_ThrowRangeError(ctx, "invalid code point");+                goto fail;+            }+        } else {+            c &= 0xffff;+        }+        if (string_buffer_putc(ctx, b, c))+            break;+    }+    return string_buffer_pop(ctx, b);+ fail:+    string_buffer_pop(ctx, b);+    return JS_EXCEPTION;+}++JSValue js_string_concat(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv)+{+    int i;+    StringBuffer b_s, *b = &b_s;+    JSValue r;+    +    r = JS_ToStringCheckObject(ctx, *this_val);+    if (JS_IsException(r))+        return JS_EXCEPTION;+    string_buffer_push(ctx, b, 0);+    if (string_buffer_concat(ctx, b, r))+        goto done;++    for (i = 0; i < argc; i++) {+        if (string_buffer_concat(ctx, b, argv[i]))+            goto done;+    }+ done:+    return string_buffer_pop(ctx, b);+}++JSValue js_string_indexOf(JSContext *ctx, JSValue *this_val,+                          int argc, JSValue *argv, int lastIndexOf)+{+    int i, len, v_len, pos, start, stop, ret, inc, j;++    *this_val = JS_ToStringCheckObject(ctx, *this_val);+    if (JS_IsException(*this_val))+        return JS_EXCEPTION;+    argv[0] = JS_ToString(ctx, argv[0]);+    if (JS_IsException(argv[0]))+        return JS_EXCEPTION;+    len = js_string_len(ctx, *this_val);+    v_len = js_string_len(ctx, argv[0]);+    if (lastIndexOf) {+        pos = len - v_len;+        if (argc > 1) {+            double d;+            if (JS_ToNumber(ctx, &d, argv[1]))+                goto fail;+            if (!isnan(d)) {+                if (d <= 0)+                    pos = 0;+                else if (d < pos)+                    pos = d;+            }+        }+        start = pos;+        stop = 0;+        inc = -1;+    } else {+        pos = 0;+        if (argc > 1) {+            if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))+                goto fail;+        }+        start = pos;+        stop = len - v_len;+        inc = 1;+    }+    ret = -1;+    if (len >= v_len && inc * (stop - start) >= 0) {+        for (i = start;; i += inc) {+            for(j = 0; j < v_len; j++) {+                if (string_getc(ctx, *this_val, i + j) != string_getc(ctx, argv[0], j)) {+                    goto next;+                }+            }+            ret = i;+            break;+        next:+            if (i == stop)+                break;+        }+    }+    return JS_NewShortInt(ret);++fail:+    return JS_EXCEPTION;+}++static int js_string_indexof(JSContext *ctx, JSValue str, JSValue needle,+                             int start, int str_len, int needle_len)+{+    int i, j;+    for(i = start; i <= str_len - needle_len; i++) {+        for(j = 0; j < needle_len; j++) {+            if (string_getc(ctx, str, i + j) !=+                string_getc(ctx, needle, j)) {+                goto next;+            }+            +        }+        return i;+    next: ;+    }+    return -1;+}++/* Note: ascii only */+JSValue js_string_toLowerCase(JSContext *ctx, JSValue *this_val,+                              int argc, JSValue *argv, int to_lower)+{+    StringBuffer b_s, *b = &b_s;+    int i, c, len;++    *this_val = JS_ToStringCheckObject(ctx, *this_val);+    if (JS_IsException(*this_val))+        return *this_val;+    len = js_string_len(ctx, *this_val);+    string_buffer_push(ctx, b, len);+    for(i = 0; i < len; i++) {+        c = string_getc(ctx, *this_val, i);+        if (to_lower) {+            if (c >= 'A' && c <= 'Z')+                c += 'a' - 'A';+        } else {+            if (c >= 'a' && c <= 'z')+                c += 'A' - 'a';+        }+        string_buffer_putc(ctx, b, c);+    }+    return string_buffer_pop(ctx, b);+}++/* c < 128 */+static force_inline BOOL unicode_is_space_ascii(uint32_t c)+{+    return (c >= 0x0009 && c <= 0x000D) || (c == 0x0020);+}++static BOOL unicode_is_space_non_ascii(uint32_t c)+{+    return (c == 0x00A0 ||+            c == 0x1680 ||+            (c >= 0x2000 && c <= 0x200A) ||+            (c >= 0x2028 && c <= 0x2029) ||+            c == 0x202F ||+            c == 0x205F ||+            c == 0x3000 ||+            c == 0xFEFF);+}++static force_inline BOOL unicode_is_space(uint32_t c)+{+    if (likely(c < 128)) {+        return unicode_is_space_ascii(c);+    } else {+        return unicode_is_space_non_ascii(c);+    }+}++JSValue js_string_trim(JSContext *ctx, JSValue *this_val,+                       int argc, JSValue *argv, int magic)+{+    int a, b, len;++    *this_val = JS_ToStringCheckObject(ctx, *this_val);+    if (JS_IsException(*this_val))+        return *this_val;+    len = js_string_len(ctx, *this_val);+    a = 0;+    b = len;+    if (magic & 1) {+        while (a < len && unicode_is_space(string_getc(ctx, *this_val, a)))+            a++;+    }+    if (magic & 2) {+        while (b > a && unicode_is_space(string_getc(ctx, *this_val, b - 1)))+            b--;+    }+    return js_sub_string(ctx, *this_val, a, b);+}++JSValue js_string_toString(JSContext *ctx, JSValue *this_val,+                           int argc, JSValue *argv)+{+    if (!JS_IsString(ctx, *this_val))+        return JS_ThrowTypeError(ctx, "not a string");+    return *this_val;+}++JSValue js_string_repeat(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv)+{+    StringBuffer b_s, *b = &b_s;+    JSStringCharBuf buf;+    JSString *p;+    int n;+    int64_t len;+    +    if (!JS_IsString(ctx, *this_val))+        return JS_ThrowTypeError(ctx, "not a string");+    if (JS_ToInt32Sat(ctx, &n, argv[0]))+        return -1;+    p = get_string_ptr(ctx, &buf, *this_val);+    if (n < 0 || (len = (int64_t)n * p->len) > JS_STRING_LEN_MAX)+        return JS_ThrowRangeError(ctx, "invalid repeat count");+    if (p->len == 0 || n == 1)+        return *this_val;+    if (string_buffer_push(ctx, b, len))+        return JS_EXCEPTION;+    while (n-- > 0) {+        string_buffer_concat_str(ctx, b, *this_val);+    }+    return string_buffer_pop(ctx, b);+}++/**********************************************************************/++JSValue js_object_constructor(JSContext *ctx, JSValue *this_val,+                              int argc, JSValue *argv)+{+    /* XXX: incomplete */+    argc &= ~FRAME_CF_CTOR;+    if (argc <= 0) {+        return JS_NewObject(ctx);+    } else {+        return argv[0];+    }+}++JSValue js_object_defineProperty(JSContext *ctx, JSValue *this_val,+                                 int argc, JSValue *argv)+{+    JSValue *pobj, *pprop, *pdesc;+    JSValue val, getter, setter;+    JSGCRef val_ref, getter_ref;+    int flags;+    +    pobj = &argv[0];+    pprop = &argv[1];+    pdesc = &argv[2];++    if (!JS_IsObject(ctx, *pobj))+        return JS_ThrowTypeErrorNotAnObject(ctx);+    *pprop = JS_ToPropertyKey(ctx, *pprop);+    if (JS_IsException(*pprop))+        return JS_EXCEPTION;+    val = JS_UNDEFINED;+    getter = JS_UNDEFINED;+    setter = JS_UNDEFINED;+    flags = 0;+    if (JS_HasProperty(ctx, *pdesc, js_get_atom(ctx, JS_ATOM_value))) {+        flags |= JS_DEF_PROP_HAS_VALUE;+        val = JS_GetProperty(ctx, *pdesc, js_get_atom(ctx, JS_ATOM_value));+        if (JS_IsException(val))+            return JS_EXCEPTION;+    }+    if (JS_HasProperty(ctx, *pdesc, js_get_atom(ctx, JS_ATOM_get))) {+        flags |= JS_DEF_PROP_HAS_GET;+        JS_PUSH_VALUE(ctx, val);+        getter = JS_GetProperty(ctx, *pdesc, js_get_atom(ctx, JS_ATOM_get));+        JS_POP_VALUE(ctx, val);+        if (JS_IsException(getter))+            return JS_EXCEPTION;+        if (!JS_IsUndefined(getter) && !JS_IsFunction(ctx, getter))+            goto bad_getset;+    }+    if (JS_HasProperty(ctx, *pdesc, js_get_atom(ctx, JS_ATOM_set))) {+        flags |= JS_DEF_PROP_HAS_SET;+        JS_PUSH_VALUE(ctx, val);+        JS_PUSH_VALUE(ctx, getter);+        setter = JS_GetProperty(ctx, *pdesc, js_get_atom(ctx, JS_ATOM_set));+        JS_POP_VALUE(ctx, getter);+        JS_POP_VALUE(ctx, val);+        if (JS_IsException(setter))+            return JS_EXCEPTION;+        if (!JS_IsUndefined(setter) && !JS_IsFunction(ctx, setter)) {+        bad_getset:+            return JS_ThrowTypeError(ctx, "invalid getter or setter");+        }+    }+    if (flags & (JS_DEF_PROP_HAS_GET | JS_DEF_PROP_HAS_SET)) {+        if (flags & JS_DEF_PROP_HAS_VALUE)+            return JS_ThrowTypeError(ctx, "cannot have both value and get/set");+        val = getter;+    }+    val = JS_DefinePropertyInternal(ctx, *pobj, *pprop, val, setter,+                                    flags | JS_DEF_PROP_LOOKUP);+    if (JS_IsException(val))+        return val;+    return *pobj;+}++JSValue js_object_getPrototypeOf(JSContext *ctx, JSValue *this_val,+                                 int argc, JSValue *argv)+{+    JSObject *p;+    if (!JS_IsObject(ctx, argv[0]))+        return JS_ThrowTypeErrorNotAnObject(ctx);+    p = JS_VALUE_TO_PTR(argv[0]);+    return p->proto;+}++/* 'obj' must be an object. 'proto' must be JS_NULL or an object */+static JSValue js_set_prototype_internal(JSContext *ctx, JSValue obj, JSValue proto)+{+    JSObject *p, *p1;++    p = JS_VALUE_TO_PTR(obj);+    if (p->proto != proto) {+        if (proto != JS_NULL) {+            /* check if there is a cycle */+            p1 = JS_VALUE_TO_PTR(proto);+            for(;;) {+                if (p1 == p)+                    return JS_ThrowTypeError(ctx, "circular prototype chain");+                if (p1->proto == JS_NULL)+                    break;+                p1 = JS_VALUE_TO_PTR(p1->proto);+            }+        }+        +        p->proto = proto;+    }+    return JS_UNDEFINED;+}++JSValue js_object_setPrototypeOf(JSContext *ctx, JSValue *this_val,+                                 int argc, JSValue *argv)+{+    JSValue proto;+    +    if (!JS_IsObject(ctx, argv[0]))+        return JS_ThrowTypeErrorNotAnObject(ctx);+    proto = argv[1];+    if (proto != JS_NULL && !JS_IsObject(ctx, proto))+        return JS_ThrowTypeError(ctx, "not a prototype");+    if (JS_IsException(js_set_prototype_internal(ctx, argv[0], proto)))+        return JS_EXCEPTION;+    return argv[0];+}++JSValue js_object_create(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv)+{+    JSValue proto;+    proto = argv[0];+    if (proto != JS_NULL && !JS_IsObject(ctx, proto))+        return JS_ThrowTypeError(ctx, "not a prototype");+    if (argc >= 2)+        return JS_ThrowTypeError(ctx, "unsupported additional properties");+    return JS_NewObjectProtoClass(ctx, proto, JS_CLASS_OBJECT, 0);+}++JSValue js_object_keys(JSContext *ctx, JSValue *this_val,+                       int argc, JSValue *argv)+{+    JSObject *p, *pret;+    JSValue ret, str;+    JSValueArray *arr, *ret_arr;+    int array_len, prop_count, hash_mask, alloc_size, i, j, pos;+    JSGCRef ret_ref;++    if (!JS_IsObject(ctx, argv[0]))+        return JS_ThrowTypeErrorNotAnObject(ctx);+    p = JS_VALUE_TO_PTR(argv[0]);++    if (p->class_id == JS_CLASS_ARRAY) {+        array_len = p->u.array.len;+    } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) {+        array_len = p->u.typed_array.len;+    } else {+        array_len = 0;+    }+            +    arr = JS_VALUE_TO_PTR(p->props);+    prop_count = JS_VALUE_GET_INT(arr->arr[0]);+    hash_mask = JS_VALUE_GET_INT(arr->arr[1]);++    alloc_size = array_len + prop_count;+    +    ret = JS_NewArray(ctx, alloc_size);+    if (JS_IsException(ret))+        return ret;++    pos = 0;+    for(i = 0; i < array_len; i++) {+        JS_PUSH_VALUE(ctx, ret);+        str = JS_ToString(ctx, JS_NewShortInt(i));+        JS_POP_VALUE(ctx, ret);+        if (JS_IsException(str))+            return str;+        pret = JS_VALUE_TO_PTR(ret);+        ret_arr = JS_VALUE_TO_PTR(pret->u.array.tab);+        ret_arr->arr[pos++] = str;+    }+    +    for(i = 0, j = 0; j < prop_count; i++) {+        JSProperty *pr;+        p = JS_VALUE_TO_PTR(argv[0]);+        arr = JS_VALUE_TO_PTR(p->props);+        pr = (JSProperty *)&arr->arr[2 + hash_mask + 1 + 3 * i];+        /* exclude deleted properties */+        if (pr->key != JS_UNINITIALIZED) {+            JS_PUSH_VALUE(ctx, ret);+            str = JS_ToString(ctx, pr->key);+            JS_POP_VALUE(ctx, ret);+            if (JS_IsException(str))+                return str;+            pret = JS_VALUE_TO_PTR(ret);+            ret_arr = JS_VALUE_TO_PTR(pret->u.array.tab);+            ret_arr->arr[pos++] = str;+            j++;+        }+    }+    pret = JS_VALUE_TO_PTR(ret);+    pret->u.array.len = pos;+    return ret;+}++JSValue js_object_hasOwnProperty(JSContext *ctx, JSValue *this_val,+                                 int argc, JSValue *argv)+{+    JSObject *p;+    JSValue prop;+    int array_len, idx;+    +    if (JS_IsNull(*this_val) || JS_IsUndefined(*this_val))+        return JS_ThrowTypeError(ctx, "cannot convert to object");+    if (!JS_IsObject(ctx, *this_val))+        return JS_FALSE; /* XXX: could improve for strings */+    prop = JS_ToPropertyKey(ctx, argv[0]);+    p = JS_VALUE_TO_PTR(*this_val);+    if (p->class_id == JS_CLASS_ARRAY) {+        array_len = p->u.array.len;+        goto check_array;+    } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) {+        array_len = p->u.typed_array.len;+    check_array:+        if (JS_IsInt(prop)) {+            idx = JS_VALUE_GET_INT(prop);+            return JS_NewBool((idx >= 0 && idx < array_len));+        }+    }+    return JS_NewBool((find_own_property(ctx, p, prop) != NULL));+}++JSValue js_object_toString(JSContext *ctx, JSValue *this_val,+                           int argc, JSValue *argv)+{+    const char *str;+    char buf[64];+    /* XXX: not fully compliant */+    if (JS_IsIntOrShortFloat(*this_val)) {+        goto number;+    } else if (!JS_IsPtr(*this_val)) {+        switch(JS_VALUE_GET_SPECIAL_TAG(*this_val)) {+        case JS_TAG_NULL:+            str = "Null";+            break;+        case JS_TAG_UNDEFINED:+            str = "Undefined";+            break;+        case JS_TAG_SHORT_FUNC:+            str = "Function";+            break;+        case JS_TAG_BOOL:+            str = "Boolean";+            break;+        case JS_TAG_STRING_CHAR:+            goto string;+        default:+            goto object;+        }+    } else {+        JSObject *p = JS_VALUE_TO_PTR(*this_val);+        switch(p->mtag) {+        case JS_MTAG_OBJECT:+            switch(p->class_id) {+            case JS_CLASS_ARRAY:+                str = "Array";+                break;+            case JS_CLASS_ERROR:+                str = "Error";+                break;+            case JS_CLASS_CLOSURE:+            case JS_CLASS_C_FUNCTION:+                str = "Function";+                break;+            default:+            object:+                str = "Object";+                break;+            }+            break;+        case JS_MTAG_STRING:+        string:+            str = "String";+            break;+        case JS_MTAG_FLOAT64:+        number:+            str = "Number";+            break;+        default:+            goto object;+        }+    }+    js_snprintf(buf, sizeof(buf), "[object %s]", str);+    return JS_NewString(ctx, buf);+}++/**********************************************************************/++JSValue js_error_constructor(JSContext *ctx, JSValue *this_val,+                             int argc, JSValue *argv, int magic)+{+    JSValue obj, msg;+    JSObject *p;+    JSGCRef obj_ref;+    +    argc &= ~FRAME_CF_CTOR;++    obj = JS_NewObjectProtoClass(ctx, ctx->class_proto[magic], JS_CLASS_ERROR,+                                 sizeof(JSErrorData));+    if (JS_IsException(obj))+        return obj;+    p = JS_VALUE_TO_PTR(obj);+    p->u.error.message = JS_NULL;+    p->u.error.stack = JS_NULL;+    +    if (!JS_IsUndefined(argv[0])) {+        JS_PUSH_VALUE(ctx, obj);+        msg = JS_ToString(ctx, argv[0]);+        JS_POP_VALUE(ctx, obj);+        if (JS_IsException(msg))+            return msg;+        p = JS_VALUE_TO_PTR(obj);+        p->u.error.message = msg;+    } else {+        p = JS_VALUE_TO_PTR(obj);+        p->u.error.message = js_get_atom(ctx, JS_ATOM_empty);+    }+    JS_PUSH_VALUE(ctx, obj);+    build_backtrace(ctx, obj, NULL, 0, 0, 1);+    JS_POP_VALUE(ctx, obj);+    return obj;+}++JSValue js_error_toString(JSContext *ctx, JSValue *this_val,+                          int argc, JSValue *argv)+{+    JSObject *p;+    JSValue name;+    StringBuffer b_s, *b = &b_s;++    if (!JS_IsError(ctx, *this_val))+        return JS_ThrowTypeError(ctx, "not an Error object");+    name = JS_GetProperty(ctx, *this_val, js_get_atom(ctx, JS_ATOM_name));+    if (JS_IsException(name))+        return name;+    if (JS_IsUndefined(name))+        name = js_get_atom(ctx, JS_ATOM_Error);+    else+        name = JS_ToString(ctx, name);+    if (JS_IsException(name))+        return name;+    string_buffer_push(ctx, b, 0);+    string_buffer_concat(ctx, b, name);+    p = JS_VALUE_TO_PTR(*this_val);+    if (p->u.error.message != JS_NULL) {+        string_buffer_puts(ctx, b, ": ");+        p = JS_VALUE_TO_PTR(*this_val);+        string_buffer_concat(ctx, b, p->u.error.message);+    }+    return string_buffer_pop(ctx, b);+}++JSValue js_error_get_message(JSContext *ctx, JSValue *this_val,+                             int argc, JSValue *argv, int magic)+{+    JSObject *p;+    if (!JS_IsError(ctx, *this_val))+        return JS_ThrowTypeError(ctx, "not an Error object");+    p = JS_VALUE_TO_PTR(*this_val);+    if (magic == 0)+        return p->u.error.message;+    else+        return p->u.error.stack;+}++/**********************************************************************/++static JSObject *js_get_array(JSContext *ctx, JSValue obj)+{+    JSObject *p;+    p = js_get_object_class(ctx, obj, JS_CLASS_ARRAY);+    if (!p) {+        JS_ThrowTypeError(ctx, "not an array");+        return NULL;+    }+    return p;+}++JSValue js_array_get_length(JSContext *ctx, JSValue *this_val,+                            int argc, JSValue *argv)+{+    JSObject *p;+    p = js_get_array(ctx, *this_val);+    if (!p)+        return JS_EXCEPTION;+    return JS_NewShortInt(p->u.array.len);+}++static int js_array_resize(JSContext *ctx, JSValue *this_val, int new_len)+{+    JSObject *p;+    int i;++    if (new_len < 0 || new_len > JS_SHORTINT_MAX) {+        JS_ThrowTypeError(ctx, "invalid array length");+        return -1;+    }+    p = JS_VALUE_TO_PTR(*this_val);+    if (new_len < p->u.array.len) {+        JSValueArray *arr = JS_VALUE_TO_PTR(p->u.array.tab);+        /* shrink the array if the new size is small enough */+        if (new_len < (arr->size / 2) && arr->size >= 4) {+            js_shrink_value_array(ctx, &p->u.array.tab, new_len);+            p = JS_VALUE_TO_PTR(*this_val);+        } else {+            for(i = new_len; i < p->u.array.len; i++)+                arr->arr[i] = JS_UNDEFINED;+        }+    } else if (new_len > p->u.array.len) {+        JSValueArray *arr;+        JSValue new_tab;+        new_tab = js_resize_value_array(ctx, p->u.array.tab, new_len);+        if (JS_IsException(new_tab))+            return -1;+        p = JS_VALUE_TO_PTR(*this_val);+        p->u.array.tab = new_tab;+        arr = JS_VALUE_TO_PTR(p->u.array.tab);+        for(i = p->u.array.len; i < new_len; i++)+            arr->arr[i] = JS_UNDEFINED;+    }+    p->u.array.len = new_len;+    return 0;+}++JSValue js_array_set_length(JSContext *ctx, JSValue *this_val,+                            int argc, JSValue *argv)+{+    int new_len;++    if (!js_get_array(ctx, *this_val))+        return JS_EXCEPTION;+    if (JS_ToInt32(ctx, &new_len, argv[0]))+        return JS_EXCEPTION;+    if (js_array_resize(ctx, this_val, new_len))+        return JS_EXCEPTION;+    return JS_UNDEFINED;+}++JSValue js_array_constructor(JSContext *ctx, JSValue *this_val,+                             int argc, JSValue *argv)+{+    JSValue obj;+    JSObject *p;+    int len, i;+    BOOL has_init;+    +    argc &= ~FRAME_CF_CTOR;++    if (argc == 1 && JS_IsNumber(ctx, argv[0])) {+        /* XXX: we create undefined properties instead of just setting the length */+        if (JS_ToInt32(ctx, &len, argv[0]))+            return JS_EXCEPTION;+        has_init = FALSE;+    } else {+        len = argc;+        has_init = TRUE;+    }+    +    if (len < 0 || len > JS_SHORTINT_MAX)+        return JS_ThrowRangeError(ctx, "invalid array length");+    obj = JS_NewArray(ctx, len);+    if (JS_IsException(obj))+        return obj;+    p = JS_VALUE_TO_PTR(obj);+    p->u.array.len = len;++    if (has_init) {+        JSValueArray *arr = JS_VALUE_TO_PTR(p->u.array.tab);+        for(i = 0; i < argc; i++) {+            arr->arr[i] = argv[i];+        }+    }+    return obj;+}++JSValue js_array_push(JSContext *ctx, JSValue *this_val,+                      int argc, JSValue *argv, int is_unshift)+{+    JSObject *p;+    int new_len, i, from;+    JSValueArray *arr;+    JSValue new_tab;+    +    p = js_get_array(ctx, *this_val);+    if (!p)+        return JS_EXCEPTION;+    from = p->u.array.len;+    new_len = from + argc;+    if (new_len > JS_SHORTINT_MAX)+        return JS_ThrowRangeError(ctx, "invalid array length");+    new_tab = js_resize_value_array(ctx, p->u.array.tab, new_len);+    if (JS_IsException(new_tab))+        return JS_EXCEPTION;+    p = JS_VALUE_TO_PTR(*this_val);+    p->u.array.tab = new_tab;+    p->u.array.len = new_len;+    arr = JS_VALUE_TO_PTR(p->u.array.tab);+    if (is_unshift && argc > 0) {+        memmove(arr->arr + argc, arr->arr, from * sizeof(JSValue));+        from = 0;+    }+    for(i = 0; i < argc; i++) {+        arr->arr[from + i] = argv[i];+    }+    return JS_NewShortInt(new_len);+}++JSValue js_array_pop(JSContext *ctx, JSValue *this_val,+                     int argc, JSValue *argv)+{+    JSObject *p;+    JSValue ret;+    +    p = js_get_array(ctx, *this_val);+    if (!p)+        return JS_EXCEPTION;+    if (p->u.array.len > 0) {+        JSValueArray *arr = JS_VALUE_TO_PTR(p->u.array.tab);+        ret = arr->arr[--p->u.array.len];+    } else {+        ret = JS_UNDEFINED;+    }+    return ret;+}++JSValue js_array_shift(JSContext *ctx, JSValue *this_val,+                       int argc, JSValue *argv)+{+    JSObject *p;+    JSValue ret;+    +    p = js_get_array(ctx, *this_val);+    if (!p)+        return JS_EXCEPTION;+    if (p->u.array.len > 0) {+        JSValueArray *arr = JS_VALUE_TO_PTR(p->u.array.tab);+        ret = arr->arr[0];+        p->u.array.len--;+        memmove(arr->arr, arr->arr + 1, p->u.array.len * sizeof(JSValue));+    } else {+        ret = JS_UNDEFINED;+    }+    return ret;+}++JSValue js_array_join(JSContext *ctx, JSValue *this_val,+                      int argc, JSValue *argv)+{+    uint32_t i, len;+    BOOL is_array;+    JSValue sep, val;+    JSGCRef sep_ref;+    JSObject *p;+    JSValueArray *arr;+    StringBuffer b_s, *b = &b_s;+    +    if (!JS_IsObject(ctx, *this_val))+        return JS_ThrowTypeErrorNotAnObject(ctx);+    p = JS_VALUE_TO_PTR(*this_val);+    is_array = (p->class_id == JS_CLASS_ARRAY);+    if (is_array) {+        len = p->u.array.len;+    } else {+        if (js_get_length32(ctx, &len, *this_val))+            return JS_EXCEPTION;+    }++    if (argc > 0 && !JS_IsUndefined(argv[0])) {+        sep = JS_ToString(ctx, argv[0]);+        if (JS_IsException(sep))+            return sep;+    } else {+        sep = JS_NewStringChar(',');+    }+    JS_PUSH_VALUE(ctx, sep);++    string_buffer_push(ctx, b, 0);+    for(i = 0; i < len; i++) {+        if (i > 0) {+            if (string_buffer_concat(ctx, b, sep_ref.val))+                goto exception;+        }+        if (is_array) {+            p = JS_VALUE_TO_PTR(*this_val);+            arr = JS_VALUE_TO_PTR(p->u.array.tab);+            if (i < p->u.array.len)+                val = arr->arr[i];+            else+                val = JS_UNDEFINED;+        } else {+            val = JS_GetPropertyUint32(ctx, *this_val, i);+            if (JS_IsException(val))+                goto exception;+        }+        if (!JS_IsUndefined(val) && !JS_IsNull(val)) {+            if (string_buffer_concat(ctx, b, val))+                goto exception;+        }+    }+    val = string_buffer_pop(ctx, b);+    JS_POP_VALUE(ctx, sep);+    return val;++ exception:+    string_buffer_pop(ctx, b);+    JS_POP_VALUE(ctx, sep);+    return JS_EXCEPTION;+}++JSValue js_array_toString(JSContext *ctx, JSValue *this_val,+                          int argc, JSValue *argv)+{+    return js_array_join(ctx, this_val, 0, NULL);+}++JSValue js_array_isArray(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv)+{+    JSObject *p;+    p = js_get_object_class(ctx, argv[0], JS_CLASS_ARRAY);+    return JS_NewBool(p != NULL);+}++JSValue js_array_reverse(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv)+{+    int len;+    JSObject *p;+    JSValueArray *arr;++    p = js_get_array(ctx, *this_val);+    if (!p)+        return JS_EXCEPTION;+    len = p->u.array.len;+    arr = JS_VALUE_TO_PTR(p->u.array.tab);+    js_reverse_val(arr->arr, len);+    return *this_val;+}++JSValue js_array_concat(JSContext *ctx, JSValue *this_val,+                      int argc, JSValue *argv)+{+    JSObject *p;+    int len, i, j, pos;+    int64_t len64;+    JSValue obj, val;+    JSValueArray *arr, *arr1;+    +    p = js_get_array(ctx, *this_val);+    if (!p)+        return JS_EXCEPTION;+    /* do a first pass to estimate the length */+    len64 = p->u.array.len;+    for(i = 0; i < argc; i++) {+        p = js_get_object_class(ctx, argv[i], JS_CLASS_ARRAY);+        if (p) {+            len64 += p->u.array.len;+        } else {+            len64++;+        }+    }+    if (len64 > JS_SHORTINT_MAX)+        return JS_ThrowTypeError(ctx, "Array loo long");+    len = len64;++    obj = JS_NewArray(ctx, len);+    if (JS_IsException(obj))+        return obj;+    p = JS_VALUE_TO_PTR(obj);+    arr = JS_VALUE_TO_PTR(p->u.array.tab);+    +    pos = 0;+    for(i = -1; i < argc; i++) {+        val = i == -1 ? *this_val : argv[i];+        p = js_get_object_class(ctx, val, JS_CLASS_ARRAY);+        if (p) {+            arr1 = JS_VALUE_TO_PTR(p->u.array.tab);+            for(j = 0; j < p->u.array.len; j++)+                arr->arr[pos + j] = arr1->arr[j];+            pos += p->u.array.len;+        } else {+            arr->arr[pos++] = val;+        }+    }+    return obj;+}++JSValue js_array_indexOf(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv, int is_lastIndexOf)+{+    JSObject *p;+    int len, n, res;+    JSValueArray *arr;+    +    p = js_get_array(ctx, *this_val);+    if (!p)+        return JS_EXCEPTION;+    len = p->u.array.len;+    if (is_lastIndexOf) {+        n = len - 1;+    } else {+        n = 0;+    }+    if (argc > 1) {+        if (JS_ToInt32Clamp(ctx, &n, argv[1],+                            -is_lastIndexOf, len - is_lastIndexOf, len))+            return JS_EXCEPTION;+    }+    /* the array may be modified */+    p = JS_VALUE_TO_PTR(*this_val);+    len = p->u.array.len; /* the length may be modified */+    arr = JS_VALUE_TO_PTR(p->u.array.tab);+    res = -1;+    if (is_lastIndexOf) {+        n = min_int(n, len - 1);+        for(;n >= 0; n--) {+            if (js_strict_eq(ctx, argv[0], arr->arr[n])) {+                res = n;+                break;+            }+        }+    } else {+        for(;n < len; n++) {+            if (js_strict_eq(ctx, argv[0], arr->arr[n])) {+                res = n;+                break;+            }+        }+    }+    return JS_NewShortInt(res);+}++JSValue js_array_slice(JSContext *ctx, JSValue *this_val,+                       int argc, JSValue *argv)+{+    JSObject *p, *p1;+    int len, start, final, k;+    JSValueArray *arr, *arr1;+    JSValue obj;+    +    p = js_get_array(ctx, *this_val);+    if (!p)+        return JS_EXCEPTION;+    len = p->u.array.len;++    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))+        return JS_EXCEPTION;+    final = len;+    if (!JS_IsUndefined(argv[1])) {+        if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))+            return JS_EXCEPTION;+    }+    /* the array may have been modified */+    p = JS_VALUE_TO_PTR(*this_val);+    len = p->u.array.len; /* the length may be modified */+    final = min_int(final, len);++    obj = JS_NewArray(ctx, max_int(final - start, 0));+    if (JS_IsException(obj))+        return obj;+    p = JS_VALUE_TO_PTR(*this_val);+    arr = JS_VALUE_TO_PTR(p->u.array.tab);+    p1 = JS_VALUE_TO_PTR(obj);+    arr1 = JS_VALUE_TO_PTR(p1->u.array.tab);+    for(k = start; k < final; k++) {+        arr1->arr[k - start] = arr->arr[k];+    }+    return obj;+}++JSValue js_array_splice(JSContext *ctx, JSValue *this_val,+                        int argc, JSValue *argv)+{+    JSObject *p, *p1;+    int start, len, item_count, del_count, new_len, i, ret;+    JSValueArray *arr, *arr1;+    JSValue obj;+    JSGCRef obj_ref;+    +    p = js_get_array(ctx, *this_val);+    if (!p)+        return JS_EXCEPTION;+    len = p->u.array.len;++    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))+        return JS_EXCEPTION;++    if (argc == 0) {+        item_count = 0;+        del_count = 0;+    } else if (argc == 1) {+        item_count = 0;+        del_count = len - start;+    } else {+        item_count = argc - 2;+        if (JS_ToInt32Clamp(ctx, &del_count, argv[1], 0, len - start, 0))+            return JS_EXCEPTION;+    }+    new_len = len + item_count - del_count;+    +    obj = JS_NewArray(ctx, del_count);+    if (JS_IsException(obj))+        return obj;+    p = JS_VALUE_TO_PTR(*this_val);+    /* handling this case has no practical use */+    if (p->u.array.len != len)+        return JS_ThrowTypeError(ctx, "array length was modified");+    arr = JS_VALUE_TO_PTR(p->u.array.tab);+    p1 = JS_VALUE_TO_PTR(obj);+    arr1 = JS_VALUE_TO_PTR(p1->u.array.tab);++    for(i = 0; i < del_count; i++) {+        arr1->arr[i] = arr->arr[start + i];+    }++    if (item_count != del_count) {+        /* resize */+        if (del_count > item_count) {+            memmove(arr->arr + start + item_count,+                    arr->arr + start + del_count,+                    (len - (start + del_count)) * sizeof(JSValue));+        }+        JS_PUSH_VALUE(ctx, obj);+        ret = js_array_resize(ctx, this_val, new_len);+        JS_POP_VALUE(ctx, obj);+        if (ret)+            return JS_EXCEPTION;+        p = JS_VALUE_TO_PTR(*this_val);+        arr = JS_VALUE_TO_PTR(p->u.array.tab);+        if (del_count < item_count) {+            memmove(arr->arr + start + item_count,+                    arr->arr + start + del_count,+                    (len - (start + del_count)) * sizeof(JSValue));+        }+    }++    for(i = 0; i < item_count; i++)+        arr->arr[start + i] = argv[2 + i];+    +    return obj;+}++JSValue js_array_every(JSContext *ctx, JSValue *this_val,+                       int argc, JSValue *argv, int special)+{+    JSObject *p;+    JSValueArray *arr;+    JSValue res, ret, val;+    JSValue *pfunc, *pthis_arg;+    JSGCRef val_ref, ret_ref;+    int len, k, n;++    p = js_get_array(ctx, *this_val);+    if (!p)+        return JS_EXCEPTION;+    len = p->u.array.len;++    pfunc = &argv[0];+    pthis_arg = NULL;+    if (argc > 1)+        pthis_arg = &argv[1];++    if (!JS_IsFunction(ctx, *pfunc))+        return JS_ThrowTypeError(ctx, "not a function");+    +    switch (special) {+    case js_special_every:+        ret = JS_TRUE;+        break;+    case js_special_some:+        ret = JS_FALSE;+        break;+    case js_special_map:+        ret = JS_NewArray(ctx, len);+        if (JS_IsException(ret))+            return JS_EXCEPTION;+        break;+    case js_special_filter:+        ret = JS_NewArray(ctx, 0);+        if (JS_IsException(ret))+            return JS_EXCEPTION;+        break;+    case js_special_forEach:+    default:+        ret = JS_UNDEFINED;+        break;+    }+    n = 0;++    JS_PUSH_VALUE(ctx, ret);+    for(k = 0; k < len; k++) {+        if (JS_StackCheck(ctx, 5))+            goto exception;++        p = JS_VALUE_TO_PTR(*this_val);+        arr = JS_VALUE_TO_PTR(p->u.array.tab);+        /* the array length may have been modified by the function call*/+        if (k >= p->u.array.len)+            break;+        val = arr->arr[k];+        +        JS_PushArg(ctx, *this_val);+        JS_PushArg(ctx, JS_NewShortInt(k));+        JS_PushArg(ctx, val); /* arg0 */+        JS_PushArg(ctx, *pfunc); /* func */+        JS_PushArg(ctx, pthis_arg ? *pthis_arg : JS_UNDEFINED); /* this */+        JS_PUSH_VALUE(ctx, val);+        res = JS_Call(ctx, 3);+        JS_POP_VALUE(ctx, val);+        if (JS_IsException(res))+            goto exception;+        +        switch (special) {+        case js_special_every:+            if (!JS_ToBool(ctx, res)) {+                ret_ref.val = JS_FALSE;+                goto done;+            }+            break;+        case js_special_some:+            if (JS_ToBool(ctx, res)) {+                ret_ref.val = JS_TRUE;+                goto done;+            }+            break;+        case js_special_map:+            /* Note: same as defineProperty for arrays */+            res = JS_SetPropertyUint32(ctx, ret_ref.val, k, res);+            if (JS_IsException(res))+                goto exception;+            break;+        case js_special_filter:+            if (JS_ToBool(ctx, res)) {+                res = JS_SetPropertyUint32(ctx, ret_ref.val, n++, val);+                if (JS_IsException(res))+                    goto exception;+            }+            break;+        case js_special_forEach:+        default:+            break;+        }+    }+done:+    JS_POP_VALUE(ctx, ret);+    return ret;+ exception:+    ret_ref.val = JS_EXCEPTION;+    goto done;+}++JSValue js_array_reduce(JSContext *ctx, JSValue *this_val,+                        int argc, JSValue *argv, int special)+{+    JSObject *p;+    JSValueArray *arr;+    JSValue acc, *pfunc;+    JSGCRef acc_ref;+    int len, k, k1, ret;++    p = js_get_array(ctx, *this_val);+    if (!p)+        return JS_EXCEPTION;+    len = p->u.array.len;+    pfunc = &argv[0];++    if (!JS_IsFunction(ctx, *pfunc))+        return JS_ThrowTypeError(ctx, "not a function");++    k = 0;+    if (argc > 1) {+        acc = argv[1];+    } else {+        if (len == 0)+            return JS_ThrowTypeError(ctx, "empty array");+        k1 = (special == js_special_reduceRight) ? len - k - 1 : k;+        arr = JS_VALUE_TO_PTR(p->u.array.tab);+        acc = arr->arr[k1];+        k++;+    }+    for (; k < len; k++) {+        JS_PUSH_VALUE(ctx, acc);+        ret = JS_StackCheck(ctx, 6);+        JS_POP_VALUE(ctx, acc);+        if (ret)+            return JS_EXCEPTION;++        k1 = (special == js_special_reduceRight) ? len - k - 1 : k;+        p = JS_VALUE_TO_PTR(*this_val);+        arr = JS_VALUE_TO_PTR(p->u.array.tab);+        /* Note: the array length may have been modified, hence the check */+        if (k1 >= p->u.array.len)+            break;+        +        JS_PushArg(ctx, *this_val);+        JS_PushArg(ctx, JS_NewShortInt(k1));+        JS_PushArg(ctx, arr->arr[k1]);+        JS_PushArg(ctx, acc); /* arg0 */+        JS_PushArg(ctx, *pfunc); /* func */+        JS_PushArg(ctx, JS_UNDEFINED); /* this */+        acc = JS_Call(ctx, 4);+        if (JS_IsException(acc))+            return JS_EXCEPTION;+    }+    return acc;+}++/* heapsort algorithm */+static void rqsort_idx(size_t nmemb,+                       int (*cmp)(size_t, size_t, void *),+                       void (*swap)(size_t, size_t, void *),+                       void *opaque)+{+    size_t i, n, c, r, size;++    size = 1;+    if (nmemb > 1) {+        i = (nmemb / 2) * size;+        n = nmemb * size;++        while (i > 0) {+            i -= size;+            for (r = i; (c = r * 2 + size) < n; r = c) {+                if (c < n - size && cmp(c, c + size, opaque) <= 0)+                    c += size;+                if (cmp(r, c, opaque) > 0)+                    break;+                swap(r, c, opaque);+            }+        }+        for (i = n - size; i > 0; i -= size) {+            swap(0, i, opaque);++            for (r = 0; (c = r * 2 + size) < i; r = c) {+                if (c < i - size && cmp(c, c + size, opaque) <= 0)+                    c += size;+                if (cmp(r, c, opaque) > 0)+                    break;+                swap(r, c, opaque);+            }+        }+    }+}++typedef struct {+    JSContext *ctx;+    BOOL exception;+    JSValue *parr;+    JSValue *pfunc;+} JSArraySortContext;++/* return -1, 0, 1  */+static int js_array_sort_cmp(size_t i1, size_t i2, void *opaque)+{+    JSArraySortContext *s = opaque;+    JSContext *ctx = s->ctx;+    JSValueArray *arr;+    int cmp, j1, j2;+    +    if (s->exception)+        return 0;++    arr = JS_VALUE_TO_PTR(*s->parr);+    if (s->pfunc) {+        JSValue res;+        /* custom sort function is specified as returning 0 for identical+         * objects: avoid method call overhead.+         */+        if (arr->arr[2 * i1] == arr->arr[2 * i2])+            goto cmp_same;+        if (JS_StackCheck(ctx, 4))+            goto exception;+        arr = JS_VALUE_TO_PTR(*s->parr);++        JS_PushArg(ctx, arr->arr[2 * i2]);+        JS_PushArg(ctx, arr->arr[2 * i1]); /* arg0 */+        JS_PushArg(ctx, *s->pfunc); /* func */+        JS_PushArg(ctx, JS_UNDEFINED); /* this */+        res = JS_Call(ctx, 2);+        if (JS_IsException(res))+            return JS_EXCEPTION;+        if (JS_IsInt(res)) {+            int val = JS_VALUE_GET_INT(res);+            cmp = (val > 0) - (val < 0);+        } else {+            double val;+            if (JS_ToNumber(ctx, &val, res))+                goto exception;+            cmp = (val > 0) - (val < 0);+        }+    } else {+        JSValue str1, str2;+        JSGCRef str1_ref;++        str1 = arr->arr[2 * i1];+        if (!JS_IsString(ctx, str1)) {+            str1 = JS_ToString(ctx, str1);+            if (JS_IsException(str1))+                goto exception;+            arr = JS_VALUE_TO_PTR(*s->parr);+        }+        str2 = arr->arr[2 * i2];+        if (!JS_IsString(ctx, str2)) {+            JS_PUSH_VALUE(ctx, str1);+            str2 = JS_ToString(ctx, str2);+            JS_POP_VALUE(ctx, str1);+            if (JS_IsException(str2))+                goto exception;+        }+        cmp = js_string_compare(ctx, str1, str2);+    }+    if (cmp != 0)+        return cmp;+ cmp_same:+    /* make sort stable: compare array offsets */+    arr = JS_VALUE_TO_PTR(*s->parr);+    j1 = JS_VALUE_GET_INT(arr->arr[2 * i1 + 1]);+    j2 = JS_VALUE_GET_INT(arr->arr[2 * i2 + 1]);+    return (j1 > j2) - (j1 < j2);++exception:+    s->exception = TRUE;+    return 0;+}++static void js_array_sort_swap(size_t i1, size_t i2, void *opaque)+{+    JSArraySortContext *s = opaque;+    JSValueArray *arr;+    JSValue tmp, *tab;+    +    arr = JS_VALUE_TO_PTR(*s->parr);+    tab = arr->arr;+    tmp = tab[2 * i1];+    tab[2 * i1] = tab[2 * i2];+    tab[2 * i2] = tmp;++    tmp = tab[2 * i1 + 1];+    tab[2 * i1 + 1] = tab[2 * i2 + 1];+    tab[2 * i2 + 1] = tmp;+}++JSValue js_array_sort(JSContext *ctx, JSValue *this_val,+                      int argc, JSValue *argv)+{+    JSValue *pfunc = &argv[0];+    JSObject *p;+    JSValue tab_val;+    JSGCRef tab_val_ref;+    JSValueArray *tab, *arr;+    int i, len, n;+    JSArraySortContext ss, *s = &ss;+    +    if (!JS_IsUndefined(*pfunc)) {+        if (!JS_IsFunction(ctx, *pfunc))+            return JS_ThrowTypeError(ctx, "not a function");+    } else {+        pfunc = NULL;+    }+    p = js_get_array(ctx, *this_val);+    if (!p)+        return JS_EXCEPTION;++    /* create a temporary array for sorting */+    len = p->u.array.len;+    tab = js_alloc_value_array(ctx, 0, len * 2);+    if (!tab)+        return JS_EXCEPTION;++    p = JS_VALUE_TO_PTR(*this_val);+    arr = JS_VALUE_TO_PTR(p->u.array.tab);+    n = 0;+    for(i = 0; i < len; i++) {+        if (!JS_IsUndefined(arr->arr[i])) {+            tab->arr[2 * n] = arr->arr[i];+            tab->arr[2 * n + 1] = JS_NewShortInt(i);+            n++;+        }+    }+    /* the end of 'tab' is already filled with JS_UNDEFINED */+    tab_val = JS_VALUE_FROM_PTR(tab);+    +    JS_PUSH_VALUE(ctx, tab_val);+    s->ctx = ctx;+    s->exception = FALSE;+    s->parr = &tab_val_ref.val;+    s->pfunc = pfunc;+    rqsort_idx(n, js_array_sort_cmp, js_array_sort_swap, s);+    JS_POP_VALUE(ctx, tab_val);+    tab = JS_VALUE_TO_PTR(tab_val);+    if (s->exception) {+        js_free(ctx, tab);+        return JS_EXCEPTION;+    }+    +    p = JS_VALUE_TO_PTR(*this_val);+    arr = JS_VALUE_TO_PTR(p->u.array.tab);+    /* XXX: could resize the array in case it was shrank by the compare function */+    len = min_int(len, p->u.array.len);+    for(i = 0; i < len; i++) {+        arr->arr[i] = tab->arr[2 * i];+    }+    js_free(ctx, tab);+    return *this_val;+}++/**********************************************************************/++/* precondition: a and b are not NaN */+static double js_fmin(double a, double b)+{+    if (a == 0 && b == 0) {+        return uint64_as_float64(float64_as_uint64(a) | float64_as_uint64(b));+    } else if (a <= b) {+        return a;+    } else {+        return b;+    }+}++/* precondition: a and b are not NaN */+static double js_fmax(double a, double b)+{+    if (a == 0 && b == 0) {+        return uint64_as_float64(float64_as_uint64(a) & float64_as_uint64(b));+    } else if (a >= b) {+        return a;+    } else {+        return b;+    }+}++JSValue js_math_min_max(JSContext *ctx, JSValue *this_val,+                        int argc, JSValue *argv, int magic)+{+    BOOL is_max = magic;+    double r, a;+    int i;++    if (unlikely(argc == 0)) {+        return __JS_NewFloat64(ctx, is_max ? -1.0 / 0.0 : 1.0 / 0.0);+    }++    if (JS_IsInt(argv[0])) {+        int a1, r1 = JS_VALUE_GET_INT(argv[0]);+        for(i = 1; i < argc; i++) {+            if (!JS_IsInt(argv[i])) {+                r = r1;+                goto generic_case;+            }+            a1 = JS_VALUE_GET_INT(argv[i]);+            if (is_max)+                r1 = max_int(r1, a1);+            else+                r1 = min_int(r1, a1);+        }+        return JS_NewShortInt(r1);+    } else {+        if (JS_ToNumber(ctx, &r, argv[0]))+            return JS_EXCEPTION;+        i = 1;+    generic_case:+        while (i < argc) {+            if (JS_ToNumber(ctx, &a, argv[i]))+                return JS_EXCEPTION;+            if (!isnan(r)) {+                if (isnan(a)) {+                    r = a;+                } else {+                    if (is_max)+                        r = js_fmax(r, a);+                    else+                        r = js_fmin(r, a);+                }+            }+            i++;+        }+        return JS_NewFloat64(ctx, r);+    }+}++double js_math_sign(double a)+{+    if (isnan(a) || a == 0.0)+        return a;+    if (a < 0)+        return -1;+    else+        return 1;+}++double js_math_fround(double a)+{+    return (float)a;+}++JSValue js_math_imul(JSContext *ctx, JSValue *this_val,+                     int argc, JSValue *argv)+{+    int a, b;++    if (JS_ToInt32(ctx, &a, argv[0]))+        return JS_EXCEPTION;+    if (JS_ToInt32(ctx, &b, argv[1]))+        return JS_EXCEPTION;+    /* purposely ignoring overflow */+    return JS_NewInt32(ctx, (uint32_t)a * (uint32_t)b);+}++JSValue js_math_clz32(JSContext *ctx, JSValue *this_val,+                     int argc, JSValue *argv)+{+    uint32_t a, r;++    if (JS_ToUint32(ctx, &a, argv[0]))+        return JS_EXCEPTION;+    if (a == 0)+        r = 32;+    else+        r = clz32(a);+    return JS_NewInt32(ctx, r);+}++JSValue js_math_atan2(JSContext *ctx, JSValue *this_val,+                      int argc, JSValue *argv)+{+    double y, x;+    +    if (JS_ToNumber(ctx, &y, argv[0]))+        return JS_EXCEPTION;+    if (JS_ToNumber(ctx, &x, argv[1]))+        return JS_EXCEPTION;+    return JS_NewFloat64(ctx, js_atan2(y, x));+}++JSValue js_math_pow(JSContext *ctx, JSValue *this_val,+                    int argc, JSValue *argv)+{+    double y, x;+    +    if (JS_ToNumber(ctx, &x, argv[0]))+        return JS_EXCEPTION;+    if (JS_ToNumber(ctx, &y, argv[1]))+        return JS_EXCEPTION;+    return JS_NewFloat64(ctx, js_pow(x, y));+}++/* xorshift* random number generator by Marsaglia */+static uint64_t xorshift64star(uint64_t *pstate)+{+    uint64_t x;+    x = *pstate;+    x ^= x >> 12;+    x ^= x << 25;+    x ^= x >> 27;+    *pstate = x;+    return x * 0x2545F4914F6CDD1D;+}++JSValue js_math_random(JSContext *ctx, JSValue *this_val,+                       int argc, JSValue *argv)+{+    double d;+    uint64_t v;++    v = xorshift64star(&ctx->random_state);+    /* 1.0 <= u.d < 2 */+    d = uint64_as_float64(((uint64_t)0x3ff << 52) | (v >> 12));+    return __JS_NewFloat64(ctx, d - 1.0);+}++/* typed array */++#define JS_TYPED_ARRAY_COUNT (JS_CLASS_FLOAT64_ARRAY - JS_CLASS_UINT8C_ARRAY + 1)++static uint8_t typed_array_size_log2[JS_TYPED_ARRAY_COUNT] = {+    0, 0, 0, 1, 1, 2, 2, 2, 3+};++static int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValue val)+{+    int v;+    /* XXX: should support 53 bit inteers */+    if (JS_ToInt32Sat(ctx, &v, val))+        return -1;+    if (v < 0 || v > JS_SHORTINT_MAX) {+        JS_ThrowRangeError(ctx, "invalid array index");+        return -1;+    }+    *plen = v;+    return 0;+}++JSValue js_array_buffer_alloc(JSContext *ctx, uint64_t len)+{+    JSByteArray *arr;+    JSValue buffer, obj;+    JSGCRef buffer_ref;+    JSObject *p;++    if (len > JS_SHORTINT_MAX)+        return JS_ThrowRangeError(ctx, "invalid array buffer length");+    arr = js_alloc_byte_array(ctx, len);+    if (!arr)+        return JS_EXCEPTION;+    memset(arr->buf, 0, len);+    buffer = JS_VALUE_FROM_PTR(arr);+    JS_PUSH_VALUE(ctx, buffer);+    obj = JS_NewObjectClass(ctx, JS_CLASS_ARRAY_BUFFER, sizeof(JSArrayBuffer));+    JS_POP_VALUE(ctx, buffer);+    if (JS_IsException(obj))+        return obj;+    p = JS_VALUE_TO_PTR(obj);+    p->u.array_buffer.byte_buffer = buffer;+    return obj;+}++JSValue js_array_buffer_constructor(JSContext *ctx, JSValue *this_val,+                                    int argc, JSValue *argv)+{+    uint64_t len;+    if (!(argc & FRAME_CF_CTOR))+        return JS_ThrowTypeError(ctx, "must be called with new");+    if (JS_ToIndex(ctx, &len, argv[0]))+        return JS_EXCEPTION;+    return js_array_buffer_alloc(ctx, len);+}++JSValue js_array_buffer_get_byteLength(JSContext *ctx, JSValue *this_val,+                                      int argc, JSValue *argv)+{+    JSObject *p = js_get_object_class(ctx, *this_val, JS_CLASS_ARRAY_BUFFER);+    JSByteArray *arr;+    if (!p)+        return JS_ThrowTypeError(ctx, "expected an ArrayBuffer");+    arr = JS_VALUE_TO_PTR(p->u.array_buffer.byte_buffer);+    return JS_NewShortInt(arr->size);+}++JSValue js_typed_array_base_constructor(JSContext *ctx, JSValue *this_val,+                                        int argc, JSValue *argv)+{+    return JS_ThrowTypeError(ctx, "cannot be called");+}++static JSValue js_typed_array_constructor_obj(JSContext *ctx, JSValue *this_val,+                                              int argc, JSValue *argv, int magic)+{+    int i, len;+    JSValue val, obj;+    JSGCRef obj_ref;+    JSObject *p;+    +    p = JS_VALUE_TO_PTR(argv[0]);+    if (p->class_id == JS_CLASS_ARRAY) {+        len = p->u.array.len;+    } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&+               p->class_id <= JS_CLASS_FLOAT64_ARRAY) {+        len = p->u.typed_array.len;+    } else {+        return JS_ThrowTypeError(ctx, "unsupported object class");+    }+    val = JS_NewShortInt(len);+    obj = js_typed_array_constructor(ctx, NULL, 1 | FRAME_CF_CTOR, &val, magic);+    if (JS_IsException(obj))+        return obj;++    for(i = 0; i < len; i++) {+        JS_PUSH_VALUE(ctx, obj);+        val = JS_GetProperty(ctx, argv[0], JS_NewShortInt(i));+        JS_POP_VALUE(ctx, obj);+        if (JS_IsException(val))+            return val;+        JS_PUSH_VALUE(ctx, obj);+        val = JS_SetPropertyInternal(ctx, obj, JS_NewShortInt(i), val, FALSE);+        JS_POP_VALUE(ctx, obj);+        if (JS_IsException(val))+            return val;+    }+    return obj;+}++JSValue js_typed_array_constructor(JSContext *ctx, JSValue *this_val,+                                   int argc, JSValue *argv, int magic)+{+    int size_log2;+    uint64_t len, offset, byte_length;+    JSObject *p;+    JSByteArray *arr;+    JSValue buffer, obj;+    JSGCRef buffer_ref;+    +    if (!(argc & FRAME_CF_CTOR))+        return JS_ThrowTypeError(ctx, "must be called with new");+    size_log2 = typed_array_size_log2[magic - JS_CLASS_UINT8C_ARRAY];+    if (!JS_IsObject(ctx, argv[0])) {+        if (JS_ToIndex(ctx, &len, argv[0]))+            return JS_EXCEPTION;+        buffer = js_array_buffer_alloc(ctx, len << size_log2);+        if (JS_IsException(buffer))+            return JS_EXCEPTION;+        offset = 0;+    } else {+        p = JS_VALUE_TO_PTR(argv[0]);+        if (p->class_id == JS_CLASS_ARRAY_BUFFER) {+            arr = JS_VALUE_TO_PTR(p->u.array_buffer.byte_buffer);+            byte_length = arr->size;+            if (JS_ToIndex(ctx, &offset, argv[1]))+                return JS_EXCEPTION;+            if ((offset & ((1 << size_log2) - 1)) != 0 ||+                offset > byte_length)+                return JS_ThrowRangeError(ctx, "invalid offset");+            if (JS_IsUndefined(argv[2])) {+                if ((byte_length & ((1 << size_log2) - 1)) != 0)+                    goto invalid_length;+                len = (byte_length - offset) >> size_log2;+            } else {+                if (JS_ToIndex(ctx, &len, argv[2]))+                    return JS_EXCEPTION;+                if ((offset + (len << size_log2)) > byte_length) {+            invalid_length:+                    return JS_ThrowRangeError(ctx, "invalid length");+                }+            }+            buffer = argv[0];+            offset >>= size_log2;+        } else {+            return js_typed_array_constructor_obj(ctx, this_val,+                                                  argc, argv, magic);+        }+    }+    +    JS_PUSH_VALUE(ctx, buffer);+    obj = JS_NewObjectClass(ctx, magic, sizeof(JSTypedArray));+    JS_POP_VALUE(ctx, buffer);+    if (JS_IsException(obj))+        return obj;+    p = JS_VALUE_TO_PTR(obj);+    p->u.typed_array.buffer = buffer;+    p->u.typed_array.offset = offset;+    p->u.typed_array.len = len;+    return obj;+}++static JSObject *get_typed_array(JSContext *ctx, JSValue val)+{+    JSObject *p;+    if (!JS_IsObject(ctx, val))+        goto fail;+    p = JS_VALUE_TO_PTR(val);+    if (!(p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY)) {+    fail:+        JS_ThrowTypeError(ctx, "not a TypedArray");+        return NULL;+    }+    return p;+}++JSValue js_typed_array_get_length(JSContext *ctx, JSValue *this_val,+                                  int argc, JSValue *argv, int magic)+{+    JSObject *p;+    int size_log2;++    p = get_typed_array(ctx, *this_val);+    if (!p)+        return JS_EXCEPTION;+    size_log2 = typed_array_size_log2[p->class_id - JS_CLASS_UINT8C_ARRAY];+    switch(magic) {+    default:+    case 0:+        return JS_NewShortInt(p->u.typed_array.len);+    case 1:+        return JS_NewShortInt(p->u.typed_array.len << size_log2);+    case 2:+        return JS_NewShortInt(p->u.typed_array.offset << size_log2);+    case 3:+        return p->u.typed_array.buffer;+    }+}++JSValue js_typed_array_subarray(JSContext *ctx, JSValue *this_val,+                                int argc, JSValue *argv)+{+    JSObject *p, *p1;+    JSByteArray *arr;+    int start, final, len;+    uint32_t offset, count;+    JSValue obj;+    +    p = get_typed_array(ctx, *this_val);+    if (!p)+        return JS_EXCEPTION;+    len = p->u.typed_array.len;+    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))+        return JS_EXCEPTION;+    if (JS_IsUndefined(argv[1])) {+        final = len;+    } else {+        if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))+            return JS_EXCEPTION;+    }+    p = JS_VALUE_TO_PTR(*this_val);+    offset = p->u.typed_array.offset + start;+    count = max_int(final - start, 0);++    /* check offset and count */+    p1 = JS_VALUE_TO_PTR(p->u.typed_array.buffer);+    arr = JS_VALUE_TO_PTR(p1->u.array_buffer.byte_buffer);+    if (offset + count > arr->size)+        return JS_ThrowRangeError(ctx, "invalid length");+        +    obj = JS_NewObjectClass(ctx, p->class_id, sizeof(JSTypedArray));+    if (JS_IsException(obj))+        return JS_EXCEPTION;+    p = JS_VALUE_TO_PTR(*this_val);+    p1 = JS_VALUE_TO_PTR(obj);+    p1->u.typed_array.buffer = p->u.typed_array.buffer;+    p1->u.typed_array.offset = offset;+    p1->u.typed_array.len = count;+    return obj;+}++JSValue js_typed_array_set(JSContext *ctx, JSValue *this_val,+                                int argc, JSValue *argv)+{+    JSObject *p, *p1;+    uint32_t dst_len, src_len, i;+    int offset;++    p = get_typed_array(ctx, *this_val);+    if (!p)+        return JS_EXCEPTION;+    if (argc > 1) {+        if (JS_ToInt32Sat(ctx, &offset, argv[1]))+            return JS_EXCEPTION;+    } else {+        offset = 0;+    }+    if (offset < 0)+        goto range_error;+    if (!JS_IsObject(ctx, argv[0]))+        return JS_ThrowTypeErrorNotAnObject(ctx);+    p = JS_VALUE_TO_PTR(*this_val);+    dst_len = p->u.typed_array.len;+    p1 = JS_VALUE_TO_PTR(argv[0]);+    if (p1->class_id >= JS_CLASS_UINT8C_ARRAY &&+        p1->class_id <= JS_CLASS_FLOAT64_ARRAY) {+        src_len = p1->u.typed_array.len;+        if (src_len > dst_len || offset > dst_len - src_len)+            goto range_error;+        if (p1->class_id == p->class_id) {+            JSObject *src_buffer, *dst_buffer;+            JSByteArray *src_arr, *dst_arr;+            int shift = typed_array_size_log2[p->class_id - JS_CLASS_UINT8C_ARRAY];+            dst_buffer = JS_VALUE_TO_PTR(p->u.typed_array.buffer);+            dst_arr = JS_VALUE_TO_PTR(dst_buffer->u.array_buffer.byte_buffer);+            src_buffer = JS_VALUE_TO_PTR(p1->u.typed_array.buffer);+            src_arr = JS_VALUE_TO_PTR(src_buffer->u.array_buffer.byte_buffer);+            /* same type: must copy to preserve float bits */+            memmove(dst_arr->buf + ((p->u.typed_array.offset + offset) << shift),+                    src_arr->buf + (p1->u.typed_array.offset << shift),+                    src_len << shift);+            goto done;+        }+    } else {+        if (js_get_length32(ctx, (uint32_t *)&src_len, argv[0]))+            return JS_EXCEPTION;+        if (src_len > dst_len || offset > dst_len - src_len) {+        range_error:+            return JS_ThrowRangeError(ctx, "invalid array length");+        }+    }+    for(i = 0; i < src_len; i++) {+        JSValue val;+        val = JS_GetPropertyUint32(ctx, argv[0], i);+        if (JS_IsException(val))+            return JS_EXCEPTION;+        val = JS_SetPropertyUint32(ctx, *this_val, offset + i, val);+        if (JS_IsException(val))+            return JS_EXCEPTION;+    }+ done:+    return JS_UNDEFINED;+}++/* Date */++JSValue js_date_constructor(JSContext *ctx, JSValue *this_val,+                            int argc, JSValue *argv)+{+    return JS_ThrowTypeError(ctx, "only Date.now() is supported");+}++/* global */++JSValue js_global_eval(JSContext *ctx, JSValue *this_val,+                       int argc, JSValue *argv)+{+    JSValue val;+    +    if (!JS_IsString(ctx, argv[0]))+        return argv[0];+    val = JS_Parse2(ctx, argv[0], NULL, 0, "<input>", JS_EVAL_RETVAL);+    if (JS_IsException(val))+        return val;+    return JS_Run(ctx, val);+}++JSValue js_global_isNaN(JSContext *ctx, JSValue *this_val,+                        int argc, JSValue *argv)+{+    double d;+    if (unlikely(JS_ToNumber(ctx, &d, argv[0])))+        return JS_EXCEPTION;+    return JS_NewBool(isnan(d));+}++JSValue js_global_isFinite(JSContext *ctx, JSValue *this_val,+                                  int argc, JSValue *argv)+{+    double d;+    if (unlikely(JS_ToNumber(ctx, &d, argv[0])))+        return JS_EXCEPTION;+    return JS_NewBool(isfinite(d));+}++/* JSON */++JSValue js_json_parse(JSContext *ctx, JSValue *this_val,+                      int argc, JSValue *argv)+{+    JSValue val;+    +    val = JS_ToString(ctx, argv[0]);+    if (JS_IsException(val))+        return val;+    return JS_Parse2(ctx, val, NULL, 0, "<input>", JS_EVAL_JSON);+}++static int js_to_quoted_string(JSContext *ctx, StringBuffer *b, JSValue str)+{+    int i, c;+    JSStringCharBuf buf;+    JSString *p;+    JSGCRef str_ref;+    size_t clen;++    JS_PUSH_VALUE(ctx, str);+    string_buffer_putc(ctx, b, '\"');++    i = 0;+    for(;;) {+        /* XXX: inefficient */+        p = get_string_ptr(ctx, &buf, str_ref.val);+        if (i >= p->len)+            break;+        c = utf8_get(p->buf + i, &clen);+        i += clen;++        switch(c) {+        case '\t':+            c = 't';+            goto quote;+        case '\r':+            c = 'r';+            goto quote;+        case '\n':+            c = 'n';+            goto quote;+        case '\b':+            c = 'b';+            goto quote;+        case '\f':+            c = 'f';+            goto quote;+        case '\"':+        case '\\':+        quote:+            string_buffer_putc(ctx, b, '\\');+            string_buffer_putc(ctx, b, c);+            break;+        default:+            if (c < 32 || (c >= 0xd800 && c < 0xe000)) {+                char buf[7];+                js_snprintf(buf, sizeof(buf), "\\u%04x", c);+                string_buffer_puts(ctx, b, buf);+            } else {+                string_buffer_putc(ctx, b, c);+            }+            break;+        }+    }+    string_buffer_putc(ctx, b, '\"');+    JS_POP_VALUE(ctx, str);+    return 0;+}++#define JSON_REC_SIZE 3++static int check_circular_ref(JSContext *ctx, JSValue *stack_top, JSValue val)+{+    JSValue *sp;+    for(sp = ctx->sp; sp < stack_top; sp += JSON_REC_SIZE) {+        if (sp[0] == val) {+            JS_ThrowTypeError(ctx, "circular reference");+            return -1;+        }+    }+    return 0;+}++/* XXX: no space nor replacer */+JSValue js_json_stringify(JSContext *ctx, JSValue *this_val,+                          int argc, JSValue *argv)+{+    JSValue obj, *stack_top;+    StringBuffer b_s, *b = &b_s;+    int idx, ret;+    +#if 0+    if (JS_IsNumber(ctx, *pspace)) {+        int n;+        if (JS_ToInt32Clamp(ctx, &n, *pspace, 0, 10, 0))+            return JS_EXCEPTION;+        *pspace = JS_NewStringLen(ctx, "          ", n);+    } else if (JS_IsString(ctx, *pspace)) {+        *pspace = js_sub_string(ctx, *pspace, 0, 10);+    } else {+        *pspace = js_get_atom(ctx, JS_ATOM_empty);+    }+#endif+    string_buffer_push(ctx, b, 0);+    stack_top = ctx->sp;++    ret = JS_StackCheck(ctx, JSON_REC_SIZE);+    if (ret)+        goto fail;+    *--ctx->sp = JS_NULL; /* keys */+    *--ctx->sp = JS_NewShortInt(0); /* prop index */+    *--ctx->sp = argv[0]; /* object */+    +    while (ctx->sp < stack_top) {+        obj = ctx->sp[0];+        if (JS_IsFunction(ctx, obj)) {+            goto output_null;+        } else if (JS_IsObject(ctx, obj)) {+            JSObject *p = JS_VALUE_TO_PTR(obj);+            idx = JS_VALUE_GET_INT(ctx->sp[1]);+            if (p->class_id == JS_CLASS_ARRAY) {+                JSValueArray *arr;+                JSValue val;++                /* array */+                if (idx == 0)+                    string_buffer_putc(ctx, b, '[');+                p = JS_VALUE_TO_PTR(ctx->sp[0]);+                if (idx >= p->u.array.len) {+                    /* end of array */+                    string_buffer_putc(ctx, b, ']');+                    ctx->sp += JSON_REC_SIZE;+                } else {+                    if (idx != 0)+                        string_buffer_putc(ctx, b, ',');+                    ctx->sp[1] = JS_NewShortInt(idx + 1);+                    ret = JS_StackCheck(ctx, JSON_REC_SIZE);+                    if (ret)+                        goto fail;+                    p = JS_VALUE_TO_PTR(ctx->sp[0]);+                    arr = JS_VALUE_TO_PTR(p->u.array.tab);+                    val = arr->arr[idx];+                    if (check_circular_ref(ctx, stack_top, val))+                        goto fail;+                    *--ctx->sp = JS_NULL;+                    *--ctx->sp = JS_NewShortInt(0);+                    *--ctx->sp = val;+                }+            } else {+                JSValueArray *arr;+                JSValue val, prop;+                JSGCRef val_ref;+                int saved_idx;+                +                /* object */+                if (idx == 0) {+                    string_buffer_putc(ctx, b, '{');+                    ctx->sp[2] = js_object_keys(ctx, NULL, 1, &ctx->sp[0]);+                    if (JS_IsException(ctx->sp[2]))+                        goto fail;+                }+                saved_idx = idx;+                for(;;) {+                    p = JS_VALUE_TO_PTR(ctx->sp[2]); /* keys */+                    if (idx >= p->u.array.len) {+                        /* end of object */+                        string_buffer_putc(ctx, b, '}');+                        ctx->sp += JSON_REC_SIZE;+                        goto end_obj;+                    } else {+                        arr = JS_VALUE_TO_PTR(p->u.array.tab);+                        prop = JS_ToPropertyKey(ctx, arr->arr[idx]);+                        val = JS_GetProperty(ctx, ctx->sp[0], prop);+                        if (JS_IsException(val))+                            goto fail;+                        /* skip undefined properties */+                        if (!JS_IsUndefined(val))+                            break;+                        idx++;+                    }+                }+                JS_PUSH_VALUE(ctx, val);+                if (saved_idx != 0)+                    string_buffer_putc(ctx, b, ',');+                ctx->sp[1] = JS_NewShortInt(idx + 1);+                p = JS_VALUE_TO_PTR(ctx->sp[2]);+                arr = JS_VALUE_TO_PTR(p->u.array.tab);+                ret = js_to_quoted_string(ctx, b, arr->arr[idx]);+                string_buffer_putc(ctx, b, ':');+                ret |= JS_StackCheck(ctx, JSON_REC_SIZE);+                JS_POP_VALUE(ctx, val);+                if (ret)+                    goto fail;+                if (check_circular_ref(ctx, stack_top, val))+                    goto fail;+                *--ctx->sp = JS_NULL;+                *--ctx->sp = JS_NewShortInt(0);+                *--ctx->sp = val;+            end_obj: ;+            }+        } else if (JS_IsNumber(ctx, obj)) {+            double d;+            ret = JS_ToNumber(ctx, &d, obj);+            if (ret)+                goto fail;+            if (!isfinite(d))+                goto output_null;+            goto to_string;+        } else if (JS_IsBool(obj)) {+        to_string:+            if (string_buffer_concat(ctx, b, obj))+                goto fail;+            ctx->sp += JSON_REC_SIZE;+        } else if (JS_IsString(ctx, obj)) {+            if (js_to_quoted_string(ctx, b, obj))+                goto fail;+            ctx->sp += JSON_REC_SIZE;+        } else {+        output_null:+            string_buffer_concat(ctx, b, js_get_atom(ctx, JS_ATOM_null));+            ctx->sp += JSON_REC_SIZE;+        }+    }+    return string_buffer_pop(ctx, b);+    + fail:+    ctx->sp = stack_top;+    string_buffer_pop(ctx, b);+    return JS_EXCEPTION;+}++/**********************************************************************/+/* regexp */++typedef enum {+#define REDEF(id, size) REOP_ ## id,+#include "mquickjs_opcode.h"+#undef REDEF+    REOP_COUNT,+} REOPCodeEnum;++#define CAPTURE_COUNT_MAX 255+#define REGISTER_COUNT_MAX 255++typedef struct {+#ifdef DUMP_REOP+    const char *name;+#endif+    uint8_t size;+} REOpCode;++static const REOpCode reopcode_info[REOP_COUNT] = {+#ifdef DUMP_REOP+#define REDEF(id, size) { #id, size },+#else+#define REDEF(id, size) { size },+#endif+#include "mquickjs_opcode.h"+#undef REDEF+};++#define LRE_FLAG_GLOBAL     (1 << 0)+#define LRE_FLAG_IGNORECASE (1 << 1)+#define LRE_FLAG_MULTILINE  (1 << 2)+#define LRE_FLAG_DOTALL     (1 << 3)+#define LRE_FLAG_UNICODE    (1 << 4)+#define LRE_FLAG_STICKY     (1 << 5)++#define RE_HEADER_FLAGS          0+#define RE_HEADER_CAPTURE_COUNT  2+#define RE_HEADER_REGISTER_COUNT 3++#define RE_HEADER_LEN 4++#define CLASS_RANGE_BASE 0x40000000++typedef enum {+    CHAR_RANGE_d,+    CHAR_RANGE_D,+    CHAR_RANGE_s,+    CHAR_RANGE_S,+    CHAR_RANGE_w,+    CHAR_RANGE_W,+} CharRangeEnum;++static int lre_get_capture_count(const uint8_t *bc_buf)+{+    return bc_buf[RE_HEADER_CAPTURE_COUNT];+}++static int lre_get_alloc_count(const uint8_t *bc_buf)+{+    return bc_buf[RE_HEADER_CAPTURE_COUNT] * 2 + bc_buf[RE_HEADER_REGISTER_COUNT];+}++static int lre_get_flags(const uint8_t *bc_buf)+{+    return get_u16(bc_buf + RE_HEADER_FLAGS);+}++#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;+    uint32_t val, val2;++    assert(buf_len >= RE_HEADER_LEN);+    re_flags = lre_get_flags(buf);+    bc_len = buf_len - RE_HEADER_LEN;++    printf("flags: 0x%x capture_count=%d reg_count=%d bytecode_len=%d\n",+           re_flags, buf[RE_HEADER_CAPTURE_COUNT], buf[RE_HEADER_REGISTER_COUNT],+           bc_len);++    buf += RE_HEADER_LEN;++    pos = 0;+    while (pos < bc_len) {+        printf("%5u: ", pos);+        opcode = buf[pos];+        len = reopcode_info[opcode].size;+        if (opcode >= REOP_COUNT) {+            printf(" invalid opcode=0x%02x\n", opcode);+            break;+        }+        if ((pos + len) > bc_len) {+            printf(" buffer overflow (opcode=0x%02x)\n", opcode);+            break;+        }+        printf("%s", reopcode_info[opcode].name);+        switch(opcode) {+        case REOP_char1:+        case REOP_char2:+        case REOP_char3:+        case REOP_char4:+            {+                int i, n;+                n = opcode - REOP_char1 + 1;+                for(i = 0; i < n; i++) {+                    val = buf[pos + 1 + i];+                    if (val >= ' ' && val <= 126)+                        printf(" '%c'", val);+                    else+                        printf(" 0x%2x", val);+                }+            }+            break;+        case REOP_goto:+        case REOP_split_goto_first:+        case REOP_split_next_first:+        case REOP_lookahead:+        case REOP_negative_lookahead:+            val = get_u32(buf + pos + 1);+            val += (pos + 5);+            printf(" %u", val);+            break;+        case REOP_loop:+            val2 = buf[pos + 1];+            val = get_u32(buf + pos + 2);+            val += (pos + 6);+            printf(" r%u, %u", val2, val);+            break;+        case REOP_loop_split_goto_first:+        case REOP_loop_split_next_first:+        case REOP_loop_check_adv_split_goto_first:+        case REOP_loop_check_adv_split_next_first:+            {+                uint32_t limit;+                val2 = buf[pos + 1];+                limit = get_u32(buf + pos + 2);+                val = get_u32(buf + pos + 6);+                val += (pos + 10);+                printf(" r%u, %u, %u", val2, limit, val);+            }+            break;+        case REOP_save_start:+        case REOP_save_end:+        case REOP_back_reference:+        case REOP_back_reference_i:+            printf(" %u", buf[pos + 1]);+            break;+        case REOP_save_reset:+            printf(" %u %u", buf[pos + 1], buf[pos + 2]);+            break;+        case REOP_set_i32:+            val = buf[pos + 1];+            val2 = get_u32(buf + pos + 2);+            printf(" r%u, %d", val, val2);+            break;+        case REOP_set_char_pos:+        case REOP_check_advance:+            val = buf[pos + 1];+            printf(" r%u", val);+            break;+        case REOP_range8:+            {+                int n, i;+                n = buf[pos + 1];+                len += n * 2;+                for(i = 0; i < n * 2; i++) {+                    val = buf[pos + 2 + i];+                    printf(" 0x%02x", val);+                }+            }+            break;+        case REOP_range:+            {+                int n, i;+                n = get_u16(buf + pos + 1);+                len += n * 8;+                for(i = 0; i < n * 2; i++) {+                    val = get_u32(buf + pos + 3 + i * 4);+                    printf(" 0x%05x", val);+                }+            }+            break;+        default:+            break;+        }+        printf("\n");+        pos += len;+    }+}+#endif++static void re_emit_op(JSParseState *s, int op)+{+    emit_u8(s, op);+}++static void re_emit_op_u8(JSParseState *s, int op, uint32_t val)+{+    emit_u8(s, op);+    emit_u8(s, val);+}++static void re_emit_op_u16(JSParseState *s, int op, uint32_t val)+{+    emit_u8(s, op);+    emit_u16(s, val);+}++/* return the offset of the u32 value */+static int re_emit_op_u32(JSParseState *s, int op, uint32_t val)+{+    int pos;+    emit_u8(s, op);+    pos = s->byte_code_len;+    emit_u32(s, val);+    return pos;+}++static int re_emit_goto(JSParseState *s, int op, uint32_t val)+{+    int pos;+    emit_u8(s, op);+    pos = s->byte_code_len;+    emit_u32(s, val - (pos + 4));+    return pos;+}++static int re_emit_goto_u8(JSParseState *s, int op, uint32_t arg, uint32_t val)+{+    int pos;+    emit_u8(s, op);+    emit_u8(s, arg);+    pos = s->byte_code_len;+    emit_u32(s, val - (pos + 4));+    return pos;+}++static int re_emit_goto_u8_u32(JSParseState *s, int op, uint32_t arg0, uint32_t arg1, uint32_t val)+{+    int pos;+    emit_u8(s, op);+    emit_u8(s, arg0);+    emit_u32(s, arg1);+    pos = s->byte_code_len;+    emit_u32(s, val - (pos + 4));+    return pos;+}++static void re_emit_char(JSParseState *s, int c)+{+    uint8_t buf[4];+    size_t n, i;+    n = unicode_to_utf8(buf, c);+    re_emit_op(s, REOP_char1 + n - 1);+    for(i = 0; i < n; i++)+        emit_u8(s, buf[i]);+}++static void re_parse_expect(JSParseState *s, int c)+{+    if (s->source_buf[s->buf_pos] != c)+        return js_parse_error(s, "expecting '%c'", c);+    s->buf_pos++;+}++/* return JS_SHORTINT_MAX in case of overflow */+static int parse_digits(const uint8_t **pp)+{+    const uint8_t *p;+    uint64_t v;+    int c;++    p = *pp;+    v = 0;+    for(;;) {+        c = *p;+        if (c < '0' || c > '9')+            break;+        v = v * 10 + c - '0';+        if (v >= JS_SHORTINT_MAX)+            v = JS_SHORTINT_MAX;+        p++;+    }+    *pp = p;+    return v;+}++/* need_check_adv: false if the opcodes always advance the char pointer+   need_capture_init: true if all the captures in the atom are not set+*/+static BOOL re_need_check_adv_and_capture_init(BOOL *pneed_capture_init,+                                               const uint8_t *bc_buf, int bc_buf_len)+{+    int pos, opcode, len;+    uint32_t val;+    BOOL need_check_adv, need_capture_init;++    need_check_adv = TRUE;+    need_capture_init = FALSE;+    pos = 0;+    while (pos < bc_buf_len) {+        opcode = bc_buf[pos];+        len = reopcode_info[opcode].size;+        switch(opcode) {+        case REOP_range8:+            val = bc_buf[pos + 1];+            len += val * 2;+            need_check_adv = FALSE;+            break;+        case REOP_range:+            val = get_u16(bc_buf + pos + 1);+            len += val * 8;+            need_check_adv = FALSE;+            break;+        case REOP_char1:+        case REOP_char2:+        case REOP_char3:+        case REOP_char4:+        case REOP_dot:+        case REOP_any:+        case REOP_space:+        case REOP_not_space:+            need_check_adv = FALSE;+            break;+        case REOP_line_start:+        case REOP_line_start_m:+        case REOP_line_end:+        case REOP_line_end_m:+        case REOP_set_i32:+        case REOP_set_char_pos:+        case REOP_word_boundary:+        case REOP_not_word_boundary:+            /* no effect */+            break;+        case REOP_save_start:+        case REOP_save_end:+        case REOP_save_reset:+            break;+        default:+            /* safe behavior: we cannot predict the outcome */+            need_capture_init = TRUE;+            goto done;+        }+        pos += len;+    }+ done:+    *pneed_capture_init = need_capture_init;+    return need_check_adv;+}++/* return the character or a class range (>= CLASS_RANGE_BASE) if inclass+   = TRUE */+static int get_class_atom(JSParseState *s, BOOL inclass)+{+    const uint8_t *p;+    uint32_t c;+    int ret;+    size_t len;+    +    p = s->source_buf + s->buf_pos;+    c = *p;+    switch(c) {+    case '\\':+        p++;+        c = *p++;+        switch(c) {+        case 'd':+            c = CHAR_RANGE_d;+            goto class_range;+        case 'D':+            c = CHAR_RANGE_D;+            goto class_range;+        case 's':+            c = CHAR_RANGE_s;+            goto class_range;+        case 'S':+            c = CHAR_RANGE_S;+            goto class_range;+        case 'w':+            c = CHAR_RANGE_w;+            goto class_range;+        case 'W':+            c = CHAR_RANGE_W;+        class_range:+            c += CLASS_RANGE_BASE;+            break;+        case 'c':+            c = *p;+            if ((c >= 'a' && c <= 'z') ||+                (c >= 'A' && c <= 'Z') ||+                (((c >= '0' && c <= '9') || c == '_') &&+                 inclass && !s->is_unicode)) {   /* Annex B.1.4 */+                c &= 0x1f;+                p++;+            } else if (s->is_unicode) {+                goto invalid_escape;+            } else {+                /* otherwise return '\' and 'c' */+                p--;+                c = '\\';+            }+            break;+        case '-':+            if (!inclass && s->is_unicode)+                goto invalid_escape;+            break;+        case '^':+        case '$':+        case '\\':+        case '.':+        case '*':+        case '+':+        case '?':+        case '(':+        case ')':+        case '[':+        case ']':+        case '{':+        case '}':+        case '|':+        case '/':+            /* always valid to escape these characters */+            break;+        default:+            p--;+            ret = js_parse_escape(p, &len);+            if (ret < 0) {+                if (s->is_unicode) {+                invalid_escape:+                    s->buf_pos = p - s->source_buf;+                    js_parse_error(s, "invalid escape sequence in regular expression");+                } else {+                    goto normal_char;+                }+            }+            p += len;+            c = ret;+            break;+        }+        break;+    case '\0':+    case '/': /* safety for end of regexp in JS parser */+        if ((p - s->source_buf) >= s->buf_len)+            js_parse_error(s, "unexpected end");+        goto normal_char;+    default:+    normal_char:+        /* normal char */+        ret = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &len);+        /* Note: should not fail with normal JS strings */+        if (ret < 0)+            js_parse_error(s, "malformed unicode char"); +        p += len;+        c = ret;+        break;+    }+    s->buf_pos = p - s->source_buf;+    return c;+}++/* code point ranges for Zs,Zl or Zp property */+static const uint16_t char_range_s[] = {+    0x0009, 0x000D + 1,+    0x0020, 0x0020 + 1,+    0x00A0, 0x00A0 + 1,+    0x1680, 0x1680 + 1,+    0x2000, 0x200A + 1,+    /* 2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; */+    /* 2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; */+    0x2028, 0x2029 + 1,+    0x202F, 0x202F + 1,+    0x205F, 0x205F + 1,+    0x3000, 0x3000 + 1,+    /* FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; */+    0xFEFF, 0xFEFF + 1,+};++static const uint16_t char_range_w[] = {+    0x0030, 0x0039 + 1,+    0x0041, 0x005A + 1,+    0x005F, 0x005F + 1,+    0x0061, 0x007A + 1,+};++static void re_emit_range_base1(JSParseState *s, const uint16_t *tab, int n)+{+    int i;+    for(i = 0; i < n; i++)+        emit_u32(s, tab[i]);+}++static void re_emit_range_base(JSParseState *s, int c)+{+    BOOL invert;+    invert = c & 1;+    if (invert)+        emit_u32(s, 0);+    switch(c & ~1) {+    case CHAR_RANGE_d:+        emit_u32(s, 0x30);+        emit_u32(s, 0x39 + 1);+        break;+    case CHAR_RANGE_s:+        re_emit_range_base1(s, char_range_s, countof(char_range_s));+        break;+    case CHAR_RANGE_w:+        re_emit_range_base1(s, char_range_w, countof(char_range_w));+        break;+    default:+        abort();+    }+    if (invert)+        emit_u32(s, 0x110000);+}++static int range_sort_cmp(size_t i1, size_t i2, void *opaque)+{+    uint8_t *tab = opaque;+    return get_u32(&tab[8 * i1]) - get_u32(&tab[8 * i2]);+}++static void range_sort_swap(size_t i1, size_t i2, void *opaque)+{+    uint8_t *tab = opaque;+    uint64_t tmp;+    tmp = get_u64(&tab[8 * i1]);+    put_u64(&tab[8 * i1], get_u64(&tab[8 * i2]));+    put_u64(&tab[8 * i2], tmp);+}++/* merge consecutive intervals, remove empty intervals and handle overlapping intervals */ +static int range_compress(uint8_t *tab, int len)+{+    int i, j;+    uint32_t start, end, start2, end2;++    i = 0;+    j = 0;+    while (i < len) {+        start = get_u32(&tab[8 * i]);+        end = get_u32(&tab[8 * i + 4]);+        if (start == end) {+            /* empty interval : remove */+        } else if ((i + 1) < len) {+            start2 = get_u32(&tab[8 * i + 8]);+            end2 = get_u32(&tab[8 * i + 12]);+            if (end < start2) {+                goto copy;+            } else {+                /* union of the intervals */+                put_u32(&tab[8 * i + 8], start);+                put_u32(&tab[8 * i + 12], max_uint32(end, end2));+            }+        } else {+        copy:+            put_u32(&tab[8 * j], start);+            put_u32(&tab[8 * j + 4], end);+            j++;+        }+        i++;+    }+    return j;+}++static void re_range_optimize(JSParseState *s, int range_start, BOOL invert)+{+    int n, n1;+    JSByteArray *arr;++    n = (unsigned)(s->byte_code_len - range_start) / 8;++    arr = JS_VALUE_TO_PTR(s->byte_code);+    rqsort_idx(n, range_sort_cmp, range_sort_swap, arr->buf + range_start);++    /* must compress before inverting */+    n1 = range_compress(arr->buf + range_start, n);+    s->byte_code_len -= (n - n1) * 8;++    if (invert) {+        emit_insert(s, range_start, 4);+        arr = JS_VALUE_TO_PTR(s->byte_code);+        put_u32(arr->buf + range_start, 0);+        emit_u32(s, 0x110000);+        arr = JS_VALUE_TO_PTR(s->byte_code);+        n = n1 + 1;+        n1 = range_compress(arr->buf + range_start, n);+        s->byte_code_len -= (n - n1) * 8;+    }+    n = n1;+    +    if (n > 65534)+        js_parse_error(s, "range too big");++    /* compress to 8 bit if possible */+    /* XXX: adjust threshold */+    if (n > 0 && n < 16) {+        uint8_t *tab = arr->buf + range_start;+        int c, i;+        c = get_u32(&tab[8 * (n - 1) + 4]);+        if (c < 254 || (c == 0x110000 &&+                        get_u32(&tab[8 * (n - 1)]) < 254)) {+            s->byte_code_len = range_start - 3;+            re_emit_op_u8(s, REOP_range8, n);+            for(i = 0; i < 2 * n; i++) {+                c = get_u32(&tab[4 * i]);+                if (c == 0x110000)+                    c = 0xff;+                emit_u8(s, c);+            }+            goto done;+        }+    }+    +    put_u16(arr->buf + range_start - 2, n);+ done: ;+}++/* add the intersection of the two intervals and if offset != 0 the+   translated interval */+static void add_interval_intersect(JSParseState *s,+                                   uint32_t start, uint32_t end,+                                   uint32_t start1, uint32_t end1,+                                   int offset)+{+    start = max_uint32(start, start1);+    end = min_uint32(end, end1);+    if (start < end) {+        emit_u32(s, start);+        emit_u32(s, end);+        if (offset != 0) {+            emit_u32(s, start + offset);+            emit_u32(s, end + offset);+        }+    }+}++static void re_parse_char_class(JSParseState *s)+{+    uint32_t c1, c2;+    BOOL invert;+    int range_start;+    +    s->buf_pos++; /* skip '[' */++    invert = FALSE;+    if (s->source_buf[s->buf_pos] == '^') {+        s->buf_pos++;+        invert = TRUE;+    }+    +    re_emit_op_u16(s, REOP_range, 0);+    range_start = s->byte_code_len;+ +    for(;;) {+        if (s->source_buf[s->buf_pos] == ']')+            break;++        c1 = get_class_atom(s, TRUE);+        if (s->source_buf[s->buf_pos] == '-' && s->source_buf[s->buf_pos + 1] != ']') {+            s->buf_pos++;+            if (c1 >= CLASS_RANGE_BASE) +                goto invalid_class_range;+            c2 = get_class_atom(s, TRUE);+            if (c2 >= CLASS_RANGE_BASE) +                goto invalid_class_range;+            if (c2 < c1) {+            invalid_class_range:+                js_parse_error(s, "invalid class range");+            }+            goto add_range;+        } else {+            if (c1 >= CLASS_RANGE_BASE) {+                re_emit_range_base(s, c1 - CLASS_RANGE_BASE);+            } else {+                c2 = c1;+            add_range:+                c2++;+                if (s->ignore_case) {+                    /* add the intervals exclude the cased characters */+                    add_interval_intersect(s, c1, c2, 0, 'A', 0);+                    add_interval_intersect(s, c1, c2, 'Z' + 1, 'a', 0);+                    add_interval_intersect(s, c1, c2, 'z' + 1, INT32_MAX, 0);+                    /* include all the possible cases */+                    add_interval_intersect(s, c1, c2, 'A', 'Z' + 1, 32);+                    add_interval_intersect(s, c1, c2, 'a', 'z' + 1, -32);+                } else {+                    emit_u32(s, c1);+                    emit_u32(s, c2);+                }+            }+        }+    }+    s->buf_pos++;    /* skip ']' */+    re_range_optimize(s, range_start, invert);+}++static void re_parse_quantifier(JSParseState *s, int last_atom_start, int last_capture_count)+{+    int c, quant_min, quant_max;+    JSByteArray *arr;+    BOOL greedy;+    const uint8_t *p;+        +    p = s->source_buf + s->buf_pos;+    c = *p;+    switch(c) {+    case '*':+        p++;+        quant_min = 0;+        quant_max = JS_SHORTINT_MAX;+        goto quantifier;+    case '+':+        p++;+        quant_min = 1;+        quant_max = JS_SHORTINT_MAX;+        goto quantifier;+    case '?':+        p++;+        quant_min = 0;+        quant_max = 1;+        goto quantifier;+    case '{':+        {+            if (!is_digit(p[1]))+                goto invalid_quant_count;+            p++;+            quant_min = parse_digits(&p);+            quant_max = quant_min;+            if (*p == ',') {+                p++;+                if (is_digit(*p)) {+                    quant_max = parse_digits(&p);+                    if (quant_max < quant_min) {+                    invalid_quant_count:+                        js_parse_error(s, "invalid repetition count");+                    }+                } else {+                    quant_max = JS_SHORTINT_MAX; /* infinity */+                }+            }+            s->buf_pos = p - s->source_buf;+            re_parse_expect(s, '}');+            p = s->source_buf + s->buf_pos;+        }+    quantifier:+        greedy = TRUE;++        if (*p == '?') {+            p++;+            greedy = FALSE;+        }+        s->buf_pos = p - s->source_buf;++        if (last_atom_start < 0)+            js_parse_error(s, "nothing to repeat");+        {+            BOOL need_capture_init, add_zero_advance_check;+            int len, pos;+                +            /* 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. */+            arr = JS_VALUE_TO_PTR(s->byte_code);+            add_zero_advance_check =+                re_need_check_adv_and_capture_init(&need_capture_init,+                                                   arr->buf + last_atom_start,+                                                   s->byte_code_len - last_atom_start);+            +            /* general case: need to reset the capture at each+               iteration. We don't do it if there are no captures+               in the atom or if we are sure all captures are+               initialized in the atom. If quant_min = 0, we still+               need to reset once the captures in case the atom+               does not match. */+            if (need_capture_init && last_capture_count != s->capture_count) {+                emit_insert(s, last_atom_start, 3);+                int pos = last_atom_start;+                arr = JS_VALUE_TO_PTR(s->byte_code);+                arr->buf[pos++] = REOP_save_reset;+                arr->buf[pos++] = last_capture_count;+                arr->buf[pos++] = s->capture_count - 1;+            }++            len = s->byte_code_len - last_atom_start;+            if (quant_min == 0) {+                /* need to reset the capture in case the atom is+                   not executed */+                if (!need_capture_init && last_capture_count != s->capture_count) {+                    emit_insert(s, last_atom_start, 3);+                    arr = JS_VALUE_TO_PTR(s->byte_code);+                    arr->buf[last_atom_start++] = REOP_save_reset;+                    arr->buf[last_atom_start++] = last_capture_count;+                    arr->buf[last_atom_start++] = s->capture_count - 1;+                }+                if (quant_max == 0) {+                    s->byte_code_len = last_atom_start;+                } else if (quant_max == 1 || quant_max == JS_SHORTINT_MAX) {+                    BOOL has_goto = (quant_max == JS_SHORTINT_MAX);+                    emit_insert(s, last_atom_start, 5 + add_zero_advance_check * 2);+                    arr = JS_VALUE_TO_PTR(s->byte_code);+                    arr->buf[last_atom_start] = REOP_split_goto_first ++                        greedy;+                    put_u32(arr->buf + last_atom_start + 1,+                            len + 5 * has_goto + add_zero_advance_check * 2 * 2);+                    if (add_zero_advance_check) {+                        arr->buf[last_atom_start + 1 + 4] = REOP_set_char_pos;+                        arr->buf[last_atom_start + 1 + 4 + 1] = 0;+                        re_emit_op_u8(s, REOP_check_advance, 0);+                    }+                    if (has_goto)+                        re_emit_goto(s, REOP_goto, last_atom_start);+                } else {+                    emit_insert(s, last_atom_start, 11 + add_zero_advance_check * 2);+                    pos = last_atom_start;+                    arr = JS_VALUE_TO_PTR(s->byte_code);+                    arr->buf[pos++] = REOP_split_goto_first + greedy;+                    put_u32(arr->buf + pos, 6 + add_zero_advance_check * 2 + len + 10);+                    pos += 4;++                    arr->buf[pos++] = REOP_set_i32;+                    arr->buf[pos++] = 0;+                    put_u32(arr->buf + pos, quant_max);+                    pos += 4;+                    last_atom_start = pos;+                    if (add_zero_advance_check) {+                        arr->buf[pos++] = REOP_set_char_pos;+                        arr->buf[pos++] = 0;+                    }+                    re_emit_goto_u8_u32(s, (add_zero_advance_check ? REOP_loop_check_adv_split_next_first : REOP_loop_split_next_first) - greedy, 0, quant_max, last_atom_start);+                }+            } else if (quant_min == 1 && quant_max == JS_SHORTINT_MAX &&+                       !add_zero_advance_check) {+                re_emit_goto(s, REOP_split_next_first - greedy,+                             last_atom_start);+            } else {+                if (quant_min == quant_max)+                    add_zero_advance_check = FALSE;+                emit_insert(s, last_atom_start, 6 + add_zero_advance_check * 2);+                /* Note: we assume the string length is < JS_SHORTINT_MAX */+                pos = last_atom_start;+                arr = JS_VALUE_TO_PTR(s->byte_code);+                arr->buf[pos++] = REOP_set_i32;+                arr->buf[pos++] = 0;+                put_u32(arr->buf + pos, quant_max);+                pos += 4;+                last_atom_start = pos;+                if (add_zero_advance_check) {+                    arr->buf[pos++] = REOP_set_char_pos;+                    arr->buf[pos++] = 0;+                }+                if (quant_min == quant_max) {+                    /* a simple loop is enough */+                    re_emit_goto_u8(s, REOP_loop, 0, last_atom_start);+                } else {+                    re_emit_goto_u8_u32(s, (add_zero_advance_check ? REOP_loop_check_adv_split_next_first : REOP_loop_split_next_first) - greedy, 0, quant_max - quant_min, last_atom_start);+                }+            }+            last_atom_start = -1;+        }+        break;+    default:+        break;+    }+}++/* return the number of bytes if char otherwise 0 */+static int re_is_char(const uint8_t *buf, int start, int end)+{+    int n;+    if (!(buf[start] >= REOP_char1 && buf[start] <= REOP_char4))+        return 0;+    n = buf[start] - REOP_char1 + 1;+    if ((end - start) != (n + 1))+        return 0;+    return n;+}++static int re_parse_alternative(JSParseState *s, int state, int dummy_param)+{+    int term_start, last_term_start, last_atom_start, last_capture_count, c, n1, n2, i;+    JSByteArray *arr;+    +    PARSE_START3();++    last_term_start = -1;+    for(;;) {+        if (s->buf_pos >= s->buf_len)+            break;+        term_start = s->byte_code_len;++        last_atom_start = -1;+        last_capture_count = 0;+        c = s->source_buf[s->buf_pos];+        switch(c) {+        case '|':+        case ')':+            goto done;+        case '^':+            s->buf_pos++;+            re_emit_op(s, s->multi_line ? REOP_line_start_m : REOP_line_start);+            break;+        case '$':+            s->buf_pos++;+            re_emit_op(s, s->multi_line ? REOP_line_end_m : REOP_line_end);+            break;+        case '.':+            s->buf_pos++;+            last_atom_start = s->byte_code_len;+            last_capture_count = s->capture_count;+            re_emit_op(s, s->dotall ? REOP_any : REOP_dot);+            break;+        case '{': +            /* As an extension (see ES6 annex B), we accept '{' not+               followed by digits as a normal atom */+            if (!s->is_unicode && !is_digit(s->source_buf[s->buf_pos + 1]))+                goto parse_class_atom;+            /* fall thru */+        case '*':+        case '+':+        case '?':+            js_parse_error(s, "nothing to repeat");+        case '(':+            if (s->source_buf[s->buf_pos + 1] == '?') {+                c = s->source_buf[s->buf_pos + 2];+                if (c == ':') {+                    s->buf_pos += 3;+                    last_atom_start = s->byte_code_len;+                    last_capture_count = s->capture_count;+                    PARSE_CALL_SAVE4(s, 0, re_parse_disjunction, 0,+                                     last_term_start, term_start, last_atom_start, last_capture_count);+                    re_parse_expect(s, ')');+                } else if ((c == '=' || c == '!')) {+                    int is_neg, pos;+                    is_neg = (c == '!');+                    s->buf_pos += 3;+                    /* lookahead */+                    pos = re_emit_op_u32(s, REOP_lookahead + is_neg, 0);+                    PARSE_CALL_SAVE6(s, 1, re_parse_disjunction, 0,+                                     last_term_start, term_start, last_atom_start, last_capture_count,+                                     is_neg, pos);+                    re_parse_expect(s, ')');+                    re_emit_op(s, REOP_lookahead_match + is_neg);+                    /* jump after the 'match' after the lookahead is successful */+                    arr = JS_VALUE_TO_PTR(s->byte_code);+                    put_u32(arr->buf + pos, s->byte_code_len - (pos + 4));+                } else {+                    js_parse_error(s, "invalid group");+                }+            } else {+                int capture_index;+                s->buf_pos++;+                /* capture without group name */+                if (s->capture_count >= CAPTURE_COUNT_MAX)+                    js_parse_error(s, "too many captures");+                last_atom_start = s->byte_code_len;+                last_capture_count = s->capture_count;+                capture_index = s->capture_count++;+                re_emit_op_u8(s, REOP_save_start, capture_index);++                PARSE_CALL_SAVE5(s, 2, re_parse_disjunction, 0,+                                 last_term_start, term_start, last_atom_start, last_capture_count,+                                 capture_index);++                re_emit_op_u8(s, REOP_save_end, capture_index);++                re_parse_expect(s, ')');+            }+            break;+        case '\\':+            switch(s->source_buf[s->buf_pos + 1]) {+            case 'b':+            case 'B':+                if (s->source_buf[s->buf_pos + 1] != 'b') {+                    re_emit_op(s, REOP_not_word_boundary);+                } else {+                    re_emit_op(s, REOP_word_boundary);+                }+                s->buf_pos += 2;+                break;+            case '0':+                s->buf_pos += 2;+                c = 0;+                if (is_digit(s->source_buf[s->buf_pos]))+                    js_parse_error(s, "invalid decimal escape in regular expression");+                goto normal_char;+            case '1': case '2': case '3': case '4':+            case '5': case '6': case '7': case '8':+            case '9':+                {+                    const uint8_t *p;+                    p = s->source_buf + s->buf_pos + 1;+                    c = parse_digits(&p);+                    s->buf_pos = p - s->source_buf;+                    if (c > CAPTURE_COUNT_MAX)+                        js_parse_error(s, "back reference is out of range");+                    /* the range is checked afterwards as we don't know the number of captures */+                    last_atom_start = s->byte_code_len;+                    last_capture_count = s->capture_count;+                    re_emit_op_u8(s, REOP_back_reference + s->ignore_case, c);+                }+                break;+            default:+                goto parse_class_atom;+            }+            break;+        case '[':+            last_atom_start = s->byte_code_len;+            last_capture_count = s->capture_count;+            re_parse_char_class(s);+            break;+        case ']':+        case '}':+            if (s->is_unicode)+                js_parse_error(s, "syntax error");+            goto parse_class_atom;+        default:+        parse_class_atom:+            c = get_class_atom(s, FALSE);+        normal_char:+            last_atom_start = s->byte_code_len;+            last_capture_count = s->capture_count;+            if (c >= CLASS_RANGE_BASE) {+                int range_start;+                c -= CLASS_RANGE_BASE;+                if (c == CHAR_RANGE_s || c == CHAR_RANGE_S) {+                    re_emit_op(s, REOP_space + c - CHAR_RANGE_s);+                } else {+                    re_emit_op_u16(s, REOP_range, 0);+                    range_start = s->byte_code_len;+                +                    re_emit_range_base(s, c);+                    re_range_optimize(s, range_start, FALSE);+                }+            } else {+                if (s->ignore_case &&+                    ((c >= 'A' && c <= 'Z') ||+                     (c >= 'a' && c <= 'z'))) {+                    /* XXX: could add specific operation */+                    if (c >= 'a')+                        c -= 32;+                    re_emit_op_u8(s, REOP_range8, 2);+                    emit_u8(s, c);+                    emit_u8(s, c + 1);+                    emit_u8(s, c + 32);+                    emit_u8(s, c + 32 + 1);+                } else {+                    re_emit_char(s, c);+                }+            }+            break;+        }++        /* quantifier */+        if (last_atom_start >= 0) {+            re_parse_quantifier(s, last_atom_start, last_capture_count);+        }++        /* combine several characters when possible */+        arr = JS_VALUE_TO_PTR(s->byte_code);+        if (last_term_start >= 0 &&+            (n1 = re_is_char(arr->buf, last_term_start, term_start)) > 0 &&+            (n2 = re_is_char(arr->buf, term_start, s->byte_code_len)) > 0 &&+            (n1 + n2) <= 4) {+            n1 += n2;+            arr->buf[last_term_start] = REOP_char1 + n1 - 1;+            for(i = 0; i < n2; i++)+                arr->buf[last_term_start + n1 + i] = arr->buf[last_term_start + n1 + i + 1];+            s->byte_code_len--;+        } else {+            last_term_start = term_start;+        }+    }+ done:+    return PARSE_STATE_RET;+}++static int re_parse_disjunction(JSParseState *s, int state, int dummy_param)+{+    int start, len, pos;+    JSByteArray *arr;++    PARSE_START2();+    +    start = s->byte_code_len;++    PARSE_CALL_SAVE1(s, 0, re_parse_alternative, 0, start);+    while (s->source_buf[s->buf_pos] == '|') {+        s->buf_pos++;++        len = s->byte_code_len - start;++        /* insert a split before the first alternative */+        emit_insert(s, start, 5);+        arr = JS_VALUE_TO_PTR(s->byte_code);+        arr->buf[start] = REOP_split_next_first;+        put_u32(arr->buf + start + 1, len + 5);++        pos = re_emit_op_u32(s, REOP_goto, 0);++        PARSE_CALL_SAVE2(s, 1, re_parse_alternative, 0, start, pos);++        /* patch the goto */+        len = s->byte_code_len - (pos + 4);+        arr = JS_VALUE_TO_PTR(s->byte_code);+        put_u32(arr->buf + pos, len);+    }+    return PARSE_STATE_RET;+}++/* Allocate the registers as a stack. The control flow is recursive so+   the analysis can be linear. */+static int re_compute_register_count(JSParseState *s, 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;+    pos = 0;+    while (pos < bc_buf_len) {+        opcode = bc_buf[pos];+        len = reopcode_info[opcode].size;+        assert(opcode < REOP_COUNT);+        assert((pos + len) <= bc_buf_len);+        switch(opcode) {+        case REOP_set_i32:+        case REOP_set_char_pos:+            bc_buf[pos + 1] = stack_size;+            stack_size++;+            if (stack_size > stack_size_max) {+                if (stack_size > REGISTER_COUNT_MAX)+                    js_parse_error(s, "too many regexp registers");+                stack_size_max = stack_size;+            }+            break;+        case REOP_check_advance:+        case REOP_loop:+        case REOP_loop_split_goto_first:+        case REOP_loop_split_next_first:+            assert(stack_size > 0);+            stack_size--;+            bc_buf[pos + 1] = stack_size;+            break;+        case REOP_loop_check_adv_split_goto_first:+        case REOP_loop_check_adv_split_next_first:+            assert(stack_size >= 2);+            stack_size -= 2;+            bc_buf[pos + 1] = stack_size;+            break;+        case REOP_range8:+            val = bc_buf[pos + 1];+            len += val * 2;+            break;+        case REOP_range:+            val = get_u16(bc_buf + pos + 1);+            len += val * 8;+            break;+        case REOP_back_reference:+        case REOP_back_reference_i:+            /* validate back references */+            if (bc_buf[pos + 1] >= s->capture_count)+                js_parse_error(s, "back reference is out of range");+            break;+        }+        pos += len;+    }+    return stack_size_max;+}++/* return a JSByteArray. 'source' must be a string */+static JSValue js_parse_regexp(JSParseState *s, int re_flags)+{+    JSByteArray *arr;+    int register_count;+    +    s->multi_line = ((re_flags & LRE_FLAG_MULTILINE) != 0);+    s->dotall = ((re_flags & LRE_FLAG_DOTALL) != 0);+    s->ignore_case = ((re_flags & LRE_FLAG_IGNORECASE) != 0);+    s->is_unicode = ((re_flags & LRE_FLAG_UNICODE) != 0);+    s->byte_code = JS_NULL;+    s->byte_code_len = 0;+    s->capture_count = 1;+    +    emit_u16(s, re_flags);+    emit_u8(s, 0); /* number of captures */+    emit_u8(s, 0); /* number of registers */++    if (!(re_flags & LRE_FLAG_STICKY)) {+        re_emit_op_u32(s, REOP_split_goto_first, 1 + 5);+        re_emit_op(s, REOP_any);+        re_emit_op_u32(s, REOP_goto, -(5 + 1 + 5));+    }+    re_emit_op_u8(s, REOP_save_start, 0);++    js_parse_call(s, PARSE_FUNC_re_parse_disjunction, 0);++    re_emit_op_u8(s, REOP_save_end, 0);+    re_emit_op(s, REOP_match);++    if (s->buf_pos != s->buf_len)+        js_parse_error(s, "extraneous characters at the end");++    arr = JS_VALUE_TO_PTR(s->byte_code);+    arr->buf[RE_HEADER_CAPTURE_COUNT] = s->capture_count;+    register_count =+        re_compute_register_count(s, arr->buf + RE_HEADER_LEN,+                                  s->byte_code_len - RE_HEADER_LEN);+    arr->buf[RE_HEADER_REGISTER_COUNT] = register_count;+    +    js_shrink_byte_array(s->ctx, &s->byte_code, s->byte_code_len);++#ifdef DUMP_REOP+    arr = JS_VALUE_TO_PTR(s->byte_code);+    lre_dump_bytecode(arr->buf, arr->size);+#endif+    +    return s->byte_code;+}++/* regexp interpreter */++#define CP_LS   0x2028+#define CP_PS   0x2029++static BOOL is_line_terminator(uint32_t c)+{+    return (c == '\n' || c == '\r' || c == CP_LS || c == CP_PS);+}++static BOOL is_word_char(uint32_t c)+{+    return ((c >= '0' && c <= '9') ||+            (c >= 'a' && c <= 'z') ||+            (c >= 'A' && c <= 'Z') ||+            (c == '_'));+}++/* Note: we canonicalize as in the unicode case, but only handle ASCII characters */+static int lre_canonicalize(uint32_t c)+{+    if (c >= 'A' && c <= 'Z') {+        c = c - 'A' + 'a';+    }+    return c;+}++#define GET_CHAR(c, cptr, cbuf_end)                          \+    do {                                                     \+        size_t clen;                                         \+        c = utf8_get(cptr, &clen);                           \+        cptr += clen;                                        \+    } while (0)++#define PEEK_CHAR(c, cptr, cbuf_end)                         \+    do {                                                                \+        size_t clen;                                         \+        c = utf8_get(cptr, &clen);                           \+    } while (0)++#define PEEK_PREV_CHAR(c, cptr, cbuf_start)                  \+    do {                                                     \+        const uint8_t *cptr1 = cptr - 1;                     \+        size_t clen;                                         \+        while ((*cptr1 & 0xc0) == 0x80)                                  \+            cptr1--;                                                     \+        c = utf8_get(cptr1, &clen);                                      \+    } while (0)++typedef enum {+    RE_EXEC_STATE_SPLIT,+    RE_EXEC_STATE_LOOKAHEAD,+    RE_EXEC_STATE_NEGATIVE_LOOKAHEAD,+} REExecStateEnum;++//#define DUMP_REEXEC++/* return 1 if match, 0 if not match or < 0 if error. str must be a+   JSString. capture_buf and byte_code are JSByteArray */+static int lre_exec(JSContext *ctx, JSValue capture_buf,+                    JSValue byte_code, JSValue str, int cindex)+{+    const uint8_t *pc, *cptr, *cbuf;+    uint32_t *capture;+    int opcode, capture_count;+    uint32_t val, c, idx;+    const uint8_t *cbuf_end;+    JSValue *sp, *bp, *initial_sp, *saved_stack_bottom;+    JSByteArray *arr; /* temporary use */+    JSString *ps; /* temporary use */+    JSGCRef capture_buf_ref, byte_code_ref, str_ref;++    arr = JS_VALUE_TO_PTR(byte_code);+    pc = arr->buf;+    arr = JS_VALUE_TO_PTR(capture_buf);+    capture = (uint32_t *)arr->buf;+    capture_count = lre_get_capture_count(pc);+    pc += RE_HEADER_LEN;+    ps = JS_VALUE_TO_PTR(str);+    cbuf = ps->buf;+    cbuf_end = cbuf + ps->len;+    cptr = cbuf + cindex;++    saved_stack_bottom = ctx->stack_bottom;+    initial_sp = ctx->sp;+    sp = initial_sp;+    bp = initial_sp;+    +#define LRE_POLL_INTERRUPT() do {                       \+        if (unlikely(--ctx->interrupt_counter <= 0)) {  \+            JSValue ret;                                \+            int saved_pc, saved_cptr;                   \+            arr = JS_VALUE_TO_PTR(byte_code);      \+            saved_pc = pc - arr->buf;                   \+            saved_cptr = cptr - cbuf;                   \+            JS_PUSH_VALUE(ctx, capture_buf);            \+            JS_PUSH_VALUE(ctx, byte_code);              \+            JS_PUSH_VALUE(ctx, str);                    \+            ctx->sp = sp;                               \+            ret = __js_poll_interrupt(ctx);             \+            JS_POP_VALUE(ctx, str);                     \+            JS_POP_VALUE(ctx, byte_code);               \+            JS_POP_VALUE(ctx, capture_buf);             \+            if (JS_IsException(ret)) {                  \+                ctx->sp = initial_sp;                   \+                ctx->stack_bottom = saved_stack_bottom; \+                return -1;                              \+            }                                           \+            arr = JS_VALUE_TO_PTR(byte_code);      \+            pc = arr->buf + saved_pc;                   \+            ps = JS_VALUE_TO_PTR(str);             \+            cbuf = ps->buf;                             \+            cbuf_end = cbuf + ps->len;                  \+            cptr = cbuf + saved_cptr;                   \+            arr = JS_VALUE_TO_PTR(capture_buf);    \+            capture = (uint32_t *)arr->buf;             \+        }                                               \+    } while(0)++#define CHECK_STACK_SPACE(n)                            \+    {                                                   \+        if (unlikely((sp - ctx->stack_bottom) < (n))) { \+            int ret, saved_pc, saved_cptr;              \+            arr = JS_VALUE_TO_PTR(byte_code);      \+            saved_pc = pc - arr->buf;                   \+            saved_cptr = cptr - cbuf;                   \+            JS_PUSH_VALUE(ctx, capture_buf);            \+            JS_PUSH_VALUE(ctx, byte_code);              \+            JS_PUSH_VALUE(ctx, str);                    \+            ctx->sp = sp;                               \+            ret = JS_StackCheck(ctx, n);                \+            JS_POP_VALUE(ctx, str);                     \+            JS_POP_VALUE(ctx, byte_code);               \+            JS_POP_VALUE(ctx, capture_buf);             \+            if (ret < 0) {                              \+                ctx->sp = initial_sp;                   \+                ctx->stack_bottom = saved_stack_bottom; \+                return -1;                              \+            }                                           \+            arr = JS_VALUE_TO_PTR(byte_code);      \+            pc = arr->buf + saved_pc;                   \+            ps = JS_VALUE_TO_PTR(str);             \+            cbuf = ps->buf;                             \+            cbuf_end = cbuf + ps->len;                  \+            cptr = cbuf + saved_cptr;                   \+            arr = JS_VALUE_TO_PTR(capture_buf);    \+            capture = (uint32_t *)arr->buf;             \+        }                                               \+    }++#define SAVE_CAPTURE(idx, value)                        \+    {                                                   \+        int __v = (value);                              \+        CHECK_STACK_SPACE(2);                           \+        sp[-2] = JS_NewShortInt(idx);                   \+        sp[-1] = JS_NewShortInt(capture[idx]);   \+        sp -= 2;                                                \+        capture[idx] = __v;                                     \+    }++    /* avoid saving the previous value if already saved */+#define SAVE_CAPTURE_CHECK(idx, value)                    \+    {                                                     \+        int __v = (value);                                \+        JSValue *sp1;                           \+        sp1 = sp;                               \+        for(;;) {                               \+            if (sp1 < bp) {                             \+                if (JS_VALUE_GET_INT(sp1[0]) == (idx))  \+                    break;                              \+                sp1 += 2;                               \+            } else {                                    \+                CHECK_STACK_SPACE(2);                   \+                sp[-2] = JS_NewShortInt(idx);           \+                sp[-1] = JS_NewShortInt(capture[idx]);  \+                sp -= 2;                                \+                break;                                  \+            }                                           \+        }                                               \+        capture[idx] = __v;                             \+    }++#define RE_PC_TYPE_TO_VALUE(pc, type) (((type) << 1) | (((pc) - ((JSByteArray *)JS_VALUE_TO_PTR(byte_code))->buf) << 3))+#define RE_VALUE_TO_PC(val) (((val) >> 3) + ((JSByteArray *)JS_VALUE_TO_PTR(byte_code))->buf)+#define RE_VALUE_TO_TYPE(val) (((val) >> 1) & 3)++#ifdef DUMP_REEXEC+    printf("%5s %5s %5s %5s %s\n", "PC", "CP", "BP", "SP", "OPCODE");+#endif    +    for(;;) {+        opcode = *pc++;+#ifdef DUMP_REEXEC+        printf("%5ld %5ld %5ld %5ld %s\n",+               pc - 1 - ((JSByteArray *)JS_VALUE_TO_PTR(byte_code))->buf - RE_HEADER_LEN,+               cptr - cbuf,+               bp - initial_sp,+               sp - initial_sp,+               reopcode_info[opcode].name);+#endif        +        switch(opcode) {+        case REOP_match:+            ctx->sp = initial_sp;+            ctx->stack_bottom = saved_stack_bottom;+            return 1;+        no_match:+            for(;;) {+                REExecStateEnum type;+                if (bp == initial_sp) {+                    ctx->sp = initial_sp;+                    ctx->stack_bottom = saved_stack_bottom;+                    return 0;+                }+                /* undo the modifications to capture[] and regs[] */+                while (sp < bp) {+                    int idx2 = JS_VALUE_GET_INT(sp[0]);+                    capture[idx2] = JS_VALUE_GET_INT(sp[1]);+                    sp += 2;+                }+                +                pc = RE_VALUE_TO_PC(sp[0]);+                type = RE_VALUE_TO_TYPE(sp[0]);+                cptr = JS_VALUE_GET_INT(sp[1]) + cbuf;+                bp = VALUE_TO_SP(ctx, sp[2]);+                sp += 3;+                if (type != RE_EXEC_STATE_LOOKAHEAD)+                    break;+            }+            LRE_POLL_INTERRUPT();+            break;+        case REOP_lookahead_match:+            /* pop all the saved states until reaching the start of+               the lookahead and keep the updated captures and+               variables and the corresponding undo info. */+            {+                JSValue *sp1, *sp_start, *next_sp;+                REExecStateEnum type;++                sp_start = sp;+                for(;;) {+                    sp1 = sp;+                    sp = bp;+                    pc = RE_VALUE_TO_PC(sp[0]);+                    type = RE_VALUE_TO_TYPE(sp[0]);+                    cptr = JS_VALUE_GET_INT(sp[1]) + cbuf;+                    bp = VALUE_TO_SP(ctx, sp[2]);+                    sp[2] = SP_TO_VALUE(ctx, sp1); /* save the next value for the copy step */+                    sp += 3;+                    if (type == RE_EXEC_STATE_LOOKAHEAD)+                        break;+                }+                if (sp != initial_sp) {+                    /* keep the undo info if there is a saved state */+                    sp1 = sp;+                    while (sp1 != sp_start) {+                        sp1 -= 3;+                        next_sp = VALUE_TO_SP(ctx, sp1[2]);+                        while (sp1 != next_sp) {+                            *--sp = *--sp1;+                        }+                    }+                }+            }+            break;+        case REOP_negative_lookahead_match:+            /* pop all the saved states until reaching start of the negative lookahead */+            for(;;) {+                REExecStateEnum type;+                type = RE_VALUE_TO_TYPE(bp[0]);+                /* undo the modifications to capture[] and regs[] */+                while (sp < bp) {+                    int idx2 = JS_VALUE_GET_INT(sp[0]);+                    capture[idx2] = JS_VALUE_GET_INT(sp[1]);+                    sp += 2;+                }+                pc = RE_VALUE_TO_PC(sp[0]);+                type = RE_VALUE_TO_TYPE(sp[0]);+                cptr = JS_VALUE_GET_INT(sp[1]) + cbuf;+                bp = VALUE_TO_SP(ctx, sp[2]);+                sp += 3;+                if (type == RE_EXEC_STATE_NEGATIVE_LOOKAHEAD)+                    break;+            }+            goto no_match;++        case REOP_char1:+            if ((cbuf_end - cptr) < 1)+                goto no_match;+            if (pc[0] != cptr[0])+                goto no_match;+            pc++;+            cptr++;+            break;+        case REOP_char2:+            if ((cbuf_end - cptr) < 2)+                goto no_match;+            if (get_u16(pc) != get_u16(cptr))+                goto no_match;+            pc += 2;+            cptr += 2;+            break;+        case REOP_char3:+            if ((cbuf_end - cptr) < 3)+                goto no_match;+            if (get_u16(pc) != get_u16(cptr) || pc[2] != cptr[2])+                goto no_match;+            pc += 3;+            cptr += 3;+            break;+        case REOP_char4:+            if ((cbuf_end - cptr) < 4)+                goto no_match;+            if (get_u32(pc) != get_u32(cptr))+                goto no_match;+            pc += 4;+            cptr += 4;+            break;+        case REOP_split_goto_first:+        case REOP_split_next_first:+            {+                const uint8_t *pc1;++                val = get_u32(pc);+                pc += 4;+                CHECK_STACK_SPACE(3);+                if (opcode == REOP_split_next_first) {+                    pc1 = pc + (int)val;+                } else {+                    pc1 = pc;+                    pc = pc + (int)val;+                }+                sp -= 3;+                sp[0] = RE_PC_TYPE_TO_VALUE(pc1, RE_EXEC_STATE_SPLIT);+                sp[1] = JS_NewShortInt(cptr - cbuf);+                sp[2] = SP_TO_VALUE(ctx, bp);+                bp = sp;+            }+            break;+        case REOP_lookahead:+        case REOP_negative_lookahead:+            val = get_u32(pc);+            pc += 4;+            CHECK_STACK_SPACE(3);+            sp -= 3;+            sp[0] = RE_PC_TYPE_TO_VALUE(pc + (int)val,+                                        RE_EXEC_STATE_LOOKAHEAD + opcode - REOP_lookahead);+            sp[1] = JS_NewShortInt(cptr - cbuf);+            sp[2] = SP_TO_VALUE(ctx, bp);+            bp = sp;+            break;+        case REOP_goto:+            val = get_u32(pc);+            pc += 4 + (int)val;+            LRE_POLL_INTERRUPT();+            break;+        case REOP_line_start:+        case REOP_line_start_m:+            if (cptr == cbuf)+                break;+            if (opcode == REOP_line_start)+                goto no_match;+            PEEK_PREV_CHAR(c, cptr, cbuf);+            if (!is_line_terminator(c))+                goto no_match;+            break;+        case REOP_line_end:+        case REOP_line_end_m:+            if (cptr == cbuf_end)+                break;+            if (opcode == REOP_line_end)+                goto no_match;+            PEEK_CHAR(c, cptr, cbuf_end);+            if (!is_line_terminator(c))+                goto no_match;+            break;+        case REOP_dot:+            if (cptr == cbuf_end)+                goto no_match;+            GET_CHAR(c, cptr, cbuf_end);+            if (is_line_terminator(c))+                goto no_match;+            break;+        case REOP_any:+            if (cptr == cbuf_end)+                goto no_match;+            GET_CHAR(c, cptr, cbuf_end);+            break;+        case REOP_space:+        case REOP_not_space:+            {+                BOOL v1;+                if (cptr == cbuf_end)+                    goto no_match;+                c = cptr[0];+                if (c < 128) {+                    cptr++;+                    v1 = unicode_is_space_ascii(c);+                } else {+                    size_t clen;+                    c = __utf8_get(cptr, &clen);+                    cptr += clen;+                    v1 = unicode_is_space_non_ascii(c);+                }+                v1 ^= (opcode - REOP_space);+                if (!v1)+                    goto no_match;+            }+            break;+        case REOP_save_start:+        case REOP_save_end:+            val = *pc++;+            assert(val < capture_count);+            idx = 2 * val + opcode - REOP_save_start;+            SAVE_CAPTURE(idx, cptr - cbuf);+            break;+        case REOP_save_reset:+            {+                uint32_t val2;+                val = pc[0];+                val2 = pc[1];+                pc += 2;+                assert(val2 < capture_count);+                CHECK_STACK_SPACE(2 * (val2 - val + 1));+                while (val <= val2) {+                    idx = 2 * val;+                    SAVE_CAPTURE(idx, 0);+                    idx = 2 * val + 1;+                    SAVE_CAPTURE(idx, 0);+                    val++;+                }+            }+            break;+        case REOP_set_i32:+            idx = pc[0];+            val = get_u32(pc + 1);+            pc += 5;+            SAVE_CAPTURE_CHECK(2 * capture_count + idx, val);+            break;+        case REOP_loop:+            {+                uint32_t val2;+                idx = pc[0];+                val = get_u32(pc + 1);+                pc += 5;++                val2 = capture[2 * capture_count + idx] - 1;+                SAVE_CAPTURE_CHECK(2 * capture_count + idx, val2);+                if (val2 != 0) {+                    pc += (int)val;+                    LRE_POLL_INTERRUPT();+                }+            }+            break;+        case REOP_loop_split_goto_first:+        case REOP_loop_split_next_first:+        case REOP_loop_check_adv_split_goto_first:+        case REOP_loop_check_adv_split_next_first:+            {+                const uint8_t *pc1;+                uint32_t val2, limit;+                idx = pc[0];+                limit = get_u32(pc + 1);+                val = get_u32(pc + 5);+                pc += 9;++                /* decrement the counter */+                val2 = capture[2 * capture_count + idx] - 1;+                SAVE_CAPTURE_CHECK(2 * capture_count + idx, val2);+                +                if (val2 > limit) {+                    /* normal loop if counter > limit */+                    pc += (int)val;+                    LRE_POLL_INTERRUPT();+                } else {+                    /* check advance */+                    if ((opcode == REOP_loop_check_adv_split_goto_first ||+                         opcode == REOP_loop_check_adv_split_next_first) &&+                        capture[2 * capture_count + idx + 1] == (cptr - cbuf) &&+                        val2 != limit) {+                        goto no_match;+                    }+                    +                    /* otherwise conditional split */+                    if (val2 != 0) {+                        CHECK_STACK_SPACE(3);+                        if (opcode == REOP_loop_split_next_first ||+                            opcode == REOP_loop_check_adv_split_next_first) {+                            pc1 = pc + (int)val;+                        } else {+                            pc1 = pc;+                            pc = pc + (int)val;+                        }+                        sp -= 3;+                        sp[0] = RE_PC_TYPE_TO_VALUE(pc1, RE_EXEC_STATE_SPLIT);+                        sp[1] = JS_NewShortInt(cptr - cbuf);+                        sp[2] = SP_TO_VALUE(ctx, bp);+                        bp = sp;+                    }+                }+            }+            break;+        case REOP_set_char_pos:+            idx = pc[0];+            pc++;+            SAVE_CAPTURE_CHECK(2 * capture_count + idx, cptr - cbuf);+            break;+        case REOP_check_advance:+            idx = pc[0];+            pc++;+            if (capture[2 * capture_count + idx] == cptr - cbuf)+                goto no_match;+            break;+        case REOP_word_boundary:+        case REOP_not_word_boundary:+            {+                BOOL v1, v2;+                BOOL is_boundary = (opcode == REOP_word_boundary);+                /* char before */+                if (cptr == cbuf) {+                    v1 = FALSE;+                } else {+                    PEEK_PREV_CHAR(c, cptr, cbuf);+                    v1 = is_word_char(c);+                }+                /* current char */+                if (cptr >= cbuf_end) {+                    v2 = FALSE;+                } else {+                    PEEK_CHAR(c, cptr, cbuf_end);+                    v2 = is_word_char(c);+                }+                if (v1 ^ v2 ^ is_boundary)+                    goto no_match;+            }+            break;+            /* assumption: 8 bit and small number of ranges */+        case REOP_range8:+            {+                int n, i;+                n = pc[0];+                pc++;+                if (cptr >= cbuf_end)+                    goto no_match;+                GET_CHAR(c, cptr, cbuf_end);+                for(i = 0; i < n - 1; i++) {+                    if (c >= pc[2 * i] && c < pc[2 * i + 1])+                        goto range8_match;+                }+                /* 0xff = max code point value */+                if (c >= pc[2 * i] &&+                    (c < pc[2 * i + 1] || pc[2 * i + 1] == 0xff))+                    goto range8_match;+                goto no_match;+            range8_match:+                pc += 2 * n;+            }+            break;+        case REOP_range:+            {+                int n;+                uint32_t low, high, idx_min, idx_max, idx;++                n = get_u16(pc); /* n must be >= 1 */+                pc += 2;+                if (cptr >= cbuf_end || n == 0)+                    goto no_match;+                GET_CHAR(c, cptr, cbuf_end);+                idx_min = 0;+                low = get_u32(pc + 0 * 8);+                if (c < low)+                    goto no_match;+                idx_max = n - 1;+                high = get_u32(pc + idx_max * 8 + 4);+                if (c >= high)+                    goto no_match;+                while (idx_min <= idx_max) {+                    idx = (idx_min + idx_max) / 2;+                    low = get_u32(pc + idx * 8);+                    high = get_u32(pc + idx * 8 + 4);+                    if (c < low)+                        idx_max = idx - 1;+                    else if (c >= high)+                        idx_min = idx + 1;+                    else+                        goto range_match;+                }+                goto no_match;+            range_match:+                pc += 8 * n;+            }+            break;+        case REOP_back_reference:+        case REOP_back_reference_i:+            val = pc[0];+            pc++;+            if (capture[2 * val] != -1 && capture[2 * val + 1] != -1) {+                const uint8_t *cptr1, *cptr1_end;+                int c1, c2;++                cptr1 = cbuf + capture[2 * val];+                cptr1_end = cbuf + capture[2 * val + 1];+                while (cptr1 < cptr1_end) {+                    if (cptr >= cbuf_end)+                        goto no_match;+                    GET_CHAR(c1, cptr1, cptr1_end);+                    GET_CHAR(c2, cptr, cbuf_end);+                    if (opcode == REOP_back_reference_i) {+                        c1 = lre_canonicalize(c1);+                        c2 = lre_canonicalize(c2);+                    }+                    if (c1 != c2)+                        goto no_match;+                }+            }+            break;+        default:+#ifdef DUMP_REEXEC+            printf("unknown opcode pc=%ld\n", pc - 1 - ((JSByteArray *)JS_VALUE_TO_PTR(byte_code))->buf - RE_HEADER_LEN);+#endif            +            abort();+        }+    }+}++/* regexp js interface */++/* return the length */+static size_t js_parse_regexp_flags(int *pre_flags, const uint8_t *buf)+{+    const uint8_t *p = buf;+    int mask, re_flags;+    re_flags = 0;+    while (*p != '\0') {+        switch(*p) {+#if 0+        case 'd':+            mask = LRE_FLAG_INDICES;+            break;+#endif                +        case 'g':+            mask = LRE_FLAG_GLOBAL;+            break;+        case 'i':+            mask = LRE_FLAG_IGNORECASE;+            break;+        case 'm':+            mask = LRE_FLAG_MULTILINE;+            break;+        case 's':+            mask = LRE_FLAG_DOTALL;+            break;+        case 'u':+            mask = LRE_FLAG_UNICODE;+            break;+#if 0+        case 'v':+            mask = LRE_FLAG_UNICODE_SETS;+            break;+#endif+        case 'y':+            mask = LRE_FLAG_STICKY;+            break;+        default:+            goto done;+        }+        if ((re_flags & mask) != 0) +            break;+        re_flags |= mask;+        p++;+    }+ done:+    *pre_flags = re_flags;+    return p - buf;+}++/* pattern and flags must be strings */+static JSValue js_compile_regexp(JSContext *ctx, JSValue pattern, JSValue flags)+{+    int re_flags;+    +    re_flags = 0;+    if (!JS_IsUndefined(flags)) {+        JSString *ps;+        JSStringCharBuf buf;+        size_t len;+        ps = get_string_ptr(ctx, &buf, flags);+        len = js_parse_regexp_flags(&re_flags, ps->buf);+        if (len != ps->len)+            return JS_ThrowSyntaxError(ctx, "invalid regular expression flags");+    }++    return JS_Parse2(ctx, pattern, NULL, 0, "<regexp>",+                     JS_EVAL_REGEXP | (re_flags << JS_EVAL_REGEXP_FLAGS_SHIFT));+}++static JSRegExp *js_get_regexp(JSContext *ctx, JSValue obj)+{+    JSObject *p;+    p = js_get_object_class(ctx, obj, JS_CLASS_REGEXP);+    if (!p) {+        JS_ThrowTypeError(ctx, "not a regular expression");+        return NULL;+    }+    return &p->u.regexp;+}++JSValue js_regexp_get_lastIndex(JSContext *ctx, JSValue *this_val,+                                int argc, JSValue *argv)+{+    JSRegExp *re = js_get_regexp(ctx, *this_val);+    if (!re)+        return JS_EXCEPTION;+    return JS_NewInt32(ctx, re->last_index);+}++JSValue js_regexp_get_source(JSContext *ctx, JSValue *this_val,+                             int argc, JSValue *argv)+{+    JSRegExp *re = js_get_regexp(ctx, *this_val);+    if (!re)+        return JS_EXCEPTION;+    /* XXX: not complete */+    return re->source;+}++JSValue js_regexp_set_lastIndex(JSContext *ctx, JSValue *this_val,+                                int argc, JSValue *argv)+{+    JSRegExp *re;+    int last_index;+    if (JS_ToInt32(ctx, &last_index, argv[0]))+        return JS_EXCEPTION;+    re = js_get_regexp(ctx, *this_val);+    if (!re)+        return JS_EXCEPTION;+    re->last_index = last_index;+    return JS_UNDEFINED;+}++#define RE_FLAG_COUNT 6++/* return the string length */+static size_t js_regexp_flags_str(char *buf, int re_flags)+{+    static const char flag_char[RE_FLAG_COUNT] = { 'g', 'i', 'm', 's', 'u', 'y' };+    char *p = buf;+    int i;+    +    for(i = 0; i < RE_FLAG_COUNT; i++) {+        if ((re_flags >> i) & 1)+            *p++ = flag_char[i];+    }+    *p = '\0';+    return p - buf;+}++static void dump_regexp(JSContext *ctx, JSObject *p)+{+    JSStringCharBuf buf;+    JSString *ps;+    char buf2[RE_FLAG_COUNT + 1];+    JSByteArray *arr;+    +    js_putchar(ctx, '/');+    ps = get_string_ptr(ctx, &buf, p->u.regexp.source);+    if (ps->len == 0) {+        js_printf(ctx, "(?:)");+    } else {+        js_printf(ctx, "%" JSValue_PRI, p->u.regexp.source);+    }+    arr = JS_VALUE_TO_PTR(p->u.regexp.byte_code);+    js_regexp_flags_str(buf2, lre_get_flags(arr->buf));+    js_printf(ctx, "/%s", buf2);+}++JSValue js_regexp_get_flags(JSContext *ctx, JSValue *this_val,+                            int argc, JSValue *argv)+{+    JSRegExp *re;+    JSByteArray *arr;+    size_t len;+    char buf[RE_FLAG_COUNT + 1];++    re = js_get_regexp(ctx, *this_val);+    if (!re)+        return JS_EXCEPTION;+    arr = JS_VALUE_TO_PTR(re->byte_code);+    len = js_regexp_flags_str(buf, lre_get_flags(arr->buf));+    return JS_NewStringLen(ctx, buf, len);+}++JSValue js_regexp_constructor(JSContext *ctx, JSValue *this_val,+                              int argc, JSValue *argv)+{+    JSValue obj, byte_code;+    JSObject *p;+    JSGCRef byte_code_ref;++    argc &= ~FRAME_CF_CTOR;+    +    argv[0] = JS_ToString(ctx, argv[0]);+    if (JS_IsException(argv[0]))+        return JS_EXCEPTION;+    if (!JS_IsUndefined(argv[1])) {+        argv[1] = JS_ToString(ctx, argv[1]);+        if (JS_IsException(argv[1]))+            return JS_EXCEPTION;+    }+    byte_code = js_compile_regexp(ctx, argv[0], argv[1]);+    if (JS_IsException(byte_code))+        return JS_EXCEPTION;+    JS_PUSH_VALUE(ctx, byte_code);+    obj = JS_NewObjectClass(ctx, JS_CLASS_REGEXP, sizeof(JSRegExp));+    JS_POP_VALUE(ctx, byte_code);+    if (JS_IsException(obj))+        return obj;+    p = JS_VALUE_TO_PTR(obj);+    p->u.regexp.source = argv[0];+    p->u.regexp.byte_code = byte_code;+    p->u.regexp.last_index = 0;+    return obj;+}++enum {+    MAGIC_REGEXP_EXEC,+    MAGIC_REGEXP_TEST,+    MAGIC_REGEXP_SEARCH,+    MAGIC_REGEXP_FORCE_GLOBAL, /* same as exec but force the global flag */+};++JSValue js_regexp_exec(JSContext *ctx, JSValue *this_val,+                       int argc, JSValue *argv, int magic)+{+    JSObject *p;+    JSRegExp *re;+    JSValue obj, *capture_buf, res;+    uint32_t *capture, last_index_utf8;+    int rc, capture_count, i, re_flags, last_index;+    JSByteArray *bc_arr, *carr;+    JSGCRef capture_buf_ref, obj_ref;+    JSString *str;+    JSStringCharBuf str_buf;++    re = js_get_regexp(ctx, *this_val);+    if (!re)+        return JS_EXCEPTION;++    argv[0] = JS_ToString(ctx, argv[0]);+    if (JS_IsException(argv[0]))+        return JS_EXCEPTION;++    p = JS_VALUE_TO_PTR(*this_val);+    re = &p->u.regexp;+    last_index = max_int(re->last_index, 0);++    bc_arr = JS_VALUE_TO_PTR(re->byte_code);+    re_flags = lre_get_flags(bc_arr->buf);+    if (magic == MAGIC_REGEXP_FORCE_GLOBAL)+        re_flags |= MAGIC_REGEXP_FORCE_GLOBAL;+    if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0 ||+        magic == MAGIC_REGEXP_SEARCH) {+        last_index = 0;+    }+    capture_count = lre_get_capture_count(bc_arr->buf);++    carr = js_alloc_byte_array(ctx, sizeof(uint32_t) * lre_get_alloc_count(bc_arr->buf));+    if (!carr)+        goto fail;+    capture_buf = JS_PushGCRef(ctx, &capture_buf_ref);+    *capture_buf = JS_VALUE_FROM_PTR(carr);+    capture = (uint32_t *)carr->buf;+    for(i = 0; i < 2 * capture_count; i++)+        capture[i] = -1;+    +    if (last_index <= 0)+        last_index_utf8 = 0;+    else+        last_index_utf8 = js_string_utf16_to_utf8_pos(ctx, argv[0], last_index) / 2;+    if (last_index_utf8 > js_string_byte_len(ctx, argv[0])) {+        rc = 2;+    } else {+        p = JS_VALUE_TO_PTR(*this_val);+        re = &p->u.regexp;+        str = get_string_ptr(ctx, &str_buf, argv[0]);+        /* JS_VALUE_FROM_PTR(str) is acceptable here because the+           GC ignores pointers outside the heap */+        rc = lre_exec(ctx, *capture_buf, re->byte_code, JS_VALUE_FROM_PTR(str),+                      last_index_utf8);+    }+    if (rc != 1) {+        if (rc >= 0) {+            if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {+                p = JS_VALUE_TO_PTR(*this_val);+                re = &p->u.regexp;+                re->last_index = 0;+            }+            if (magic == MAGIC_REGEXP_SEARCH)+                obj = JS_NewShortInt(-1);+            else if (magic == MAGIC_REGEXP_TEST)+                obj = JS_FALSE;+            else+                obj = JS_NULL;+        } else {+            goto fail;+        }+    } else {+        capture = (uint32_t *)((JSByteArray *)JS_VALUE_TO_PTR(*capture_buf))->buf;+        if (magic == MAGIC_REGEXP_SEARCH) {+            obj = JS_NewShortInt(js_string_utf8_to_utf16_pos(ctx, argv[0], capture[0] * 2));+            goto done;+        } +        if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {+            p = JS_VALUE_TO_PTR(*this_val);+            re = &p->u.regexp;+            re->last_index = js_string_utf8_to_utf16_pos(ctx, argv[0], capture[1] * 2);+        }+        if (magic == MAGIC_REGEXP_TEST) {+            obj = JS_TRUE;+        } else {+            obj = JS_NewArray(ctx, capture_count);+            if (JS_IsException(obj))+                goto fail;++            JS_PUSH_VALUE(ctx, obj);+            capture = (uint32_t *)((JSByteArray *)JS_VALUE_TO_PTR(*capture_buf))->buf;+            res = JS_DefinePropertyValue(ctx, obj, js_get_atom(ctx, JS_ATOM_index),+                                         JS_NewShortInt(js_string_utf8_to_utf16_pos(ctx, argv[0], capture[0] * 2)));+            JS_POP_VALUE(ctx, obj);+            if (JS_IsException(res))+                goto fail;++            JS_PUSH_VALUE(ctx, obj);+            res = JS_DefinePropertyValue(ctx, obj, js_get_atom(ctx, JS_ATOM_input),+                                         argv[0]);+            JS_POP_VALUE(ctx, obj);+            if (JS_IsException(res))+                goto fail;++            for(i = 0; i < capture_count; i++) {+                int start, end;+                JSValue val;++                capture = (uint32_t *)((JSByteArray *)JS_VALUE_TO_PTR(*capture_buf))->buf;+                start = capture[2 * i];+                end = capture[2 * i + 1];+                if (start != -1 && end != -1) {+                    JSValueArray *arr;+                    JS_PUSH_VALUE(ctx, obj);+                    val = js_sub_string_utf8(ctx, argv[0], 2 * start, 2 * end);+                    JS_POP_VALUE(ctx, obj);+                    if (JS_IsException(val))+                        goto fail;+                    p = JS_VALUE_TO_PTR(obj);+                    arr = JS_VALUE_TO_PTR(p->u.array.tab);+                    arr->arr[i] = val;+                }+            }+        }+    }+ done:+    JS_PopGCRef(ctx, &capture_buf_ref);+    return obj;+ fail:+    obj = JS_EXCEPTION;+    goto done;+}++/* if regexp replace: capture_buf != NULL, needle = NULL+   if string replace: capture_buf = NULL, captures_len = 1, needle != NULL+*/+static int js_string_concat_subst(JSContext *ctx, StringBuffer *b,+                                  JSValue *str, JSValue *rep,+                                  uint32_t pos, uint32_t end_of_match,+                                  JSValue *capture_buf, uint32_t captures_len,+                                  JSValue *needle)+{+    JSStringCharBuf buf_rep;+    JSString *p;+    int rep_len, i, j, j0, c, k;++    if (JS_IsFunction(ctx, *rep)) {+        JSValue res, val;+        JSGCRef val_ref;+        int ret;+        +        if (JS_StackCheck(ctx, 4 + captures_len))+            return -1;+        JS_PushArg(ctx, *str);+        JS_PushArg(ctx, JS_NewShortInt(pos));+        if (capture_buf) {+            for(k = captures_len - 1; k >= 0; k--) {+                uint32_t *captures = (uint32_t *)((JSByteArray *)JS_VALUE_TO_PTR(*capture_buf))->buf;+                if (captures[2 * k] != -1 && captures[2 * k + 1] != -1) {+                    val = js_sub_string_utf8(ctx, *str, captures[2 * k] * 2, captures[2 * k + 1] * 2);+                    if (JS_IsException(val))+                        return -1;+                    JS_PUSH_VALUE(ctx, val);+                    ret = JS_StackCheck(ctx, 3 + k);+                    JS_POP_VALUE(ctx, val);+                    if (ret)+                        return -1;+                } else {+                    val = JS_UNDEFINED;+                }+                JS_PushArg(ctx, val);+            }+        } else {+            JS_PushArg(ctx, *needle);+        }+        JS_PushArg(ctx, *rep); /* function */+        JS_PushArg(ctx, JS_UNDEFINED); /* this_val */+        res = JS_Call(ctx, 2 + captures_len);+        if (JS_IsException(res))+            return -1;+        return string_buffer_concat(ctx, b, res);+    }+    +    p = get_string_ptr(ctx, &buf_rep, *rep);+    rep_len = p->len;+    i = 0;+    for(;;) {+        p = get_string_ptr(ctx, &buf_rep, *rep);+        j = i;+        while (j < rep_len && p->buf[j] != '$')+            j++;+        if (j + 1 >= rep_len)+            break;+        j0 = j++; /* j0 = position of '$' */+        c = p->buf[j++];+        string_buffer_concat_utf8(ctx, b, *rep, 2 * i, 2 * j0);+        if (c == '$') {+            string_buffer_putc(ctx, b, '$');+        } else if (c == '&') {+            if (capture_buf) {+                string_buffer_concat_utf16(ctx, b, *str, pos, end_of_match);+            } else {+                string_buffer_concat_str(ctx, b, *needle);+            }+        } else if (c == '`') {+            string_buffer_concat_utf16(ctx, b, *str, 0, pos);+        } else if (c == '\'') {+            string_buffer_concat_utf16(ctx, b, *str, end_of_match, js_string_len(ctx, *str));+        } else if (c >= '0' && c <= '9') {+            k = c - '0';+            if (j < rep_len) {+                c = p->buf[j];+                if (c >= '0' && c <= '9') {+                    k = k * 10 + c - '0';+                    j++;+                }+            }+            if (k >= 1 && k < captures_len) {+                uint32_t *captures = (uint32_t *)((JSByteArray *)JS_VALUE_TO_PTR(*capture_buf))->buf;+                if (captures[2 * k] != -1 && captures[2 * k + 1] != -1) {+                    string_buffer_concat_utf8(ctx, b, *str,+                                              captures[2 * k] * 2, captures[2 * k + 1] * 2);+                }+            } else {+                goto no_rep;+            }+        } else {+        no_rep:+            string_buffer_concat_utf8(ctx, b, *rep, 2 * j0, 2 * j);+        }+        i = j;+    }+    return string_buffer_concat_utf8(ctx, b, *rep, 2 * i, 2 * rep_len);+}++JSValue js_string_replace(JSContext *ctx, JSValue *this_val,+                          int argc, JSValue *argv, int is_replaceAll)+{+    StringBuffer b_s, *b = &b_s;+    int pos, endOfLastMatch, needle_len, input_len;+    BOOL is_first, is_regexp;++    *this_val = JS_ToString(ctx, *this_val);+    if (JS_IsException(*this_val))+        return JS_EXCEPTION;+    is_regexp = (JS_GetClassID(ctx, argv[0]) == JS_CLASS_REGEXP);+    if (!is_regexp) {+        argv[0] = JS_ToString(ctx, argv[0]);+        if (JS_IsException(argv[0]))+            return JS_EXCEPTION;+    }+    if (!JS_IsFunction(ctx, argv[1])) {+        argv[1] = JS_ToString(ctx, argv[1]);+        if (JS_IsException(argv[1]))+            return JS_EXCEPTION;+    }+    input_len = js_string_len(ctx, *this_val);+    endOfLastMatch = 0;++    string_buffer_push(ctx, b, 0);+    +    if (is_regexp) {+        int start, end, last_index, ret, re_flags, i, capture_count;+        JSObject *p;+        JSByteArray *bc_arr, *carr;+        JSValue *capture_buf;+        uint32_t *capture;+        JSGCRef capture_buf_ref;+        +        p = JS_VALUE_TO_PTR(argv[0]);+        bc_arr = JS_VALUE_TO_PTR(p->u.regexp.byte_code);+        re_flags = lre_get_flags(bc_arr->buf);+        capture_count = lre_get_capture_count(bc_arr->buf);++        if (re_flags & LRE_FLAG_GLOBAL)+            p->u.regexp.last_index = 0;+        +        if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {+            last_index = 0;+        } else {+            last_index = max_int(p->u.regexp.last_index, 0);+        }+        +        carr = js_alloc_byte_array(ctx, sizeof(uint32_t) * lre_get_alloc_count(bc_arr->buf));+        if (!carr) {+            string_buffer_pop(ctx, b);+            return JS_EXCEPTION;+        }+        capture_buf = JS_PushGCRef(ctx, &capture_buf_ref);+        *capture_buf = JS_VALUE_FROM_PTR(carr);+        capture = (uint32_t *)carr->buf;+        for(i = 0; i < 2 * capture_count; i++)+            capture[i] = -1;++        for(;;) {+            if (last_index > input_len) {+                ret = 0;+            } else {+                JSString *str;+                JSStringCharBuf str_buf;+                p = JS_VALUE_TO_PTR(argv[0]);+                str = get_string_ptr(ctx, &str_buf, *this_val);+                /* JS_VALUE_FROM_PTR(str) is acceptable here because the+                   GC ignores pointers outside the heap */+                ret = lre_exec(ctx, *capture_buf, p->u.regexp.byte_code,+                               JS_VALUE_FROM_PTR(str),+                               js_string_utf16_to_utf8_pos(ctx, *this_val, last_index) / 2);+            }+            if (ret < 0) {+                JS_PopGCRef(ctx, &capture_buf_ref);+                string_buffer_pop(ctx, b);+                return JS_EXCEPTION;+            }+            if (ret == 0) {+                if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {+                    p = JS_VALUE_TO_PTR(argv[0]);+                    p->u.regexp.last_index = 0;+                }+                break;+            }+            capture = (uint32_t *)((JSByteArray *)JS_VALUE_TO_PTR(*capture_buf))->buf;+            start = js_string_utf8_to_utf16_pos(ctx, *this_val, capture[0] * 2);+            end = js_string_utf8_to_utf16_pos(ctx, *this_val, capture[1] * 2);+            string_buffer_concat_utf16(ctx, b, *this_val, endOfLastMatch, start);+            js_string_concat_subst(ctx, b, this_val, &argv[1],+                                   start, end, capture_buf, capture_count, NULL);+            endOfLastMatch = end;+            if (!(re_flags & LRE_FLAG_GLOBAL)) {+                if (re_flags & LRE_FLAG_STICKY) {+                    p = JS_VALUE_TO_PTR(argv[0]);+                    p->u.regexp.last_index = end;+                }+                break;+            }+            if (end == start) {+                int c = string_getcp(ctx, *this_val, end, TRUE);+                /* since regexp are unicode by default, replace is also unicode by default */+                end += 1 + (c >= 0x10000);+            }+            last_index = end;+        }+        JS_PopGCRef(ctx, &capture_buf_ref);+    } else {+        needle_len = js_string_len(ctx, argv[0]);+        +        is_first = TRUE;+        for(;;) {+            if (unlikely(needle_len == 0)) {+                if (is_first)+                    pos = 0;+                else if (endOfLastMatch >= input_len)+                    pos = -1;+                else+                    pos = endOfLastMatch + 1;+            } else {+                pos = js_string_indexof(ctx, *this_val, argv[0], endOfLastMatch,+                                        input_len, needle_len);+            }+            if (pos < 0) {+                if (is_first) {+                    string_buffer_pop(ctx, b);+                    return *this_val;+                } else {+                    break;+                }+            }+            +            string_buffer_concat_utf16(ctx, b, *this_val, endOfLastMatch, pos);+            +            js_string_concat_subst(ctx, b, this_val, &argv[1],+                                   pos, pos + needle_len, NULL, 1, &argv[0]);++            endOfLastMatch = pos + needle_len;+            is_first = FALSE;+            if (!is_replaceAll)+                break;+        }+    }+    string_buffer_concat_utf16(ctx, b, *this_val, endOfLastMatch, input_len);+    return string_buffer_pop(ctx, b);+}++// split(sep, limit)+JSValue js_string_split(JSContext *ctx, JSValue *this_val,+                        int argc, JSValue *argv)+{+    JSValue *A, T, ret, *z;+    uint32_t lim, lengthA;+    int p, q, s, e;+    BOOL undef_sep;+    JSGCRef A_ref, z_ref;+    BOOL is_regexp;+    +    *this_val = JS_ToString(ctx, *this_val);+    if (JS_IsException(*this_val))+        return JS_EXCEPTION;+    if (JS_IsUndefined(argv[1])) {+        lim = 0xffffffff;+    } else {+        if (JS_ToUint32(ctx, &lim, argv[1]) < 0)+            return JS_EXCEPTION;+    }+    is_regexp = (JS_GetClassID(ctx, argv[0]) == JS_CLASS_REGEXP);+    if (!is_regexp) {+        undef_sep = JS_IsUndefined(argv[0]);+        argv[0] = JS_ToString(ctx, argv[0]);+        if (JS_IsException(argv[0]))+            return JS_EXCEPTION;+    } else {+        undef_sep = FALSE;+    }+    +    A = JS_PushGCRef(ctx, &A_ref);+    z = JS_PushGCRef(ctx, &z_ref);+    *A = JS_NewArray(ctx, 0);+    if (JS_IsException(*A))+        goto exception;+    lengthA = 0;++    s = js_string_len(ctx, *this_val);+    p = 0;+    if (lim == 0)+        goto done;+    if (undef_sep)+        goto add_tail;++    if (is_regexp) {+        int numberOfCaptures, i, re_flags;+        JSObject *p1;+        JSValueArray *arr;+        JSByteArray *bc_arr;+        +        p1 = JS_VALUE_TO_PTR(argv[0]);+        bc_arr = JS_VALUE_TO_PTR(p1->u.regexp.byte_code);+        re_flags = lre_get_flags(bc_arr->buf);+        +        if (s == 0) {+            p1 = JS_VALUE_TO_PTR(argv[0]);+            p1->u.regexp.last_index = 0;+            *z = js_regexp_exec(ctx, &argv[0], 1, this_val, MAGIC_REGEXP_FORCE_GLOBAL);+            if (JS_IsException(*z))+                goto exception;+            if (JS_IsNull(*z))+                goto add_tail;+            goto done;+        }+        q = 0;+        while (q < s) {+            p1 = JS_VALUE_TO_PTR(argv[0]);+            p1->u.regexp.last_index = q;+            /* XXX: need sticky behavior */+            *z = js_regexp_exec(ctx, &argv[0], 1, this_val, MAGIC_REGEXP_FORCE_GLOBAL);+            if (JS_IsException(*z))+                goto exception;+            if (JS_IsNull(*z)) {+                if (!(re_flags & LRE_FLAG_STICKY)) {+                    break;+                } else {+                    int c = string_getcp(ctx, *this_val, q, TRUE);+                    /* since regexp are unicode by default, split is also unicode by default */+                    q += 1 + (c >= 0x10000);+                }+            } else {+                if (!(re_flags & LRE_FLAG_STICKY)) {+                    JSValue res;+                    res = JS_GetProperty(ctx, *z, js_get_atom(ctx, JS_ATOM_index));+                    if (JS_IsException(res))+                        goto exception;+                    q = JS_VALUE_GET_INT(res);+                }+                p1 = JS_VALUE_TO_PTR(argv[0]);+                e = p1->u.regexp.last_index;+                if (e > s)+                    e = s;+                if (e == p) {+                    int c = string_getcp(ctx, *this_val, q, TRUE);+                    /* since regexp are unicode by default, split is also unicode by default */+                    q += 1 + (c >= 0x10000);+                } else {+                    T = js_sub_string(ctx, *this_val, p, q);+                    if (JS_IsException(T))+                        goto exception;+                    ret = JS_SetPropertyUint32(ctx, *A, lengthA++, T);+                    if (JS_IsException(ret))+                        goto exception;+                    if (lengthA == lim)+                        goto done;+                    p1 = JS_VALUE_TO_PTR(*z);+                    numberOfCaptures = p1->u.array.len;+                    for(i = 1; i < numberOfCaptures; i++) {+                        p1 = JS_VALUE_TO_PTR(*z);+                        arr = JS_VALUE_TO_PTR(p1->u.array.tab);+                        T = arr->arr[i];+                        ret = JS_SetPropertyUint32(ctx, *A, lengthA++, T);+                        if (JS_IsException(ret))+                            goto exception;+                    }+                    q = p = e;+                }+            }+        }+    } else {+        int r = js_string_len(ctx, argv[0]);+        if (s == 0) {+            if (r != 0)+                goto add_tail;+            goto done;+        }+        +        for (q = 0; (q += !r) <= s - r - !r; q = p = e + r) {+            +            e = js_string_indexof(ctx, *this_val, argv[0], q, s, r);+            if (e < 0)+                break;+            T = js_sub_string(ctx, *this_val, p, e);+            if (JS_IsException(T))+                goto exception;+            ret = JS_SetPropertyUint32(ctx, *A, lengthA++, T);+            if (JS_IsException(ret))+                goto exception;+            if (lengthA == lim)+                goto done;+        }+    }+add_tail:+    T = js_sub_string(ctx, *this_val, p, s);+    if (JS_IsException(T))+        goto exception;+    ret = JS_SetPropertyUint32(ctx, *A, lengthA++, T);+    if (JS_IsException(ret))+        goto exception;+    +done:+    JS_PopGCRef(ctx, &z_ref);+    return JS_PopGCRef(ctx, &A_ref);++exception:+    JS_PopGCRef(ctx, &z_ref);+    JS_PopGCRef(ctx, &A_ref);+    return JS_EXCEPTION;+}++JSValue js_string_match(JSContext *ctx, JSValue *this_val,+                        int argc, JSValue *argv)+{+    JSRegExp *re;+    int global, n;+    JSValue *A, *result, ret;+    JSObject *p;+    JSValueArray *arr;+    JSByteArray *barr;+    JSGCRef A_ref, result_ref;+    +    re = js_get_regexp(ctx, argv[0]);+    if (!re)+        return JS_EXCEPTION;+    barr = JS_VALUE_TO_PTR(re->byte_code);+    global = lre_get_flags(barr->buf) & LRE_FLAG_GLOBAL;+    if (!global)+        return js_regexp_exec(ctx, &argv[0], 1, this_val, 0);++    p = JS_VALUE_TO_PTR(argv[0]);+    re = &p->u.regexp;+    re->last_index = 0;++    A = JS_PushGCRef(ctx, &A_ref);+    result = JS_PushGCRef(ctx, &result_ref);+    *A = JS_NULL;+    n = 0;+    for(;;) {+        *result = js_regexp_exec(ctx, &argv[0], 1, this_val, 0);+        if (JS_IsException(*result))+            goto fail;+        if (*result == JS_NULL)+            break;+        if (*A == JS_NULL) {+            *A = JS_NewArray(ctx, 1);+            if (JS_IsException(*A))+                goto fail;+        }++        p = JS_VALUE_TO_PTR(*result);+        arr = JS_VALUE_TO_PTR(p->u.array.tab);++        ret = JS_SetPropertyUint32(ctx, *A, n++, arr->arr[0]);+        if (JS_IsException(ret)) {+        fail:+            *A = JS_EXCEPTION;+            break;+        }+    }+    JS_PopGCRef(ctx, &result_ref);+    return JS_PopGCRef(ctx, &A_ref);+}++JSValue js_string_search(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv)+{+    return js_regexp_exec(ctx, &argv[0], 1, this_val, MAGIC_REGEXP_SEARCH);+}
+ mquickjs/mquickjs.h view
@@ -0,0 +1,382 @@+/*+ * Micro QuickJS Javascript Engine+ *+ * Copyright (c) 2017-2025 Fabrice Bellard+ * Copyright (c) 2017-2025 Charlie Gordon+ *+ * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ *+ * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+ * THE SOFTWARE.+ */+#ifndef MQUICKJS_H+#define MQUICKJS_H++#include <inttypes.h>++#if defined(__GNUC__) || defined(__clang__)+#define __js_printf_like(f, a)   __attribute__((format(printf, f, a)))+#else+#define __js_printf_like(a, b)+#endif++#if INTPTR_MAX >= INT64_MAX+#define JS_PTR64 /* pointers are 64 bit wide instead of 32 bit wide */+#endif++typedef struct JSContext JSContext;++#ifdef JS_PTR64+typedef uint64_t JSWord;+typedef uint64_t JSValue;+#define JSW  8+#define JSValue_PRI  PRIo64+#define JS_USE_SHORT_FLOAT+#else+typedef uint32_t JSWord;+typedef uint32_t JSValue;+#define JSW  4+#define JSValue_PRI  PRIo32+#endif++#define JS_BOOL int++enum {+    JS_TAG_INT         = 0, /* 31 bit integer (1 bit) */+    JS_TAG_PTR         = 1, /* pointer (2 bits) */+    JS_TAG_SPECIAL     = 3, /* other special values (2 bits) */+    JS_TAG_BOOL        = JS_TAG_SPECIAL | (0 << 2), /* (5 bits) */+    JS_TAG_NULL        = JS_TAG_SPECIAL | (1 << 2), /* (5 bits) */+    JS_TAG_UNDEFINED   = JS_TAG_SPECIAL | (2 << 2), /* (5 bits) */+    JS_TAG_EXCEPTION   = JS_TAG_SPECIAL | (3 << 2), /* (5 bits) */+    JS_TAG_SHORT_FUNC  = JS_TAG_SPECIAL | (4 << 2), /* (5 bits) */+    JS_TAG_UNINITIALIZED = JS_TAG_SPECIAL | (5 << 2), /* (5 bits) */+    JS_TAG_STRING_CHAR  = JS_TAG_SPECIAL | (6 << 2), /* (5 bits) */+    JS_TAG_CATCH_OFFSET = JS_TAG_SPECIAL | (7 << 2), /* (5 bits) */+#ifdef JS_USE_SHORT_FLOAT+    JS_TAG_SHORT_FLOAT  = 5,  /* 3 bits */+#endif+};++#define JS_TAG_SPECIAL_BITS 5++#define JS_VALUE_GET_INT(v) ((int)(v) >> 1)+#define JS_VALUE_GET_SPECIAL_VALUE(v) ((int)(v) >> JS_TAG_SPECIAL_BITS)+#define JS_VALUE_GET_SPECIAL_TAG(v) ((v) & ((1 << JS_TAG_SPECIAL_BITS) - 1))+#define JS_VALUE_MAKE_SPECIAL(tag, v) ((tag) | ((v) << JS_TAG_SPECIAL_BITS))++#define JS_NULL      JS_VALUE_MAKE_SPECIAL(JS_TAG_NULL, 0)+#define JS_UNDEFINED JS_VALUE_MAKE_SPECIAL(JS_TAG_UNDEFINED, 0)+#define JS_UNINITIALIZED JS_VALUE_MAKE_SPECIAL(JS_TAG_UNINITIALIZED, 0)+#define JS_FALSE     JS_VALUE_MAKE_SPECIAL(JS_TAG_BOOL, 0)+#define JS_TRUE      JS_VALUE_MAKE_SPECIAL(JS_TAG_BOOL, 1)++#define JS_EX_NORMAL 0 /* all exceptions except not enough memory */+#define JS_EX_CALL   1 /* specific exception to generate a tail call. The call flags are added */+#define JS_EXCEPTION JS_VALUE_MAKE_SPECIAL(JS_TAG_EXCEPTION, JS_EX_NORMAL)++typedef enum {+    JS_CLASS_OBJECT,+    JS_CLASS_ARRAY,+    JS_CLASS_C_FUNCTION,+    JS_CLASS_CLOSURE,+    JS_CLASS_NUMBER,+    JS_CLASS_BOOLEAN,+    JS_CLASS_STRING,+    JS_CLASS_DATE,+    JS_CLASS_REGEXP,++    JS_CLASS_ERROR,+    JS_CLASS_EVAL_ERROR,+    JS_CLASS_RANGE_ERROR,+    JS_CLASS_REFERENCE_ERROR,+    JS_CLASS_SYNTAX_ERROR,+    JS_CLASS_TYPE_ERROR,+    JS_CLASS_URI_ERROR,+    JS_CLASS_INTERNAL_ERROR,++    JS_CLASS_ARRAY_BUFFER,+    JS_CLASS_TYPED_ARRAY,++    JS_CLASS_UINT8C_ARRAY,+    JS_CLASS_INT8_ARRAY,+    JS_CLASS_UINT8_ARRAY,+    JS_CLASS_INT16_ARRAY,+    JS_CLASS_UINT16_ARRAY,+    JS_CLASS_INT32_ARRAY,+    JS_CLASS_UINT32_ARRAY,+    JS_CLASS_FLOAT32_ARRAY,+    JS_CLASS_FLOAT64_ARRAY,++    JS_CLASS_USER, /* user classes start from this value */+} JSObjectClassEnum;++/* predefined functions */+typedef enum {+    JS_CFUNCTION_bound,+    JS_CFUNCTION_USER, /* user functions start from this value */+} JSCFunctionEnum;++/* temporary buffer to hold C strings */+typedef struct {+    uint8_t buf[5]; +} JSCStringBuf;++typedef struct JSGCRef {+    JSValue val;+    struct JSGCRef *prev;+} JSGCRef;++/* stack of JSGCRef */+JSValue *JS_PushGCRef(JSContext *ctx, JSGCRef *ref);+JSValue JS_PopGCRef(JSContext *ctx, JSGCRef *ref);++#define JS_PUSH_VALUE(ctx, v) do { JS_PushGCRef(ctx, &v ## _ref); v ## _ref.val = v; } while (0)+#define JS_POP_VALUE(ctx, v) v = JS_PopGCRef(ctx, &v ## _ref)++/* list of JSGCRef (they can be removed in any order, slower) */+JSValue *JS_AddGCRef(JSContext *ctx, JSGCRef *ref);+void JS_DeleteGCRef(JSContext *ctx, JSGCRef *ref);++JSValue JS_NewFloat64(JSContext *ctx, double d);+JSValue JS_NewInt32(JSContext *ctx, int32_t val);+JSValue JS_NewUint32(JSContext *ctx, uint32_t val);+JSValue JS_NewInt64(JSContext *ctx, int64_t val);++static inline JS_BOOL JS_IsInt(JSValue v)+{+    return (v & 1) == JS_TAG_INT;+}++static inline JS_BOOL JS_IsPtr(JSValue v)+{+    return (v & (JSW - 1)) == JS_TAG_PTR;+}++#ifdef JS_USE_SHORT_FLOAT+static inline JS_BOOL JS_IsShortFloat(JSValue v)+{+    return (v & (JSW - 1)) == JS_TAG_SHORT_FLOAT;+}+#endif++static inline JS_BOOL JS_IsBool(JSValue v)+{+    return JS_VALUE_GET_SPECIAL_TAG(v) == JS_TAG_BOOL;+}++static inline JS_BOOL JS_IsNull(JSValue v)+{+    return v == JS_NULL;+}++static inline JS_BOOL JS_IsUndefined(JSValue v)+{+    return v == JS_UNDEFINED;+}++static inline JS_BOOL JS_IsUninitialized(JSValue v)+{+    return v == JS_UNINITIALIZED;+}++static inline JS_BOOL JS_IsException(JSValue v)+{+    return v == JS_EXCEPTION;+}++static inline JSValue JS_NewBool(int val)+{+    return JS_VALUE_MAKE_SPECIAL(JS_TAG_BOOL, (val != 0));+}++JS_BOOL JS_IsNumber(JSContext *ctx, JSValue val);+JS_BOOL JS_IsString(JSContext *ctx, JSValue val);+JS_BOOL JS_IsError(JSContext *ctx, JSValue val);+JS_BOOL JS_IsFunction(JSContext *ctx, JSValue val);++int JS_GetClassID(JSContext *ctx, JSValue val);+void JS_SetOpaque(JSContext *ctx, JSValue val, void *opaque);+void *JS_GetOpaque(JSContext *ctx, JSValue val);++typedef JSValue JSCFunction(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv);+/* no JS function call be called from a C finalizer */+typedef void (*JSCFinalizer)(JSContext *ctx, void *opaque);++typedef enum JSCFunctionDefEnum {  /* XXX: should rename for namespace isolation */+    JS_CFUNC_generic,+    JS_CFUNC_generic_magic,+    JS_CFUNC_constructor,+    JS_CFUNC_constructor_magic,+    JS_CFUNC_generic_params,+    JS_CFUNC_f_f,+} JSCFunctionDefEnum;++typedef union JSCFunctionType {+    JSCFunction *generic;+    JSValue (*generic_magic)(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv, int magic);+    JSCFunction *constructor;+    JSValue (*constructor_magic)(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv, int magic);+    JSValue (*generic_params)(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv, JSValue params);+    double (*f_f)(double f);+} JSCFunctionType;++typedef struct JSCFunctionDef {+    JSCFunctionType func;+    JSValue name;+    uint8_t def_type;+    uint8_t arg_count;+    int16_t magic;+} JSCFunctionDef;++typedef struct {+    const JSWord *stdlib_table;+    const JSCFunctionDef *c_function_table;+    const JSCFinalizer *c_finalizer_table;+    uint32_t stdlib_table_len;+    uint32_t stdlib_table_align;+    uint32_t sorted_atoms_offset;+    uint32_t global_object_offset;+    uint32_t class_count;+} JSSTDLibraryDef;++typedef void JSWriteFunc(void *opaque, const void *buf, size_t buf_len);+/* return != 0 if the JS code needs to be interrupted */+typedef int JSInterruptHandler(JSContext *ctx, void *opaque);++JSContext *JS_NewContext(void *mem_start, size_t mem_size, const JSSTDLibraryDef *stdlib_def);+/* if prepare_compilation is true, the context will be used to compile+   to a binary file. JS_NewContext2() is not expected to be used in+   the embedded version */+JSContext *JS_NewContext2(void *mem_start, size_t mem_size, const JSSTDLibraryDef *stdlib_def, JS_BOOL prepare_compilation);+void JS_FreeContext(JSContext *ctx);+void JS_SetContextOpaque(JSContext *ctx, void *opaque);+void JS_SetInterruptHandler(JSContext *ctx, JSInterruptHandler *interrupt_handler);+void JS_SetRandomSeed(JSContext *ctx, uint64_t seed);+JSValue JS_GetGlobalObject(JSContext *ctx);+JSValue JS_Throw(JSContext *ctx, JSValue obj);+JSValue __js_printf_like(3, 4) JS_ThrowError(JSContext *ctx, JSObjectClassEnum error_num,+                                           const char *fmt, ...);+#define JS_ThrowTypeError(ctx, fmt, ...) JS_ThrowError(ctx, JS_CLASS_TYPE_ERROR, fmt, ##__VA_ARGS__)+#define JS_ThrowReferenceError(ctx, fmt, ...) JS_ThrowError(ctx, JS_CLASS_REFERENCE_ERROR, fmt, ##__VA_ARGS__)+#define JS_ThrowInternalError(ctx, fmt, ...) JS_ThrowError(ctx, JS_CLASS_INTERNAL_ERROR, fmt, ##__VA_ARGS__)+#define JS_ThrowRangeError(ctx, fmt, ...) JS_ThrowError(ctx, JS_CLASS_RANGE_ERROR, fmt, ##__VA_ARGS__)+#define JS_ThrowSyntaxError(ctx, fmt, ...) JS_ThrowError(ctx, JS_CLASS_SYNTAX_ERROR, fmt, ##__VA_ARGS__)+JSValue JS_ThrowOutOfMemory(JSContext *ctx);+JSValue JS_GetPropertyStr(JSContext *ctx, JSValue this_obj, const char *str);+JSValue JS_GetPropertyUint32(JSContext *ctx, JSValue obj, uint32_t idx);+JSValue JS_SetPropertyStr(JSContext *ctx, JSValue this_obj,+                          const char *str, JSValue val);+JSValue JS_SetPropertyUint32(JSContext *ctx, JSValue this_obj,+                             uint32_t idx, JSValue val);+JSValue JS_NewObjectClassUser(JSContext *ctx, int class_id);+JSValue JS_NewObject(JSContext *ctx);+JSValue JS_NewArray(JSContext *ctx, int initial_len);+/* create a C function with an object parameter (closure) */+JSValue JS_NewCFunctionParams(JSContext *ctx, int func_idx, JSValue params);++#define JS_EVAL_RETVAL    (1 << 0) /* return the last value instead of undefined (slower code) */+#define JS_EVAL_REPL      (1 << 1) /* implicitly defined global variables in assignments */+#define JS_EVAL_STRIP_COL (1 << 2) /* strip column number debug information (save memory) */+#define JS_EVAL_JSON      (1 << 3) /* parse as JSON and return the object */+#define JS_EVAL_REGEXP    (1 << 4) /* internal use */+#define JS_EVAL_REGEXP_FLAGS_SHIFT 8  /* internal use */+JSValue JS_Parse(JSContext *ctx, const char *input, size_t input_len,+                 const char *filename, int eval_flags);+JSValue JS_Run(JSContext *ctx, JSValue val);+JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,+                const char *filename, int eval_flags);+void JS_GC(JSContext *ctx);+JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len);+JSValue JS_NewString(JSContext *ctx, const char *buf);+const char *JS_ToCStringLen(JSContext *ctx, size_t *plen, JSValue val, JSCStringBuf *buf);+const char *JS_ToCString(JSContext *ctx, JSValue val, JSCStringBuf *buf);+JSValue JS_ToString(JSContext *ctx, JSValue val);+int JS_ToInt32(JSContext *ctx, int *pres, JSValue val);+int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValue val);+int JS_ToInt32Sat(JSContext *ctx, int *pres, JSValue val);+int JS_ToNumber(JSContext *ctx, double *pres, JSValue val);++JSValue JS_GetException(JSContext *ctx);+int JS_StackCheck(JSContext *ctx, uint32_t len);+void JS_PushArg(JSContext *ctx, JSValue val);+#define FRAME_CF_CTOR           (1 << 16) /* also ored with argc in+                                             C constructors */+JSValue JS_Call(JSContext *ctx, int call_flags);++#define JS_BYTECODE_MAGIC   0xacfb++typedef struct {+    uint16_t magic; /* JS_BYTECODE_MAGIC */+    uint16_t version;+    uintptr_t base_addr;+    JSValue unique_strings;+    JSValue main_func;+} JSBytecodeHeader;++/* only used on the host when compiling to file */+void JS_PrepareBytecode(JSContext *ctx,+                        JSBytecodeHeader *hdr,+                        const uint8_t **pdata_buf, uint32_t *pdata_len,+                        JSValue eval_code);+/* only used on the host when compiling to file */+int JS_RelocateBytecode2(JSContext *ctx, JSBytecodeHeader *hdr,+                         uint8_t *buf, uint32_t buf_len,+                         uintptr_t new_base_addr, JS_BOOL update_atoms);+#if JSW == 8+typedef struct {+    uint16_t magic; /* JS_BYTECODE_MAGIC */+    uint16_t version;+    uint32_t base_addr;+    uint32_t unique_strings;+    uint32_t main_func;+} JSBytecodeHeader32;++/* only used on the host when compiling to file. A 32 bit bytecode is generated on a 64 bit host. */+int JS_PrepareBytecode64to32(JSContext *ctx,+                             JSBytecodeHeader32 *hdr,+                             const uint8_t **pdata_buf, uint32_t *pdata_len,+                             JSValue eval_code);+#endif++JS_BOOL JS_IsBytecode(const uint8_t *buf, size_t buf_len);+/* Relocate the bytecode in 'buf' so that it can be executed+   later. Return 0 if OK, != 0 if error */+int JS_RelocateBytecode(JSContext *ctx,+                        uint8_t *buf, uint32_t buf_len);+/* Load the precompiled bytecode from 'buf'. 'buf' must be allocated+   as long as the JSContext exists. Use JS_Run() to execute+   it. warning: the bytecode is not checked so it should come from a+   trusted source. */+JSValue JS_LoadBytecode(JSContext *ctx, const uint8_t *buf);++/* debug functions */+void JS_SetLogFunc(JSContext *ctx, JSWriteFunc *write_func);+void JS_PrintValue(JSContext *ctx, JSValue val);+#define JS_DUMP_LONG      (1 << 0) /* display object/array content */+#define JS_DUMP_NOQUOTE   (1 << 1) /* strings: no quote for identifiers */+/* for low level dumps: don't dump special properties and use specific+   quotes to distinguish string chars, unique strings and normal+   strings */+#define JS_DUMP_RAW       (1 << 2)+void JS_PrintValueF(JSContext *ctx, JSValue val, int flags);+void JS_DumpValueF(JSContext *ctx, const char *str,+                   JSValue val, int flags);+void JS_DumpValue(JSContext *ctx, const char *str,+                  JSValue val);+void JS_DumpMemory(JSContext *ctx, JS_BOOL is_long);++#endif /* MQUICKJS_H */
+ mquickjs/mquickjs_atom.h view
@@ -0,0 +1,76 @@+#define JS_ATOM_null 0+#define JS_ATOM_false 2+#define JS_ATOM_true 4+#define JS_ATOM_if 6+#define JS_ATOM_else 8+#define JS_ATOM_return 10+#define JS_ATOM_var 12+#define JS_ATOM_this 14+#define JS_ATOM_delete 16+#define JS_ATOM_void 18+#define JS_ATOM_typeof 20+#define JS_ATOM_new 22+#define JS_ATOM_in 24+#define JS_ATOM_instanceof 26+#define JS_ATOM_do 29+#define JS_ATOM_while 31+#define JS_ATOM_for 33+#define JS_ATOM_break 35+#define JS_ATOM_continue 37+#define JS_ATOM_switch 40+#define JS_ATOM_case 42+#define JS_ATOM_default 44+#define JS_ATOM_throw 46+#define JS_ATOM_try 48+#define JS_ATOM_catch 50+#define JS_ATOM_finally 52+#define JS_ATOM_function 54+#define JS_ATOM_debugger 57+#define JS_ATOM_with 60+#define JS_ATOM_class 62+#define JS_ATOM_const 64+#define JS_ATOM_enum 66+#define JS_ATOM_export 68+#define JS_ATOM_extends 70+#define JS_ATOM_import 72+#define JS_ATOM_super 74+#define JS_ATOM_implements 76+#define JS_ATOM_interface 79+#define JS_ATOM_let 82+#define JS_ATOM_package 84+#define JS_ATOM_private 86+#define JS_ATOM_protected 88+#define JS_ATOM_public 91+#define JS_ATOM_static 93+#define JS_ATOM_yield 95+#define JS_ATOM_empty 97+#define JS_ATOM_toString 99+#define JS_ATOM_valueOf 102+#define JS_ATOM_number 104+#define JS_ATOM_object 106+#define JS_ATOM_undefined 108+#define JS_ATOM_string 111+#define JS_ATOM_boolean 113+#define JS_ATOM__ret_ 115+#define JS_ATOM__eval_ 117+#define JS_ATOM_eval 119+#define JS_ATOM_arguments 121+#define JS_ATOM_value 124+#define JS_ATOM_get 126+#define JS_ATOM_set 128+#define JS_ATOM_prototype 130+#define JS_ATOM_constructor 133+#define JS_ATOM_length 136+#define JS_ATOM_target 138+#define JS_ATOM_of 140+#define JS_ATOM_NaN 142+#define JS_ATOM_Infinity 144+#define JS_ATOM__Infinity 147+#define JS_ATOM_name 150+#define JS_ATOM_Error 152+#define JS_ATOM___proto__ 154+#define JS_ATOM_index 157+#define JS_ATOM_input 159++#define JS_ATOM_END 161+
+ mquickjs/mquickjs_build.h view
@@ -0,0 +1,97 @@+/*+ * Micro QuickJS build utility+ *+ * Copyright (c) 2017-2025 Fabrice Bellard+ * Copyright (c) 2017-2025 Charlie Gordon+ *+ * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ *+ * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+ * THE SOFTWARE.+ */+#ifndef MQUICKJS_BUILD_H+#define MQUICKJS_BUILD_H++#include <stdlib.h>+#include <inttypes.h>++enum {+    JS_DEF_END,+    JS_DEF_CFUNC,+    JS_DEF_CGETSET,+    JS_DEF_PROP_DOUBLE,+    JS_DEF_PROP_UNDEFINED,+    JS_DEF_PROP_STRING,+    JS_DEF_PROP_NULL,+    JS_DEF_CLASS,+};++typedef struct JSClassDef JSClassDef;++typedef struct JSPropDef {+    int def_type;+    const char *name;+    union {+        struct {+            uint8_t length;+            const char *magic;+            const char *cproto_name;+            const char *func_name;+        } func;+        struct {+            const char *magic;+            const char *cproto_name;+            const char *get_func_name;+            const char *set_func_name;+        } getset;+        double f64;+        const JSClassDef *class1;+        const char *str;+    } u;+} JSPropDef;++typedef struct JSClassDef {+    const char *name;+    int length;+    const char *cproto_name;+    const char *func_name;+    const char *class_id;+    const JSPropDef *class_props; /* NULL if none */+    const JSPropDef *proto_props; /* NULL if none */+    const JSClassDef *parent_class; /* NULL if none */+    const char *finalizer_name; /* "NULL" if none */+} JSClassDef;++#define JS_PROP_END { JS_DEF_END }+#define JS_CFUNC_DEF(name, length, func_name) { JS_DEF_CFUNC, name, { .func = { length, "0", "generic", #func_name } } }+#define JS_CFUNC_MAGIC_DEF(name, length, func_name, magic) { JS_DEF_CFUNC, name, { .func = { length, #magic, "generic_magic", #func_name } } }+#define JS_CFUNC_SPECIAL_DEF(name, length, proto, func_name) { JS_DEF_CFUNC, name, { .func = { length, "0", #proto, #func_name } } }+#define JS_CGETSET_DEF(name, get_name, set_name) { JS_DEF_CGETSET, name, { .getset = { "0", "generic", #get_name, #set_name } } }+#define JS_CGETSET_MAGIC_DEF(name, get_name, set_name, magic) { JS_DEF_CGETSET, name, { .getset = { #magic, "generic_magic", #get_name, #set_name } } }+#define JS_PROP_CLASS_DEF(name, cl) { JS_DEF_CLASS, name, { .class1 = cl } }+#define JS_PROP_DOUBLE_DEF(name, val, flags) { JS_DEF_PROP_DOUBLE, name, { .f64 = val } }+#define JS_PROP_UNDEFINED_DEF(name, flags) { JS_DEF_PROP_UNDEFINED, name }+#define JS_PROP_NULL_DEF(name, flags) { JS_DEF_PROP_NULL, name }+#define JS_PROP_STRING_DEF(name, cstr, flags) { JS_DEF_PROP_STRING, name, { .str = cstr } }++#define JS_CLASS_DEF(name, length, func_name, class_id, class_props, proto_props, parent_class, finalizer_name) { name, length, "constructor", #func_name, #class_id, class_props, proto_props, parent_class, #finalizer_name }+#define JS_CLASS_MAGIC_DEF(name, length, func_name, class_id, class_props, proto_props, parent_class, finalizer_name) { name, length, "constructor_magic", #func_name, #class_id, class_props, proto_props, parent_class, #finalizer_name }+#define JS_OBJECT_DEF(name, obj_props) { name, 0, NULL, NULL, NULL, obj_props, NULL, NULL, NULL }++int build_atoms(const char *stdlib_name, const JSPropDef *global_obj,+                const JSPropDef *c_function_decl, int argc, char **argv);++#endif /* MQUICKJS_BUILD_H */
+ mquickjs/mquickjs_opcode.h view
@@ -0,0 +1,264 @@+/*+ * Micro QuickJS opcode definitions+ *+ * Copyright (c) 2017-2025 Fabrice Bellard+ * Copyright (c) 2017-2025 Charlie Gordon+ *+ * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ *+ * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+ * THE SOFTWARE.+ */+#ifdef FMT+FMT(none)+FMT(none_int)+FMT(none_loc)+FMT(none_arg)+FMT(none_var_ref)+FMT(u8)+FMT(i8)+FMT(loc8)+FMT(const8)+FMT(label8)+FMT(u16)+FMT(i16)+FMT(label16)+FMT(npop)+FMT(npopx)+FMT(loc)+FMT(arg)+FMT(var_ref)+FMT(u32)+FMT(i32)+FMT(const16)+FMT(label)+FMT(value)+#undef FMT+#endif /* FMT */++#ifdef DEF++#ifndef def+#define def(id, size, n_pop, n_push, f) DEF(id, size, n_pop, n_push, f)+#endif++DEF(invalid, 1, 0, 0, none) /* never emitted */++/* push values */+DEF(     push_value, 5, 0, 1, value)+DEF(     push_const, 3, 0, 1, const16)+DEF(       fclosure, 3, 0, 1, const16)+DEF(      undefined, 1, 0, 1, none)+DEF(           null, 1, 0, 1, none)+DEF(      push_this, 1, 0, 1, none) /* only used at the start of a function */+DEF(     push_false, 1, 0, 1, none)+DEF(      push_true, 1, 0, 1, none)+DEF(         object, 3, 0, 1, u16)+DEF(      this_func, 1, 0, 1, none)+DEF(      arguments, 1, 0, 1, none)+DEF(     new_target, 1, 0, 1, none)++DEF(           drop, 1, 1, 0, none) /* a -> */+DEF(            nip, 1, 2, 1, none) /* a b -> b */+//DEF(           nip1, 1, 3, 2, none) /* a b c -> b c */+DEF(            dup, 1, 1, 2, none) /* a -> a a */+DEF(           dup1, 1, 2, 3, none) /* a b -> a a b */+DEF(           dup2, 1, 2, 4, none) /* a b -> a b a b */+//DEF(           dup3, 1, 3, 6, none) /* a b c -> a b c a b c */+DEF(        insert2, 1, 2, 3, none) /* obj a -> a obj a (dup_x1) */+DEF(        insert3, 1, 3, 4, none) /* obj prop a -> a obj prop a (dup_x2) */+//DEF(        insert4, 1, 4, 5, none) /* this obj prop a -> a this obj prop a */+DEF(          perm3, 1, 3, 3, none) /* obj a b -> a obj b */+DEF(          perm4, 1, 4, 4, none) /* obj prop a b -> a obj prop b */+//DEF(          perm5, 1, 5, 5, none) /* this obj prop a b -> a this obj prop b */+DEF(           swap, 1, 2, 2, none) /* a b -> b a */+//DEF(          swap2, 1, 4, 4, none) /* a b c d -> c d a b */+DEF(          rot3l, 1, 3, 3, none) /* x a b -> a b x */+//DEF(          rot3r, 1, 3, 3, none) /* a b x -> x a b */+//DEF(          rot4l, 1, 4, 4, none) /* x a b c -> a b c x */+//DEF(          rot5l, 1, 5, 5, none) /* x a b c d -> a b c d x */++DEF(call_constructor, 3, 1, 1, npop) /* func args... -> ret (arguments are not counted in n_pop) */+DEF(           call, 3, 1, 1, npop) /* func args... -> ret (arguments are not counted in n_pop) */+DEF(    call_method, 3, 2, 1, npop) /* this func args.. -> ret (arguments are not counted in n_pop) */+DEF(     array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */+DEF(         return, 1, 1, 0, none)+DEF(   return_undef, 1, 0, 0, none)+DEF(          throw, 1, 1, 0, none)+DEF(         regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a bytecode string */++DEF(      get_field, 3, 1, 1, const16) /* obj -> val */+DEF(     get_field2, 3, 1, 2, const16) /* obj -> obj val */+DEF(      put_field, 3, 2, 0, const16) /* obj val -> */+DEF(   get_array_el, 1, 2, 1, none) /* obj prop -> val */+DEF(  get_array_el2, 1, 2, 2, none) /* obj prop -> obj value */+DEF(   put_array_el, 1, 3, 0, none) /* obj prop val -> */+DEF(     get_length, 1, 1, 1, none) /* obj -> val */+DEF(    get_length2, 1, 1, 2, none) /* obj -> obj val */+DEF(   define_field, 3, 2, 1, const16) /* obj val -> obj */+DEF(   define_getter, 3, 2, 1, const16) /* obj val -> obj */+DEF(   define_setter, 3, 2, 1, const16) /* obj val -> obj */+DEF(      set_proto, 1, 2, 1, none) /* obj proto -> obj */++DEF(        get_loc, 3, 0, 1, loc)+DEF(        put_loc, 3, 1, 0, loc) /* must come after get_loc */+DEF(        get_arg, 3, 0, 1, arg)+DEF(        put_arg, 3, 1, 0, arg) /* must come after get_arg */+DEF(    get_var_ref, 3, 0, 1, var_ref) +DEF(    put_var_ref, 3, 1, 0, var_ref) /* must come after get_var_ref */+DEF(get_var_ref_nocheck, 3, 0, 1, var_ref) +DEF(put_var_ref_nocheck, 3, 1, 0, var_ref)+DEF(       if_false, 5, 1, 0, label)+DEF(        if_true, 5, 1, 0, label) /* must come after if_false */+DEF(           goto, 5, 0, 0, label) /* must come after if_true */+DEF(          catch, 5, 0, 1, label)+DEF(          gosub, 5, 0, 0, label) /* used to execute the finally block */+DEF(            ret, 1, 1, 0, none) /* used to return from the finally block */++DEF(   for_in_start, 1, 1, 1, none) /* obj -> iter */+DEF(   for_of_start, 1, 1, 1, none) /* obj -> iter */+DEF(    for_of_next, 1, 1, 3, none) /* iter -> iter val done */++/* arithmetic/logic operations */+DEF(            neg, 1, 1, 1, none)+DEF(           plus, 1, 1, 1, none)+DEF(            dec, 1, 1, 1, none)+DEF(            inc, 1, 1, 1, none)+DEF(       post_dec, 1, 1, 2, none)+DEF(       post_inc, 1, 1, 2, none)+DEF(            not, 1, 1, 1, none)+DEF(           lnot, 1, 1, 1, none)+DEF(         typeof, 1, 1, 1, none)+DEF(         delete, 1, 2, 1, none) /* obj prop -> ret */++DEF(            mul, 1, 2, 1, none)+DEF(            div, 1, 2, 1, none)+DEF(            mod, 1, 2, 1, none)+DEF(            add, 1, 2, 1, none)+DEF(            sub, 1, 2, 1, none)+DEF(            pow, 1, 2, 1, none)+DEF(            shl, 1, 2, 1, none)+DEF(            sar, 1, 2, 1, none)+DEF(            shr, 1, 2, 1, none)+DEF(             lt, 1, 2, 1, none)+DEF(            lte, 1, 2, 1, none)+DEF(             gt, 1, 2, 1, none)+DEF(            gte, 1, 2, 1, none)+DEF(     instanceof, 1, 2, 1, none)+DEF(             in, 1, 2, 1, none)+DEF(             eq, 1, 2, 1, none)+DEF(            neq, 1, 2, 1, none)+DEF(      strict_eq, 1, 2, 1, none)+DEF(     strict_neq, 1, 2, 1, none)+DEF(            and, 1, 2, 1, none)+DEF(            xor, 1, 2, 1, none)+DEF(             or, 1, 2, 1, none)+/* must be the last non short and non temporary opcode */+DEF(            nop, 1, 0, 0, none) ++DEF(    push_minus1, 1, 0, 1, none_int)+DEF(         push_0, 1, 0, 1, none_int)+DEF(         push_1, 1, 0, 1, none_int)+DEF(         push_2, 1, 0, 1, none_int)+DEF(         push_3, 1, 0, 1, none_int)+DEF(         push_4, 1, 0, 1, none_int)+DEF(         push_5, 1, 0, 1, none_int)+DEF(         push_6, 1, 0, 1, none_int)+DEF(         push_7, 1, 0, 1, none_int)+DEF(        push_i8, 2, 0, 1, i8)+DEF(       push_i16, 3, 0, 1, i16)+DEF(    push_const8, 2, 0, 1, const8)+DEF(      fclosure8, 2, 0, 1, const8) /* must follow push_const8 */+DEF(push_empty_string, 1, 0, 1, none)++DEF(       get_loc8, 2, 0, 1, loc8)+DEF(       put_loc8, 2, 1, 0, loc8) /* must follow get_loc8 */++DEF(       get_loc0, 1, 0, 1, none_loc)+DEF(       get_loc1, 1, 0, 1, none_loc)+DEF(       get_loc2, 1, 0, 1, none_loc)+DEF(       get_loc3, 1, 0, 1, none_loc)+DEF(       put_loc0, 1, 1, 0, none_loc)  /* must follow get_loc */+DEF(       put_loc1, 1, 1, 0, none_loc)+DEF(       put_loc2, 1, 1, 0, none_loc)+DEF(       put_loc3, 1, 1, 0, none_loc)+DEF(       get_arg0, 1, 0, 1, none_arg)+DEF(       get_arg1, 1, 0, 1, none_arg)+DEF(       get_arg2, 1, 0, 1, none_arg)+DEF(       get_arg3, 1, 0, 1, none_arg)+DEF(       put_arg0, 1, 1, 0, none_arg)  /* must follow get_arg */+DEF(       put_arg1, 1, 1, 0, none_arg)+DEF(       put_arg2, 1, 1, 0, none_arg)+DEF(       put_arg3, 1, 1, 0, none_arg)+#if 0+DEF(      if_false8, 2, 1, 0, label8)+DEF(       if_true8, 2, 1, 0, label8) /* must come after if_false8 */+DEF(          goto8, 2, 0, 0, label8) /* must come after if_true8 */+DEF(         goto16, 3, 0, 0, label16)++DEF(          call0, 1, 1, 1, npopx)+DEF(          call1, 1, 1, 1, npopx)+DEF(          call2, 1, 1, 1, npopx)+DEF(          call3, 1, 1, 1, npopx)+#endif++#undef DEF+#undef def+#endif  /* DEF */++#ifdef REDEF++/* regular expression bytecode */+REDEF(invalid, 1) /* never used */+REDEF(char1, 2)+REDEF(char2, 3)+REDEF(char3, 4)+REDEF(char4, 5)+REDEF(dot, 1)+REDEF(any, 1) /* same as dot but match any character including line terminator */+REDEF(space, 1)+REDEF(not_space, 1) /* must come after */+REDEF(line_start, 1)+REDEF(line_start_m, 1)+REDEF(line_end, 1)+REDEF(line_end_m, 1)+REDEF(goto, 5)+REDEF(split_goto_first, 5)+REDEF(split_next_first, 5)+REDEF(match, 1)+REDEF(lookahead_match, 1)+REDEF(negative_lookahead_match, 1) /* must come after */+REDEF(save_start, 2) /* save start position */+REDEF(save_end, 2) /* save end position, must come after saved_start */+REDEF(save_reset, 3) /* reset save positions */+REDEF(loop, 6) /* decrement the top the stack and goto if != 0 */+REDEF(loop_split_goto_first, 10) /* loop and then split */+REDEF(loop_split_next_first, 10)+REDEF(loop_check_adv_split_goto_first, 10) /* loop and then check advance and split */+REDEF(loop_check_adv_split_next_first, 10)+REDEF(set_i32, 6) /* store the immediate value to a register */+REDEF(word_boundary, 1)+REDEF(not_word_boundary, 1)+REDEF(back_reference, 2)+REDEF(back_reference_i, 2)+REDEF(range8, 2) /* variable length */+REDEF(range, 3) /* variable length */+REDEF(lookahead, 5)+REDEF(negative_lookahead, 5) /* must come after */+REDEF(set_char_pos, 2) /* store the character position to a register */+REDEF(check_advance, 2) /* check that the register is different from the character position */++#endif /* REDEF */
+ mquickjs/mquickjs_priv.h view
@@ -0,0 +1,268 @@+/* microj private definitions */+#ifndef MICROJS_PRIV_H+#define MICROJS_PRIV_H++#include "mquickjs.h"+#include "libm.h"++#define JS_DUMP /* 2.6 kB */+//#define DUMP_EXEC+//#define DUMP_FUNC_BYTECODE /* dump the bytecode of each compiled function */+//#define DUMP_REOP /* dump regexp bytecode */+//#define DUMP_GC+//#define DUMP_TOKEN /* dump parsed tokens */+/* run GC before at each malloc() and modify the allocated data pointers */+//#define DEBUG_GC+#if defined(DUMP_FUNC_BYTECODE) || defined(DUMP_EXEC)+#define DUMP_BYTECODE /* include the dump_byte_code() function */+#endif++#define JS_VALUE_TO_PTR(v) (void *)((uintptr_t)(v) - 1)+#define JS_VALUE_FROM_PTR(ptr) (JSWord)((uintptr_t)(ptr) + 1)++#define JS_IS_ROM_PTR(ctx, ptr) ((uintptr_t)(ptr) < (uintptr_t)ctx || (uintptr_t)(ptr) >= (uintptr_t)ctx->stack_top)++enum {+    JS_MTAG_FREE,+    /* javascript values */+    JS_MTAG_OBJECT,+    JS_MTAG_FLOAT64,+    JS_MTAG_STRING,+    /* other special memory blocks */+    JS_MTAG_FUNCTION_BYTECODE,+    JS_MTAG_VALUE_ARRAY,+    JS_MTAG_BYTE_ARRAY,+    JS_MTAG_VARREF,++    JS_MTAG_COUNT,+};++/* JS_MTAG_BITS bits are reserved at the start of every memory block */+#define JS_MTAG_BITS 4++#define JS_MB_HEADER \+    JSWord gc_mark: 1; \+    JSWord mtag: (JS_MTAG_BITS - 1)++typedef enum {+    JS_PROP_NORMAL,+    JS_PROP_GETSET, /* value is a two element JSValueArray */+    JS_PROP_VARREF, /* value is a JSVarRef (used for global variables) */+    JS_PROP_SPECIAL, /* for the prototype and constructor properties in ROM */+} JSPropTypeEnum;++#define JS_MB_HEADER_DEF(tag) ((tag) << 1)+#define JS_VALUE_ARRAY_HEADER(size) (JS_MB_HEADER_DEF(JS_MTAG_VALUE_ARRAY) | ((size) << JS_MTAG_BITS))++#define JS_ROM_VALUE(offset) JS_VALUE_FROM_PTR(&js_stdlib_table[offset])++/* runtime helpers */+JSValue js_function_constructor(JSContext *ctx, JSValue *this_val,+                                int argc, JSValue *argv);+JSValue js_function_get_prototype(JSContext *ctx, JSValue *this_val,+                                  int argc, JSValue *argv);+JSValue js_function_set_prototype(JSContext *ctx, JSValue *this_val,+                                  int argc, JSValue *argv);+JSValue js_function_get_length_name(JSContext *ctx, JSValue *this_val,+                                    int argc, JSValue *argv, int is_name);+JSValue js_function_toString(JSContext *ctx, JSValue *this_val,+                             int argc, JSValue *argv);+JSValue js_function_call(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv);+JSValue js_function_apply(JSContext *ctx, JSValue *this_val,+                          int argc, JSValue *argv);+JSValue js_function_bind(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv);+JSValue js_function_bound(JSContext *ctx, JSValue *this_val,+                          int argc, JSValue *argv, JSValue params);++JSValue js_array_get_length(JSContext *ctx, JSValue *this_val,+                            int argc, JSValue *argv);+JSValue js_array_set_length(JSContext *ctx, JSValue *this_val,+                            int argc, JSValue *argv);++JSValue js_number_constructor(JSContext *ctx, JSValue *this_val,+                              int argc, JSValue *argv);+JSValue js_number_toString(JSContext *ctx, JSValue *this_val,+                           int argc, JSValue *argv);+JSValue js_number_toFixed(JSContext *ctx, JSValue *this_val,+                          int argc, JSValue *argv);+JSValue js_number_toExponential(JSContext *ctx, JSValue *this_val,+                                int argc, JSValue *argv);+JSValue js_number_toPrecision(JSContext *ctx, JSValue *this_val,+                              int argc, JSValue *argv);+JSValue js_number_parseInt(JSContext *ctx, JSValue *this_val,+                           int argc, JSValue *argv);+JSValue js_number_parseFloat(JSContext *ctx, JSValue *this_val,+                             int argc, JSValue *argv);++JSValue js_boolean_constructor(JSContext *ctx, JSValue *this_val,+                               int argc, JSValue *argv);++JSValue js_string_get_length(JSContext *ctx, JSValue *this_val,+                             int argc, JSValue *argv);+JSValue js_string_set_length(JSContext *ctx, JSValue *this_val,+                             int argc, JSValue *argv);+JSValue js_string_slice(JSContext *ctx, JSValue *this_val,+                        int argc, JSValue *argv);+JSValue js_string_substring(JSContext *ctx, JSValue *this_val,+                            int argc, JSValue *argv);+enum {+    magic_internalAt,+    magic_charAt,+    magic_charCodeAt,+    magic_codePointAt,+};+JSValue js_string_charAt(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv, int magic);+JSValue js_string_concat(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv);+JSValue js_string_indexOf(JSContext *ctx, JSValue *this_val,+                          int argc, JSValue *argv, int lastIndexOf);+JSValue js_string_match(JSContext *ctx, JSValue *this_val,+                        int argc, JSValue *argv);+JSValue js_string_replace(JSContext *ctx, JSValue *this_val,+                          int argc, JSValue *argv, int is_replaceAll);+JSValue js_string_search(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv);+JSValue js_string_split(JSContext *ctx, JSValue *this_val,+                        int argc, JSValue *argv);+JSValue js_string_toLowerCase(JSContext *ctx, JSValue *this_val,+                              int argc, JSValue *argv, int to_lower);+JSValue js_string_trim(JSContext *ctx, JSValue *this_val,+                       int argc, JSValue *argv, int magic);+JSValue js_string_toString(JSContext *ctx, JSValue *this_val,+                           int argc, JSValue *argv);+JSValue js_string_repeat(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv);++JSValue js_object_constructor(JSContext *ctx, JSValue *this_val,+                              int argc, JSValue *argv);+JSValue js_object_defineProperty(JSContext *ctx, JSValue *this_val,+                                 int argc, JSValue *argv);+JSValue js_object_getPrototypeOf(JSContext *ctx, JSValue *this_val,+                                 int argc, JSValue *argv);+JSValue js_object_setPrototypeOf(JSContext *ctx, JSValue *this_val,+                                 int argc, JSValue *argv);+JSValue js_object_create(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv);+JSValue js_object_keys(JSContext *ctx, JSValue *this_val,+                       int argc, JSValue *argv);+JSValue js_object_hasOwnProperty(JSContext *ctx, JSValue *this_val,+                                 int argc, JSValue *argv);+JSValue js_object_toString(JSContext *ctx, JSValue *this_val,+                           int argc, JSValue *argv);++JSValue js_string_constructor(JSContext *ctx, JSValue *this_val,+                              int argc, JSValue *argv);+JSValue js_string_fromCharCode(JSContext *ctx, JSValue *this_val,+                               int argc, JSValue *argv, int is_fromCodePoint);++JSValue js_error_constructor(JSContext *ctx, JSValue *this_val,+                             int argc, JSValue *argv, int magic);+JSValue js_error_toString(JSContext *ctx, JSValue *this_val,+                          int argc, JSValue *argv);+JSValue js_error_get_message(JSContext *ctx, JSValue *this_val,+                             int argc, JSValue *argv, int magic);++JSValue js_array_constructor(JSContext *ctx, JSValue *this_val,+                             int argc, JSValue *argv);+JSValue js_array_push(JSContext *ctx, JSValue *this_val,+                      int argc, JSValue *argv, int is_unshift);+JSValue js_array_pop(JSContext *ctx, JSValue *this_val,+                     int argc, JSValue *argv);+JSValue js_array_shift(JSContext *ctx, JSValue *this_val,+                       int argc, JSValue *argv);+JSValue js_array_join(JSContext *ctx, JSValue *this_val,+                      int argc, JSValue *argv);+JSValue js_array_toString(JSContext *ctx, JSValue *this_val,+                          int argc, JSValue *argv);+JSValue js_array_isArray(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv);+JSValue js_array_reverse(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv);+JSValue js_array_concat(JSContext *ctx, JSValue *this_val,+                        int argc, JSValue *argv);+JSValue js_array_indexOf(JSContext *ctx, JSValue *this_val,+                         int argc, JSValue *argv, int is_lastIndexOf);+JSValue js_array_slice(JSContext *ctx, JSValue *this_val,+                       int argc, JSValue *argv);+JSValue js_array_splice(JSContext *ctx, JSValue *this_val,+                        int argc, JSValue *argv);+JSValue js_array_sort(JSContext *ctx, JSValue *this_val,+                      int argc, JSValue *argv);++#define js_special_every    0+#define js_special_some     1+#define js_special_forEach  2+#define js_special_map      3+#define js_special_filter   4++JSValue js_array_every(JSContext *ctx, JSValue *this_val,+                       int argc, JSValue *argv, int special);++#define js_special_reduce       0+#define js_special_reduceRight  1++JSValue js_array_reduce(JSContext *ctx, JSValue *this_val,+                        int argc, JSValue *argv, int special);++JSValue js_math_min_max(JSContext *ctx, JSValue *this_val,+                        int argc, JSValue *argv, int magic);+double js_math_sign(double a);+double js_math_fround(double a);+JSValue js_math_imul(JSContext *ctx, JSValue *this_val,+                     int argc, JSValue *argv);+JSValue js_math_clz32(JSContext *ctx, JSValue *this_val,+                      int argc, JSValue *argv);+JSValue js_math_atan2(JSContext *ctx, JSValue *this_val,+                      int argc, JSValue *argv);+JSValue js_math_pow(JSContext *ctx, JSValue *this_val,+                    int argc, JSValue *argv);+JSValue js_math_random(JSContext *ctx, JSValue *this_val,+                       int argc, JSValue *argv);++JSValue js_array_buffer_constructor(JSContext *ctx, JSValue *this_val,+                                    int argc, JSValue *argv);+JSValue js_array_buffer_get_byteLength(JSContext *ctx, JSValue *this_val,+                                       int argc, JSValue *argv);+JSValue js_typed_array_base_constructor(JSContext *ctx, JSValue *this_val,+                                        int argc, JSValue *argv);+JSValue js_typed_array_constructor(JSContext *ctx, JSValue *this_val,+                                   int argc, JSValue *argv, int magic);+JSValue js_typed_array_get_length(JSContext *ctx, JSValue *this_val,+                                  int argc, JSValue *argv, int magic);+JSValue js_typed_array_subarray(JSContext *ctx, JSValue *this_val,+                                int argc, JSValue *argv);+JSValue js_typed_array_set(JSContext *ctx, JSValue *this_val,+                           int argc, JSValue *argv);++JSValue js_date_constructor(JSContext *ctx, JSValue *this_val,+                            int argc, JSValue *argv);++JSValue js_global_eval(JSContext *ctx, JSValue *this_val,+                       int argc, JSValue *argv);+JSValue js_global_isNaN(JSContext *ctx, JSValue *this_val,+                        int argc, JSValue *argv);+JSValue js_global_isFinite(JSContext *ctx, JSValue *this_val,+                           int argc, JSValue *argv);++JSValue js_json_parse(JSContext *ctx, JSValue *this_val,+                      int argc, JSValue *argv);+JSValue js_json_stringify(JSContext *ctx, JSValue *this_val,+                          int argc, JSValue *argv);++JSValue js_regexp_constructor(JSContext *ctx, JSValue *this_val,+                              int argc, JSValue *argv);+JSValue js_regexp_get_lastIndex(JSContext *ctx, JSValue *this_val,+                                int argc, JSValue *argv);+JSValue js_regexp_set_lastIndex(JSContext *ctx, JSValue *this_val,+                                int argc, JSValue *argv);+JSValue js_regexp_get_source(JSContext *ctx, JSValue *this_val,+                             int argc, JSValue *argv);+JSValue js_regexp_get_flags(JSContext *ctx, JSValue *this_val,+                            int argc, JSValue *argv);+JSValue js_regexp_exec(JSContext *ctx, JSValue *this_val,+                       int argc, JSValue *argv, int is_test);++#endif /* MICROJS_PRIV_H */
+ mquickjs/softfp_template.h view
@@ -0,0 +1,970 @@+/*+ * SoftFP Library+ * + * Copyright (c) 2016 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.+ */+#if F_SIZE == 32+#define F_UINT uint32_t+#define F_ULONG uint64_t+#define MANT_SIZE 23+#define EXP_SIZE 8+#elif F_SIZE == 64+#define F_UHALF uint32_t+#define F_UINT uint64_t+#ifdef HAVE_INT128+#define F_ULONG uint128_t+#endif+#define MANT_SIZE 52+#define EXP_SIZE 11+#elif F_SIZE == 128+#define F_UHALF uint64_t+#define F_UINT uint128_t+#define MANT_SIZE 112+#define EXP_SIZE 15+#else+#error unsupported F_SIZE+#endif++#define EXP_MASK ((1 << EXP_SIZE) - 1)+#define MANT_MASK (((F_UINT)1 << MANT_SIZE) - 1)+#define SIGN_MASK ((F_UINT)1 << (F_SIZE - 1))+#define IMANT_SIZE (F_SIZE - 2) /* internal mantissa size */+#define RND_SIZE (IMANT_SIZE - MANT_SIZE)+#define QNAN_MASK ((F_UINT)1 << (MANT_SIZE - 1))+#define EXP_BIAS ((1 << (EXP_SIZE - 1)) - 1)++/* quiet NaN */+#define F_QNAN glue(F_QNAN, F_SIZE)+#define clz glue(clz, F_SIZE)+#define pack_sf glue(pack_sf, F_SIZE)+#define unpack_sf glue(unpack_sf, F_SIZE)+#define rshift_rnd glue(rshift_rnd, F_SIZE)+#define round_pack_sf glue(roundpack_sf, F_SIZE)+#define normalize_sf glue(normalize_sf, F_SIZE)+#define normalize2_sf glue(normalize2_sf, F_SIZE)+#define issignan_sf glue(issignan_sf, F_SIZE)+#define isnan_sf glue(isnan_sf, F_SIZE)+#define add_sf glue(add_sf, F_SIZE)+#define mul_sf glue(mul_sf, F_SIZE)+#define fma_sf glue(fma_sf, F_SIZE)+#define div_sf glue(div_sf, F_SIZE)+#define sqrt_sf glue(sqrt_sf, F_SIZE)+#define normalize_subnormal_sf glue(normalize_subnormal_sf, F_SIZE)+#define divrem_u glue(divrem_u, F_SIZE)+#define sqrtrem_u glue(sqrtrem_u, F_SIZE)+#define mul_u glue(mul_u, F_SIZE)+#define cvt_sf32_sf glue(cvt_sf32_sf, F_SIZE)+#define cvt_sf64_sf glue(cvt_sf64_sf, F_SIZE)++static const F_UINT F_QNAN = (((F_UINT)EXP_MASK << MANT_SIZE) | ((F_UINT)1 << (MANT_SIZE - 1)));++static inline F_UINT pack_sf(uint32_t a_sign, uint32_t a_exp, F_UINT a_mant)+{+    return ((F_UINT)a_sign << (F_SIZE - 1)) |+        ((F_UINT)a_exp << MANT_SIZE) | +        (a_mant & MANT_MASK);+}++static inline F_UINT unpack_sf(uint32_t *pa_sign, int32_t *pa_exp,+                               F_UINT a)+{+    *pa_sign = a >> (F_SIZE - 1);+    *pa_exp = (a >> MANT_SIZE) & EXP_MASK;+    return a & MANT_MASK;+} ++static F_UINT rshift_rnd(F_UINT a, int d)+{+    F_UINT mask;+    if (d != 0) {+        if (d >= F_SIZE) {+            a = (a != 0);+        } else {+            mask = ((F_UINT)1 << d) - 1;+            a = (a >> d) | ((a & mask) != 0);+        }+    }+    return a;+}++#if F_USE_FFLAGS+#define FFLAGS_PARAM , uint32_t *pfflags+#define FFLAGS_ARG   , pfflags+#else+#define FFLAGS_PARAM+#define FFLAGS_ARG+#endif++/* a_mant is considered to have its MSB at F_SIZE - 2 bits */+static F_UINT round_pack_sf(uint32_t a_sign, int a_exp, F_UINT a_mant,+                            RoundingModeEnum rm FFLAGS_PARAM)+{+    int diff;+    uint32_t addend, rnd_bits;++    switch(rm) {+    case RM_RNE:+    case RM_RMM:+        addend = (1 << (RND_SIZE - 1));+        break;+    case RM_RTZ:+        addend = 0;+        break;+    default:+    case RM_RDN:+    case RM_RUP:+        //        printf("s=%d rm=%d m=%x\n", a_sign, rm, a_mant);+        if (a_sign ^ (rm & 1))+            addend = (1 << RND_SIZE) - 1;+        else+            addend = 0;+        break;+    }++    /* potentially subnormal */+    if (a_exp <= 0) {+        BOOL is_subnormal;+        /* Note: we set the underflow flag if the rounded result+           is subnormal and inexact */+        is_subnormal = (a_exp < 0 || +                        (a_mant + addend) < ((F_UINT)1 << (F_SIZE - 1)));+        diff = 1 - a_exp;+        a_mant = rshift_rnd(a_mant, diff);+        rnd_bits = a_mant & ((1 << RND_SIZE ) - 1);+        if (is_subnormal && rnd_bits != 0) {+#if F_USE_FFLAGS+            *pfflags |= FFLAG_UNDERFLOW;+#endif            +        }+        a_exp = 1;+    } else {+        rnd_bits = a_mant & ((1 << RND_SIZE ) - 1);+    }+#if F_USE_FFLAGS+    if (rnd_bits != 0)+        *pfflags |= FFLAG_INEXACT;+#endif    +    a_mant = (a_mant + addend) >> RND_SIZE;+    /* half way: select even result */+    if (rm == RM_RNE && rnd_bits == (1 << (RND_SIZE - 1)))+        a_mant &= ~1;+    /* Note the rounding adds at least 1, so this is the maximum+       value */+    a_exp += a_mant >> (MANT_SIZE + 1);+    if (a_mant <= MANT_MASK) {+        /* denormalized or zero */+        a_exp = 0;+    } else if (a_exp >= EXP_MASK) {+        /* overflow */+        if (addend == 0) {+            a_exp = EXP_MASK - 1;+            a_mant = MANT_MASK;+        } else {+            /* infinity */+            a_exp = EXP_MASK;+            a_mant = 0;+        }+#if F_USE_FFLAGS+        *pfflags |= FFLAG_OVERFLOW | FFLAG_INEXACT;+#endif+    }+    return pack_sf(a_sign, a_exp, a_mant);+}++/* a_mant is considered to have at most F_SIZE - 1 bits */+static F_UINT normalize_sf(uint32_t a_sign, int a_exp, F_UINT a_mant,+                           RoundingModeEnum rm FFLAGS_PARAM)+{+    int shift;+    shift = clz(a_mant) - (F_SIZE - 1 - IMANT_SIZE);+    assert(shift >= 0);+    a_exp -= shift;+    a_mant <<= shift;+    return round_pack_sf(a_sign, a_exp, a_mant, rm FFLAGS_ARG);+}++static inline F_UINT normalize_subnormal_sf(int32_t *pa_exp, F_UINT a_mant)+{+    int shift;+    shift = MANT_SIZE - ((F_SIZE - 1 - clz(a_mant)));+    *pa_exp = 1 - shift;+    return a_mant << shift;+}++#if F_USE_FFLAGS+F_STATIC BOOL issignan_sf(F_UINT a)+{+    uint32_t a_exp1;+    F_UINT a_mant;+    a_exp1 = (a >> (MANT_SIZE - 1)) & ((1 << (EXP_SIZE + 1)) - 1);+    a_mant = a & MANT_MASK;+    return (a_exp1 == (2 * EXP_MASK) && a_mant != 0);+}+#endif++#ifndef F_NORMALIZE_ONLY++F_STATIC BOOL isnan_sf(F_UINT a)+{+    uint32_t a_exp;+    F_UINT a_mant;+    a_exp = (a >> MANT_SIZE) & EXP_MASK;+    a_mant = a & MANT_MASK;+    return (a_exp == EXP_MASK && a_mant != 0);+}+++F_STATIC F_UINT add_sf(F_UINT a, F_UINT b, RoundingModeEnum rm FFLAGS_PARAM)+{+    uint32_t a_sign, b_sign, a_exp, b_exp;+    F_UINT tmp, a_mant, b_mant;++    /* swap so that  abs(a) >= abs(b) */+    if ((a & ~SIGN_MASK) < (b & ~SIGN_MASK)) {+        tmp = a;+        a = b;+        b = tmp;+    }+    a_sign = a >> (F_SIZE - 1);+    b_sign = b >> (F_SIZE - 1);+    a_exp = (a >> MANT_SIZE) & EXP_MASK;+    b_exp = (b >> MANT_SIZE) & EXP_MASK;+    a_mant = (a & MANT_MASK) << 3;+    b_mant = (b & MANT_MASK) << 3;+    if (unlikely(a_exp == EXP_MASK)) {+        if (a_mant != 0) {+            /* NaN result */+#if F_USE_FFLAGS+            if (!(a_mant & (QNAN_MASK << 3)) || issignan_sf(b))+                *pfflags |= FFLAG_INVALID_OP;+#endif+            return F_QNAN;+        } else if (b_exp == EXP_MASK && a_sign != b_sign) {+#if F_USE_FFLAGS+            *pfflags |= FFLAG_INVALID_OP;+#endif+            return F_QNAN;+        } else {+            /* infinity */+            return a;+        }+    }+    if (a_exp == 0) {+        a_exp = 1;+    } else {+        a_mant |= (F_UINT)1 << (MANT_SIZE + 3);+    }+    if (b_exp == 0) {+        b_exp = 1;+    } else {+        b_mant |= (F_UINT)1 << (MANT_SIZE + 3);+    }+    b_mant = rshift_rnd(b_mant, a_exp - b_exp);+    if (a_sign == b_sign) {+        /* same signs : add the absolute values  */+        a_mant += b_mant;+    } else {+        /* different signs : subtract the absolute values  */+        a_mant -= b_mant;+        if (a_mant == 0) {+            /* zero result : the sign needs a specific handling */+            a_sign = (rm == RM_RDN);+        }+    }+    a_exp += (RND_SIZE - 3);+    return normalize_sf(a_sign, a_exp, a_mant, rm FFLAGS_ARG);+}++F_STATIC F_UINT glue(sub_sf, F_SIZE)(F_UINT a, F_UINT b, RoundingModeEnum rm FFLAGS_PARAM)+{+    return add_sf(a, b ^ SIGN_MASK, rm FFLAGS_ARG);+}++#ifdef F_ULONG++static F_UINT mul_u(F_UINT *plow, F_UINT a, F_UINT b)+{+    F_ULONG r;+    r = (F_ULONG)a * (F_ULONG)b;+    *plow = r;+    return r >> F_SIZE;+}++#else++#define FH_SIZE (F_SIZE / 2)++static F_UINT mul_u(F_UINT *plow, F_UINT a, F_UINT b)+{+    F_UHALF a0, a1, b0, b1, r0, r1, r2, r3;+    F_UINT r00, r01, r10, r11, c;+    a0 = a;+    a1 = a >> FH_SIZE;+    b0 = b;+    b1 = b >> FH_SIZE;++    r00 = (F_UINT)a0 * (F_UINT)b0;+    r01 = (F_UINT)a0 * (F_UINT)b1;+    r10 = (F_UINT)a1 * (F_UINT)b0;+    r11 = (F_UINT)a1 * (F_UINT)b1;+    +    r0 = r00;+    c = (r00 >> FH_SIZE) + (F_UHALF)r01 + (F_UHALF)r10;+    r1 = c;+    c = (c >> FH_SIZE) + (r01 >> FH_SIZE) + (r10 >> FH_SIZE) + (F_UHALF)r11;+    r2 = c;+    r3 = (c >> FH_SIZE) + (r11 >> FH_SIZE);++    *plow = ((F_UINT)r1 << FH_SIZE) | r0;+    return ((F_UINT)r3 << FH_SIZE) | r2;+}++#undef FH_SIZE++#endif++F_STATIC F_UINT mul_sf(F_UINT a, F_UINT b, RoundingModeEnum rm FFLAGS_PARAM)+{+    uint32_t a_sign, b_sign, r_sign;+    int32_t a_exp, b_exp, r_exp;+    F_UINT a_mant, b_mant, r_mant, r_mant_low;++    a_sign = a >> (F_SIZE - 1);+    b_sign = b >> (F_SIZE - 1);+    r_sign = a_sign ^ b_sign;+    a_exp = (a >> MANT_SIZE) & EXP_MASK;+    b_exp = (b >> MANT_SIZE) & EXP_MASK;+    a_mant = a & MANT_MASK;+    b_mant = b & MANT_MASK;+    if (a_exp == EXP_MASK || b_exp == EXP_MASK) {+        if (isnan_sf(a) || isnan_sf(b)) {+#if F_USE_FFLAGS+            if (issignan_sf(a) || issignan_sf(b)) {+                *pfflags |= FFLAG_INVALID_OP;+            }+#endif                +            return F_QNAN;+        } else {+            /* infinity */+            if ((a_exp == EXP_MASK && (b_exp == 0 && b_mant == 0)) ||+                (b_exp == EXP_MASK && (a_exp == 0 && a_mant == 0))) {+#if F_USE_FFLAGS+                *pfflags |= FFLAG_INVALID_OP;+#endif                +                return F_QNAN;+            } else {+                return pack_sf(r_sign, EXP_MASK, 0);+            }+        }+    }+    if (a_exp == 0) {+        if (a_mant == 0)+            return pack_sf(r_sign, 0, 0); /* zero */+        a_mant = normalize_subnormal_sf(&a_exp, a_mant);+    } else {+        a_mant |= (F_UINT)1 << MANT_SIZE;+    }+    if (b_exp == 0) {+        if (b_mant == 0)+            return pack_sf(r_sign, 0, 0); /* zero */+        b_mant = normalize_subnormal_sf(&b_exp, b_mant);+    } else {+        b_mant |= (F_UINT)1 << MANT_SIZE;+    }+    r_exp = a_exp + b_exp - (1 << (EXP_SIZE - 1)) + 2;+    +    r_mant = mul_u(&r_mant_low,a_mant << RND_SIZE, b_mant << (RND_SIZE + 1));+    r_mant |= (r_mant_low != 0);+    return normalize_sf(r_sign, r_exp, r_mant, rm FFLAGS_ARG);+}++#ifdef F_ULONG++static F_UINT divrem_u(F_UINT *pr, F_UINT ah, F_UINT al, F_UINT b)+{+    F_ULONG a;+    a = ((F_ULONG)ah << F_SIZE) | al;+    *pr = a % b;+    return a / b;+}++#else++/* XXX: optimize */+static F_UINT divrem_u(F_UINT *pr, F_UINT a1, F_UINT a0, F_UINT b)+{+    int i, qb, ab;++    assert(a1 < b);+    for(i = 0; i < F_SIZE; i++) {+        ab = a1 >> (F_SIZE - 1);+        a1 = (a1 << 1) | (a0 >> (F_SIZE - 1));+        if (ab || a1 >= b) {+            a1 -= b;+            qb = 1;+        } else {+            qb = 0;+        }+        a0 = (a0 << 1) | qb;+    }+    *pr = a1;+    return a0;+}++#endif++F_STATIC F_UINT div_sf(F_UINT a, F_UINT b, RoundingModeEnum rm FFLAGS_PARAM)+{+    uint32_t a_sign, b_sign, r_sign;+    int32_t a_exp, b_exp, r_exp;+    F_UINT a_mant, b_mant, r_mant, r;++    a_sign = a >> (F_SIZE - 1);+    b_sign = b >> (F_SIZE - 1);+    r_sign = a_sign ^ b_sign;+    a_exp = (a >> MANT_SIZE) & EXP_MASK;+    b_exp = (b >> MANT_SIZE) & EXP_MASK;+    a_mant = a & MANT_MASK;+    b_mant = b & MANT_MASK;+    if (a_exp == EXP_MASK) {+        if (a_mant != 0 || isnan_sf(b)) {+#if F_USE_FFLAGS+            if (issignan_sf(a) || issignan_sf(b)) {+                *pfflags |= FFLAG_INVALID_OP;+            }+#endif            +            return F_QNAN;+        } else if (b_exp == EXP_MASK) {+#if F_USE_FFLAGS+            *pfflags |= FFLAG_INVALID_OP;+#endif            +            return F_QNAN;+        } else {+            return pack_sf(r_sign, EXP_MASK, 0);+        }+    } else if (b_exp == EXP_MASK) {+        if (b_mant != 0) {+#if F_USE_FFLAGS+            if (issignan_sf(a) || issignan_sf(b)) {+                *pfflags |= FFLAG_INVALID_OP;+            }+#endif            +            return F_QNAN;+        } else {+            return pack_sf(r_sign, 0, 0);+        }+    }++    if (b_exp == 0) {+        if (b_mant == 0) { +            /* zero */+            if (a_exp == 0 && a_mant == 0) {+#if F_USE_FFLAGS+                *pfflags |= FFLAG_INVALID_OP;+#endif                +                return F_QNAN;+            } else {+#if F_USE_FFLAGS+                *pfflags |= FFLAG_DIVIDE_ZERO;+#endif                +                return pack_sf(r_sign, EXP_MASK, 0);+            }+        }+        b_mant = normalize_subnormal_sf(&b_exp, b_mant);+    } else {+        b_mant |= (F_UINT)1 << MANT_SIZE;+    }+    if (a_exp == 0) {+        if (a_mant == 0)+            return pack_sf(r_sign, 0, 0); /* zero */+        a_mant = normalize_subnormal_sf(&a_exp, a_mant);+    } else {+        a_mant |= (F_UINT)1 << MANT_SIZE;+    }+    r_exp = a_exp - b_exp + (1 << (EXP_SIZE - 1)) - 1;+    r_mant = divrem_u(&r, a_mant, 0, b_mant << 2);+    if (r != 0)+        r_mant |= 1;+    return normalize_sf(r_sign, r_exp, r_mant, rm FFLAGS_ARG);+}++#ifdef F_ULONG++/* compute sqrt(a) with a = ah*2^F_SIZE+al and a < 2^(F_SIZE - 2)+   return true if not exact square. */+static int sqrtrem_u(F_UINT *pr, F_UINT ah, F_UINT al)+{+    F_ULONG a, u, s;+    int l, inexact;++    /* 2^l >= a */+    if (ah != 0) {+        l = 2 * F_SIZE - clz(ah - 1);+    } else {+        if (al == 0) {+            *pr = 0;+            return 0;+        }+        l = F_SIZE - clz(al - 1);+    }+    a = ((F_ULONG)ah << F_SIZE) | al;+    u = (F_ULONG)1 << ((l + 1) / 2);+    for(;;) {+        s = u;+        u = ((a / s) + s) / 2;+        if (u >= s)+            break;+    }+    inexact = (a - s * s) != 0;+    *pr = s;+    return inexact;+}++#else++static int sqrtrem_u(F_UINT *pr, F_UINT a1, F_UINT a0)+{+    int l, inexact;+    F_UINT u, s, r, q, sq0, sq1;++    /* 2^l >= a */+    if (a1 != 0) {+        l = 2 * F_SIZE - clz(a1 - 1);+    } else {+        if (a0 == 0) {+            *pr = 0;+            return 0;+        }+        l = F_SIZE - clz(a0 - 1);+    }+    u = (F_UINT)1 << ((l + 1) / 2);+    for(;;) {+        s = u;+        q = divrem_u(&r, a1, a0, s);+        u = (q + s) / 2;+        if (u >= s)+            break;+    }+    sq1 = mul_u(&sq0, s, s);+    inexact = (sq0 != a0 || sq1 != a1);+    *pr = s;+    return inexact;+}++#endif++F_STATIC F_UINT sqrt_sf(F_UINT a, RoundingModeEnum rm FFLAGS_PARAM)+{+    uint32_t a_sign;+    int32_t a_exp;+    F_UINT a_mant;++    a_sign = a >> (F_SIZE - 1);+    a_exp = (a >> MANT_SIZE) & EXP_MASK;+    a_mant = a & MANT_MASK;+    if (a_exp == EXP_MASK) {+        if (a_mant != 0) {+#if F_USE_FFLAGS+            if (issignan_sf(a)) {+                *pfflags |= FFLAG_INVALID_OP;+            }+#endif            +            return F_QNAN;+        } else if (a_sign) {+            goto neg_error;+        } else {+            return a; /* +infinity */+        }+    }+    if (a_sign) {+        if (a_exp == 0 && a_mant == 0)+            return a; /* -zero */+    neg_error:+#if F_USE_FFLAGS+        *pfflags |= FFLAG_INVALID_OP;+#endif        +        return F_QNAN;+    }+    if (a_exp == 0) {+        if (a_mant == 0)+            return pack_sf(0, 0, 0); /* zero */+        a_mant = normalize_subnormal_sf(&a_exp, a_mant);+    } else {+        a_mant |= (F_UINT)1 << MANT_SIZE;+    }+    a_exp -= EXP_MASK / 2;+    /* simpler to handle an even exponent */+    if (a_exp & 1) {+        a_exp--;+        a_mant <<= 1;+    }+    a_exp = (a_exp >> 1) + EXP_MASK / 2;+    a_mant <<= (F_SIZE - 4 - MANT_SIZE);+    if (sqrtrem_u(&a_mant, a_mant, 0))+        a_mant |= 1;+    return normalize_sf(a_sign, a_exp, a_mant, rm FFLAGS_ARG);+}++/* comparisons */++F_STATIC int glue(eq_quiet_sf, F_SIZE)(F_UINT a, F_UINT b FFLAGS_PARAM)+{+    if (isnan_sf(a) || isnan_sf(b)) {+#if F_USE_FFLAGS+        if (issignan_sf(a) || issignan_sf(b)) {+            *pfflags |= FFLAG_INVALID_OP;+        }+#endif        +        return 0;+    }++    if ((F_UINT)((a | b) << 1) == 0)+        return 1; /* zero case */+    return (a == b);+}++F_STATIC int glue(le_sf, F_SIZE)(F_UINT a, F_UINT b FFLAGS_PARAM)+{+    uint32_t a_sign, b_sign;++    if (isnan_sf(a) || isnan_sf(b)) {+#if F_USE_FFLAGS+        *pfflags |= FFLAG_INVALID_OP;+#endif        +        return 0;+    }++    a_sign = a >> (F_SIZE - 1);+    b_sign = b >> (F_SIZE - 1);+    if (a_sign != b_sign) {+        return (a_sign || ((F_UINT)((a | b) << 1) == 0));+    } else {+        if (a_sign) {+            return (a >= b);+        } else {+            return (a <= b);+        }+    }+}++F_STATIC int glue(lt_sf, F_SIZE)(F_UINT a, F_UINT b FFLAGS_PARAM)+{+    uint32_t a_sign, b_sign;++    if (isnan_sf(a) || isnan_sf(b)) {+#if F_USE_FFLAGS+        *pfflags |= FFLAG_INVALID_OP;+#endif        +        return 0;+    }++    a_sign = a >> (F_SIZE - 1);+    b_sign = b >> (F_SIZE - 1);+    if (a_sign != b_sign) {+        return (a_sign && ((F_UINT)((a | b) << 1) != 0));+    } else {+        if (a_sign) {+            return (a > b);+        } else {+            return (a < b);+        }+    }+}++/* return -1 (a < b), 0 (a = b), 1 (a > b) or 2 (a = nan or b =+   nan) */+F_STATIC int glue(cmp_sf, F_SIZE)(F_UINT a, F_UINT b FFLAGS_PARAM)+{+    uint32_t a_sign, b_sign;++    if (isnan_sf(a) || isnan_sf(b)) {+#if F_USE_FFLAGS+        *pfflags |= FFLAG_INVALID_OP;+#endif        +        return 2;+    }++    a_sign = a >> (F_SIZE - 1);+    b_sign = b >> (F_SIZE - 1);+    if (a_sign != b_sign) {+        if ((F_UINT)((a | b) << 1) != 0)+            return 1 - 2 * a_sign;+        else+            return 0; /* -0 = +0 */+    } else {+        if (a < b)+            return 2 * a_sign - 1;+        else if (a > b)+            return 1 - 2 * a_sign;+        else+            return 0;+    }+}++/* conversions between floats */++#if F_SIZE >= 64++F_STATIC F_UINT cvt_sf32_sf(uint32_t a FFLAGS_PARAM)+{+    uint32_t a_sign;+    int32_t a_exp;+    F_UINT a_mant;++    a_mant = unpack_sf32(&a_sign, &a_exp, a);+    if (a_exp == 0xff) {+        if (a_mant != 0) {+            /* NaN */+#if F_USE_FFLAGS+            if (issignan_sf32(a)) {+                *pfflags |= FFLAG_INVALID_OP;+            }+#endif            +            return F_QNAN;+        } else {+            /* infinity */+            return pack_sf(a_sign, EXP_MASK, 0);+        }+    }+    if (a_exp == 0) {+        if (a_mant == 0)+            return pack_sf(a_sign, 0, 0); /* zero */+        a_mant = normalize_subnormal_sf32(&a_exp, a_mant);+    }+    /* convert the exponent value */+    a_exp = a_exp - 0x7f + (EXP_MASK / 2);+    /* shift the mantissa */+    a_mant <<= (MANT_SIZE - 23);+    /* We assume the target float is large enough to that no+       normalization is necessary */+    return pack_sf(a_sign, a_exp, a_mant);+}++F_STATIC uint32_t glue(glue(cvt_sf, F_SIZE), _sf32)(F_UINT a, RoundingModeEnum rm FFLAGS_PARAM)+{+    uint32_t a_sign;+    int32_t a_exp;+    F_UINT a_mant;++    a_mant = unpack_sf(&a_sign, &a_exp, a);+    if (a_exp == EXP_MASK) {+        if (a_mant != 0) {+            /* NaN */+#if F_USE_FFLAGS+            if (issignan_sf(a)) {+                *pfflags |= FFLAG_INVALID_OP;+            }+#endif            +            return F_QNAN32;+        } else {+            /* infinity */+            return pack_sf32(a_sign, 0xff, 0);+        }+    }+    if (a_exp == 0) {+        if (a_mant == 0)+            return pack_sf32(a_sign, 0, 0); /* zero */+        normalize_subnormal_sf(&a_exp, a_mant);+    } else {+        a_mant |= (F_UINT)1 << MANT_SIZE;+    }+    /* convert the exponent value */+    a_exp = a_exp - (EXP_MASK / 2) + 0x7f;+    /* shift the mantissa */+    a_mant = rshift_rnd(a_mant, MANT_SIZE - (32 - 2));+    return normalize_sf32(a_sign, a_exp, a_mant, rm FFLAGS_ARG);+}++#endif++#if F_SIZE >= 128++F_STATIC F_UINT cvt_sf64_sf(uint64_t a FFLAGS_PARAM)+{+    uint32_t a_sign;+    int32_t a_exp;+    F_UINT a_mant;++    a_mant = unpack_sf64(&a_sign, &a_exp, a);++    if (a_exp == 0x7ff) {+        if (a_mant != 0) {+            /* NaN */+#if F_USE_FFLAGS+            if (issignan_sf64(a)) {+                *pfflags |= FFLAG_INVALID_OP;+            }+#endif+            return F_QNAN;+        } else {+            /* infinity */+            return pack_sf(a_sign, EXP_MASK, 0);+        }+    }+    if (a_exp == 0) {+        if (a_mant == 0)+            return pack_sf(a_sign, 0, 0); /* zero */+        a_mant = normalize_subnormal_sf64(&a_exp, a_mant);+    }+    /* convert the exponent value */+    a_exp = a_exp - 0x3ff + (EXP_MASK / 2);+    /* shift the mantissa */+    a_mant <<= (MANT_SIZE - 52);+    return pack_sf(a_sign, a_exp, a_mant);+}++F_STATIC uint64_t glue(glue(cvt_sf, F_SIZE), _sf64)(F_UINT a, RoundingModeEnum rm FFLAGS_PARAM)+{+    uint32_t a_sign;+    int32_t a_exp;+    F_UINT a_mant;++    a_mant = unpack_sf(&a_sign, &a_exp, a);+    if (a_exp == EXP_MASK) {+        if (a_mant != 0) {+            /* NaN */+#if F_USE_FFLAGS+            if (issignan_sf(a)) {+                *pfflags |= FFLAG_INVALID_OP;+            }+#endif            +            return F_QNAN64;+        } else {+            /* infinity */+            return pack_sf64(a_sign, 0x7ff, 0);+        }+    }+    if (a_exp == 0) {+        if (a_mant == 0)+            return pack_sf64(a_sign, 0, 0); /* zero */+        normalize_subnormal_sf(&a_exp, a_mant);+    } else {+        a_mant |= (F_UINT)1 << MANT_SIZE;+    }+    /* convert the exponent value */+    a_exp = a_exp - (EXP_MASK / 2) + 0x3ff;+    /* shift the mantissa */+    a_mant = rshift_rnd(a_mant, MANT_SIZE - (64 - 2));+    return normalize_sf64(a_sign, a_exp, a_mant, rm, pfflags);+}++#endif++#undef clz++#define ICVT_SIZE 32+#include "softfp_template_icvt.h"++#define ICVT_SIZE 64+#include "softfp_template_icvt.h"++/* additional libm functions */++/* return a mod b (exact) */+F_STATIC F_UINT glue(fmod_sf, F_SIZE)(F_UINT a, F_UINT b FFLAGS_PARAM)+{+    uint32_t a_sign;+    int32_t a_exp, b_exp, n;+    F_UINT a_mant, b_mant, a_abs, b_abs;+    +    a_abs = a & ~SIGN_MASK;+    b_abs = b & ~SIGN_MASK;+    if (b_abs == 0 ||+        a_abs >= ((F_UINT)EXP_MASK << MANT_SIZE) ||+        b_abs > ((F_UINT)EXP_MASK << MANT_SIZE)) {+        /* XXX: flags */+        return F_QNAN;+    }+    if (a_abs < b_abs) {+        return a; /* |a| < |b| return a */+    } else if (a_abs == b_abs) {+        return a & SIGN_MASK; /* |a| = |b| return copy_sign(0, a) */+    }+    +    a_sign = a >> (F_SIZE - 1);+    a_exp = (a >> MANT_SIZE) & EXP_MASK;+    b_exp = (b >> MANT_SIZE) & EXP_MASK;+    a_mant = (a & MANT_MASK);+    b_mant = (b & MANT_MASK);++    if (a_exp == 0) {+        a_mant = normalize_subnormal_sf(&a_exp, a_mant);+    } else {+        a_mant |= (F_UINT)1 << MANT_SIZE;+    }+    if (b_exp == 0) {+        b_mant = normalize_subnormal_sf(&b_exp, b_mant);+    } else {+        b_mant |= (F_UINT)1 << MANT_SIZE;+    }+    n = a_exp - b_exp;+    if (a_mant >= b_mant)+        a_mant -= b_mant;+    /* here a_mant < b_mant and n >= 0 */+    /* multiply a_mant by 2^n */+    /* XXX: do it faster */+    while (n != 0) {+        a_mant <<= 1;+        if (a_mant >= b_mant)+            a_mant -= b_mant;+        n--;+    }+    /* Note: the rounding mode does not matter because the result is+       exact */+    return normalize_sf(a_sign, b_exp, a_mant << RND_SIZE, RM_RNE FFLAGS_ARG);+}+#endif /* F_NORMALIZE_ONLY */++#undef F_SIZE+#undef F_UINT+#undef F_ULONG+#undef F_UHALF+#undef MANT_SIZE+#undef EXP_SIZE+#undef EXP_MASK+#undef MANT_MASK+#undef SIGN_MASK+#undef IMANT_SIZE+#undef RND_SIZE+#undef QNAN_MASK+#undef F_QNAN+#undef F_NORMALIZE_ONLY+#undef EXP_BIAS++#undef pack_sf+#undef unpack_sf+#undef rshift_rnd+#undef round_pack_sf+#undef normalize_sf+#undef normalize2_sf+#undef issignan_sf+#undef isnan_sf+#undef add_sf+#undef mul_sf+#undef fma_sf+#undef div_sf+#undef sqrt_sf+#undef normalize_subnormal_sf+#undef divrem_u+#undef sqrtrem_u+#undef mul_u+#undef cvt_sf32_sf+#undef cvt_sf64_sf
+ mquickjs/softfp_template_icvt.h view
@@ -0,0 +1,172 @@+/*+ * SoftFP Library+ * + * Copyright (c) 2016 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.+ */+#if ICVT_SIZE == 32+#define ICVT_UINT uint32_t+#define ICVT_INT int32_t+#elif ICVT_SIZE == 64+#define ICVT_UINT uint64_t+#define ICVT_INT int64_t+#elif ICVT_SIZE == 128+#define ICVT_UINT uint128_t+#define ICVT_INT int128_t+#else+#error unsupported icvt+#endif++/* conversions between float and integers */+static ICVT_INT glue(glue(glue(internal_cvt_sf, F_SIZE), _i), ICVT_SIZE)(F_UINT a, RoundingModeEnum rm,+                                                                         BOOL is_unsigned FFLAGS_PARAM)+{+    uint32_t a_sign, addend, rnd_bits;+    int32_t a_exp;+    F_UINT a_mant;+    ICVT_UINT r, r_max;++    a_sign = a >> (F_SIZE - 1);+    a_exp = (a >> MANT_SIZE) & EXP_MASK;+    a_mant = a & MANT_MASK;+    if (a_exp == EXP_MASK && a_mant != 0)+        a_sign = 0; /* NaN is like +infinity */+    if (a_exp == 0) {+        a_exp = 1;+    } else {+        a_mant |= (F_UINT)1 << MANT_SIZE;+    }+    a_mant <<= RND_SIZE;+    a_exp = a_exp - (EXP_MASK / 2) - MANT_SIZE;++    if (is_unsigned)+        r_max = (ICVT_UINT)a_sign - 1;+    else+        r_max = ((ICVT_UINT)1 << (ICVT_SIZE - 1)) - (ICVT_UINT)(a_sign ^ 1);+    if (a_exp >= 0) {+        if (a_exp <= (ICVT_SIZE - 1 - MANT_SIZE)) {+            r = (ICVT_UINT)(a_mant >> RND_SIZE) << a_exp;+            if (r > r_max)+                goto overflow;+        } else {+        overflow:+#if F_USE_FFLAGS+            *pfflags |= FFLAG_INVALID_OP;+#endif            +            return r_max;+        }+    } else {+        a_mant = rshift_rnd(a_mant, -a_exp);++        switch(rm) {+        case RM_RNE:+        case RM_RMM:+            addend = (1 << (RND_SIZE - 1));+            break;+        case RM_RTZ:+            addend = 0;+            break;+        default:+        case RM_RDN:+        case RM_RUP:+            if (a_sign ^ (rm & 1))+                addend = (1 << RND_SIZE) - 1;+            else+                addend = 0;+            break;+        }+        +        rnd_bits = a_mant & ((1 << RND_SIZE ) - 1);+        a_mant = (a_mant + addend) >> RND_SIZE;+        /* half way: select even result */+        if (rm == RM_RNE && rnd_bits == (1 << (RND_SIZE - 1)))+            a_mant &= ~1;+        if (a_mant > r_max)+            goto overflow;+        r = a_mant;+#if F_USE_FFLAGS+        if (rnd_bits != 0)+            *pfflags |= FFLAG_INEXACT;+#endif        +    }+    if (a_sign)+        r = -r;+    return r;+}++F_STATIC ICVT_INT __maybe_unused glue(glue(glue(cvt_sf, F_SIZE), _i), ICVT_SIZE)(F_UINT a, RoundingModeEnum rm FFLAGS_PARAM)+{+    return glue(glue(glue(internal_cvt_sf, F_SIZE), _i), ICVT_SIZE)(a, rm, +                                                                    FALSE FFLAGS_ARG);+}++F_STATIC ICVT_UINT __maybe_unused glue(glue(glue(cvt_sf, F_SIZE), _u), ICVT_SIZE)(F_UINT a, RoundingModeEnum rm FFLAGS_PARAM)+{+    return glue(glue(glue(internal_cvt_sf, F_SIZE), _i), ICVT_SIZE) (a, rm, +                                                                     TRUE FFLAGS_ARG);+}++/* conversions between float and integers */+static F_UINT glue(glue(glue(internal_cvt_i, ICVT_SIZE), _sf), F_SIZE)(ICVT_INT a, +                                                                       RoundingModeEnum rm,+                                                                       BOOL is_unsigned FFLAGS_PARAM)+{+    uint32_t a_sign;+    int32_t a_exp;+    F_UINT a_mant;+    ICVT_UINT r, mask;+    int l;++    if (!is_unsigned && a < 0) {+        a_sign = 1;+        r = -(ICVT_UINT)a;+    } else {+        a_sign = 0;+        r = a;+    }+    a_exp = (EXP_MASK / 2) + F_SIZE - 2;+    /* need to reduce range before generic float normalization */+    l = ICVT_SIZE - glue(clz, ICVT_SIZE)(r) - (F_SIZE - 1);+    if (l > 0) {+        mask = r & (((ICVT_UINT)1 << l) - 1);+        r = (r >> l) | ((r & mask) != 0);+        a_exp += l;+    }+    a_mant = r;+    return normalize_sf(a_sign, a_exp, a_mant, rm FFLAGS_ARG);+}++F_STATIC F_UINT __maybe_unused glue(glue(glue(cvt_i, ICVT_SIZE), _sf), F_SIZE)(ICVT_INT a, +                                                       RoundingModeEnum rm+                                                       FFLAGS_PARAM)+{+    return glue(glue(glue(internal_cvt_i, ICVT_SIZE), _sf), F_SIZE)(a, rm, FALSE FFLAGS_ARG);+}++F_STATIC F_UINT __maybe_unused glue(glue(glue(cvt_u, ICVT_SIZE), _sf), F_SIZE)(ICVT_UINT a, +                                                       RoundingModeEnum rm+                                                       FFLAGS_PARAM)+{+    return glue(glue(glue(internal_cvt_i, ICVT_SIZE), _sf), F_SIZE)(a, rm, TRUE FFLAGS_ARG);+}++#undef ICVT_SIZE+#undef ICVT_INT+#undef ICVT_UINT
+ mquickjs/stdlib_wrapper.c view
@@ -0,0 +1,44 @@+/* Wrapper to include the generated stdlib definition with stub functions */+#include <stdio.h>+#include <string.h>+#include "mquickjs.h"++/* Stub implementations for required functions */+static JSValue js_date_now(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv) {+    return JS_NewFloat64(ctx, 0.0); /* TODO: implement with real time */+}++static JSValue js_print(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv) {+    int i;+    JSCStringBuf buf;+    for (i = 0; i < argc; i++) {+        if (i > 0) printf(" ");+        const char *str = JS_ToCString(ctx, argv[i], &buf);+        if (str) printf("%s", str);+    }+    printf("\n");+    return JS_UNDEFINED;+}++static JSValue js_performance_now(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv) {+    return JS_NewFloat64(ctx, 0.0); /* TODO: implement with real time */+}++static JSValue js_gc(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv) {+    JS_GC(ctx);+    return JS_UNDEFINED;+}++static JSValue js_load(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv) {+    return JS_ThrowTypeError(ctx, "load() not implemented");+}++static JSValue js_setTimeout(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv) {+    return JS_ThrowTypeError(ctx, "setTimeout() not implemented");+}++static JSValue js_clearTimeout(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv) {+    return JS_ThrowTypeError(ctx, "clearTimeout() not implemented");+}++#include "mqjs_stdlib.h"
+ src/MQuickJS.hs view
@@ -0,0 +1,615 @@+{-# LANGUAGE BangPatterns, QuasiQuotes, TemplateHaskell, OverloadedStrings, ScopedTypeVariables, FlexibleContexts #-}++{-|+Module      : MQuickJS+Description : Haskell bindings to the [Micro QuickJS](https://github.com/bellard/mquickjs) library+License     : MIT++This is a very basic wrapper for the [Micro QuickJS](https://github.com/bellard/mquickjs) library.++The current functionality includes evaluating JS code, calling a JS function in the global scope+and marshalling 'Value's to and from 'JSValue's.+-}+module MQuickJS (JSValue, JSContextPtr, mquickjs, mquickjsWithMemory, mquickjsMultithreaded, mquickjsMultithreadedWithMemory, call, eval, eval_, withJSValue, fromJSValue_) where++import           Foreign+import           Foreign.C                   (CString, CInt, CDouble, CSize)+import           Data.ByteString             (ByteString, useAsCString, useAsCStringLen, packCString)+import           Data.Text.Encoding          (encodeUtf8)+import qualified Language.C.Inline           as C+import           Control.Monad.Catch         (MonadThrow(..), MonadCatch(..), MonadMask(..), finally)+import           Control.Monad               (when, forM_)+import           Control.Monad.Reader        (MonadReader, runReaderT, ask)+import           Control.Monad.Trans.Reader  (ReaderT)+import           Control.Monad.IO.Class      (MonadIO, liftIO)+import           Control.Monad.IO.Unlift     (MonadUnliftIO(..), UnliftIO(..), askUnliftIO)+import           Data.Aeson                  (Key,Value(..), encode, toJSON)+import qualified Data.Aeson                  as Aeson+import qualified Data.Aeson.Key              as Key+import           Data.Scientific             (fromFloatDigits, toRealFloat, toBoundedInteger, isInteger)+import           Data.Text                   (Text)+import           Data.Vector                 (fromList, imapM_)+import           Data.Aeson.KeyMap         (KeyMap, empty, insert, toList)+import           Data.String.Conv            (toS)+import           Data.Time.Clock.POSIX       (posixSecondsToUTCTime)+import           Control.Concurrent          (rtsSupportsBoundThreads, runInBoundThread)++import           MQuickJS.Types+import           MQuickJS.Error+++C.context mquickjsCtx+C.include "<stddef.h>"+C.include "mquickjs.h"++-- Reference to the stdlib defined in example_stdlib.c+C.verbatim "extern const JSSTDLibraryDef js_stdlib;"++foreign import ccall "JS_NewContext"+  jsNewContext :: Ptr Word8 -> CSize -> Ptr () -> IO (Ptr JSContext)++foreign import ccall "JS_FreeContext"+  jsFreeContext :: Ptr JSContext -> IO ()++++-- Micro QuickJS uses automatic GC, no manual reference counting needed+jsFreeValue :: JSContextPtr -> JSValue -> IO ()+jsFreeValue _ _ = return ()  -- No-op in Micro QuickJS++++type JSContextPtr = Ptr JSContext+type JSValueConstPtr = Ptr JSValueConst++jsIs_ :: (MonadIO m, Storable p, Eq n, Num n) => p -> (Ptr p -> IO n) -> m Bool+jsIs_ val fun = do+  b <- liftIO $ with val fun+  return $ b == 1++-- jsIsNumber :: MonadIO m => JSValue -> m Bool+-- jsIsNumber val = jsIs_ val $ \valPtr -> [C.block| int { return JS_IsNumber(*$(JSValueConst *valPtr)); } |]++-- Micro QuickJS uses JS_GetClassID instead of JS_IsArray+jsIsArray :: MonadIO m => JSContextPtr -> JSValue -> m Bool+jsIsArray ctxPtr val = do+  classId <- liftIO $ [C.block| int { return JS_GetClassID($(JSContext *ctxPtr), $(JSValue val)); } |]+  return $ classId == 1  -- JS_CLASS_ARRAY = 1++-- Micro QuickJS uses JS_GetClassID for Date detection (JS_CLASS_DATE = 7)+jsIsDate :: MonadIO m => JSContextPtr -> JSValue -> m Bool+jsIsDate ctxPtr val = do+  classId <- liftIO $ [C.block| int { return JS_GetClassID($(JSContext *ctxPtr), $(JSValue val)); } |]+  return $ classId == 7  -- JS_CLASS_DATE = 7+++jsIsTryAll :: MonadThrow m =>+  JSValue -> [JSValue -> m Bool] -> [JSTypeEnum] -> JSTypeEnum -> m JSTypeEnum+jsIsTryAll _ [] _ def = return def+jsIsTryAll jsval (f:funs)(l:lbls) def = do+  b <- f jsval+  if b then return l else jsIsTryAll jsval funs lbls def+jsIsTryAll _ _ _ _ = throwM $ InternalError $ "jsIsTryAll_ unreachable case"+++-- Micro QuickJS type detection - simpler approach using helper functions+jsIs :: (MonadIO m, MonadThrow m) => JSContextPtr -> JSValue -> m JSTypeEnum+jsIs ctx jsval = liftIO $ do+  -- Check for exception first+  isException <- [C.block| int { return JS_IsException($(JSValue jsval)); } |]+  if isException /= 0 then return $ JSTypeFromTag JSTagException+  else do+    -- Check for null/undefined+    isNull <- [C.block| int { return $(JSValue jsval) == JS_NULL; } |]+    if isNull /= 0 then return $ JSTypeFromTag JSTagNull+    else do+      isUndef <- [C.block| int { return $(JSValue jsval) == JS_UNDEFINED; } |]+      if isUndef /= 0 then return $ JSTypeFromTag JSTagUndefined+      else do+        -- Check for boolean+        isBoolTrue <- [C.block| int { return $(JSValue jsval) == JS_TRUE; } |]+        isBoolFalse <- [C.block| int { return $(JSValue jsval) == JS_FALSE; } |]+        if isBoolTrue /= 0 || isBoolFalse /= 0 then return $ JSTypeFromTag JSTagBool+        else do+          -- Check for number (int or float)+          isNum <- [C.block| int { return JS_IsNumber($(JSContext *ctx), $(JSValue jsval)); } |]+          if isNum /= 0 then return JSIsNumber+          else do+            -- Check for string+            isStr <- [C.block| int { return JS_IsString($(JSContext *ctx), $(JSValue jsval)); } |]+            if isStr /= 0 then return $ JSTypeFromTag JSTagPtr  -- Using JSTagPtr for strings+            else do+              -- Check class ID for arrays, dates, objects+              classId <- [C.block| int { return JS_GetClassID($(JSContext *ctx), $(JSValue jsval)); } |]+              case classId of+                1 -> return JSIsArray   -- JS_CLASS_ARRAY+                7 -> return JSIsDate    -- JS_CLASS_DATE+                _ -> return $ JSTypeFromTag JSTagPtr  -- Generic object++++-- Micro QuickJS null value constant+jsNullValue :: JSValue+jsNullValue = 7  -- JS_NULL = JS_VALUE_MAKE_SPECIAL(JS_TAG_NULL, 0) = 7++-- Micro QuickJS: JS_NewBool doesn't need ctx parameter+jsNewBool :: JSContextPtr -> Bool -> IO JSValue+jsNewBool _ bool = do+  let b = if bool then 1 else 0+  return $ [C.pure| JSValue { JS_NewBool($(int b)) } |]++jsNewFloat64 :: JSContextPtr -> CDouble -> IO JSValue+jsNewFloat64 ctxPtr num =+  C.withPtr_ $ \ptr -> [C.block| void { *$(JSValue *ptr) = JS_NewFloat64($(JSContext *ctxPtr), $(double num)); } |]++jsNewInt64 :: JSContextPtr -> Int64 -> IO JSValue+jsNewInt64 ctxPtr num = do+  C.withPtr_ $ \ptr -> [C.block| void { *$(JSValue *ptr) = JS_NewInt64($(JSContext *ctxPtr), $(int64_t num)); } |]++jsNewString :: JSContextPtr -> ByteString -> IO JSValue+jsNewString ctxPtr s = C.withPtr_ $ \ptr -> useAsCStringLen s $ \(cstringPtr, cstringLen) -> do+  let len = fromIntegral cstringLen+  [C.block| void { *$(JSValue *ptr) = JS_NewStringLen($(JSContext *ctxPtr), $(const char *cstringPtr), $(size_t len)); } |]++++checkIsException :: (MonadThrow m, MonadIO m) => Text -> JSContextPtr -> JSValue -> m ()+checkIsException loc ctxPtr val = do+  isEx <- liftIO $ [C.block| int { return JS_IsException($(JSValue val)); } |]+  when (isEx /= 0) $ do+    err <- getErrorMessage ctxPtr+    throwM $ JSException loc err++++jsonToJSValue :: (MonadThrow m, MonadIO m) => JSContextPtr -> Value -> m JSValue+jsonToJSValue _ Null = pure jsNullValue+jsonToJSValue ctx (Bool b) = liftIO $ jsNewBool ctx b+jsonToJSValue ctx (Number n) =+  if not (isInteger n) then liftIO $ jsNewFloat64 ctx (toRealFloat n)+  else case toBoundedInteger n of+    Just i -> liftIO $ jsNewInt64 ctx i+    Nothing -> throwM $ InternalError "Value does not fit in Int64"+jsonToJSValue ctx (String s) = liftIO $ jsNewString ctx $ toS s+jsonToJSValue ctxPtr (Array xs) = do+  -- Micro QuickJS: JS_NewArray takes initial length parameter+  arrVal <- liftIO $ [C.block| JSValue { return JS_NewArray($(JSContext *ctxPtr), 0); } |]++  checkIsException "jsonToJSValue/Array/1" ctxPtr arrVal++  flip imapM_ xs $ \index value -> do+    val <- jsonToJSValue ctxPtr value+    checkIsException "jsonToJSValue/Array/2" ctxPtr val++    let idx = fromIntegral index+    -- Micro QuickJS: JS_SetPropertyUint32 returns JSValue (exception or undefined)+    res <- liftIO $ [C.block| JSValue {+      return JS_SetPropertyUint32($(JSContext *ctxPtr), $(JSValue arrVal), $(uint32_t idx), $(JSValue val));+    } |]+    checkIsException "jsonToJSValue/Array/set" ctxPtr res++  return arrVal+jsonToJSValue ctxPtr (Object o) = do+  objVal <- liftIO $ [C.block| JSValue { return JS_NewObject($(JSContext *ctxPtr)); } |]++  checkIsException "jsonToJSValue/Object/1" ctxPtr objVal++  forM_ (toList o) $ \(key,value) -> do+    val <- jsonToJSValue ctxPtr value+    checkIsException "jsonToJSValue/Object/2" ctxPtr val++    -- Micro QuickJS: JS_SetPropertyStr returns JSValue (exception or undefined)+    res <- liftIO $ useAsCString (encodeUtf8 $ Key.toText key) $ \cstringPtr ->+      [C.block| JSValue {+        return JS_SetPropertyStr($(JSContext *ctxPtr), $(JSValue objVal), $(const char *cstringPtr), $(JSValue val));+      } |]+    checkIsException "jsonToJSValue/Object/set" ctxPtr res++  return objVal+++-- Micro QuickJS: Use JS_ToNumber for boolean conversion (no JS_ToBool)+jsToBool :: (MonadThrow m, MonadIO m) => JSContextPtr -> JSValue -> m Bool+jsToBool ctxPtr val = do+    (res, code) <- liftIO $ C.withPtr $ \doublePtr ->+      [C.block| int { return JS_ToNumber($(JSContext *ctxPtr), $(double *doublePtr), $(JSValue val)); } |]+    if code == 0 then return (res /= 0)+    else getErrorMessage ctxPtr >>= throwM . JSException "jsToBool"++-- Micro QuickJS: Use JS_ToInt32 (no JS_ToInt64)+jsToInt64 :: (MonadThrow m, MonadIO m) => JSContextPtr -> JSValue -> m Int64+jsToInt64 ctxPtr val = do+  (res, code) <- liftIO $ C.withPtr $ \intPtr ->+    [C.block| int { return JS_ToInt32($(JSContext *ctxPtr), $(int *intPtr), $(JSValue val)); } |]+  if code == 0 then return (fromIntegral res)+  else getErrorMessage ctxPtr >>= throwM . JSException "jsToInt64"++-- Micro QuickJS: JS_ToNumber instead of JS_ToFloat64+jsToFloat64 :: (MonadThrow m, MonadIO m) => JSContextPtr -> JSValue -> m CDouble+jsToFloat64 ctxPtr val = do+  (res, code) <- liftIO $ C.withPtr $ \doublePtr ->+    [C.block| int { return JS_ToNumber($(JSContext *ctxPtr), $(double *doublePtr), $(JSValue val)); } |]+  if code == 0 then return res+  else getErrorMessage ctxPtr >>= throwM . JSException "jsToFloat64"++++-- Micro QuickJS: JS_ToCString requires JSCStringBuf parameter, no JS_FreeCString needed+jsToString :: MonadIO m => JSContextPtr -> JSValue -> m ByteString+jsToString ctxPtr val = liftIO $ do+    -- JSCStringBuf is 5 bytes+    allocaBytes 5 $ \bufPtr -> do+      cstring <- [C.block| const char * {+        return JS_ToCString($(JSContext *ctxPtr), $(JSValue val), (JSCStringBuf *)$(void *bufPtr));+      } |]+      if cstring == nullPtr then return ""+      else packCString cstring  -- No free needed in Micro QuickJS+++jsToJSON :: (MonadCatch m, MonadIO m) => JSContextPtr -> JSValue -> m Value+jsToJSON ctx jsval = do+  ty <- jsIs ctx jsval+  case ty of+    JSTypeFromTag JSTagException -> do+      err <- getErrorMessage ctx+      throwM $ JSException "jsToJSON/JSTagException" err+    JSTypeFromTag JSTagNull -> return Null+    JSTypeFromTag JSTagUndefined -> return Null+    JSTypeFromTag JSTagBool -> do+      b <- jsToBool ctx jsval+      return $ Bool b+    JSIsNumber -> do+      n <- jsToFloat64 ctx jsval+      return $ Number $ fromFloatDigits n+    JSIsArray -> do+      len <- do+        lenVal <- jsGetPropertyStr ctx jsval "length"+        len' <- jsToInt64 ctx lenVal+        return len'+      vs <- jsArrayToJSON ctx jsval 0 (fromIntegral len)+      return $ Array $ fromList vs+    JSIsDate -> do+      -- Micro QuickJS: Use stack-based calling for Date.getTime()+      timestampRaw <- liftIO $ [C.block| JSValue {+        JSValue date = $(JSValue jsval);+        JSContext *ctx = $(JSContext *ctx);+        JSValue getter = JS_GetPropertyStr(ctx, date, "getTime");+        // Stack-based call: push this, func, then call+        JS_PushArg(ctx, date);      // this+        JS_PushArg(ctx, getter);    // func+        return JS_Call(ctx, 0);     // 0 args+      } |]+      checkIsException "jsToJSON/Date" ctx timestampRaw+      timestamp <- jsToFloat64 ctx timestampRaw+      return $ toJSON $ posixSecondsToUTCTime $ realToFrac $ timestamp / 1000+    JSTypeFromTag JSTagPtr -> do+      -- JSTagPtr can be string or object - check which one+      isStr <- liftIO $ [C.block| int { return JS_IsString($(JSContext *ctx), $(JSValue jsval)); } |]+      if isStr /= 0 then do+        s <- jsToString ctx jsval+        return $ String $ toS s+      else do+        o <- jsObjectToJSON ctx jsval+        return $ Object o+    JSTypeFromTag f -> throwM $ UnsupportedTypeTag f+    JSIsError -> throwM $ InternalError "JSIsError unreachable"+++jsArrayToJSON :: (MonadCatch m, MonadIO m) => JSContextPtr -> JSValue -> Int -> Int -> m [Value]+jsArrayToJSON ctxPtr jsval index len =+  if index < len then do+    v <- do+      let idx = fromIntegral index+      val <- liftIO $ [C.block| JSValue {+        return JS_GetPropertyUint32($(JSContext *ctxPtr), $(JSValue jsval), $(uint32_t idx));+      } |]++      checkIsException "jsArrayToJSON" ctxPtr val+      jsToJSON ctxPtr val++    vs <- jsArrayToJSON ctxPtr jsval (index+1) len+    return $ v:vs+  else return []+++++++forLoop :: (Num a, Ord a, Monad m) => a -> (a -> m ()) -> m ()+forLoop end f = go 0+  where+    go !x | x < end   = f x >> go (x+1)+          | otherwise = return ()+++++-- Micro QuickJS: Use JavaScript Object.keys() for property enumeration+-- since JS_GetOwnPropertyNames is not available in the public API+jsObjectToJSON :: (MonadCatch m, MonadIO m) => JSContextPtr -> JSValue -> m (KeyMap Value)+jsObjectToJSON ctxPtr obj = do+    -- Get Object.keys(obj) via JavaScript evaluation+    keysArray <- liftIO $ [C.block| JSValue {+      JSContext *ctx = $(JSContext *ctxPtr);+      JSValue obj = $(JSValue obj);++      // Get Object constructor from global+      JSValue global = JS_GetGlobalObject(ctx);+      JSValue objectCtor = JS_GetPropertyStr(ctx, global, "Object");+      JSValue keysFunc = JS_GetPropertyStr(ctx, objectCtor, "keys");++      // Stack-based call: Object.keys(obj)+      JS_PushArg(ctx, obj);        // arg+      JS_PushArg(ctx, keysFunc);   // func+      JS_PushArg(ctx, objectCtor); // this+      return JS_Call(ctx, 1);      // 1 argument+    } |]++    checkIsException "jsObjectToJSON/keys" ctxPtr keysArray++    -- Get array length+    lenVal <- jsGetPropertyStr ctxPtr keysArray "length"+    len <- jsToInt64 ctxPtr lenVal++    -- Iterate through keys+    collectProps ctxPtr obj keysArray 0 (fromIntegral len)+  where+    collectProps :: (MonadCatch m, MonadIO m) => JSContextPtr -> JSValue -> JSValue -> Int -> Int -> m (KeyMap Value)+    collectProps ctx objVal keysArr !index end+      | index < end = do+          let idx = fromIntegral index++          -- Get key at index+          keyVal <- liftIO $ [C.block| JSValue {+            return JS_GetPropertyUint32($(JSContext *ctx), $(JSValue keysArr), $(uint32_t idx));+          } |]+          checkIsException "jsObjectToJSON/getKey" ctx keyVal+          keyStr <- jsToString ctx keyVal++          -- Get property value+          propVal <- liftIO $ useAsCString keyStr $ \ckey ->+            [C.block| JSValue {+              return JS_GetPropertyStr($(JSContext *ctx), $(JSValue objVal), $(const char *ckey));+            } |]+          checkIsException "jsObjectToJSON/getProp" ctx propVal+          val <- jsToJSON ctx propVal++          rest <- collectProps ctx objVal keysArr (index + 1) end+          return $ insert (Key.fromText $ toS keyStr) val rest++      | otherwise = return empty++++getErrorMessage :: MonadIO m => JSContextPtr -> m Text+getErrorMessage ctxPtr = liftIO $ do+  ex <- [C.block| JSValue { return JS_GetException($(JSContext *ctxPtr)); } |]+  res <- jsToString ctxPtr ex+  return $ toS res++++jsGetPropertyStr :: MonadIO m => JSContextPtr -> JSValue -> ByteString -> m JSValue+jsGetPropertyStr ctxPtr val str = liftIO $+  useAsCString str $ \prop ->+    [C.block| JSValue { return JS_GetPropertyStr($(JSContext *ctxPtr), $(JSValue val), $(const char *prop)); } |]+++-- Micro QuickJS: Stack-based function calling+-- Push args in reverse order, then func, then this, then call with argc+-- See mquickjs.c: arg[n-1] first, then ..., then arg[0], then func, then this_obj+jsCall :: JSContextPtr -> JSValue -> CInt -> (Ptr JSValue) -> IO JSValue+jsCall ctxt fun_obj argc argv = do+  -- Push arguments in reverse order (last arg first), then func, then this (JS_NULL)+  forM_ (reverse [0..(fromIntegral argc - 1)]) $ \i -> do+    arg <- peekElemOff argv i+    let argVal = arg+    [C.block| void {+      JSContext *ctx = $(JSContext *ctxt);+      JSValue v = $(JSValue argVal);+      JS_PushArg(ctx, v);+    } |]+  let funVal = fun_obj+  [C.block| void {+    JSContext *ctx = $(JSContext *ctxt);+    JS_PushArg(ctx, $(JSValue funVal));+    JS_PushArg(ctx, JS_NULL);+  } |]+  [C.block| JSValue { return JS_Call($(JSContext *ctxt), $(int argc)); } |]+++jsEval :: JSContextPtr -> CString -> CSize -> CString -> CInt -> IO JSValue+jsEval ctxPtr input input_len filename eval_flags =+  [C.block| JSValue { return JS_Eval($(JSContext *ctxPtr), $(const char *input), $(size_t input_len), $(const char *filename), $(int eval_flags)); } |]+++evalRaw :: JSContextPtr -> JSEvalType -> ByteString -> IO JSValue+evalRaw ctx eTyp code =+    useAsCString "script.js" $ \cfilename ->+        useAsCStringLen code $ \(ccode, ccode_len) ->+            jsEval ctx ccode (fromIntegral ccode_len) cfilename (toCType eTyp)+++++evalAs :: (MonadMask m, MonadReader JSContextPtr m, MonadIO m) => JSEvalType -> ByteString -> m Value+evalAs eTyp code = do+  ctx <- ask+  val <- liftIO $ evalRaw ctx eTyp code+  -- checkIsException "evalAs" ctx val+  jsToJSON ctx val `finally` freeJSValue val++++{-|+Evaluates the given string and returns a 'Value' (if the result can be converted).+-}+eval :: (MonadMask m, MonadReader JSContextPtr m, MonadIO m) => ByteString -> m Value+eval = evalAs WithRetval  -- Micro QuickJS needs JS_EVAL_RETVAL flag to return the value++evalAs_ :: (MonadThrow m, MonadReader JSContextPtr m, MonadIO m) => JSEvalType -> ByteString -> m ()+evalAs_ eTyp code = do+  ctx <- ask+  val <- liftIO $ evalRaw ctx eTyp code+  checkIsException "evalAs_" ctx val+  freeJSValue val++++{-|+More efficient than 'eval' if we don't care about the value of the expression,+e.g. if we are evaluating a function definition or performing other side-effects such as+printing to console/modifying state.+-}+eval_ :: (MonadThrow m, MonadReader JSContextPtr m, MonadIO m) => ByteString -> m ()+eval_ = evalAs_ Global+++fromJSValue_ :: (MonadCatch m, MonadReader JSContextPtr m, MonadIO m) => JSValue -> m Value+fromJSValue_ val = do+  ctx <- ask+  jsToJSON ctx val++++-- fromJSValue :: (Aeson.FromJSON a, MonadCatch m, MonadReader JSContextPtr m, MonadIO m) => JSValue -> m a+-- fromJSValue val = do+--   jsonval <- fromJSValue_ val++--   case Aeson.fromJSON jsonval of+--     Aeson.Success a -> return a+--     Aeson.Error err -> throwM $ InternalError err++++{-|+Takes a value with a defined 'ToJSON' instance. This value is marshalled to a 'JSValue'+and passed as an argument to the callback function, provided as the second argument to 'withJSValue'+-}+withJSValue :: (MonadMask m, MonadReader JSContextPtr m, MonadIO m, Aeson.ToJSON a) => a -> (JSValue -> m b) -> m b+withJSValue v f = do++  ctx <- ask+  val <- jsonToJSValue ctx (Aeson.toJSON v)+  f val `finally` freeJSValue val+++++callRaw :: (MonadThrow m, MonadIO m) => JSContextPtr -> ByteString -> [JSValue] -> m JSValue+callRaw ctxPtr funName args = do+    globalObject <- liftIO $ [C.block| JSValue { return JS_GetGlobalObject($(JSContext *ctxPtr)); } |]++    fun <- jsGetPropertyStr ctxPtr globalObject funName++    ty <- jsIs ctxPtr fun+    case ty of+      JSTypeFromTag JSTagException -> do+        err <- getErrorMessage ctxPtr+        throwM $ JSException "callRaw" err+      JSTypeFromTag JSTagUndefined -> throwM $ JSValueUndefined $ toS funName+      JSTypeFromTag JSTagPtr -> do+        -- Micro QuickJS: Stack-based calling+        res <- liftIO $ withArrayLen args $ \len argv -> jsCall ctxPtr fun (fromIntegral len) argv+        return res+      _ -> throwM $ JSValueIncorrectType {name = toS funName, expected = JSTypeFromTag JSTagPtr, found = ty }+++-- call :: (MonadThrow m, MonadReader JSContextPtr m, MonadIO m) => String -> [JSValue] -> m JSValue+-- call funName args = do+--   ctx <- ask+--   val <- callRaw ctx funName args+--   checkIsException ctx val+--   return val++++call :: (MonadMask m, MonadReader JSContextPtr m, MonadIO m) => ByteString -> [JSValue] -> m Value+call funName args = do+  ctx <- ask+  val <- callRaw ctx funName args+  jsToJSON ctx val `finally` freeJSValue val+++freeJSValue :: (MonadThrow m, MonadReader JSContextPtr m, MonadIO m) => JSValue -> m ()+freeJSValue val = do+  ctx <- ask+  liftIO $ jsFreeValue ctx val++{-|+This function initialises a new JS runtime and performs the given computation within this context.++For example, we can evaluate an expression:++>mquickjs $ do+>  res <- eval "1+2"+>  liftIO $ print res++Declare a function and call it on an argument:++>mquickjs $ do+>  _ <- eval_ "f = (x) => x+1"+>  res <- eval "f(2)"+>  liftIO $ print res++Pass a Haskell value to the JS runtime:++>mquickjs $ do+>  _ <- eval_ "f = (x) => x+1"+>  res <- withJSValue (3::Int) $ \x -> call "f" [x]+>  liftIO $ print res++-}+mquickjs :: MonadIO m => ReaderT (Ptr JSContext) m b -> m b+mquickjs = mquickjsWithMemory (10 * 1024 * 1024)  -- 10MB default++mquickjsWithMemory :: MonadIO m => Int -> ReaderT (Ptr JSContext) m b -> m b+mquickjsWithMemory memSize f = do+  (memBuf, ctx) <- liftIO $ do+    _memBuf <- mallocBytes memSize+    _ctx <- [C.block| JSContext * {+      return JS_NewContext($(uint8_t *_memBuf), $(size_t memSizeC), &js_stdlib);+    } |]+    return (_memBuf, _ctx)++  res <- runReaderT f ctx+  cleanup memBuf ctx+  return res+  where+    memSizeC = fromIntegral memSize+    cleanup memBuf ctx = liftIO $ do+      jsFreeContext ctx+      free memBuf++{-|+This env differs from regular 'mquickjs', in that it wraps the computation in the 'runInBoundThread' function.+This is needed when running the Haskell program mutithreaded (e.g. when using the testing framework Tasty),+since mquickjs does not like being called from an OS thread other than the one it was started in.+Because Haskell uses lightweight threads, this might happen if threaded mode is enabled, as is the case in Tasty.+This problem does not occur when running via Main.hs, if compiled as single threaded...+For more info see the paper [Extending the Haskell Foreign Function Interface with Concurrency](https://simonmar.github.io/bib/papers/conc-ffi.pdf)+-}+mquickjsMultithreaded :: MonadUnliftIO m => ReaderT (Ptr JSContext) m b -> m b+mquickjsMultithreaded = mquickjsMultithreadedWithMemory (10 * 1024 * 1024)  -- 10MB default++mquickjsMultithreadedWithMemory :: MonadUnliftIO m => Int -> ReaderT (Ptr JSContext) m b -> m b+mquickjsMultithreadedWithMemory memSize f+  | rtsSupportsBoundThreads = do+    (u :: UnliftIO m) <- askUnliftIO++    liftIO $ runInBoundThread $ do+      memBuf <- mallocBytes memSize+      ctx <- [C.block| JSContext * {+        return JS_NewContext($(uint8_t *memBuf), $(size_t memSizeC), &js_stdlib);+      } |]++      res <- unliftIO u $ runReaderT f ctx+      cleanup memBuf ctx+      return res+  | otherwise = mquickjsWithMemory memSize f+  where+    memSizeC = fromIntegral memSize+    cleanup memBuf ctx = do+      jsFreeContext ctx+      free memBuf
+ src/MQuickJS/Error.hs view
@@ -0,0 +1,109 @@+{-# LANGUAGE ExistentialQuantification, DuplicateRecordFields, GeneralizedNewtypeDeriving, DerivingStrategies, DeriveGeneric, RecordWildCards #-}++module MQuickJS.Error where+import           Control.Exception   (Exception(..), SomeException)+import           Data.Typeable       (cast)+import           Data.Text           (Text)+import           Data.String.Conv    (toS)+import           Type.Reflection     (Typeable)+import           GHC.Generics+import           Foreign.C.Types+import           Data.Aeson          (ToJSON(..))++import           MQuickJS.Types+++data SomeJSRuntimeException = forall e . Exception e => SomeJSRuntimeException e deriving Typeable++instance Show SomeJSRuntimeException where+    show (SomeJSRuntimeException e) = show e++instance Exception SomeJSRuntimeException++jsRuntimeExceptionToException :: Exception e => e -> SomeException+jsRuntimeExceptionToException = toException . SomeJSRuntimeException++jsRuntimeExceptionFromException :: Exception e => SomeException -> Maybe e+jsRuntimeExceptionFromException x = do+    SomeJSRuntimeException a <- fromException x+    cast a++++instance ToJSON CLong where+  toJSON cl = toJSON (fromIntegral cl :: Integer)++data UnknownJSTag = UnknownJSTag {raw_tag :: !CLong}+  deriving (Generic, Typeable)++instance Exception UnknownJSTag where+  toException   = jsRuntimeExceptionToException+  fromException = jsRuntimeExceptionFromException+++instance Show UnknownJSTag where+  show UnknownJSTag{..} = "Uknown JS tag: " ++ show raw_tag+++data UnsupportedTypeTag = UnsupportedTypeTag {_tag :: JSTagEnum}+  deriving (Generic, Typeable)++instance Exception UnsupportedTypeTag where+  toException   = jsRuntimeExceptionToException+  fromException = jsRuntimeExceptionFromException++instance Show UnsupportedTypeTag where+  show UnsupportedTypeTag{..} = "Unsupported type tag: " ++ show _tag+++data JSException = JSException {location :: Text, message :: Text}+  deriving (Generic, Typeable)++instance Exception JSException where+  toException   = jsRuntimeExceptionToException+  fromException = jsRuntimeExceptionFromException+++instance Show JSException where+    show JSException{..} = "JS runtime threw an exception in " ++ toS location ++ ":\n=================\n" ++ toS message ++ "\n=================\n"++++data JSValueUndefined = JSValueUndefined {value :: Text}+  deriving (Generic, Typeable)++instance Exception JSValueUndefined where+  toException   = jsRuntimeExceptionToException+  fromException = jsRuntimeExceptionFromException+++instance Show JSValueUndefined where+  show JSValueUndefined{..} =  "The JS value '" ++ toS value ++ "' is undefined."+++data JSValueIncorrectType =+  JSValueIncorrectType {+    name :: Text+  , expected :: JSTypeEnum+  , found :: JSTypeEnum+  }+  deriving (Generic, Typeable)++instance Exception JSValueIncorrectType where+  toException   = jsRuntimeExceptionToException+  fromException = jsRuntimeExceptionFromException+++instance Show JSValueIncorrectType where+  show JSValueIncorrectType{..} = "Type mismatch of the JS value '" ++ toS name ++ "'. Expected: " ++ show expected ++ ", found: " ++ show found+++data InternalError = InternalError { message :: Text }+  deriving (Generic, Typeable)++instance Exception InternalError where+  toException   = jsRuntimeExceptionToException+  fromException = jsRuntimeExceptionFromException++instance Show InternalError where+  show InternalError{..} = "Internal error occured:\n" ++ toS message
+ src/MQuickJS/Types.hsc view
@@ -0,0 +1,113 @@+{-# LANGUAGE QuasiQuotes, TemplateHaskell, OverloadedStrings, MultiParamTypeClasses, FlexibleInstances, GeneralizedNewtypeDeriving #-}++module MQuickJS.Types where++import qualified Data.Map                  as Map+import           Data.Bits                 (Bits)+import           Data.Word                 (Word64, Word32)+import           Foreign.C.Types+import           Foreign.Ptr               (plusPtr)+import           Foreign.Storable          (Storable(..))+import           Language.C.Inline+import           Language.C.Inline.Context (Context(..), TypesTable)+import qualified Language.C.Types          as C++#include <stddef.h>+#include "mquickjs.h"++-- Micro QuickJS uses a simple uint64_t or uint32_t for JSValue (no struct)+-- Note: We use Word64/Word32 instead of CULong/CUInt because CULong is only+-- 32 bits on Windows even on 64-bit systems (LLP64 data model), while the C+-- code uses uint64_t which is always 64 bits on 64-bit platforms.+#if INTPTR_MAX >= INT64_MAX+type JSValue = Word64  -- 64-bit (matches C's uint64_t)+#else+type JSValue = Word32  -- 32-bit (matches C's uint32_t)+#endif++type JSValueConst = JSValue++newtype JSContext = JSContext { _unusedContext :: CUChar }+++type JSBool = CInt++-- Note: JSAtom, JSPropertyEnum, and JSRefCountHeader are not exposed in Micro QuickJS public API++++class ToCType ty cty where+  toCType :: ty -> cty+++class FromCType ty cty where+  fromCType :: cty -> Maybe ty+++-- Micro QuickJS has a simpler tag system+-- Note: JS_TAG_SPECIAL is not included as a separate constructor because+-- JS_TAG_BOOL has the same value (3). The specific special tags (Bool, Null, etc.)+-- are the user-facing values.+data JSTagEnum = JSTagInt+               | JSTagPtr+               | JSTagBool+               | JSTagNull+               | JSTagUndefined+               | JSTagUninitialized+               | JSTagCatchOffset+               | JSTagException+  deriving (Show, Eq)++instance Num a => ToCType JSTagEnum a where+  toCType JSTagInt              = #{const JS_TAG_INT}+  toCType JSTagPtr              = #{const JS_TAG_PTR}+  toCType JSTagBool             = #{const JS_TAG_BOOL}+  toCType JSTagNull             = #{const JS_TAG_NULL}+  toCType JSTagUndefined        = #{const JS_TAG_UNDEFINED}+  toCType JSTagUninitialized    = #{const JS_TAG_UNINITIALIZED}+  toCType JSTagCatchOffset      = #{const JS_TAG_CATCH_OFFSET}+  toCType JSTagException        = #{const JS_TAG_EXCEPTION}+++instance (Eq a, Num a) => FromCType JSTagEnum a where+  fromCType (#{const JS_TAG_INT}) = Just JSTagInt+  fromCType (#{const JS_TAG_PTR}) = Just JSTagPtr+  fromCType (#{const JS_TAG_BOOL}) = Just JSTagBool+  fromCType (#{const JS_TAG_NULL}) = Just JSTagNull+  fromCType (#{const JS_TAG_UNDEFINED}) = Just JSTagUndefined+  fromCType (#{const JS_TAG_UNINITIALIZED}) = Just JSTagUninitialized+  fromCType (#{const JS_TAG_CATCH_OFFSET}) = Just JSTagCatchOffset+  fromCType (#{const JS_TAG_EXCEPTION}) = Just JSTagException+  fromCType _ = Nothing++data JSTypeEnum = JSTypeFromTag JSTagEnum+                | JSIsNumber+                | JSIsArray+                | JSIsDate+                | JSIsError+  deriving Show++-- Micro QuickJS eval flags (different from original QuickJS)+data JSEvalType = Global | WithRetval++instance Num a => ToCType JSEvalType a where+  toCType Global = 0  -- No special flags for global eval+  toCType WithRetval = #{const JS_EVAL_RETVAL}  -- Return last value instead of undefined+++mquickjsCtx :: Context+mquickjsCtx = baseCtx <> fptrCtx <> ctx+  where+    ctx = mempty+      { ctxTypesTable = mquickjsTypesTable+      }++mquickjsTypesTable :: TypesTable+mquickjsTypesTable = Map.fromList+  [+    (C.TypeName "JSValue", [t| JSValue |])+  , (C.TypeName "JSValueConst", [t| JSValueConst |])+  , (C.TypeName "JSContext", [t| JSContext |])+  , (C.TypeName "JSBool", [t| JSBool |])+  ]+
+ test/Spec.hs view
@@ -0,0 +1,904 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++module Main where++import           Test.Tasty              (TestTree, testGroup, defaultMain, after, DependencyType(..))+import           Test.Tasty.HUnit        (testCase, assertBool)+import           Test.Tasty.QuickCheck   (testProperty, QuickCheckTests(..), QuickCheckVerbose(..))+import           Test.HUnit              (Assertion, (@?=), assertFailure)+import qualified Test.QuickCheck         as QC+import qualified Test.QuickCheck.Monadic as QC+import           Data.Aeson              (Value(..))+import           Control.Monad.IO.Class  (liftIO)+import           Control.Monad.Catch     (try, SomeException, MonadCatch(..))+import           Data.Text               (pack)+import qualified Data.HashMap.Strict            as HM+import qualified Data.Aeson.KeyMap             as KM+import qualified Data.Aeson.Key             as K+import qualified Data.Vector             as V+import           MQuickJS+import           MQuickJS.Error (SomeJSRuntimeException, JSValueUndefined, JSException)+import           Control.Monad (guard)+import qualified Data.Text as T++genText  = do+  k <- QC.choose (0,200)+  t <- pack <$> QC.vectorOf k (QC.oneof $ map pure $ ['0'..'~'])+  pure t+++genVal 0 = QC.oneof+  [+    String <$> genText+  , Number . fromInteger <$> QC.arbitrary+  , Bool <$> QC.arbitrary+  , pure Null+  ]+genVal n | n > 0 = QC.oneof+  [+    do { k <- QC.choose (0,n) ; Object . KM.fromList <$> (zip <$> QC.vectorOf k (K.fromText <$> genText) <*> QC.vectorOf k genVal') }+  , do { k <- QC.choose (0,n) ; Array . V.fromList <$> QC.vectorOf k genVal' }+  , String <$> genText+  , Number . fromInteger <$> QC.arbitrary+  , Bool <$> QC.arbitrary+  , pure Null+  ]+  where genVal' = genVal (n `div` 2)++-- | There's an Arbitrary instance for Value floating around, but our tests don't pass+--   with it because it produces null characters in text. These are not valid+--   javascript strings, so we have our own.+newtype GenVal = GenVal Value deriving Show+instance QC.Arbitrary GenVal where+  arbitrary = GenVal <$> QC.sized genVal++marshall_to_from_JSValue :: GenVal -> QC.Property+marshall_to_from_JSValue (GenVal val) = QC.monadicIO $ do+  val' <- QC.run $ mquickjsMultithreaded $ withJSValue val $ \jsval ->+    fromJSValue_ jsval+  pure $ (val QC.=== val')++-- | Basic evaluation tests+evalTests :: TestTree+evalTests = testGroup "eval"+  [ testCase "simple arithmetic" $ mquickjsMultithreaded $ do+      v <- eval "1 + 2;"+      liftIO $ v @?= Number 3++  , testCase "multiplication" $ mquickjsMultithreaded $ do+      v <- eval "6 * 7;"+      liftIO $ v @?= Number 42++  , testCase "division returns float" $ mquickjsMultithreaded $ do+      v <- eval "10 / 4;"+      liftIO $ v @?= Number 2.5++  , testCase "modulo operator" $ mquickjsMultithreaded $ do+      v <- eval "17 % 5;"+      liftIO $ v @?= Number 2++  , testCase "negative numbers" $ mquickjsMultithreaded $ do+      v <- eval "-42;"+      liftIO $ v @?= Number (-42)++  , testCase "floating point arithmetic" $ mquickjsMultithreaded $ do+      v <- eval "3.14 * 2;"+      liftIO $ v @?= Number 6.28++  , testCase "string literal" $ mquickjsMultithreaded $ do+      v <- eval "'hello';"+      liftIO $ v @?= String "hello"++  , testCase "string concatenation" $ mquickjsMultithreaded $ do+      v <- eval "'hello' + ' ' + 'world';"+      liftIO $ v @?= String "hello world"++  , testCase "boolean true" $ mquickjsMultithreaded $ do+      v <- eval "true;"+      liftIO $ v @?= Bool True++  , testCase "boolean false" $ mquickjsMultithreaded $ do+      v <- eval "false;"+      liftIO $ v @?= Bool False++  , testCase "boolean expression" $ mquickjsMultithreaded $ do+      v <- eval "5 > 3;"+      liftIO $ v @?= Bool True++  , testCase "null value" $ mquickjsMultithreaded $ do+      v <- eval "null;"+      liftIO $ v @?= Null++  , testCase "undefined becomes null" $ mquickjsMultithreaded $ do+      v <- eval "undefined;"+      liftIO $ v @?= Null++  , testCase "array literal" $ mquickjsMultithreaded $ do+      v <- eval "[1, 2, 3];"+      liftIO $ v @?= Array (V.fromList [Number 1, Number 2, Number 3])++  , testCase "empty array" $ mquickjsMultithreaded $ do+      v <- eval "[];"+      liftIO $ v @?= Array V.empty++  , testCase "mixed array" $ mquickjsMultithreaded $ do+      v <- eval "[1, 'two', true, null];"+      liftIO $ v @?= Array (V.fromList [Number 1, String "two", Bool True, Null])++  , testCase "object literal" $ mquickjsMultithreaded $ do+      v <- eval "({a: 1, b: 2});"+      liftIO $ v @?= Object (KM.fromList [(K.fromText "a", Number 1), (K.fromText "b", Number 2)])++  , testCase "empty object" $ mquickjsMultithreaded $ do+      v <- eval "({});"+      liftIO $ v @?= Object KM.empty++  , testCase "nested object" $ mquickjsMultithreaded $ do+      v <- eval "({outer: {inner: 42}});"+      liftIO $ v @?= Object (KM.fromList [(K.fromText "outer", Object (KM.fromList [(K.fromText "inner", Number 42)]))])++  , testCase "nested array" $ mquickjsMultithreaded $ do+      v <- eval "[[1, 2], [3, 4]];"+      liftIO $ v @?= Array (V.fromList [Array (V.fromList [Number 1, Number 2]), Array (V.fromList [Number 3, Number 4])])++  , testCase "ternary operator" $ mquickjsMultithreaded $ do+      v <- eval "true ? 'yes' : 'no';"+      liftIO $ v @?= String "yes"++  , testCase "logical AND" $ mquickjsMultithreaded $ do+      v <- eval "true && false;"+      liftIO $ v @?= Bool False++  , testCase "logical OR" $ mquickjsMultithreaded $ do+      v <- eval "true || false;"+      liftIO $ v @?= Bool True++  , testCase "equality check" $ mquickjsMultithreaded $ do+      v <- eval "5 === 5;"+      liftIO $ v @?= Bool True++  , testCase "inequality check" $ mquickjsMultithreaded $ do+      v <- eval "5 !== 3;"+      liftIO $ v @?= Bool True+  ]++-- | Function definition and calling tests+-- Note: Micro QuickJS has limited ES6 support - no arrow functions, const/let, etc.+functionTests :: TestTree+functionTests = testGroup "functions"+  [ testCase "define and call simple function" $ mquickjsMultithreaded $ do+      eval_ "function add(a, b) { return a + b; }"+      v <- eval "add(2, 3);"+      liftIO $ v @?= Number 5++  , testCase "function with var" $ mquickjsMultithreaded $ do+      eval_ "function double(x) { return x * 2; }"+      v <- eval "double(21);"+      liftIO $ v @?= Number 42++  , testCase "call with withJSValue" $ mquickjsMultithreaded $ do+      eval_ "function increment(x) { return x + 1; }"+      v <- withJSValue (5 :: Int) $ \x -> call "increment" [x]+      liftIO $ v @?= Number 6++  , testCase "call with multiple args" $ mquickjsMultithreaded $ do+      eval_ "function subtract(a, b) { return a - b; }"+      v <- withJSValue (10 :: Int) $ \a ->+           withJSValue (3 :: Int) $ \b ->+             call "subtract" [a, b]+      liftIO $ v @?= Number 7++  , testCase "call with string argument" $ mquickjsMultithreaded $ do+      eval_ "function greet(name) { return 'Hello, ' + name + '!'; }"+      v <- withJSValue ("World" :: T.Text) $ \name -> call "greet" [name]+      liftIO $ v @?= String "Hello, World!"++  , testCase "call with array argument" $ mquickjsMultithreaded $ do+      eval_ "function sumArray(arr) { var total = 0; for (var i = 0; i < arr.length; i++) { total = total + arr[i]; } return total; }"+      v <- withJSValue ([1, 2, 3, 4, 5] :: [Int]) $ \arr -> call "sumArray" [arr]+      liftIO $ v @?= Number 15++  , testCase "call with object argument" $ mquickjsMultithreaded $ do+      eval_ "function getField(obj) { return obj.value; }"+      let obj = Object (KM.fromList [(K.fromText "value", Number 99)])+      v <- withJSValue obj $ \o -> call "getField" [o]+      liftIO $ v @?= Number 99++  , testCase "function returning object" $ mquickjsMultithreaded $ do+      eval_ "function makePoint(x, y) { return {x: x, y: y}; }"+      v <- eval "makePoint(10, 20);"+      liftIO $ v @?= Object (KM.fromList [(K.fromText "x", Number 10), (K.fromText "y", Number 20)])++  , testCase "function returning array" $ mquickjsMultithreaded $ do+      eval_ "function makeArray(n) { var arr = []; for (var i = 0; i < n; i++) { arr.push(i); } return arr; }"+      v <- eval "makeArray(5);"+      liftIO $ v @?= Array (V.fromList [Number 0, Number 1, Number 2, Number 3, Number 4])++  , testCase "recursive function" $ mquickjsMultithreaded $ do+      eval_ "function factorial(n) { return n <= 1 ? 1 : n * factorial(n - 1); }"+      v <- eval "factorial(5);"+      liftIO $ v @?= Number 120++  , testCase "closure" $ mquickjsMultithreaded $ do+      eval_ "function makeCounter() { var count = 0; return function() { count = count + 1; return count; }; }"+      eval_ "var counter = makeCounter();"+      v1 <- eval "counter();"+      v2 <- eval "counter();"+      v3 <- eval "counter();"+      liftIO $ v1 @?= Number 1+      liftIO $ v2 @?= Number 2+      liftIO $ v3 @?= Number 3++  , testCase "higher-order function" $ mquickjsMultithreaded $ do+      eval_ "function apply(f, x) { return f(x); }"+      eval_ "function square(x) { return x * x; }"+      v <- eval "apply(square, 5);"+      liftIO $ v @?= Number 25+  ]++-- | Error handling tests+errorTests :: TestTree+errorTests = testGroup "error handling"+  [ testCase "throw string" $ mquickjsMultithreaded $+      try (eval "throw 'Error'") >>= \case+        Left (_ :: SomeJSRuntimeException) -> return ()+        Right _ -> liftIO $ assertFailure "should fail with an Exception..."++  , testCase "throw Error object" $ mquickjsMultithreaded $+      try (eval "throw new Error('Something went wrong')") >>= \case+        Left (_ :: SomeJSRuntimeException) -> return ()+        Right _ -> liftIO $ assertFailure "should fail with an Exception..."++  , testCase "reference error" $ mquickjsMultithreaded $+      try (eval "nonExistentVariable") >>= \case+        Left (_ :: SomeJSRuntimeException) -> return ()+        Right _ -> liftIO $ assertFailure "should fail with ReferenceError..."++  , testCase "syntax error" $ mquickjsMultithreaded $+      try (eval "function {") >>= \case+        Left (_ :: SomeJSRuntimeException) -> return ()+        Right _ -> liftIO $ assertFailure "should fail with SyntaxError..."++  , testCase "type error" $ mquickjsMultithreaded $+      try (eval "null.foo") >>= \case+        Left (_ :: SomeJSRuntimeException) -> return ()+        Right _ -> liftIO $ assertFailure "should fail with TypeError..."++  , testCase "call undefined function" $ mquickjsMultithreaded $+      try (call "nonExistentFunction" []) >>= \case+        Left (_ :: SomeJSRuntimeException) -> return ()+        Right _ -> liftIO $ assertFailure "should fail when calling undefined function..."++  , testCase "division by zero returns infinity" $ mquickjsMultithreaded $ do+      v <- eval "1 / 0;"+      -- JavaScript returns Infinity for division by zero+      case v of+        Number n -> liftIO $ assertBool "should be infinite" (isInfinite (fromRational (toRational n) :: Double))+        _ -> liftIO $ assertFailure "expected Number"+  ]++-- | String handling tests+-- Note: Micro QuickJS has limited ES6 support - no template literals+stringTests :: TestTree+stringTests = testGroup "strings"+  [ testCase "empty string" $ mquickjsMultithreaded $ do+      v <- eval "''"+      liftIO $ v @?= String ""++  , testCase "string with spaces" $ mquickjsMultithreaded $ do+      v <- eval "'  hello  '"+      liftIO $ v @?= String "  hello  "++  , testCase "string length" $ mquickjsMultithreaded $ do+      v <- eval "'hello'.length"+      liftIO $ v @?= Number 5++  , testCase "string methods - toUpperCase" $ mquickjsMultithreaded $ do+      v <- eval "'hello'.toUpperCase()"+      liftIO $ v @?= String "HELLO"++  , testCase "string methods - toLowerCase" $ mquickjsMultithreaded $ do+      v <- eval "'HELLO'.toLowerCase()"+      liftIO $ v @?= String "hello"++  , testCase "string methods - substring" $ mquickjsMultithreaded $ do+      v <- eval "'hello world'.substring(0, 5)"+      liftIO $ v @?= String "hello"++  , testCase "string methods - split" $ mquickjsMultithreaded $ do+      v <- eval "'a,b,c'.split(',')"+      liftIO $ v @?= Array (V.fromList [String "a", String "b", String "c"])++  , testCase "string methods - trim" $ mquickjsMultithreaded $ do+      v <- eval "'  hello  '.trim()"+      liftIO $ v @?= String "hello"++  , testCase "string with newlines" $ mquickjsMultithreaded $ do+      v <- eval "'line1\\nline2'"+      liftIO $ v @?= String "line1\nline2"++  , testCase "string with tabs" $ mquickjsMultithreaded $ do+      v <- eval "'col1\\tcol2'"+      liftIO $ v @?= String "col1\tcol2"++  , testCase "string with special chars" $ mquickjsMultithreaded $ do+      v <- eval "'hello\\\\world'"+      liftIO $ v @?= String "hello\\world"++  , testCase "string with quotes" $ mquickjsMultithreaded $ do+      v <- eval "'it\\'s a test'"+      liftIO $ v @?= String "it's a test"++  , testCase "string concatenation interpolation" $ mquickjsMultithreaded $ do+      eval_ "var name = 'world'"+      v <- eval "'hello ' + name"+      liftIO $ v @?= String "hello world"+  ]++-- | Array operation tests+-- Note: Micro QuickJS has limited ES6 array methods, using ES5-compatible approaches+arrayTests :: TestTree+arrayTests = testGroup "arrays"+  [ testCase "array length" $ mquickjsMultithreaded $ do+      v <- eval "[1, 2, 3].length"+      liftIO $ v @?= Number 3++  , testCase "array indexing" $ mquickjsMultithreaded $ do+      v <- eval "[10, 20, 30][1]"+      liftIO $ v @?= Number 20++  , testCase "array push and access" $ mquickjsMultithreaded $ do+      eval_ "var arr = [1, 2]; arr.push(3);"+      v <- eval "arr"+      liftIO $ v @?= Array (V.fromList [Number 1, Number 2, Number 3])++  , testCase "array pop" $ mquickjsMultithreaded $ do+      v <- eval "var arr = [1, 2, 3]; arr.pop()"+      liftIO $ v @?= Number 3++  , testCase "array shift" $ mquickjsMultithreaded $ do+      v <- eval "var arr = [1, 2, 3]; arr.shift()"+      liftIO $ v @?= Number 1++  , testCase "array unshift" $ mquickjsMultithreaded $ do+      eval_ "var arr = [2, 3]; arr.unshift(1);"+      v <- eval "arr"+      liftIO $ v @?= Array (V.fromList [Number 1, Number 2, Number 3])++  , testCase "array concat" $ mquickjsMultithreaded $ do+      v <- eval "[1, 2].concat([3, 4])"+      liftIO $ v @?= Array (V.fromList [Number 1, Number 2, Number 3, Number 4])++  , testCase "array slice" $ mquickjsMultithreaded $ do+      v <- eval "[1, 2, 3, 4, 5].slice(1, 4)"+      liftIO $ v @?= Array (V.fromList [Number 2, Number 3, Number 4])++  , testCase "array reverse" $ mquickjsMultithreaded $ do+      v <- eval "[1, 2, 3].reverse()"+      liftIO $ v @?= Array (V.fromList [Number 3, Number 2, Number 1])++  , testCase "array join" $ mquickjsMultithreaded $ do+      v <- eval "[1, 2, 3].join('-')"+      liftIO $ v @?= String "1-2-3"++  , testCase "array indexOf" $ mquickjsMultithreaded $ do+      v <- eval "[1, 2, 3, 2].indexOf(2)"+      liftIO $ v @?= Number 1++  , testCase "array lastIndexOf" $ mquickjsMultithreaded $ do+      v <- eval "[1, 2, 3, 2].lastIndexOf(2)"+      liftIO $ v @?= Number 3++  , testCase "array sort numbers" $ mquickjsMultithreaded $ do+      eval_ "function compareNumbers(a, b) { return a - b; }"+      v <- eval "[3, 1, 4, 1, 5].sort(compareNumbers)"+      liftIO $ v @?= Array (V.fromList [Number 1, Number 1, Number 3, Number 4, Number 5])++  , testCase "array sort strings" $ mquickjsMultithreaded $ do+      v <- eval "['banana', 'apple', 'cherry'].sort()"+      liftIO $ v @?= Array (V.fromList [String "apple", String "banana", String "cherry"])++  , testCase "array splice" $ mquickjsMultithreaded $ do+      eval_ "var arr = [1, 2, 3, 4, 5]; arr.splice(2, 2);"+      v <- eval "arr"+      liftIO $ v @?= Array (V.fromList [Number 1, Number 2, Number 5])+  ]++-- | Object operation tests+-- Note: Micro QuickJS has limited ES6 support - using ES5 compatible patterns+objectTests :: TestTree+objectTests = testGroup "objects"+  [ testCase "object property access dot notation" $ mquickjsMultithreaded $ do+      v <- eval "({a: 1, b: 2}).a"+      liftIO $ v @?= Number 1++  , testCase "object property access bracket notation" $ mquickjsMultithreaded $ do+      v <- eval "({a: 1, b: 2})['b']"+      liftIO $ v @?= Number 2++  , testCase "Object.keys" $ mquickjsMultithreaded $ do+      v <- eval "Object.keys({a: 1, b: 2, c: 3})"+      liftIO $ v @?= Array (V.fromList [String "a", String "b", String "c"])++  , testCase "nested property access" $ mquickjsMultithreaded $ do+      v <- eval "({outer: {inner: {value: 42}}}).outer.inner.value"+      liftIO $ v @?= Number 42++  , testCase "object with method" $ mquickjsMultithreaded $ do+      v <- eval "({value: 5, double: function() { return this.value * 2; }}).double()"+      liftIO $ v @?= Number 10++  , testCase "object property assignment" $ mquickjsMultithreaded $ do+      eval_ "var obj = {}; obj.x = 10; obj.y = 20;"+      v <- eval "obj"+      liftIO $ v @?= Object (KM.fromList [(K.fromText "x", Number 10), (K.fromText "y", Number 20)])++  , testCase "delete object property" $ mquickjsMultithreaded $ do+      eval_ "var obj = {a: 1, b: 2}; delete obj.a;"+      v <- eval "obj"+      liftIO $ v @?= Object (KM.fromList [(K.fromText "b", Number 2)])++  , testCase "in operator" $ mquickjsMultithreaded $ do+      v <- eval "'a' in {a: 1, b: 2}"+      liftIO $ v @?= Bool True++  , testCase "hasOwnProperty" $ mquickjsMultithreaded $ do+      v <- eval "({a: 1}).hasOwnProperty('a')"+      liftIO $ v @?= Bool True++  , testCase "object with array property" $ mquickjsMultithreaded $ do+      v <- eval "({items: [1, 2, 3]}).items"+      liftIO $ v @?= Array (V.fromList [Number 1, Number 2, Number 3])+  ]++-- | Built-in Math tests+mathTests :: TestTree+mathTests = testGroup "Math"+  [ testCase "Math.PI" $ mquickjsMultithreaded $ do+      Number v <- eval "Math.PI"+      liftIO $ assertBool "PI should be approximately 3.14159" (abs (realToFrac v - 3.14159265358979) < 0.00001)++  , testCase "Math.abs" $ mquickjsMultithreaded $ do+      v <- eval "Math.abs(-42)"+      liftIO $ v @?= Number 42++  , testCase "Math.floor" $ mquickjsMultithreaded $ do+      v <- eval "Math.floor(3.7)"+      liftIO $ v @?= Number 3++  , testCase "Math.ceil" $ mquickjsMultithreaded $ do+      v <- eval "Math.ceil(3.2)"+      liftIO $ v @?= Number 4++  , testCase "Math.round" $ mquickjsMultithreaded $ do+      v <- eval "Math.round(3.5)"+      liftIO $ v @?= Number 4++  , testCase "Math.max" $ mquickjsMultithreaded $ do+      v <- eval "Math.max(1, 5, 3)"+      liftIO $ v @?= Number 5++  , testCase "Math.min" $ mquickjsMultithreaded $ do+      v <- eval "Math.min(1, 5, 3)"+      liftIO $ v @?= Number 1++  , testCase "Math.pow" $ mquickjsMultithreaded $ do+      v <- eval "Math.pow(2, 10)"+      liftIO $ v @?= Number 1024++  , testCase "Math.sqrt" $ mquickjsMultithreaded $ do+      v <- eval "Math.sqrt(16)"+      liftIO $ v @?= Number 4++  , testCase "Math.random produces number between 0 and 1" $ mquickjsMultithreaded $ do+      Number v <- eval "Math.random()"+      liftIO $ assertBool "random should be >= 0 and < 1" (v >= 0 && v < 1)+  ]++-- | JSON tests+jsonTests :: TestTree+jsonTests = testGroup "JSON"+  [ testCase "JSON.stringify object" $ mquickjsMultithreaded $ do+      v <- eval "JSON.stringify({a: 1, b: 2})"+      -- Note: key order may vary+      case v of+        String s -> liftIO $ assertBool "should contain expected content"+          (T.isInfixOf "\"a\":1" s && T.isInfixOf "\"b\":2" s)+        _ -> liftIO $ assertFailure "expected String"++  , testCase "JSON.stringify array" $ mquickjsMultithreaded $ do+      v <- eval "JSON.stringify([1, 2, 3])"+      liftIO $ v @?= String "[1,2,3]"++  , testCase "JSON.parse object" $ mquickjsMultithreaded $ do+      v <- eval "JSON.parse('{\"x\": 10, \"y\": 20}')"+      liftIO $ v @?= Object (KM.fromList [(K.fromText "x", Number 10), (K.fromText "y", Number 20)])++  , testCase "JSON.parse array" $ mquickjsMultithreaded $ do+      v <- eval "JSON.parse('[1, 2, 3]')"+      liftIO $ v @?= Array (V.fromList [Number 1, Number 2, Number 3])++  , testCase "JSON roundtrip" $ mquickjsMultithreaded $ do+      v <- eval "JSON.parse(JSON.stringify({nested: {value: 42}}))"+      liftIO $ v @?= Object (KM.fromList [(K.fromText "nested", Object (KM.fromList [(K.fromText "value", Number 42)]))])+  ]++-- | Edge cases and special values tests+-- Note: Micro QuickJS has limited ES6 support - using ES5 compatible patterns+edgeCaseTests :: TestTree+edgeCaseTests = testGroup "edge cases"+  [ testCase "large integer" $ mquickjsMultithreaded $ do+      v <- eval "1000000000"+      liftIO $ v @?= Number 1000000000++  , testCase "very small float" $ mquickjsMultithreaded $ do+      Number v <- eval "0.0000001"+      liftIO $ assertBool "should be small positive number" (v > 0 && v < 0.001)++  , testCase "NaN check" $ mquickjsMultithreaded $ do+      v <- eval "isNaN(NaN)"+      liftIO $ v @?= Bool True++  , testCase "Infinity" $ mquickjsMultithreaded $ do+      v <- eval "Infinity > 1000000"+      liftIO $ v @?= Bool True++  , testCase "negative Infinity" $ mquickjsMultithreaded $ do+      v <- eval "-Infinity < -1000000"+      liftIO $ v @?= Bool True++  , testCase "multiple statements with var" $ mquickjsMultithreaded $ do+      v <- eval "var x = 5; var y = 10; x + y;"+      liftIO $ v @?= Number 15++  , testCase "var declaration" $ mquickjsMultithreaded $ do+      eval_ "var PI = 3.14159"+      v <- eval "PI"+      liftIO $ v @?= Number 3.14159++  , testCase "var reassignment" $ mquickjsMultithreaded $ do+      eval_ "var counter = 0"+      eval_ "counter = counter + 1"+      v <- eval "counter"+      liftIO $ v @?= Number 1++  , testCase "typeof operator" $ mquickjsMultithreaded $ do+      v1 <- eval "typeof 42"+      v2 <- eval "typeof 'hello'"+      v3 <- eval "typeof true"+      v4 <- eval "typeof {}"+      v5 <- eval "typeof []"+      liftIO $ v1 @?= String "number"+      liftIO $ v2 @?= String "string"+      liftIO $ v3 @?= String "boolean"+      liftIO $ v4 @?= String "object"+      liftIO $ v5 @?= String "object"++  , testCase "array with many elements" $ mquickjsMultithreaded $ do+      eval_ "function makeArray(n) { var arr = []; for (var i = 0; i < n; i++) { arr.push(i); } return arr; }"+      v <- eval "makeArray(100)"+      case v of+        Array arr -> liftIO $ V.length arr @?= 100+        _ -> liftIO $ assertFailure "expected Array"++  , testCase "deeply nested structure" $ mquickjsMultithreaded $ do+      v <- eval "({a: {b: {c: {d: {e: 'deep'}}}}})"+      liftIO $ v @?= Object (KM.fromList+        [(K.fromText "a", Object (KM.fromList+          [(K.fromText "b", Object (KM.fromList+            [(K.fromText "c", Object (KM.fromList+              [(K.fromText "d", Object (KM.fromList+                [(K.fromText "e", String "deep")]))]))]))]))])++  , testCase "scientific notation" $ mquickjsMultithreaded $ do+      v <- eval "1e6"+      liftIO $ v @?= Number 1000000++  , testCase "hexadecimal" $ mquickjsMultithreaded $ do+      v <- eval "0xFF"+      liftIO $ v @?= Number 255++  , testCase "binary literal" $ mquickjsMultithreaded $ do+      v <- eval "parseInt('1010', 2)"+      liftIO $ v @?= Number 10+  ]++-- | Control flow tests+-- Note: Micro QuickJS has limited ES6 support - using ES5 compatible patterns+controlFlowTests :: TestTree+controlFlowTests = testGroup "control flow"+  [ testCase "if-else expression" $ mquickjsMultithreaded $ do+      eval_ "function test(x) { if (x > 0) { return 'positive'; } else { return 'non-positive'; } }"+      v1 <- eval "test(5)"+      v2 <- eval "test(-5)"+      liftIO $ v1 @?= String "positive"+      liftIO $ v2 @?= String "non-positive"++  , testCase "for loop" $ mquickjsMultithreaded $ do+      eval_ "function sumTo(n) { var sum = 0; for (var i = 1; i <= n; i++) { sum = sum + i; } return sum; }"+      v <- eval "sumTo(10)"+      liftIO $ v @?= Number 55++  , testCase "while loop" $ mquickjsMultithreaded $ do+      eval_ "function countdown(n) { var result = []; while (n > 0) { result.push(n); n = n - 1; } return result; }"+      v <- eval "countdown(5)"+      liftIO $ v @?= Array (V.fromList [Number 5, Number 4, Number 3, Number 2, Number 1])++  , testCase "for-in loop" $ mquickjsMultithreaded $ do+      eval_ "function getKeys(obj) { var keys = []; for (var k in obj) { keys.push(k); } return keys; }"+      v <- eval "getKeys({a: 1, b: 2})"+      liftIO $ v @?= Array (V.fromList [String "a", String "b"])++  , testCase "switch statement" $ mquickjsMultithreaded $ do+      eval_ "function dayName(n) { switch(n) { case 0: return 'Sunday'; case 1: return 'Monday'; default: return 'Other'; } }"+      v1 <- eval "dayName(0)"+      v2 <- eval "dayName(1)"+      v3 <- eval "dayName(5)"+      liftIO $ v1 @?= String "Sunday"+      liftIO $ v2 @?= String "Monday"+      liftIO $ v3 @?= String "Other"++  , testCase "try-catch in JS" $ mquickjsMultithreaded $ do+      eval_ "function safeDiv(a, b) { try { if (b === 0) throw 'Division by zero'; return a / b; } catch(e) { return null; } }"+      v1 <- eval "safeDiv(10, 2)"+      v2 <- eval "safeDiv(10, 0)"+      liftIO $ v1 @?= Number 5+      liftIO $ v2 @?= Null++  , testCase "do-while loop" $ mquickjsMultithreaded $ do+      eval_ "function doWhileTest() { var x = 0; do { x = x + 1; } while (x < 5); return x; }"+      v <- eval "doWhileTest()"+      liftIO $ v @?= Number 5++  , testCase "break statement" $ mquickjsMultithreaded $ do+      eval_ "function findFirst(arr, target) { for (var i = 0; i < arr.length; i++) { if (arr[i] === target) { return i; } } return -1; }"+      v <- eval "findFirst([1, 2, 3, 4, 5], 3)"+      liftIO $ v @?= Number 2++  , testCase "continue statement" $ mquickjsMultithreaded $ do+      eval_ "function sumEven(n) { var sum = 0; for (var i = 1; i <= n; i++) { if (i % 2 !== 0) continue; sum = sum + i; } return sum; }"+      v <- eval "sumEven(10)"+      liftIO $ v @?= Number 30+  ]++-- | Tests for different entry point functions+entryPointTests :: TestTree+entryPointTests = testGroup "entry points"+  [ testCase "mquickjs basic eval" $ mquickjs $ do+      v <- eval "1 + 2"+      liftIO $ v @?= Number 3++  , testCase "mquickjsWithMemory basic eval" $ mquickjsWithMemory (10 * 1024 * 1024) $ do+      v <- eval "1 + 2"+      liftIO $ v @?= Number 3++  , testCase "mquickjsMultithreaded basic eval" $ mquickjsMultithreaded $ do+      v <- eval "1 + 2"+      liftIO $ v @?= Number 3++  , testCase "mquickjsMultithreadedWithMemory basic eval" $ mquickjsMultithreadedWithMemory (10 * 1024 * 1024) $ do+      v <- eval "1 + 2"+      liftIO $ v @?= Number 3++  , testCase "mquickjsWithMemory custom allocation" $ mquickjsWithMemory (50 * 1024 * 1024) $ do+      -- Test with larger memory allocation+      eval_ "var arr = []; for (var i = 0; i < 10000; i++) { arr.push({index: i, data: 'test'}); }"+      v <- eval "arr.length"+      liftIO $ v @?= Number 10000++  , testCase "mquickjsMultithreadedWithMemory custom allocation" $ mquickjsMultithreadedWithMemory (50 * 1024 * 1024) $ do+      -- Test with larger memory allocation+      eval_ "var arr = []; for (var i = 0; i < 10000; i++) { arr.push({index: i, data: 'test'}); }"+      v <- eval "arr.length"+      liftIO $ v @?= Number 10000+  ]++-- | Tests for Haskell-JavaScript interop via withJSValue and call+interopTests :: TestTree+interopTests = testGroup "Haskell-JS interop"+  [ testCase "pass Int to JS" $ mquickjsMultithreaded $ do+      eval_ "function identity(x) { return x; }"+      v <- withJSValue (42 :: Int) $ \x -> call "identity" [x]+      liftIO $ v @?= Number 42++  , testCase "pass negative Int to JS" $ mquickjsMultithreaded $ do+      eval_ "function identity(x) { return x; }"+      v <- withJSValue ((-100) :: Int) $ \x -> call "identity" [x]+      liftIO $ v @?= Number (-100)++  , testCase "pass Double to JS" $ mquickjsMultithreaded $ do+      eval_ "function identity(x) { return x; }"+      v <- withJSValue (3.14159 :: Double) $ \x -> call "identity" [x]+      case v of+        Number n -> liftIO $ assertBool "should be close to pi" (abs (realToFrac n - 3.14159) < 0.0001)+        _ -> liftIO $ assertFailure "expected Number"++  , testCase "pass Bool True to JS" $ mquickjsMultithreaded $ do+      eval_ "function identity(x) { return x; }"+      v <- withJSValue True $ \x -> call "identity" [x]+      liftIO $ v @?= Bool True++  , testCase "pass Bool False to JS" $ mquickjsMultithreaded $ do+      eval_ "function identity(x) { return x; }"+      v <- withJSValue False $ \x -> call "identity" [x]+      liftIO $ v @?= Bool False++  , testCase "pass Null to JS" $ mquickjsMultithreaded $ do+      eval_ "function identity(x) { return x; }"+      v <- withJSValue Null $ \x -> call "identity" [x]+      liftIO $ v @?= Null++  , testCase "pass Text to JS" $ mquickjsMultithreaded $ do+      eval_ "function identity(x) { return x; }"+      v <- withJSValue ("hello world" :: T.Text) $ \x -> call "identity" [x]+      liftIO $ v @?= String "hello world"++  , testCase "pass empty Text to JS" $ mquickjsMultithreaded $ do+      eval_ "function identity(x) { return x; }"+      v <- withJSValue ("" :: T.Text) $ \x -> call "identity" [x]+      liftIO $ v @?= String ""++  , testCase "pass list of Ints to JS" $ mquickjsMultithreaded $ do+      eval_ "function identity(x) { return x; }"+      v <- withJSValue ([1, 2, 3] :: [Int]) $ \x -> call "identity" [x]+      liftIO $ v @?= Array (V.fromList [Number 1, Number 2, Number 3])++  , testCase "pass empty list to JS" $ mquickjsMultithreaded $ do+      eval_ "function identity(x) { return x; }"+      v <- withJSValue ([] :: [Int]) $ \x -> call "identity" [x]+      liftIO $ v @?= Array V.empty++  , testCase "pass nested list to JS" $ mquickjsMultithreaded $ do+      eval_ "function identity(x) { return x; }"+      v <- withJSValue ([[1, 2], [3, 4]] :: [[Int]]) $ \x -> call "identity" [x]+      liftIO $ v @?= Array (V.fromList [Array (V.fromList [Number 1, Number 2]), Array (V.fromList [Number 3, Number 4])])++  , testCase "pass Aeson Object to JS" $ mquickjsMultithreaded $ do+      eval_ "function identity(x) { return x; }"+      let obj = Object (KM.fromList [(K.fromText "name", String "test"), (K.fromText "value", Number 42)])+      v <- withJSValue obj $ \x -> call "identity" [x]+      liftIO $ v @?= obj++  , testCase "pass empty Object to JS" $ mquickjsMultithreaded $ do+      eval_ "function identity(x) { return x; }"+      let obj = Object KM.empty+      v <- withJSValue obj $ \x -> call "identity" [x]+      liftIO $ v @?= obj++  , testCase "pass nested Object to JS" $ mquickjsMultithreaded $ do+      eval_ "function identity(x) { return x; }"+      let inner = Object (KM.fromList [(K.fromText "value", Number 99)])+      let obj = Object (KM.fromList [(K.fromText "nested", inner)])+      v <- withJSValue obj $ \x -> call "identity" [x]+      liftIO $ v @?= obj++  , testCase "JS function transforms Haskell Int" $ mquickjsMultithreaded $ do+      eval_ "function double(x) { return x * 2; }"+      v <- withJSValue (21 :: Int) $ \x -> call "double" [x]+      liftIO $ v @?= Number 42++  , testCase "JS function transforms Haskell String" $ mquickjsMultithreaded $ do+      eval_ "function shout(s) { return s.toUpperCase() + '!'; }"+      v <- withJSValue ("hello" :: T.Text) $ \x -> call "shout" [x]+      liftIO $ v @?= String "HELLO!"++  , testCase "JS function transforms Haskell Array" $ mquickjsMultithreaded $ do+      eval_ "function sumArray(arr) { var sum = 0; for (var i = 0; i < arr.length; i++) { sum = sum + arr[i]; } return sum; }"+      v <- withJSValue ([1, 2, 3, 4, 5] :: [Int]) $ \arr -> call "sumArray" [arr]+      liftIO $ v @?= Number 15++  , testCase "JS function extracts Object field" $ mquickjsMultithreaded $ do+      eval_ "function getName(obj) { return obj.name; }"+      let obj = Object (KM.fromList [(K.fromText "name", String "Alice"), (K.fromText "age", Number 30)])+      v <- withJSValue obj $ \x -> call "getName" [x]+      liftIO $ v @?= String "Alice"++  , testCase "JS function modifies Object" $ mquickjsMultithreaded $ do+      eval_ "function addField(obj) { obj.added = true; return obj; }"+      let obj = Object (KM.fromList [(K.fromText "original", Number 1)])+      v <- withJSValue obj $ \x -> call "addField" [x]+      liftIO $ v @?= Object (KM.fromList [(K.fromText "original", Number 1), (K.fromText "added", Bool True)])++  , testCase "pass multiple different types" $ mquickjsMultithreaded $ do+      -- Note: Test with single argument to avoid argument order issues+      eval_ "function formatValue(val) { return 'value: ' + val; }"+      v <- withJSValue (42 :: Int) $ \num -> call "formatValue" [num]+      liftIO $ v @?= String "value: 42"++  , testCase "nested withJSValue calls" $ mquickjsMultithreaded $ do+      eval_ "function add(a, b) { return a + b; }"+      v <- withJSValue (10 :: Int) $ \a -> do+             withJSValue (20 :: Int) $ \b -> do+               call "add" [a, b]+      liftIO $ v @?= Number 30++  , testCase "call function with zero arguments" $ mquickjsMultithreaded $ do+      eval_ "function getFortyTwo() { return 42; }"+      v <- call "getFortyTwo" []+      liftIO $ v @?= Number 42++  , testCase "call function that returns undefined" $ mquickjsMultithreaded $ do+      eval_ "function returnNothing() { }"+      v <- call "returnNothing" []+      liftIO $ v @?= Null++  , testCase "pass array and get element back" $ mquickjsMultithreaded $ do+      eval_ "function getSecond(arr) { return arr[1]; }"+      v <- withJSValue ([10, 20, 30] :: [Int]) $ \arr -> call "getSecond" [arr]+      liftIO $ v @?= Number 20++  , testCase "pass object and get nested value" $ mquickjsMultithreaded $ do+      eval_ "function getDeep(obj) { return obj.level1.level2.value; }"+      let obj = Object (KM.fromList+            [(K.fromText "level1", Object (KM.fromList+              [(K.fromText "level2", Object (KM.fromList+                [(K.fromText "value", Number 999)]))]))])+      v <- withJSValue obj $ \x -> call "getDeep" [x]+      liftIO $ v @?= Number 999++  , testCase "JS modifies array elements" $ mquickjsMultithreaded $ do+      eval_ "function doubleAll(arr) { var result = []; for (var i = 0; i < arr.length; i++) { result.push(arr[i] * 2); } return result; }"+      v <- withJSValue ([1, 2, 3] :: [Int]) $ \arr -> call "doubleAll" [arr]+      liftIO $ v @?= Array (V.fromList [Number 2, Number 4, Number 6])++  , testCase "roundtrip complex structure" $ mquickjsMultithreaded $ do+      eval_ "function identity(x) { return x; }"+      let complex = Object (KM.fromList+            [ (K.fromText "name", String "test")+            , (K.fromText "values", Array (V.fromList [Number 1, Number 2, Number 3]))+            , (K.fromText "nested", Object (KM.fromList [(K.fromText "flag", Bool True)]))+            , (K.fromText "nothing", Null)+            ])+      v <- withJSValue complex $ \x -> call "identity" [x]+      liftIO $ v @?= complex++  , testCase "use Haskell value in JS expression via global" $ mquickjsMultithreaded $ do+      -- Declare global variable first, then set it+      eval_ "var globalValue = 0;"+      eval_ "function setGlobal(val) { globalValue = val; }"+      eval_ "function useGlobal() { return globalValue * 2; }"+      _ <- withJSValue (21 :: Int) $ \x -> call "setGlobal" [x]+      v <- call "useGlobal" []+      liftIO $ v @?= Number 42++  , testCase "multiple sequential calls" $ mquickjsMultithreaded $ do+      eval_ "var accumulator = 0;"+      eval_ "function addTo(x) { accumulator = accumulator + x; return accumulator; }"+      v1 <- withJSValue (10 :: Int) $ \x -> call "addTo" [x]+      v2 <- withJSValue (20 :: Int) $ \x -> call "addTo" [x]+      v3 <- withJSValue (12 :: Int) $ \x -> call "addTo" [x]+      liftIO $ v1 @?= Number 10+      liftIO $ v2 @?= Number 30+      liftIO $ v3 @?= Number 42++  , testCase "pass mixed array to JS" $ mquickjsMultithreaded $ do+      eval_ "function getTypes(arr) { var types = []; for (var i = 0; i < arr.length; i++) { types.push(typeof arr[i]); } return types; }"+      let mixed = Array (V.fromList [Number 1, String "two", Bool True, Null])+      v <- withJSValue mixed $ \arr -> call "getTypes" [arr]+      liftIO $ v @?= Array (V.fromList [String "number", String "string", String "boolean", String "object"])+  ]++tests :: TestTree+tests =+  -- adjustOption (\_ -> QuickCheckTests 10) $+  -- adjustOption (\_ -> QuickCheckVerbose True) $+  testGroup "MQuickJS"+    [ testCase "empty mquickjs call" (mquickjsMultithreaded $ pure ())+    , entryPointTests+    , evalTests+    , functionTests+    , errorTests+    , stringTests+    , arrayTests+    , objectTests+    , mathTests+    , jsonTests+    , edgeCaseTests+    , controlFlowTests+    , interopTests+    , testProperty "marshalling Value to JSValue and back" marshall_to_from_JSValue+    ]++main = defaultMain tests